linux cpufreq framework(4)_cpufreq governor
作者:wowo 发布于:2015-8-23 21:15 分类:电源管理子系统
1. 前言
由“linux cpufreq framework(3)_cpufreq core”的描述可知,cpufreq policy负责设定cpu调频的一个大致范围,而cpu的具体运行频率,则需要由相应的cufreq governor决定(可自行调节频率的CPU除外,后面会再详细介绍)。那到底什么是cpufreq governor?它的运行机制是什么?这就是本文要描述的内容。
2. cpufreq governor的实现
2.1 struct cpufreq_governor
kernel通过struct cpufreq_governor抽象cpufreq governor,如下:
1: /* include/linux/cpufreq.h */
2: struct cpufreq_governor {
3: char name[CPUFREQ_NAME_LEN];
4: int initialized;
5: int (*governor) (struct cpufreq_policy *policy,6: unsigned int event);7: ssize_t (*show_setspeed) (struct cpufreq_policy *policy,
8: char *buf);
9: int (*store_setspeed) (struct cpufreq_policy *policy,10: unsigned int freq);11: unsigned int max_transition_latency; /* HW must be able to switch to12: next freq faster than this value in nano secs or we13: will fallback to performance governor */14: struct list_head governor_list;
15: struct module *owner;
16: };
name,该governor的名称,唯一标识某个governor。
initialized,记录governor是否已经初始化okay。
max_transition_latency,容许的最大频率切换延迟,硬件频率的切换必须小于这个值,才能满足需求。
governor_list,用于将该governor挂到一个全局的governor链表(cpufreq_governor_list)上。
show_setspeed和store_setspeed,回忆一下“linux cpufreq framework(3)_cpufreq core”所描述的“scaling_setspeed ”,有些governor支持从用户空间修改频率值,此时该governor必须提供show_setspeed和store_setspeed两个回调函数,用于响应用户空间的scaling_setspeed请求。
governor,cpufreq governor的主要功能都是通过该回调函数实现,该函数借助不同的event,以状态机的形式,实现governor的启动、停止等操作,具体请参考后续的描述。
2.2 governor event
kernel将governor的控制方式抽象为下面的5个event,cpufreq core在合适的时机(具体参考下面第3章的介绍),以event的形式(.governor回调),控制governor完成相应的调频动作。
1: /* include/linux/cpufreq.h */
2:3: /* Governor Events */
4: #define CPUFREQ_GOV_START 15: #define CPUFREQ_GOV_STOP 26: #define CPUFREQ_GOV_LIMITS 37: #define CPUFREQ_GOV_POLICY_INIT 48: #define CPUFREQ_GOV_POLICY_EXIT 5
CPUFREQ_GOV_POLICY_INIT,policy启动新的governor之前(通常在cpufreq policy刚创建或者governor改变时)发送。governor接收到这个event之后,会进行前期的准备工作,例如初始化一些必要的数据结构(如timer)等。并不是所有governor都需要这个event,后面如果有时间,我们以ondemand governor为例,再介绍它的意义。
CPUFREQ_GOV_START启动governor。
CPUFREQ_GOV_STOP、CPUFREQ_GOV_POLICY_EXIT,和前面两个event的意义相反。
CPUFREQ_GOV_LIMITS,通常在governor启动后发送,要求governor检查并修改频率值,使其在policy规定的有效范围内。
2.3 governor register
所有governor都是通过cpufreq_register_governor注册到kernel中的,该接口比较简单,查找是否有相同名称的governor已经注册,如果没有,将这个governor挂到全局的链表即可,如下:
1: int cpufreq_register_governor(struct cpufreq_governor *governor)2: {3: int err;
4:5: if (!governor)
6: return -EINVAL;
7:8: if (cpufreq_disabled())
9: return -ENODEV;
10:11: mutex_lock(&cpufreq_governor_mutex);12:13: governor->initialized = 0;14: err = -EBUSY;15: if (__find_governor(governor->name) == NULL) {
16: err = 0;17: list_add(&governor->governor_list, &cpufreq_governor_list);18: }19:20: mutex_unlock(&cpufreq_governor_mutex);21: return err;
22: }23: EXPORT_SYMBOL_GPL(cpufreq_register_governor);
3 governor相关的调用流程
3.1 启动流程
“linux cpufreq framework(3)_cpufreq core”中介绍过,添加cpufreq设备时,会调用cpufreq_init_policy,该接口的主要功能是为当前的cpufreq policy分配并启动一个cpufreq governor,如下:
1: static void cpufreq_init_policy(struct cpufreq_policy *policy)2: {3: struct cpufreq_governor *gov = NULL;
4: struct cpufreq_policy new_policy;
5: int ret = 0;
6:7: memcpy(&new_policy, policy, sizeof(*policy));
8:9: /* Update governor of new_policy to the governor used before hotplug */
10: gov = __find_governor(per_cpu(cpufreq_cpu_governor, policy->cpu));11: if (gov)
12: pr_debug("Restoring governor %s for cpu %d\n",
13: policy->governor->name, policy->cpu);14: else
15: gov = CPUFREQ_DEFAULT_GOVERNOR;16:17: new_policy.governor = gov;18:19: /* Use the default policy if its valid. */
20: if (cpufreq_driver->setpolicy)
21: cpufreq_parse_governor(gov->name, &new_policy.policy, NULL);22:23: /* set default policy */
24: ret = cpufreq_set_policy(policy, &new_policy);25: if (ret) {
26: pr_debug("setting policy failed\n");
27: if (cpufreq_driver->exit)28: cpufreq_driver->exit(policy);
29: }30: }
9~13行:首先查看是否在hotplug之前最后使用的governor(保存在per cpu的全局变量cpufreq_cpu_governor中),如果有,则直接使用这个governor。
14~15行:如果没有,则使用默认的governor----CPUFREQ_DEFAULT_GOVERNOR,该governor在include/linux/cpufreq.h中定义,可以通过kernel配置项选择,可选的governor包括performace、powersave、userspace、ondmand和conservative五种。
20~21行:如果cpufreq driver提供了setpolicy接口,则说明CPU可以在policy指定的有效范围内,确定具体的运行频率,因此不再需要governor确定运行频率。但如果此时的governor是performace和powersave两种,则有必要通知到cpufreq driver,以便它的setpolicy接口可以根据实际情况正确设置频率范围。怎么通知呢?通过struct cpufreq_policy结构中的policy变量(名字很费解啊!),可选的值有两个,CPUFREQ_POLICY_PERFORMANCE和CPUFREQ_POLICY_POWERSAVE。
24行:调用cpufreq_set_policy,启动governor,代码如下。
1: static int cpufreq_set_policy(struct cpufreq_policy *policy,2: struct cpufreq_policy *new_policy)
3: {4: ...5: if (cpufreq_driver->setpolicy) {
6: policy->policy = new_policy->policy;7: pr_debug("setting range\n");
8: return cpufreq_driver->setpolicy(new_policy);
9: }10:11: if (new_policy->governor == policy->governor)
12: goto out;
13:14: pr_debug("governor switch\n");
15:16: /* save old, working values */
17: old_gov = policy->governor;18: /* end old governor */
19: if (old_gov) {
20: __cpufreq_governor(policy, CPUFREQ_GOV_STOP);21: up_write(&policy->rwsem);22: __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT);23: down_write(&policy->rwsem);24: }25:26: /* start new governor */
27: policy->governor = new_policy->governor;28: if (!__cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT)) {
29: if (!__cpufreq_governor(policy, CPUFREQ_GOV_START))
30: goto out;
31:32: up_write(&policy->rwsem);33: __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT);34: down_write(&policy->rwsem);35: }36:37: /* new governor failed, so re-start old one */
38: pr_debug("starting governor %s failed\n", policy->governor->name);
39: if (old_gov) {
40: policy->governor = old_gov;41: __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT);42: __cpufreq_governor(policy, CPUFREQ_GOV_START);43: }44:45: return -EINVAL;
46:47: out:48: pr_debug("governor: change or update limits\n");
49: return __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
50: }
5~9行,对应上面20~21行的逻辑,如果有setpolicy接口,则直接调用,不再进行后续的governor操作,因此使用CPUFREQ_POLICY_PERFORMANCE和CPUFREQ_POLICY_POWERSAVE两个值,变相的传递governor的信息。
11~12行,如果新旧governor相同,直接返回。
19~24行,如果存在旧的governor,停止它,流程是:
CPUFREQ_GOV_STOP---->CPUFREQ_GOV_POLICY_EXIT剩余的代码:启动新的governor,流程是:CPUFREQ_GOV_POLICY_INIT---->CPUFREQ_GOV_START---->CPUFREQ_GOV_LIMITS
3.2 调频流程
前面已经多次提到基于cpufreq governor的调频思路,这里再总结一下:
1)有两种类型的cpu:一种只需要给定调频范围,cpu会在该范围内自行确定运行频率;另一种需要软件指定具体的运行频率。
2)对第一种cpu,cpufreq policy中会指定频率范围policy->{min, max},之后通过setpolicy接口,使其生效即可。
3)对第二种cpu,cpufreq policy在指定频率范围的同时,会指明使用的governor。governor在启动后,会动态的(例如启动一个timer,监测系统运行情况,并根据负荷调整频率),或者静态的(直接设置为某一个合适的频率值),设定cpu运行频率。
kernel document对这个过程有详细的解释,如下:
Documentation\cpu-freq\governors.txt
CPU can be set to switch independently | CPU can only be set
within specific "limits" | to specific frequencies"CPUfreq policy"
consists of frequency limits (policy->{min,max})
and CPUfreq governor to be used
/ \
/ \
/ the cpufreq governor decides
/ (dynamically or statically)
/ what target_freq to set within
/ the limits of policy->{min,max}
/ \
/ \
Using the ->setpolicy call, Using the ->target/target_index call,
the limits and the the frequency closest
"policy" is set. to target_freq is set.
It is assured that it
is within policy->{min,max}
4 常用的governor介绍
最后,我们介绍一下kernel中常见的cpufreq governor。
1)Performance
性能优先的governor,直接将cpu频率设置为policy->{min,max}中的最大值。
2)Powersave
功耗优先的governor,直接将cpu频率设置为policy->{min,max}中的最小值。
3)Userspace
由用户空间程序通过scaling_setspeed文件修改频率。
4)Ondemand
根据CPU的当前使用率,动态的调节CPU频率。
5)Conservative
类似Ondemand,不过频率调节的会平滑一下,不会忽然调整为最大值,又忽然调整为最小值。
原创文章,转发请注明出处。蜗窝科技,www.wowotech.net。

