4、CPU性能调优:CPU频率调节、调度器选择、大小核架构优化

CPU调优这块,说实话是Android性能优化里最硬核的部分之一。我早年做功耗优化时,经常遇到一种情况:手机跑分很高,但用户一用就发热降频,体验反而更差。说白了,CPU调优就是在性能和功耗之间走钢丝。

今天咱们就聊聊三个核心方向:频率怎么调、调度器怎么选、大小核怎么用。嗯,每个点我都会结合自己踩过的坑来讲。

4.1 CPU频率调节:不只是“拉满”那么简单

很多人一提到性能优化,第一反应就是“把CPU频率拉满”。我刚开始也这么干过,结果呢?手机烫得能煎鸡蛋,续航直接腰斩。后来才明白,频率调节的核心是按需分配

4.1.1 调频策略(Governor)的选择

Linux内核里提供了好几种调频策略,Android里常用的有这几个:

Governor 特点 适用场景
performance 一直跑最高频 跑分、游戏加载
powersave 一直跑最低频 待机、后台任务
ondemand 负载高时快速升频 日常使用(较老设备)
interactive 根据用户交互预测升频 Android 4.x~8.x 主流
schedutil 基于调度器负载信息调频 Android 9+ 主流

我个人习惯用 schedutil。为什么?因为它能跟调度器深度配合,调频更精准。我记得在某个项目里,把 interactive 换成 schedutil 后,滑动流畅度提升了约8%,功耗反而降了5%。

查看当前调频策略:

adb shell cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor

临时切换策略(需要root):

adb shell "echo schedutil > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"

4.1.2 调频参数微调

光选策略还不够,参数也得调。以 schedutil 为例,有几个关键参数:

  • up_rate_limit_us:升频延迟,默认5000us。调小能让CPU更快响应突发负载,但太激进会频繁跳频。
  • down_rate_limit_us:降频延迟,默认10000us。调大可以避免负载波动时频繁降频。
  • hispeed_load:触发最高频的负载阈值,默认90%。调低到80%能让重负载任务更快跑满。

我的经验:在游戏场景下,我会把 up_rate_limit_us 降到2000us,hispeed_load 降到85%。这样进游戏加载时,CPU能瞬间冲到最高频,减少卡顿感。但日常使用建议保持默认,否则续航会崩。

4.2 调度器选择:谁来决定下一个跑谁?

调度器负责决定“下一个该哪个任务上CPU跑”。这个选择直接影响响应速度和公平性。Android里主流调度器有这几个:

调度器 核心思想 优缺点
CFS(完全公平调度) 按权重分配时间片 公平性好,但交互响应不够快
HMP(异构多处理) 大小核独立调度 简单粗暴,但负载均衡差
EAS(能耗感知调度) 结合能耗模型调度 省电且流畅,Android 11+ 标配

现在新设备基本都是EAS了。EAS会为每个任务估算“跑在大核上要多少电,跑在小核上要多少时间”,然后选最优解。说白了,就是用最少的电干最多的活

注意:EAS依赖CPU的能耗模型(Energy Model),如果模型不准,调度反而会变差。我曾经遇到过某款芯片的能耗模型参数写反了,导致小核任务被误判为更耗电,结果全往大核上塞,功耗直接炸了。后来手动校准了模型参数才解决。

4.2.1 调度器参数调优

EAS有几个关键参数可以调:

  • sched_energy_aware:是否启用EAS,默认1(开启)。
  • sched_boost:调度器升压等级,0~100。调高会让调度器更倾向于用大核。
  • sched_migration_cost_ns:任务迁移成本,默认500000ns。调小会让任务更频繁地迁移到更优的核上。
# 查看EAS是否启用
adb shell cat /proc/sys/kernel/sched_energy_aware

# 临时调整调度器升压(需要root)
adb shell "echo 50 > /proc/sys/kernel/sched_boost"

避坑指南:我曾经把 sched_migration_cost_ns 调得太小,结果任务在大小核之间来回跳,反而增加了开销。建议保持默认,除非你很清楚自己在做什么。

4.3 大小核架构优化:让对的核干对的活

现在手机基本都是大小核架构,比如1+3+4(1个超大核+3个大核+4个小核)或者4+4。怎么用好这些核,是性能优化的关键。

4.3.1 任务分类与绑核

我的做法是把任务分成三类:

  • 前台交互任务(UI线程、输入事件):绑到大核或超大核,保证响应速度。
  • 后台计算任务(网络请求、数据处理):绑到小核,省电。
  • 实时任务(音频、视频解码):绑到特定核,避免被其他任务干扰。

绑核可以用 taskset 命令,或者在代码里用 sched_setaffinity

// C代码示例:将当前线程绑定到CPU0和CPU1
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(0, &cpuset);
CPU_SET(1, &cpuset);
sched_setaffinity(0, sizeof(cpuset), &cpuset);

查看CPU拓扑:

adb shell cat /sys/devices/system/cpu/cpu*/topology/core_id

查看每个核的频率范围:

adb shell cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_available_frequencies

4.3.2 大小核负载均衡

EAS调度器会自动做负载均衡,但有时候不准。我习惯手动干预:

  • 前台应用:强制使用大核+超大核,小核只跑后台服务。
  • 游戏场景:把渲染线程绑到超大核,逻辑线程绑到大核,音频线程绑到小核。
  • 待机场景:所有任务都往小核上赶,大核直接休眠。

注意:绑核不是万能的。我见过有人把所有线程都绑到大核上,结果大核过热降频,性能反而比不绑还差。记住,过犹不及

4.3.3 实战案例:优化一个视频播放器

我记得有个项目,视频播放器在低端机上卡顿。分析后发现,解码线程和UI线程都在小核上跑,互相抢资源。我的优化方案:

  1. 把解码线程绑到两个大核上(CPU4-5)。
  2. 把UI线程绑到超大核上(CPU6)。
  3. 把网络请求线程绑到小核上(CPU0-3)。
  4. 调整 schedutilup_rate_limit_us 到3000us,让解码线程能快速升频。

结果呢?卡顿率从15%降到了3%,功耗只增加了2%。嗯,这就是大小核优化的魅力。

4.4 总结与工具推荐

CPU性能调优,说白了就是三件事:频率调对、调度选对、核用对。我常用的工具有:

  • Perfetto:看调度轨迹、频率变化,必装。
  • Simpleperf:分析CPU热点函数。
  • /proc/stat/sys/devices/system/cpu:手动查看CPU状态。

最后一句:别迷信参数。每个芯片、每个系统版本都不一样。我的习惯是:先跑基准测试,再调参数,再跑测试,反复迭代。调优没有银弹,只有耐心。

好了,CPU调优就聊到这儿。下一章咱们讲GPU和显示优化,那个更刺激——毕竟用户对卡顿的感知,80%来自显示。