前言
linux kernel主要通过三类机制实现SMP系统CPU core的电源管理功能:
- cpu hotplug。根据应用场景,enable/disable CPU core.
- cpuidle framework。在没有进程调度的时候,让CPU core进入idle状态.
- cpufreq framework。根据使用场景和系统负荷,调整CPU core的电压(voltage)和频率(frequency).
对CPU core来说,功耗和性能是一对不可调和的矛盾,通过调整CPU的电压和频率,可以在功耗和性能之间找一个平衡点。
由于调整是在系统运行的过程中,因此cpufreq framework的功能也称作动态电压/频率调整(Dynamic Voltage/Frequency Scaling,DVFS)。
cpufreq framework概述
cpufreq framework的核心功能,是通过调整CPU core的电压和频率,兼顾系统的性能和功耗。在不需要高性能时,降低电压和频率,以降低功耗;在需要高性能时,提高电压和频率,以提高性能。
cpufreq framework中的几个概念:policy(策略)选择合适调频范围,governor(调节器)来决定如何计算合适的频率,cpufreq_driver来实现真正的调频工作(平台相关)
cpufreq framework实现了两种调频方式:
- 对于可以自动调频的CPU,CPU根据自身的负荷,自动调整电压和频率,cpufreq framework只需提供频率的调整范围,和大致的应用场景(例如,是高性能场景,还是低性能场景),无需governor参与。
- 对于不可以自动调频的CPU,需要governor根据应用场景计算合适的频率,通过driver控制CPU的频率和电压(基于clock framework和regulator framework)。
常用governor类型
- 性能(Performance):总是将CPU置于最高能耗也是最高性能的状态,即硬件所支持的最高频/最高压。
- 节能(Powersaving):总是将CPU置于最低能耗也是最差性能的状态,即硬件所支持的最低频/最低压。
- 按需(Ondemand):设置CPU负载的阈值T,当负载低于T时,调节至一个刚好能够满足当前负载需求的最低频/最低压;当负载高于T时,立即提升到最高性能状态。
- 保守(Conservative):跟Ondemand策略类似,设置CPU负载的阈值T,当负载低于T时,调节至一个刚好能够满足当前负载需求的最低频/最低压;但当负载高于T时,不是立即设置为最高性能状态,而是逐级升高主频/电压。
- 用户(Userspace):将控制接口通过sysfs开放给用户,由用户进行自定义策略。
- 调度信息(Schedutil):这是从Linux-4.7版本开始才引入的策略,其原理是根据调度器所提供的CPU利用率信息进行电压/频率调节,效果上类似于Ondemand策略,但是更加精确和自然(因为调度器掌握了最好的CPU使用情况)。
用户层接口
sysfs目录在/sys/devices/system/cpu/cpu0/cpufreq
名称 | 说明 |
---|---|
cpuinfo_max_freq/cpuinfo_min_freq | CPU 硬件所支持的最高运行频率及最低运行频率 |
cpuinfo_cur_freq | 从 CPU 硬件寄存器中读取 CPU 当前所处的运行频率 |
affected_cpus | 该cpufreq策略影响到哪些cpu(没有显示处于offline状态的cpu) |
related_cpus | 该cpufreq策略影响到哪些cpu(包括了online+offline的所有cpu) |
scaling_max_freq/scaling_min_freq | cpufreq策略支持的最高运行频率及最低运行频率 |
scaling_cur_freq | cpufreq策略当前设置的运行频率 |
scaling_available_governors | 当前系统支持的governors |
scaling_available_frequencies | 支持的调频频率 |
scaling_driver | 当前使用的调频驱动 |
scaling_governor | 当前使用的governor |
scaling_setspeed | 需将governor切换为userspace才能使用,往这个文件echo数值,会切换频率 |
以下是将governor切换为ondemand后生成的ondemand文件夹下出现的配置文件 | |
sampling_rate | 当前使用的采样间隔,单位:微秒 |
sampling_rate_min | 允许使用的最短采样间隔 |
sampling_rate_max | 允许使用的最长采样间隔 |
up_threshold | 阈值,系统负载超过该值时,governor会自动提高CPU的运行频率 |
ignore_nice_load | 可以设置为0或1(0 是默认设置)。当这个参数设置为 1 时,任何具有“nice”值的处理器不计入总处理器利用率。在设置为0时,所有处理器都计入利用率。 |
cpufreq 软件架构
本节从概念上介绍软件架构分层,以及各部分的主要功能和相关结构体的主要成员,具体实现下节介绍。
- cpufreq core:把一些公共的逻辑和接口代码抽象出来,这些代码与平台无关,也与governor无关.
- governor core:governor计算合适的频率,需要我们提供必要的频率范围和参数(阈值等),governor core把一些公共的逻辑和接口代码抽象出来,这些代码与具体的governor无关
- governor:具体的governor实现,每种governor计算频率的方式不同,governor的实现与平台无关.
- cpufreq driver:完成平台相关的初始化,基于cpu subsystem driver、OPP、clock framework、regulator framework等模块,提供对CPU频率和电压的控制。
cpufreq core
cpufreq core是cpufreq framework的核心模块,和kernel其它framework类似,它主要实现三类功能:
- 对上,以sysfs的形式向用户空间提供统一的接口,以notifier的形式向其它driver提供频率变化的通知;
- 对下,提供CPU频率和电压控制的驱动框架,方便底层driver的开发;同时,提供governor框架,用于实现不同的频率调整机制;
- 内部,封装各种逻辑,实现所需功能。这些逻辑主要围绕
struct cpufreq_policy
、struct cpufreq_driver
和struct cpufreq_governor
三个数据结构进行。
struct cpufreq_policy
kernel使用cpufreq policy(即“调频策略”)来抽象cpufreq。所谓的调频策略,即频率调整的范围,它从一定程度上,代表了cpufreq的属性。这就是struct cpufreq_policy结构的含义。
kernel抽象出一个CPU bus,所有的CPU device都挂在这个bus上。cpufreq是CPU device的一类特定功能,被抽象为一个subsys interface(kernel使用struct subsys_interface
结构表示),bus下所有的这一类特定功能(subsys interface)都挂载在bus的struct subsys_private
变量的“interface”链表上
简单来讲就是将cpufreq_freq作为所有cpu设备的一个功能,注册到了cpu_subsys总线上,匹配过程如下
(1)register_cpu
1 | //drivers/base/cpu.c |
每个cpu都将自己的dev注册到cpu_subsys总线的bus->p->klist_devices
(2)cpufreq初始化
1 | //driver/cpufreq/cpufreq.c |
理解了cpufreq_policy在总线上的结构之后,我们继续看他的定义
1 | //driver/cpufreq/cpufreq.h |
有些平台,所有cpu core的频率和电压时统一控制的,即改变某个core上的频率,其它core同样受影响。此时只需要实现其中一个core(通常为cpu0)的cpufreq即可,其它core的cpufreq直接是cpu0的符号链接。
而另一些些平台,不同core可以单独控制,这时不同cpu目录下的cpufreq就不一样了。
到底某一个cpufreq可以控制多少cpu core呢?可通过affected_cpus和related_cpus两个sysfs文件查看,区别是:affected_cpus表示该cpufreq影响到哪些cpu(没有显示处于offline状态的cpu),related_cpus则包括了online+offline的所有cpu。affected_cpus对应policy->cpus
,related_cpus对应policy->related_cpus
struct cpufreq_driver
struct cpufreq_driver用于抽象cpufreq驱动,是平台驱动工程师关注最多的结构,其定义如下:
1 | //driver/cpufreq/cpufreq.h |
struct cpufreq_governor
对于不能自动调频的CPU,必须由软件计算合适的频率。根据使用场景的不同,会有不同的方案,这是由governor模块负责的
1 | //driver/cpufreq/cpufreq.h |
cpufreq driver
实现cpufreq core抽象出来的struct cpufreq_driver
回调函数,平台相关
cpufreq governor
cpufreq governor模块需要实现cpufreq core抽象出来的struct cpufreq_governor
,内核提供了多种governor,在之前的内核版本中,每种governor几乎是独立的代码,它们各自用自己的方式实现对系统的负载进行监测,很多时候,检测的逻辑其实是很相似的,各个governor最大的不同之处其实是根据检测的结果,计算合适频率的方式。所以,为了减少代码的重复,在新版本中将一些公共的逻辑代码被单独抽象出来(drivers/cpufreq/cpufreq_governor.c
),不同的governor实现回调函数即可。
struct dbs_governor
是核心数据结构:
1 | //drivers/cpufreq/cpufreq_governor.h |
struct dbs_data
是governor计算频率使用的相关参数,包括阈值,采样率等
1 | //drivers/cpufreq/cpufreq_governor.h |
struct policy_dbs_info
是policy和governor传递的私有数据,可以将他看成struct dbs_data
的封装
1 | //drivers/cpufreq/cpufreq_governor.h |
struct cpu_dbs_info
把计算cpu负载需要使用到的一些辅助变量整合在了一起,percpu变量
1 | //drivers/cpufreq/cpufreq_governor.h |
cpufreq core
上节介绍了各个数据结构主要内容,本节通过cpufreq的初始化流程入手来了解动态调频的相关功能。
cpufreq_register_driver
函数为cpufreq驱动注册的入口,驱动程序通过调用该函数进行初始化,并传入相关的的struct cpufreq_driver
,介绍struct cpufreq_policy
时提到cpufreq_register_driver
会调用subsys_interface_register
,最终执行回调函数cpufreq_add_dev
,下面来详细介绍一下
1 | //driver/cpufreq/cpufreq.c |
(1)cpufreq_global_kobject
1 | //driver/cpufreq/cpufreq.c |
(2)约束条件
即policy->max和policy->min,限制动态调频的最大/小值,为了管理该约束条件,引入了cpufreq Qos策略,详见后文《freq Qos策略和限频流程》
(3)cpufreq notifiers
cpufreq的通知系统使用了内核的标准通知接口。它对外提供了两个通知事件:policy通知和transition通知。
policy通知用于通知其它模块policy改变,事件分别是:
- CPUFREQ_CREATE_POLICY===>cpufreq_online
- CPUFREQ_REMOVE_POLICY====>cpufreq_policy_free
transition通知链用于在驱动实施调整cpu的频率时,用于通知相关的注册者。每次调整频率时,该通知会发出两次通知事件:
- CPUFREQ_PRECHANGE 调整前的通知。
- CPUFREQ_POSTCHANGE 完成调整后的通知。
对应结构体
SRCU_NOTIFIER_HEAD_STATIC(cpufreq_transition_notifier_list);
static BLOCKING_NOTIFIER_HEAD(cpufreq_policy_notifier_list);
(4)cpufreq_add_dev_interface
创建sys节点,/sys/device/system/cpu/cpufreq/policyx目录下的一些可选属性,包括
- driver提供一些额外的sysfs attribute(需要驱动支持,cpufreq_driver->attr)
- cpuinfo_cur_freq:cpu当前运行频率(需要驱动支持cpufreq_driver->get)
- scaling_cur_freq:policy当前设置的运行频率(必定创建)
- bios_limit:硬件限制(需要驱动支持cpufreq_driver->bios_limit)
(5)CONFIG_CPU_FREQ_STAT功能
记录每个CPU在policy中各个频率的时间,单位为 jiffies,对应节点如下
1 | root@kylin-cp302l2:/sys/devices/system/cpu/cpu0/cpufreq/stats |
当cpufreq policy频率改变完成时,cpufreq driver通过cpufreq_freq_transition_end->cpufreq_notify_transition(CPUFREQ_POSTCHANGE)
发出通知,最终cpufreq_stats模块cpufreq_stats_record_transition
函数记录切换到哪一个目标频点并更新对应的时间。
cpufreq_stats模块代码位于drivers/cpufreq/cpufreq_stats.c
(6)CONFIG_CPU_FREQ_TIMES功能
记录每个进程在policy中各个频率的时间, 单位为每个tick的时间,对应节点如下
1 | root@kylin-cp302l2:/proc/1099 |
- 当cpufreq policy频率改变完成时,cpufreq driver通过
cpufreq_freq_transition_end->cpufreq_notify_transition(CPUFREQ_POSTCHANGE)
发出通知,最终cpufreq_times模块cpufreq_times_record_transition
函数记录切换到哪一个目标频点。 - cputime模块接收到timer中断后,会调用
cpufreq_acct_update_power
将该tick添加到cpufreq_times模块当前任务的频点统计上。
cpufreq_stats模块代码位于drivers/cpufreq/cpufreq_times.c
上面这两个功能必须要有freq table
(7)使用默认governor初始化policy
实现setpolicy则直接调用该回调,若实现target,则初始化相关governor,详见下节《cpufreq governor》
(8)温控设备联动
cpufreq driver
cpufreq driver主要完成平台相关的CPU频率/电压的控制,它在cpufreq framework中是非常简单的一个模块,主要包括:
- 平台相关的初始化动作,包括cpu的clock/regulator获取、初始化等。
- 生成frequency table,即cpu所支持的频率/电压列表。
- 定义一个
struct cpufreq_driver
变量,填充必要的字段,并根据平台的特性,实现其中的回调函数。 - 调用
cpufreq_register_driver
将driver注册到cpufreq framework中。 - cpufreq core会在CPU设备添加时,调用
driver->init
接口。driver需要在该接口中初始化struct cpufreq_policy
变量。 - 系统运行过程中,cpufreq core会根据实际情况,调用driver的setpolicy或者target/target_index等接口,设置CPU的调频策略或者频率值。
- 系统suspend的时中,会将CPU的频率设置为指定的值,或者调用driver的suspend回调函数;系统resume时,调用driver的resume回调函数。
frequency table
frequency table是CPU core可以正确运行的一组频率/电压组合,之所以存在的一个思考点是:table是频率和电压之间的一个一一对应的组合,因此cpufreq framework只需要关心频率,所有的策略都称做“调频”策略。而cpufreq driver可以在“调频”的同时,通过table取出和频率对应的电压,进行修改CPU core电压,实现“调压”的功能,这简化了设计。
1 | //driver/cpufreq/cpufreq.h |
名称 | 说明 |
---|---|
flags | CPUFREQ_BOOST_FREQ,表示这个频率值是一个boost频率 |
driver_data | 由driver使用,具体意义由driver定义,例如电压 |
frequency | 频率值(kHz),无需排序。 CPUFREQ_ENTRY_INVALID:无效频率值 CPUFREQ_TABLE_END:表示table的结束 |
Boost表示智能超频技术,是一个在x86平台上的功能,具体可参考“turbo-boost-technology.html”,本文不做过多描述。
init
init回调函数主要功能就是初始化struct cpufreq_policy
,对driver而言,不太关心其的内部实现,其实cpufreq framework也在努力实现这个目标,包括将相应的初始化过程封装成一个API等,主要关心的成员:
- cpus:告诉cpufreq core,该policy适用于哪些cpu。大多数情况下,系统中所有的cpu都有相同的硬件逻辑,因此只需要一个policy,就可以管理所有的cpu core。
- clk:clock指针,cpufreq core可以利用该指针,获取当前实际的频率值。
- cpuinfo:该cpu调频相关的固定信息,包括最大频率、最小频率、切换延迟,其中最大频率、最小频率可以通过frequency table推导得出。
- min、max:调频策略所对应的最小频率、最大频率,初始化时,可以和上面的cpuinfo中的min、max相同。
- freq_table:对应的frequency table。
cpuinfo、min、max、freq_table等都可以通过cpufreq core提供的cpufreq_generic_init接口初始化:
1 | //driver/cpufreq/cpufreq.c |
该接口以需要初始化的policy、frequency table以及切换延迟为参数,从table中解析policy初始化所需的信息,初始化policy。
一般情况下,在init中调用cpufreq_generic_init即可。
verify
当上层软件需要设定一个新的policy的时候,会调用driver->verify
,检查该policy是否合法。cpufreq core封装了下面两个接口,辅助完成这个功能:
1 | //drivers/cpufreq/freq_table.c |
cpufreq_frequency_table_verify
根据指定的frequency table,检查policy是否合法,检查逻辑很简单:policy的频率范围{min,max},是否超出policy->cpuinfo的频率范围,是否超出frequency table中的频率范围。cpufreq_generic_frequency_table_verify
是前者的封装,使用policy->freq_table。
cpufreq framework中“频率”的几个层次。
(1))最底层:frequency table中定义的频率,有限的离散频率,代表了cpu的调频能力。
(2)往上,是policy->cpuinfo中的频率范围,它对cpu调频进行的简单的限制,该限制可以和frequency table一致,也可以小于table中的范围。必须在driver初始化时给定,之后不能再修改。
(3)再往上,是policy的频率范围,代表调频策略。对于可以自动调频的CPU,只需要把这个范围告知CPU即可,此时它是调频的基本单位。对于不可以自动调频的CPU,它是软件层面的一个限制。该范围可以通过sysfs修改。
(4)最上面,是policy->cur,对那些不可以调频的CPU,该值就是CPU的运行频率。
setpolicy
对于可以自动调频的CPU,driver需要提供该接口,通过该接口,将调频范围告知CPU。
target
不建议使用了,就不讲了。
target_index
对于不可以自动调频的CPU,该接口用于指定CPU的运行频率。index表示frequency table中的index。
driver需要通过index,将频率值取出,通过clock framework提供的API,将CPU的频率设置为对应的值。
同时,driver可以调用OPP interface,获取该频率对应的电压值,通过regulator framework提供的API,将CPU的电压设置为对应的值。
get
用于获取指定cpu的频率值,如果可以的话,driver应尽可能提供。如果在init接口中给policy->clk
赋值的话,则可以使用cpufreq framework提供的通用接口:
1 | //driver/cpufreq/cpufreq.c |
该接口会直接调用clock framework API,从policy->clk中获取频率值。
freq_attr
如果cpufreq driver需要提供一些额外的sysfs attribute,可以通过如下的attribute宏设置,然后保存在cpufreq_driver->attr
数组中,例如freq table,内核已经定义好cpufreq_freq_attr_scaling_available_freqs
,可直接使用
1 | //include/linux/cpufreq.h |
其他
- exit,和init对应,在CPU device被remove时调用。
- stop_cpu,在CPU被stop时调用。
- suspend、resume回调函数:系统给suspend的时候,clock、regulator等driver有可能被suspend,因此需要在这之前将CPU设置为一个确定的频率值。driver可以通过suspend回调设置,也可以通过policy中的suspend_freq字段设置(cpufreq core会自动切换)
cpufreq governor
注册cpufreq_governor
系统中可以同时存在多个governor,一个policy通过cpufreq_policy->governor指针和某个governor相关联。要想一个governor能够被使用,首先要把该governor注册到cpufreq framework中
1 | //driver/cpufreq/cpufreq.c |
cpufreq core定义了一个全局链表变量:cpufreq_governor_list
,注册函数首先根据governor的名称,通过__find_governor()函数查找该governor是否已經被注册过,如果没有被注册过,则把代表该governor的结构体添加到cpufreq_governor_list链表中。
该函数会在所有governor模块驱动的入口函数调用,只要编译该模块,就会注册到cpufreq framework中
初始化流程
内核通过CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE
配置来指定一个默认的governor,即def_gov。
若要使用传统的governor初始化,需要cpufreq_driver提供target接口,例如intel_pstate(启动参数添加intel_pstate=passive)
在动态调频驱动初始化流程如下
1 | //driver/cpufreq/cpufreq.c |
(1)如果驱动提供了driver->setpolicy
回调,则说明CPU可以在policy指定的频率范围内,自行确定运行频率,无需governor参与。但如果此时的governor是performace和powersave两种,则有必要通知到驱动,以便driver->setpolicy
接口可以根据实际情况正确设置频率范围。
通过policy->policy
变量通知驱动,可选值:CPUFREQ_POLICY_PERFORMANCE和CPUFREQ_POLICY_POWERSAVE
接下来调用cpufreq_set_policy
1 | //driver/cpufreq/cpufreq.c |
1 | //driver/cpufreq/cpufreq_governor.c |
(1)governor core将一些通用的初始化放到一起,调用通用的初始化函数cpufreq_dbs_governor_init
(2)policy_dbs是dbs_data的封装,policy_dbs保存在每个cpu的policy结构体中,当cpufreq_driver->flag
存在CPUFREQ_HAVE_GOVERNOR_PER_POLICY
,表示不同的CPU,有不同的频率控制方式,若没有该标志,则将policy_dbs->dbs_data
保存在governor->gdbs_data
(即共用该结构)。
启动governor
1 | cpufreq_start_governor(policy); |
启动governor中比较重要的是设置调频回调函数,该函数是真正调频时计算合适频率的函数
计算方式简介
例如ondemand策略中的调频接口od_dbs_update
1 | //drivers/cpufreq/cpufreq_ondemand.c |
(1)当前负载load = 100 * (time_elapsed - idle_time) / time_elapsed
idle_time = 本次idle时间 - 上次idle时间
time_elapsed = 本次总运行时间 - 上次总运行时间
(2)表明我们为了进一步节省电力,我们希望在计算出来的新频率的基础上,再乘以一个powersave_bias设定的百分比,作为真正的运行频率,powersave_bias的值从0-1000,每一步代表0.1%
powersave_bias可参考Documentation/admin-guide/pm/cpufreq.rst:514
cpufreq 频率设置函数分析
上述文章介绍了cpufreq framework各部分功能即初始化过程,本节介绍调频流程。
performance 和 powersave让 CPU 一直跑在最高/低频率,没有调频过程。
ondemand 和 conservation则和调度器有关。
ondemand 和 conservation 之前的调频方式是开启一个 timer,定期去计算各个 CPU 的负载,在commit
cpufreq: governor: Replace timers with utilization update callbacks之后则改为和调度器相关
percpu变量update_util_data
是调度器与调频驱动沟通的桥梁,cpufreq_update_util
函数访问其中的回调函数进行调频。
1 | //kernel/sched/cpufreq.c |
触发调频的时机,以调度节拍为例,调度器CFS
1 | 时钟中断 --> |
前面介绍启动governor时中注册了调频函数dbs_update_util_handler
,下面分析一下调频流程
1 | //driver/cpufreq/cpufreq_governor.c |
对于可以自动调频的CPU,driver中同样调用cpufreq_add_update_util_hook
来注册调频函数,原理同上。
freq Qos和限频流程
freq Qos主要用于cpufreq framework中policy->max和policy->min的调整。简单来说每个policy对应最大频率和最小频率两个约束,某个模块想要更改policy的频率限制时,就会调用相关接口向freq Qos中请求,freq Qos根据自己的规则判断使用哪个频率限制,若有更新则利用notifier block通知cpufreq framework更新policy。
本节介绍freq Qos的设计实现,并结合cpufrq framework说明如何应用。
初始化
1 | //kernel/power/qos.c |
新分配一个freq_constraints
结构后可以直接调用freq_constraints_init
,函数中分别对min_freq和max_freq进行初始化
注意其type的初始化:min_freq
这个限制赋值的type竟然是PM_QOS_MAX
,而max_freq
这个限制赋值的type竟然是PM_QOS_MIN
!
这样当限制最大频率的时候,pm_qos_constraints->list
链表上生效的就是最小值,也就是说对最大频率的限制,谁限制的小谁生效。当限制最小频率的时候,pm_qos_constraints->list
链表上生效的就是最大值,也就是说对最小频率的限制,谁限制的大谁生效。在后续函数介绍中还会详细说明。
通知机制
1 | //kernel/power/qos.c |
注册一个notifier,在频率限制生效时,会发出一个通知
规则
在初始化的时候提到过,对最大频率的限制,谁限制的小谁生效;对最小频率的限制,谁限制的大谁生效。体现在函数pm_qos_get_value
,该函数从当前freq Qos中选择一个合适的频率限制
1 |
|
pm_qos_constraints->list
链表是由小到大排列的,min_freq这个限制的type是PM_QOS_MAX,则返回最后一个元素,即最大值,而max_freq这个限制的type是PM_QOS_MIN,则返回第一个元素,即最小值,这就是freq Qos的核心规则。
添加请求
1 | //kernel/power/qos.c |
可以发现freq_qos_add_request最终调用pm_qos_update_target,向min或max添加请求,如下
1 | //kernel/power/qos.c |
到这里可以发现,我们添加了频率限制,不一定就会更新,要满足规则才可以。
另外还有一个函数freq_qos_update_request,它会清空所有的request,重新添加当前request
1 |
|
用户层使用echo xx > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
,实际驱动就是调用了freq_qos_update_reques
频率限制更新
下面列出cpufreq framework注册的回调函数的频率限制更新流程
1 | //driver/cpufreq/cpufreq.c |
超频
mips上的自动调核
参考资料
本文为学习以下资料,汇总整理所记笔记,侵删。
属性说明
https://blog.csdn.net/leerobin83/article/details/7476386
流程介绍
https://blog.csdn.net/DroidPhone/article/details/9346981
https://blog.csdn.net/DroidPhone/article/details/9385745
https://blog.csdn.net/droidphone/article/details/9532999
调频时机
https://www.cnblogs.com/hellokitty2/p/14909197.html
http://kernel.meizu.com/cpufreq-sched.html
https://www.cnblogs.com/hellokitty2/p/15690200.html
wowo科技的cpufreq架构介绍
http://www.wowotech.net/pm_subsystem/cpufreq_overview.html
http://www.wowotech.net/pm_subsystem/cpufreq_driver.html
http://www.wowotech.net/pm_subsystem/cpufreq_core.html
http://www.wowotech.net/pm_subsystem/cpufreq_governor.html
Qos策略,freq Qos和限制频率流程
https://www.cnblogs.com/hellokitty2/p/15685048.html
超频介绍
https://blog.csdn.net/yin262/article/details/45697221
时间统计功能
https://blog.csdn.net/feelabclihu/article/details/121299114