一、Andorid系统内核cpufreq技术机制介绍
1.什么是变频技术:
主流CPU都支持变频(frequency scaling)技术,如美国的Intel CPU 支持的Enhanced SpeedStep技术和AMD CPU支持的PowerNow!技术,还有其他PowerPC、ARM等CPU也支持变频技术。注意:变频与超频是两个不同的概念,超频是指提高核心电压等方法使CPU工作在非标准频率下,这会缩短CPU的正常使用寿命并且会降低系统的稳定性。而变频是指CPU可以工作在不同的频率下,系统在运行过程中可以随时根据发生变化的负载情况动态的在不同频率之间进行切换,从而兼顾性能和功耗。
2.cpufreq的身世:
目前很多处理器厂家都支持变频技术,但是不同厂家的硬件实现和使用方法彼此存在着很大的差别,导致每个处理器厂家都需要根据自家的硬件和使用方法在内核中加入代码,让linux支持自己的产品变频技术。这样做的结果是各个厂家的硬件实现代码分散在linux内核的各个角落里,各种不同的实现代码无法共享信息,导致内核维护以及将来添加对新的产品的支持需要很大的资金开销,因此cpufreq内核子系统应运而生。实际变频技术的开发目的是为了让系统在运行过程中随时根据系统负载的变化动态的调整 CPU 的运行频率。这种技术主要分为两个部分,一是“做什么”,二是“怎么做”。“做什么”是指如何根据系统负载的动态变化挑选出 CPU 合适的运行频率,而“怎么做”就是要按照选定的运行频率在选定的时间对 CPU 进行设置,使之真正工作在这一频率上。即机制 mechanism 与策略 policy如何选择的问题,而良好的软件设计会在架构上保证二者是清楚的隔离开并通过规范定义的接口进行通信。
二、cpufreq的设计架构
cpufreq为在android内核中更好的支持不同 CPU 的变频技术提供了统一的设计架构,如图1所示。
图1 cpufreq 框架图
如图 1 所示,cpufreq 在设计上主要分为以下三个模块:
1.User-level governors : governors 作为目标运行频率的决策者,在适当的时刻根据一定的标准选择CPU 合适的运行频率,并通过 cpufreq 模块定义的接口操作底层与 CPU 相关的变频驱动程序,将 CPU 运行在选定的运行频率上。最新的 Linux 内核提供 performance 、powersave 、userspace、conservative、ondemand 和interactive等 6种 governors 供用户选择使用,它们使用的是不同的标准并且分别适用于不同的应用场景。用户在同一时间只能选择其中一个 governor 使用,但可以在系统运行过程中根据应用需求的变化而切换使用另一个 governor 。
2.cpufreq module: 对如何在底层控制各种不同 CPU 所支持的变频技术以及如何在上层根据系统负载动态选择合适的运行频率进行了封装和抽象,并在二者之间定义了清晰的接口,从而在设计上完成了对 mechanism 与 policy 的分离。
3.CPU-specific drivers : 各个 CPU 厂商根据自家的变频技术硬件实现和使用提供与其 CPU 相关的变频驱动程序。具体代码目录位于msm8974/kernel/drivers/cpufreq/ 。设计优势:使 governor 和 CPU 相关的变频驱动程序的开发可以相互独立进行,并在最大限度上实现代码重用,内核开发人员在编写和测试新 governor 时不会再陷入到某款特定 CPU 的变频技术的硬件实现细节中去,而 CPU 厂商在向andorid 内核中添加支持其特定的 CPU 变频技术的代码时只需提供驱动程序,不必考虑在各种不同的应用场景中如何选择合适的运行频率等复杂的问题。
三、管理策略: (查看: kernel/Documentation/cpu-freq/governors.txt
)
Linux 内部共有6种对频率的管理策略performance,userspace,ondemand,powersave,conservative, interactive.
performance :CPU工作在最高频率;
powersave :CPU工作在最低频率。这两种 governors 都属于静态 governors,即 CPU 的运行频率不会根据系统运行时负载的变化动态作出调整。使用 performance
governor 是对系统高性能的最大追求,使用 powersave governor 是对系统低功耗的最大追求。
userspace:最早的cpufreq子系统使用 userspace governor 为用户提供这种灵活性。用户态应用程序对系统的变频策略进行决策,并使用提供的相应的接口调节CPU运行频率。 ondemand:userspace是内核态的检测,效率低。ondemand正是人们长期以来希望看到的一个完全在内核态下工作并且能够以更加细粒度的时间间隔对系统负载情况进行采样分析的 governor。
conservative: ondemand governor 的最初实现是在可选的频率范围内调低至下一个可用频率。这种降频策略的主导思想是尽量减小对系统性能的负面影响,从而不会使得系统性能在短时间内迅速降低以影响用户体验。但是在 ondemand governor 的这种最初实现版本在社区发布后,大量用户的使用结果表明这种担心实际上是多余的, ondemand governor在降频时对于目标频率的选择完全可以更加激进。因此最新的 ondemand governor 在降频时会在所有可选频率中一次性选择出可以保证 CPU工作在 80% 以上负荷的频率,当然如果没有任何一个可选频率满足要求的话则会选择 CPU支持的最低运行频率。大量用户的测试结果表明这种新的算法可以在不影响系统性能的前提下做到更高效的节能。在算法改进后, ondemand governor 的名字并没有改变,而 ondemand governor 最初的实现也保存了下来,并且由于其算法的保守性而得名 conservative 。
interactive: 它是为延迟时间敏感,交互工作负荷而设计的。这个governor 类似于ondemand和conservative,依靠usage设置CPU的速度,它具有不同的配置集。
四、cpufreq 在用户态所呈现的接口:
内核中的 cpufreq 子系统通过 sysfs 文件系统向上层应用提供了用户接口,对于系统中的每一个 CPU 而言,其 cpufreq 的 sysfs 用户接口位于 /sys/devices/system/cpu/cpuX/cpufreq/ 目录下,其中 X 代表 processor id ,与 /proc/cpuinfo 中的信息相对应。以 cpu0 为例,用户一般会在该目录下观察到以下文件:
cpuinfo_max_freq,cpuinfo_min_freq: CPU 硬件支持的最高运行频率及最低运行频率。
cpuinfo_cur_freq : 从 CPU 硬件寄存器中读取 CPU 当前所处的运行频率。
scaling_cur_freq : cpufreq 模块缓存的 CPU 当前运行频率,而不会对 CPU 硬件寄存器进行检查。
scaling_available_governors : 用户当前有哪些 governors 可供用户使用。
scaling_driver: 显示该 CPU 所使用的变频驱动程序。
scaling_governor : 显示当前的管理策略,往这个上echo其他类型会有相应的转变。
scaling_setspeed: 需将governor类型切换为userspace,才会出现,往这个文件echo数值,会切换主频。
前缀cpuinfo代表的是cpu硬件上支持的频率,scaling前缀代表的是可以通过CPUFreq系统用软件进行调节时所支持的频率。 cpuinfo_cur_freq代表通过硬件实际上读到的频率值,scaling_cur_freq则是软件当前的设置值,多数情况下这两个值是一致的,但是也有可能因为硬件的原因,有微小的差异。通过 cpufreq-info 的输出,读者可以很清楚的看到刚刚在上面介绍过的 /sys/devices/system/cpu/cpuX/cpufreq/ 目录下各个文件的内容。测试平台是ubuntu14.04 ,首先:
1.安装软件:
sudo apt-get install cpufrequtils.
2.查看你的cpu所支持的频率 : 执行命令:cpufreq-info,如下所示:
比如将cpu0设置为powersave模式,步骤如下:
sudo -s <br />
echo powersave > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
如CPU0所示:
五、cpufreq软件架构描述
首先CPU的硬件特性决定CPU的最高和最低工作频率,所有的频率调整数值都必须在这个范围内,使用cpuinfo_***_freq来表示。然后,在这个范围内再次定义出一个软件的调节范围,使用 scaling_***_freq来表示,同时,根据不同的硬件平台,需要一个频率表,这个频率表规定cpu工作的频率值,这些频率值要在cpuinfo_***_freq的范围内。通过这些频率信息,cpufreq系统可以根据当前cpu的负载轻重状况,合理地从频率表 中选择一个合适的频率供cpu使用,从而达到降低功耗的目的。如何选择频率表中的频率,通过不同的governor来完成,现在的内核版本提供6种 governor。选择好合适的频率后,具体的频率调节工作由scaling_driver来实现。cpufreq系统将一些公共的逻辑和接口代码抽象出来,这些代码与平台无关,也与具体的调频策略无关,内核的文档把它称为cpufreq Core(/Documents/cpufreq/core.txt)。另外一部分,与实际的调频策略相关的部分被称作 cpufreq_policy,cpufreq_policy又是由频率信息和具体的governor组成,governor才是具体策略的实现者,当然 governor需要我们提供必要的频率信息,governor的实现最好能做到平台无关,与平台相关的代码用cpufreq_driver表述,它完成 实际的频率调节工作。最后,如果其他内核模块需要在频率调节的过程中得到通知消息,则可以通过cpufreq notifiers来完成。
一种调频策略的各种限制条件的组合称之为policy,代码中用cpufreq_policy这一数据结构来表示:
其中的各个字段的解释如下:
cpus和related_cpus :这两个都是cpumask_var_t变量,cpus表示的是这一policy控制之下的所有还出于online状态的cpu,而 related_cpus则是online和offline两者的合集。主要是用于多个cpu使用同一种policy的情况,实际上,我们平常见到的大多 数系统中都是这种情况:所有的cpu同时使用同一种policy。我们需要related_cpus变量指出这个policy所管理的所有cpu编号。cpu和last_cpu : 虽然一种policy可以同时用于多个cpu,但是通常一种policy只会由其中的一个cpu进行管理,cpu变量用于记录用于管理该policy的 cpu编号,而last_cpu则是上一次管理该policy的cpu编号(因为管理policy的cpu可能会被plug out,这时候就要把管理工作迁移到另一个cpu上)。cpuinfo : 保存cpu硬件所能支持的最大和最小的频率以及切换延迟信息。min/max/cur :该policy下的可使用的最小频率,最大频率和当前频率。policy :该变量可以取以下两个值:CPUFREQ_POLICY_POWERSAVE和CPUFREQ_POLICY_PERFORMANCE,该变量只有当调 频驱动支持setpolicy回调函数的时候有效,这时候由驱动根据policy变量的值来决定系统的工作频率或状态。如果调频驱动 (cpufreq_driver)支持target回调,则频率由相应的governor来决定。governor和governor_data 指向该policy当前使用的cpufreq_governor结构和它的上下文数据。governor是实现该policy的关键所在,调频策略的逻辑由governor实现。update :有时在中断上下文中需要更新policy,需要利用该工作队列把实际的工作移到稍后的进程上下文中执行。user_policy :有时候因为特殊的原因需要修改policy的参数,比如溫度过高时,最大可允许的运行频率可能会被降低,为了在适当的时候恢复原有的运行参数,需要使用user_policy保存原始的参数(min,max,policy,governor)。
kobj :该policy在sysfs中对应的kobj的对象。
所谓的governor 即调节器。governor负责检测cpu的使用状况,从而在可用的范围中选择一个合适的频率,代码中它用cpufreq_governor结构来表示:
其中的各个字段的解释如下:
name governor的名字。initialized 初始化标志。governor 指向一个回调函数,CPUFreq Core会在不同的阶段调用该回调函数,用于该governor的启动、停止、初始化、退出动作。list_head 所有注册的governor都会利用该字段链接在一个全局链表中,以供系统查询和使用。
前面提到的gonvernor只是负责计算并提出合适的频率,但是频率的设定工作是平台相关的,这需要cpufreq_driver驱动来完成,cpufreq_driver的结构如下:
相关的字段的意义解释如下:
name 该频率驱动的名字。init 回调函数,该回调函数必须实现,CPUFreq Core会通过该回调函数对该驱动进行必要的初始化工作。verify 回调函数,该回调函数必须实现,CPUFreq Core会通过该回调函数检查policy的参数是否被驱动支持。setpolicy/target 回调函数,驱动必须实现这两个函数中的其中一个,如果不支持通过governor选择合适的运行频率,则实现setpolicy回调函数,这样系统只能 支持CPUFREQ_POLICY_POWERSAVE和CPUFREQ_POLICY_PERFORMANCE这两种工作策略。反之,实现target 回调函数,通过target回调设定governor所需要的频率。get 回调函数,用于获取cpu当前的工作频率。
getavg 回调函数,用于获取cpu当前的平均工作频率。