从安卓探究Linux内核CPU调速器
0x00 前言
生活离不开手机,安卓占据了手机系统的半壁江山。手机CPU频率是手机性能的重要指标之一,目前顶级梯队的骁龙855芯片中”大核”频率已经达到了2.84GHz,即使它使用7nm工艺制造,运行在如此高频必然需要较高的核心电压,也同时会增加耗电。为了提高能耗比,除了物理上改进cpu设计,软件上优化软件算法……还有一个重要的措施————使用CPU调速器(Governor)。
0x01 cpu如何手动调速
本文实验均在lineageOS进行(关闭高通热插拔与跳频设置)。本地化系统(如miui,flyme,emui等)或高通的热插拔技术可能会干预cpu频率,无法简单地进行手动调频。
1 | # 对cpu0进行调整 |
0x02 什么是cpu调速器
机器处在相对空闲的状态下,此时CPU不需要运行在高频率上,调速器会降低cpu频率从而省电。当机器需要进行大量计算时,调速器会升高cpu频率以防止应用出现卡顿。广义上讲,AI优化也是一种调速器,因为现在手机厂商所谓AI优化很大一部分优化效果归功于对cpu频率的精准控制(当然AI优化也不全是调速器,还有动态分辨率调整之类的其他技术)。
简单来说,调速器就是根据负载情况自动化调节cpu频率的工具。
0x03 有哪些常见的cpu调速器
- 【interactive】交互模式(在安卓使用最广泛的调速器)
- 【conservative】保守模式
- 【performance】高性能模式
- 【powersave】省电模式
- 【Wheatley】惠特利模式
- 【lionheart】狮心模式
- 【smartass】聪明模式
- 【smartassV2】聪明V2模式
0x04 如何用好调速器
(以interactive调速器为例)——调速器参数调整的学问
1.above_hispeed_delay:
核心频率超过hispeed_freq时,升频延迟时间(above_hispeed_delay)(单位uS)
(example:40000 1400000:30000)
hispeed_freq<频率<1.4GHz,且连续40000uS达到目标负载,才进行升频。
频率>1.4GHz,且连续30000uS达到目标负载,才进行升频。
2.boost:
如果非0则将频率设定为hispeed_freq,用于应对瞬间大量任务。
3.boostpulse_duration
boost时间限制(单位uS)
4.go_hispeed_load:
example: (90)
在最低频状态,且负载达到 go_hispeed_load 即90%时,CPU直接提频到hispeed_freq。
5.hispeed_freq:
example:(1728000)(即1728MHz)
设定hispeed_freq。
6.min_sample_time:
example: (40000)
需要保持当前频率多久才进行降频(单位uS)。
7.sampling_down_factor:
example: (1(default))
8.target_loads:
example: (85
1200000:75
1500000:85)
负载达到85时进行升频。频率为1.2GHz-1.5GHz时负载75%进行升频。频率>1.5GHz时负载85%进行升频。

注:
go_hispeed_load优先级高于target_loads优先级。
补充:实际案例
用实际案例解释各个调速器参数
安卓手机打开软件时的cpu频率折线图
(单位为0.1s)
- 上图为软件打开时的cpu频率曲线,可以看到cpu瞬间提频至1.7GHz(
hispeed_freq) - 但此时软件还在加载过程中,负载依然很高,延迟大约200ms(above_hispeed_delay)进行升频。升至最高频率1.98GHz
- 最终软件完全加载完毕,仍然保持当前频率(
min_sample_time),后降频至300MHz。 - 进入软件后进行滑动,ui绘制需要较多资源,cpu瞬间升至1.7GHz(
hispeed_freq)。
个人见解:
为了省电:
- 将
hispeed降低,将target_loads提高(cpu快速进入一个较低的频率,然后缓慢升频)
- 将
为了性能:
- 一是提高
hispeed,当负载升高时,cpu快速进入高频,保证响应速度(保证突发性能)。提高target_load和above_hispeed_delay防止过快升频,为省电考虑。 - 二是降低
hispeed,降低target_load和above_hispeed_delay缓慢提升频率,保证正常升频。
- 一是提高
拓展:引入前台应用/时间/用户动作(如拿起手机,是否连续触摸)等多维度信息来调整调速器参数
2019-10-21更新
0x05 调速器代码逻辑简析
——从代码理解调速器逻辑(博主能力有限,正在研究代码中,持续更新
综合两文做了一些修改和补充,原文链接:https://blog.csdn.net/xujianqun/article/details/7681011
https://blog.csdn.net/u014089131/article/details/68490573
如何判断跳频(跳到hispeed_freq的实现)
1 | if (cpu_load >= tunables->go_hispeed_load || tunables->boosted) { |
把代码转换成语言描述就是
1、如果负载超过阈值(或开启boost),就直接升频到hispeed。
2、如果负载超过阈值,频率也大于hispeed(或开启boost),就调用choose_freq确定目标频率”最大频率*负载”。
3、如果负载没有超过阈值(未开启boost),需要降频,就调用choose_freq确定目标频率”当前频率负载”,至于判断是否执行降频请继续向下阅读。
如何确定目标频率具体数值?(choose_freq的实现)
注:loadadjfreq算法
1 | cputime_speedadj = (u64)sched_get_busy(data) * pcpu->policy->cpuinfo.max_freq; |
待更新: 在应用频率前,调速器还做了那些事?
2019-10-21待更新