评论:
2018-04-21 11:49
1)有两种类型的cpu:一种只需要给定调频范围,cpu会在该范围内自行确定运行频率;另一种需要软件指定具体的运行频率。
---》对于第一种CPU自行确定运行频率,是指硬件会计算当前的loading来动态调节到某一个合适的频率吗?麻烦解惑一下,非常感谢!
2017-06-26 19:04
请教个问题,下面说的这句话:cpufreq policy 指定的频率范围->这个范围是从哪来的?
是不是应该也有一套机制的? 望指教下,谢谢。
3)对第二种cpu,cpufreq policy在指定频率范围的同时,会指明使用的governor。governor在启动后,会动态的(例如启动一个timer,监测系统运行情况,并根据负荷调整频率),或者静态的(直接设置为某一个合适的频率值),设定cpu运行频率。
2017-06-27 10:48
本质上,是CPU的硬件代替了软件governor。
2017-06-27 14:03
(1)用户空间程序(写入一个policy) -> (2)Governor 根据policy的范围,来选择一个具体的值 ->设置具体的频率(opp)
我不理解的是用户空间程序怎么决定policy的,是要自己实现一套吗? 如果用户空间不写入policy,那么Linux 这套gorverno机制就不起作用了?
2017-06-27 18:35
2017-06-27 21:26
2017-06-28 09:35
2017-03-24 20:53
2016-09-04 09:55
在cpufreq-interactive.c的cpufreq_interactive_timer函数里面在pcpu->target_freq = new_freq;语句之前的pcpu->target_freq应该是上一次采样时获得的频率,那此时的pcpu->target_freq与pcpu->policy->cur值是否一样的呢?谢谢!
2016-09-05 09:48
在你所说的那个时间点,pcpu->target_freq表示之前的freq,new_freq表示当前所要调整为的freq,而pcpu->policy->cur则是用户(例如某一个调频策略)所期望的freq。
按理说,new_freq是从pcpu->policy->cur得出的,理想情况下,二者相同,但是由于一些限制,可能会不同。
这就是它们的关系。
2016-09-05 14:35
2016-09-05 15:25
0)先明确一点,pcpu->target_freq属于interactive governor,policy->cur属于cpufreq,new_freq是一个计算的中间过程
1)interactive会定时收集信息,并根据旧的freq(pcpu->target_freq),计算新的cpufreq(就是new_freq)。
2)如果interactive觉得需要调频(新旧值不同),则用新值(new_freq)更新旧值(pcpu->target_freq)
注:你的问题发生在赋值动作之前,因此pcpu->target_freq还是旧值。
3)interactive会在自己的task中(cpufreq_interactive_speedchange_task),以新值(pcpu->target_freq)为参数,调用driver的调频接口(__cpufreq_driver_target),调整频率值
注:你所提的问题,已经有答案了----
此时pcpu->target_freq可能是无效值,因此实际传给driver的可能不一样,因此driver最终设定的实际值(policy->cur)可能与它不同;
另外,这个值就算在interactive中通过验证了,在实际的driver中,也有可能被判定为无效值,因此,实际值(policy->cur)也可能与它不同。
2016-09-06 09:54
2016-09-06 17:02
根据功耗调频,可以有ondemand、conservative、interactive三种governor选择,你可以根据自己的应用场景,例如更care功耗还是更care性能、CPU调频生效时间的快慢、等等,选择一个。具体可以看一下这个文档:
Documentation/cpu-freq/governors.txt
2015-11-25 16:37
第一种 的cpufreq driver提供了setpolicy接口的话,就不在需要governor调频的策略?
那这时候cpu如何调频的 ?由cpufreq driver驱动来实现一个调频的策略然后调用setpolicy接口? 还是由用户上层调用setpolicy接口设置频率?
2015-11-25 17:05
功能
最新评论
文章分类
随机文章
文章存档
- 2024年2月(1)
- 2023年5月(1)
- 2022年10月(1)
- 2022年8月(1)
- 2022年6月(1)
- 2022年5月(1)
- 2022年4月(2)
- 2022年2月(2)
- 2021年12月(1)
- 2021年11月(5)
- 2021年7月(1)
- 2021年6月(1)
- 2021年5月(3)
- 2020年3月(3)
- 2020年2月(2)
- 2020年1月(3)
- 2019年12月(3)
- 2019年5月(4)
- 2019年3月(1)
- 2019年1月(3)
- 2018年12月(2)
- 2018年11月(1)
- 2018年10月(2)
- 2018年8月(1)
- 2018年6月(1)
- 2018年5月(1)
- 2018年4月(7)
- 2018年2月(4)
- 2018年1月(5)
- 2017年12月(2)
- 2017年11月(2)
- 2017年10月(1)
- 2017年9月(5)
- 2017年8月(4)
- 2017年7月(4)
- 2017年6月(3)
- 2017年5月(3)
- 2017年4月(1)
- 2017年3月(8)
- 2017年2月(6)
- 2017年1月(5)
- 2016年12月(6)
- 2016年11月(11)
- 2016年10月(9)
- 2016年9月(6)
- 2016年8月(9)
- 2016年7月(5)
- 2016年6月(8)
- 2016年5月(8)
- 2016年4月(7)
- 2016年3月(5)
- 2016年2月(5)
- 2016年1月(6)
- 2015年12月(6)
- 2015年11月(9)
- 2015年10月(9)
- 2015年9月(4)
- 2015年8月(3)
- 2015年7月(7)
- 2015年6月(3)
- 2015年5月(6)
- 2015年4月(9)
- 2015年3月(9)
- 2015年2月(6)
- 2015年1月(6)
- 2014年12月(17)
- 2014年11月(8)
- 2014年10月(9)
- 2014年9月(7)
- 2014年8月(12)
- 2014年7月(6)
- 2014年6月(6)
- 2014年5月(9)
- 2014年4月(9)
- 2014年3月(7)
- 2014年2月(3)
- 2014年1月(4)
2019-04-19 17:46