2、CPU频率调节(CPUFreq):框架、策略与工具
CPU频率调节,说白了就是让CPU在「跑得快」和「省点电」之间找个平衡。我刚开始接触嵌入式Linux时,总觉得这玩意儿就是个简单的调频开关。后来在项目里被功耗问题折磨过几次,才真正理解了CPUFreq框架的深度。
嗯,咱们今天就把这个框架拆开看看。
2.1 CPUFreq框架介绍
CPUFreq是Linux内核里负责动态调整CPU频率和电压的子系统。它不是一个简单的驱动,而是一整套机制。我个人习惯把它分成三层来看:
- 底层:硬件相关的驱动层,直接操作CPU的PLL、分频器、电压调节器。这部分跟具体芯片绑定,比如高通、全志、瑞芯微都有自己的实现。
- 中间层:核心框架层,提供统一的接口给上层调用。它管理着频率表、电压表、以及各种策略的切换逻辑。
- 上层:Governor策略层,决定「什么时候该升频,什么时候该降频」。
我在一个平板项目里遇到过一个问题:CPU频率死活上不去,跑分只有标称值的一半。查了两天才发现,是底层驱动里某个分频系数配置错了。你看,底层出问题,上层再怎么调策略都没用。
2.2 Governor策略详解
Governor是CPUFreq的灵魂。它决定了CPU频率的调节行为。Linux内核目前支持6种Governor,我一个个说。
2.2.1 performance
这个最简单——CPU始终跑在最高频率。说白了就是「性能至上,功耗不管」。适合对响应速度要求极高的场景,比如实时控制系统。但你要是在电池设备上用这个,续航会很难看。
2.2.2 powersave
跟performance相反,始终跑在最低频率。省电是省电了,但系统会卡得让你怀疑人生。我一般只在调试低功耗模式时临时用一下。
2.2.3 userspace
把频率控制权交给用户态。你可以通过cpufrequtils工具手动设置频率。这个策略给了开发者最大的灵活性,但也最容易出问题。我曾经见过一个产品,开发者在userspace策略里写了个死循环调频,结果CPU温度直接飙到90度。
2.2.4 ondemand
这是经典策略。它根据CPU负载动态调频:负载高了就升频,负载低了就降频。但它的响应有延迟,因为它是周期性采样负载的。在负载剧烈波动的场景下,你会感觉到卡顿。
2.2.5 conservative
跟ondemand类似,但调频更温和。它不会一下子跳到最高频率,而是逐步升降。适合对功耗敏感、对性能要求不高的场景。我个人觉得它在某些嵌入式设备上比ondemand更省电。
2.2.6 schedutil
这是目前最推荐的策略。它直接跟调度器(CFS)集成,利用调度器已经计算好的负载信息来调频。说白了,它比ondemand更「聪明」,响应更快,功耗控制也更精细。从内核4.7开始引入,现在已经是很多平台默认的Governor了。
2.3 驱动接口与用户态工具
2.3.1 内核驱动接口
CPUFreq驱动需要实现一组回调函数。核心接口定义在include/linux/cpufreq.h中。我挑几个关键的说说:
// 驱动注册结构体
struct cpufreq_driver {
char name[CPUFREQ_NAME_LEN];
int (*init)(struct cpufreq_policy *policy);
int (*verify)(struct cpufreq_policy *policy);
int (*target)(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation);
unsigned int (*get)(unsigned int cpu);
// ... 其他回调
};
init在CPU上线时调用,负责初始化频率表。target是核心函数,负责实际设置频率。get返回当前频率。我在写驱动时,最常踩的坑是verify函数没处理好——它负责校验请求的频率是否在合法范围内。如果这个函数写错了,上层设置频率时会静默失败。
2.3.2 用户态工具:cpufrequtils
cpufrequtils是一套用户态工具,用来查看和设置CPUFreq参数。最常用的几个命令:
- cpufreq-info:查看当前CPU频率、可用Governor、可用频率等信息。
- cpufreq-set:设置Governor策略或手动指定频率。
- cpufreq-aperf:查看CPU的实际性能计数。
举个例子,查看当前CPU状态:
# cpufreq-info
analyzing CPU 0:
driver: cpufreq-dt
CPUs which run at the same hardware frequency: 0
hardware limits: 408 MHz - 1.51 GHz
available frequency steps: 408 MHz, 600 MHz, 816 MHz, 1.01 GHz, 1.21 GHz, 1.41 GHz, 1.51 GHz
available cpufreq governors: conservative, ondemand, userspace, powersave, performance, schedutil
current policy: frequency should be within 408 MHz and 1.51 GHz.
The governor "schedutil" may decide which speed to use
within this range.
current CPU frequency is 816 MHz.
设置Governor为performance:
# cpufreq-set -g performance
手动设置频率(需要userspace策略):
# cpufreq-set -g userspace
# cpufreq-set -f 1.01GHz
cat /sys/class/thermal/thermal_zone*/temp看看温度,往往能发现问题。
2.4 实际项目中的选择建议
说了这么多,到底该用哪个Governor?我根据经验给个参考:
| 场景 | 推荐Governor | 理由 |
|---|---|---|
| 服务器/高性能计算 | performance | 不需要考虑功耗,性能最大化 |
| 手机/平板(日常使用) | schedutil | 响应快,功耗控制好 |
| IoT设备(电池供电) | conservative | 调频温和,省电效果明显 |
| 实时控制系统 | performance | 避免调频带来的延迟抖动 |
| 调试/测试阶段 | userspace | 可以手动固定频率,方便复现问题 |
最后说一句:没有万能的Governor。我建议你在产品开发阶段,把几种策略都跑一遍性能测试和功耗测试,用数据说话。毕竟,理论再漂亮,不如实际跑出来的结果有说服力。