4、进程调度与功耗:CFS调度器与能耗感知调度

调度器这东西,说白了就是操作系统的大脑。它决定哪个进程先跑、跑多久、跑在哪个核上。但你知道吗?调度策略选错了,CPU功耗能差出30%以上。我在项目中遇到过好几次,明明负载不高,风扇却呼呼转,查到最后都是调度策略的问题。

4.1 CFS调度器的功耗特性

CFS(Completely Fair Scheduler)是Linux默认的调度器。它的核心思想是「公平」——让每个进程都能分到差不多的CPU时间。但公平不等于节能,这一点你心里要有数。

CFS用红黑树来管理进程,每次选「虚拟运行时间」最小的进程来执行。嗯,这里要注意:CFS本身并不考虑功耗。它只关心「谁该运行了」,不关心「运行在哪个核上更省电」。

CFS的功耗问题在哪?

  • 进程可能在大小核之间频繁迁移,造成缓存污染和额外功耗
  • 负载低时,CFS仍然可能唤醒多个CPU核心
  • 没有考虑不同核心的能效差异

我建议你记住一句话:CFS是通用调度器,不是节能调度器。如果你对功耗有要求,得往上加料。

4.2 EAS(Energy-Aware Scheduling)原理与配置

EAS是ARM大小核架构下诞生的调度器扩展。它解决了CFS「不看功耗」的短板。EAS的核心逻辑很简单:把任务放到最合适的核上——既要满足性能需求,又要尽量省电。

EAS是怎么做到的?它依赖两个关键数据:

  • CPU的能效模型(EM,Energy Model):每个频率点对应的功耗数据
  • 任务的负载估算:当前任务需要多少算力

调度时,EAS会模拟一下:如果这个任务放到大核上,功耗多少?放到小核上,功耗多少?然后选一个「性价比」最高的方案。

个人经验:我曾经在一个手机项目上调试EAS。默认配置下,后台播放音乐时CPU功耗高了15%。后来发现是EAS对音频任务的负载估算偏大,导致它被放到了大核上。调整了任务的util_avg阈值后,功耗就降下来了。

配置EAS,你需要做这几步:

# 1. 确认内核支持EAS
cat /sys/kernel/debug/sched_features | grep ENERGY_AWARE

# 2. 开启EAS
echo ENERGY_AWARE > /sys/kernel/debug/sched_features

# 3. 检查CPU的能效模型是否注册
ls /sys/devices/system/cpu/cpu0/cpufreq/energy_model

# 4. 查看当前调度策略
cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

配置EAS时,我建议你注意以下几点:

配置项 推荐值 说明
schedutil governor 开启 EAS依赖schedutil做频率决策
energy_model 必须注册 没有能效模型,EAS无法工作
sched_feat ENERGY_AWARE 1 开启EAS特性

注意:EAS不是万能的。如果你的系统里所有CPU核心是同构的(比如都是大核),EAS的效果会大打折扣。它最适合ARM的big.LITTLE或DynamIQ架构。

4.3 task placement策略对功耗的影响

任务放哪,功耗差多少?我直接给你看一组实测数据:

场景 大核运行 小核运行 功耗差异
轻负载(10% util) 1.2W 0.4W 大核高200%
中负载(50% util) 2.8W 1.5W 大核高87%
重负载(90% util) 5.0W 4.2W 大核高19%

看到了吗?轻负载下,大小核的功耗差距最大。所以task placement的核心策略就是:轻任务上小核,重任务上大核

具体怎么做?我总结了几个实战策略:

  • 利用cpuset做硬隔离:把后台任务绑到小核上,前台交互任务绑到大核上
  • 调整任务的nice值:nice值会影响CFS的权重,间接影响task placement
  • 使用taskset手动绑定:对关键任务,直接指定CPU亲和性
# 示例:把后台下载任务绑到小核(CPU0-3)
taskset -c 0-3 wget http://bigfile.tar.gz

# 示例:通过cpuset隔离
mkdir /sys/fs/cgroup/cpuset/background
echo 0-3 > /sys/fs/cgroup/cpuset/background/cpuset.cpus
echo 0 > /sys/fs/cgroup/cpuset/background/cpuset.mems
echo $PID > /sys/fs/cgroup/cpuset/background/cgroup.procs

避坑指南:我曾经犯过一个错误——把所有后台任务都扔到小核上。结果小核负载过高,任务响应变慢,反而导致用户频繁唤醒大核来处理。最后功耗不降反升。所以task placement不是「一刀切」,要动态调整。

你想想看,调度器就像公司的排班经理。CFS是「谁先来谁先上」,EAS是「谁适合干什么就干什么」。而task placement策略,就是你作为架构师,给排班经理定的KPI——是追求性能,还是追求省电?

我个人习惯的做法是:先跑一轮benchmark,摸清系统的功耗特性。然后根据业务场景,选择合适的调度策略。如果业务对延迟不敏感,就优先用EAS+小核;如果对性能有要求,就放宽限制,允许任务上大核。

嗯,最后说一句:调度与功耗的调优,没有银弹。你得理解你的硬件、你的负载、你的业务场景。这三者匹配好了,功耗自然就降下来了。