CPU 调频策略 CPU 调频模块主要分为 3 块:
CPUFreq 框架 为所有支持CPUfreq 提供了通用的代码基础结构和用户空间API。它定义了其他组件在其中运行的基本框架
CPUFreq Governor
CPU 调频的策略。CPU 在什么样负载,什么样的场景下应该跑多少频率,都是通过 CPUFreq Governor 采取一定策略来决定的CPUFreq 驱动
更新CPUFreq Governor 的决定到CPU HW ,从而更新 CPU 频率。CPUFreq Governor
曾经使用过的governor ,
performance
CPU 一直跑在最高频率powersave 让 CPU 跑在最低频率
ondemand
governor 开启一个 timer,定期去计算各个 CPU 的负载。当 CPU 负载超过 80% 时, 就会把 CPU 频率调到最高,其他情况则会根据当前负载按比例计算频率。conservation
governor 开启一个 timer,定期去计算各个 CPU 的负载。当CPU 负载超过 80% 时,默认会以 5% 的步伐递增;当 CPU 负载少于 20% 的时候,默认会以 5% 的步伐递减。 Interactive governor 它是在 Android 中引入的。它在每一个 CPU 上都注册了一个 idle notifier。当 CPU 退出 idle 状态时,interactive 就会缩减采样频率,从而可以快速响应负载变化。其他情况下,会根据当前 CPU 负载调整频率,这一点和 ondemand 类似。
总结起来,对于像 ondemand,conservation,interactive 含有调频逻辑的 governor,都包含一个共同的部分 - 负载采样,需要每隔一定时间就计算一次 CPU 负载。进而进行调频。然而,这样可能会有频率上提升的延时。对于 CPU 的负载,没有谁比调度器还清楚的了。所以 cpufreq governor 完全没必要自己去做负载采样,应该从内核调度器那里获取。而基于调度器的 cpufreq governor 就是这样引出来的。
schedutil内核调度器中的 CFS 调度类是通过 PELT(per entity load tracking) 来统计各个 Task 的负载(capacity),并映射到 0 ~ 1024(最大值可在编译时指定)。内核当中的负载均衡就是通过这些统计值来平衡各个 CPU 之间的任务。而基于调度器的 cpufreq governor 的主要原理就是把各个 CPU 的 capacity 映射到 CPU 频率,来完成调频动作,capacity 越高,当前 CPU 负载越高,所以频率也调的很高。
而当前内核社区中,已经有两个成形的方案。一个是 ARM 和 Linaro 主导的项目 - cpufreq_sched,属于 EAS 的一部分。而另外一个 Intel 主导的项目 - schedutil。
schedutil而 schedutil就是利用这个负载变化回调机制,通过 cpufreq_add_update_util_hook() 注册回调函数,当 CPU 负载出现变化的时候,就会触发 schedutil sugov_update 进行调频动作。
其调频 为,
next_freq = 1.25 * max_freq * util / max
代码语言:javascript复制其中util和max是cpufreq_update_util()中callback回来的参数。
如果util不是变化的,则将上式中的最大频率替换为CPU的当前频率:
next_freq = 1.25 * curr_freq * util / max
系数1.25对应于(util /最大值)= 0.8。
所有计算都在schedutil提供的利用率更新处理程序中执行(callback)。代码语言:javascript复制CPU freq的变化在同cluster共享,不需要额外的开销。
并且schedutil 支持快速freq 切换(fast path),当调度器有loading 变化时,就及时的callback schedutil ,schedutil计算下一个freq 并且把相关freq传给CPUfreq dirver ,从而完成CPUfreq的快速切换。
如果该cluser 不支持快速切换,在需要在一定时间内才完成CPU freq的变化。
Tuning 参数:
rate_limit_us代码语言:javascript复制连续两次执行调频之间必须经过的最短时间(以微秒为单位)(默认值:调频驱动程序的transition latency1000倍).一般是10ms。就是调频间隔的最小时间是10ms。