3、CPUFreq Governor深度解析:performance、powersave、userspace、ondemand、conservative、schedutil
各位好,我是老李。今天我们来啃一块硬骨头——CPUFreq Governor。说白了,它就是Linux内核里控制CPU频率和电压的调度策略。你手机、服务器、嵌入式设备里,CPU频率怎么变,全看它脸色。
我个人习惯把Governor比作「司机」。有的司机一脚油门踩到底,有的司机慢慢悠悠省油,还有的司机看路况实时调整。嗯,今天我们就把这几个司机挨个拉出来遛遛。
3.1 performance Governor:简单粗暴
这个Governor的逻辑就一句话:CPU频率直接拉到最高,绝不降频。
我在项目中遇到过,有些实时性要求极高的场景,比如工业控制、音频处理,用performance最省心。为什么?因为频率不变,延迟就稳定。你想想看,如果CPU突然降频,音频缓冲区可能就欠载了,那声音就「咔咔」断断续续。
3.2 powersave Governor:省电狂魔
和performance正好相反,powersave把频率锁在最低档。说白了,就是「能省则省,能慢则慢」。
这个Governor适合什么场景?后台下载、待机、或者你只是打开个文本编辑器。我建议,如果你在做IoT设备或者电池供电的嵌入式产品,powersave可以作为默认策略。但要注意,如果突然有高负载任务,系统会卡到你怀疑人生。
3.3 userspace Governor:手动挡
这个Governor把频率控制权完全交给用户空间。内核不干预,你通过/sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed这个文件手动写频率值。
说实话,现在很少有人直接用userspace了。为什么?因为手动调频太麻烦,而且你很难预测负载变化。不过,我在调试新硬件时偶尔会用——比如验证某个频率点是否稳定,或者测试DVFS的边界条件。
# 手动设置CPU0频率为1.2GHz
echo 1200000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed
scaling_available_frequencies文件里有哪些合法值。
3.4 ondemand Governor:经典老将
ondemand是Linux内核里最经典的动态调频策略。它的核心逻辑是:负载高了就升频,负载低了就降频。怎么判断负载?看CPU的「忙闲比」——也就是idle时间占比。
具体来说,内核会定期采样(比如每10ms),如果CPU忙的时间超过某个阈值(默认95%),就立刻跳到最高频。如果负载降下来,再慢慢降频。
我在项目中遇到过,ondemand在服务器上表现不错,但在移动设备上有个问题:响应不够快。比如你突然点了一下屏幕,CPU可能还在低频,等它反应过来,用户已经觉得卡了。
up_threshold:升频阈值,默认95%。调低这个值可以让CPU更积极升频。sampling_rate:采样周期,单位微秒。调小可以加快响应,但会增加开销。
3.5 conservative Governor:温和派
conservative和ondemand很像,但它的调频策略更「温柔」。ondemand是一步到位跳到最高频,而conservative是逐步升频,每次只跳一档。
你想想看,这样有什么好处?功耗波动小,更平滑。比如你只是偶尔有个小负载,conservative不会一下子把频率拉满,而是慢慢试探。这样电池寿命会更好。
但缺点也很明显:响应慢。如果突然来个大任务,conservative要好几步才能升到最高频,这段时间系统性能会受影响。我个人习惯,在功耗敏感但负载变化不剧烈的场景用conservative,比如电子书阅读器。
freq_step:每次升频的步长,默认5%。调大可以加快升频速度。down_threshold:降频阈值,默认20%。低于这个值就开始降频。
3.6 schedutil Governor:现代新秀
schedutil是Linux 4.7之后引入的,也是目前最推荐的Governor。它和前面几个最大的区别是:不再依赖独立的采样线程,而是直接利用调度器的负载信息。
说白了,调度器(CFS)本身就知道每个CPU上跑了多少任务、每个任务需要多少算力。schedutil直接从调度器拿这些数据,然后计算目标频率。这样做的好处是:响应更快,更精准。
我在项目中测试过,schedutil在手机上的表现明显优于ondemand。比如你滑动屏幕,schedutil几乎能瞬间把频率提上去,而ondemand会有几十毫秒的延迟。
# 查看当前使用的governor
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
# 切换到schedutil
echo schedutil > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
- 基于调度器负载,响应延迟低(微秒级)
- 支持EAS(Energy-Aware Scheduling),能同时考虑性能和功耗
- 不需要额外的采样线程,节省CPU开销
CONFIG_CPU_FREQ_GOV_SCHEDUTIL。而且它依赖调度器的负载跟踪,如果调度器本身有问题,schedutil也会受影响。我曾经在某个老内核上遇到过schedutil导致频率震荡的问题,后来发现是调度器的PELT算法参数没调好。
3.7 如何选择?一张表说清楚
| Governor | 特点 | 适用场景 | 功耗 | 性能 |
|---|---|---|---|---|
| performance | 固定最高频 | 实时、跑分、游戏 | 最高 | 最高 |
| powersave | 固定最低频 | 待机、后台下载 | 最低 | 最低 |
| userspace | 用户手动控制 | 调试、测试 | 取决于设置 | 取决于设置 |
| ondemand | 负载高升频,采样周期调频 | 服务器、桌面 | 中等 | 高 |
| conservative | 逐步升频,平滑过渡 | 功耗敏感、负载平稳 | 较低 | 中等 |
| schedutil | 基于调度器负载,响应快 | 移动设备、现代Linux | 低 | 高 |
最后说一句,没有「最好」的Governor,只有「最合适」的。我建议你在实际项目中,先默认用schedutil,如果遇到问题再换ondemand或conservative。至于performance和powersave,除非你有特殊需求,否则别碰。
嗯,这一章就到这里。下一章我们聊聊怎么动态切换Governor,以及如何调优参数。到时候我会分享一些我在手机和服务器上的实战经验。