17、CPU与电量:CPU频率调度(Governor)、大小核架构、C-State、如何避免CPU唤醒
说到手机续航,CPU 绝对是耗电大户。你想想看,手机里最忙的就是它了。屏幕一亮,各种 App 轮番上阵,CPU 就得跟着转。但 CPU 也不是铁打的,它怎么转、转多快、什么时候歇着,直接决定了你的手机能用一天还是半天。
我个人习惯把 CPU 比作一辆跑车。Governor 就是司机,决定踩多大油门;大小核架构是发动机排量,大核是 V8,小核是 1.0L;C-State 就是熄火还是怠速。今天咱们就把这三件事儿彻底聊透。
17.1 CPU 频率调度(Governor)
Governor 是 Linux 内核里的一个模块。它的工作很简单:决定 CPU 当前该跑多快。频率高了,性能好,但费电;频率低了,省电,但可能卡顿。
Android 里常见的 Governor 有这么几种:
| Governor 名称 | 行为特点 | 适用场景 |
|---|---|---|
| performance | 一直跑最高频率,从不降频 | 跑分、游戏(但发热严重) |
| powersave | 一直跑最低频率,能不动就不动 | 待机、听歌(但会卡) |
| ondemand | 有任务就立刻拉高频率,空闲就降下来 | 老机型默认,响应快但耗电 |
| interactive | 根据负载平滑调频,比 ondemand 更聪明 | Android 4.4~9 的标配 |
| schedutil | 基于调度器的负载信息调频,更精准 | Android 10+ 主流选择 |
我在项目中遇到过一个问题:某款手机刷抖音时发热严重。查了半天,发现是 Governor 被改成了 performance。说白了就是 CPU 一直全速跑,根本不停歇。改成 schedutil 之后,温度直接降了 5 度。
核心观点:schedutil 是目前最推荐的 Governor。它直接读取调度器的负载数据,而不是靠采样去猜。响应快,又省电。
你可以通过以下命令查看当前 Governor:
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
想改的话:
echo "schedutil" > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
注意:改 Governor 需要 root 权限。而且有些厂商锁死了这个节点,改了也没用。
17.2 大小核架构(big.LITTLE / DynamIQ)
ARM 在 2011 年提出了 big.LITTLE 架构。说白了就是:大核干重活,小核干轻活。大核性能强但费电,小核省电但性能弱。两者搭配,干活不累。
到了 DynamIQ 时代,架构更灵活了。一个簇里可以混搭大核、中核、小核。比如麒麟 9000 就是 1+3+4 的配置:1 个超大核、3 个大核、4 个小核。
为什么这样设计?
- 日常使用:刷微信、看新闻,小核就够了。大核直接休眠,省电。
- 游戏场景:大核全开,小核辅助。性能拉满。
- 后台任务:比如下载、同步,丢给小核慢慢跑,不影响前台流畅度。
我曾经调试过一款平板,待机功耗偏高。查了内核日志发现,有个后台服务一直绑定在大核上跑。我把它迁移到小核之后,待机功耗从 80mA 降到了 30mA。嗯,这里要注意:不是所有任务都适合跑在小核上。比如 UI 渲染、动画,必须用大核,否则会掉帧。
我的建议:在开发 App 时,可以用 setThreadAffinity 把计算密集型任务绑定到大核,把 IO 任务绑定到小核。但别滥用,否则调度器会乱。
17.3 C-State:CPU 的睡眠等级
C-State 是 CPU 的电源状态。C0 是工作状态,C1 是浅度睡眠,C2、C3 越来越深,直到 C10 完全断电。
每个状态的特点:
| C-State | 状态描述 | 唤醒延迟 | 省电效果 |
|---|---|---|---|
| C0 | CPU 正在执行指令 | 0 | 不省电 |
| C1 | 暂停执行,但时钟还在 | 几微秒 | 一般 |
| C2 | 关闭部分时钟 | 几十微秒 | 较好 |
| C3 | 关闭 PLL,缓存保持 | 几百微秒 | 很好 |
| C10 | 完全断电,缓存丢失 | 毫秒级 | 最佳 |
你想想看,CPU 进入 C3 之后,再唤醒需要几百微秒。如果频繁唤醒,省下的电还不够唤醒消耗的。所以 C-State 的切换策略非常关键。
避坑指南:我曾经遇到过一个问题:手机待机时,每 10 毫秒就有一个定时器唤醒 CPU。导致 CPU 一直处于 C1 和 C0 之间,根本进不了深睡眠。最后发现是一个第三方 App 的轮询逻辑写得太烂。改成 1 秒一次后,待机功耗直接砍半。
17.4 如何避免 CPU 被频繁唤醒
CPU 被唤醒,通常是因为以下几个原因:
- 定时器(Timer):App 设置了短间隔的定时器,比如 10ms 一次。
- 网络包:WiFi 或数据网络有数据包到达,触发中断。
- 传感器:加速度计、陀螺仪等传感器持续上报数据。
- AlarmManager:App 设置了频繁的闹钟。
- WakeLock:App 持锁不放,阻止系统休眠。
怎么优化?我总结了几个实战经验:
- 合并定时器:把多个短定时器合并成一个长定时器。比如 10ms 的改成 100ms,或者用
setExactAndAllowWhileIdle减少唤醒次数。 - 使用 JobScheduler:把后台任务交给系统统一调度,而不是自己写轮询。
- 减少网络心跳:很多 App 为了保持长连接,每 30 秒发一次心跳包。其实可以改成 5 分钟一次,或者用 FCM 推送代替。
- 传感器批处理:如果不需要实时数据,可以设置采样频率为 1Hz 而不是 100Hz。
一个小技巧:用 adb shell dumpsys alarm 可以查看哪些 App 设置了频繁的闹钟。我曾经用这个命令抓到一个 App,每 5 秒唤醒一次 CPU。反馈给厂商后,他们改成了 5 分钟一次,用户反馈续航明显提升。
17.5 知识体系总览
下面这张图总结了本章的核心逻辑。你可以看到,CPU 电量管理其实是一个从「调度」到「睡眠」的完整链路。
从这张图可以看得很清楚:Governor 决定频率,大小核决定谁来干活,C-State 决定怎么休息。而避免唤醒,就是让 CPU 在没事的时候能安安稳稳地睡大觉。
总结一句话:CPU 省电的核心不是「跑得慢」,而是「跑完就睡,别被吵醒」。
公众号:蓝海资料掘金营,微信 deep3321