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 被唤醒,通常是因为以下几个原因:

  1. 定时器(Timer):App 设置了短间隔的定时器,比如 10ms 一次。
  2. 网络包:WiFi 或数据网络有数据包到达,触发中断。
  3. 传感器:加速度计、陀螺仪等传感器持续上报数据。
  4. AlarmManager:App 设置了频繁的闹钟。
  5. WakeLock:App 持锁不放,阻止系统休眠。

怎么优化?我总结了几个实战经验:

  • 合并定时器:把多个短定时器合并成一个长定时器。比如 10ms 的改成 100ms,或者用 setExactAndAllowWhileIdle 减少唤醒次数。
  • 使用 JobScheduler:把后台任务交给系统统一调度,而不是自己写轮询。
  • 减少网络心跳:很多 App 为了保持长连接,每 30 秒发一次心跳包。其实可以改成 5 分钟一次,或者用 FCM 推送代替。
  • 传感器批处理:如果不需要实时数据,可以设置采样频率为 1Hz 而不是 100Hz。

一个小技巧:adb shell dumpsys alarm 可以查看哪些 App 设置了频繁的闹钟。我曾经用这个命令抓到一个 App,每 5 秒唤醒一次 CPU。反馈给厂商后,他们改成了 5 分钟一次,用户反馈续航明显提升。

17.5 知识体系总览

下面这张图总结了本章的核心逻辑。你可以看到,CPU 电量管理其实是一个从「调度」到「睡眠」的完整链路。

CPU 电量管理核心链路 CPU 频率调度 Governor (schedutil) 大小核架构 big.LITTLE / DynamIQ C-State 睡眠 C0 ~ C10 避免 CPU 频繁唤醒 合并定时器 JobScheduler 调度 减少网络心跳 传感器批处理

从这张图可以看得很清楚:Governor 决定频率,大小核决定谁来干活,C-State 决定怎么休息。而避免唤醒,就是让 CPU 在没事的时候能安安稳稳地睡大觉。

总结一句话:CPU 省电的核心不是「跑得慢」,而是「跑完就睡,别被吵醒」。


公众号:蓝海资料掘金营,微信 deep3321