Linux电源管理(1)
Linux电源管理架构
Linux电源管理十分复杂,涉及到系统级的待机、频率电压变换、系统空闲时的处理以及每个设备驱动对系统待机的支持和每个设备的运行时电源管理。
Linux的电源管理大致可以分为以下几类:
- CPU在运行时根据系统负载进行动态电压和频率变换的CPUFreq
- CPU在系统空闲时根据空闲情况进行低功耗模式的CPUIdle
- 多核系统下CPU热插拔的支持
- 系统和设备针对延迟的特别需求而提出申请的PM QoS。
- 设备驱动针对系统挂起到RAM/硬盘的一系列入口函数
- SoC进入挂起状态、SDRAM自刷新的入口
- 设备的运行时动态电源管理
- 底层的时钟、稳压器、频率/电压表支撑
CPUFreq驱动
CPUFreq子系统位于drivers/cpufreq目录下,负责运行时CPU频率和电压的动态调整,即DVFS(Dynamic Voltage Frequency Scaling)。其目的在于降低功耗(CMOS电路中的功耗与电压的平方成正比、与频率成正比)。
CPUFreq核心为CPUFreq驱动提供了一套统一的接口和notifier机制,方便CPUFreq驱动的编写和事件的通知。CPU运行频率发生变化时,内核的loops_per_jiffy常数也会发生变化。
CPUFreq驱动实现
每个SoC的具体CPUFreq驱动只需要实现电压、频率表,以及从硬件层面完成这些变化。其在内核中的抽象为cpufreq_driver。
1 | struct cpufreq_driver { |
CPUFreq驱动就是对cpufreq_driver数据结构的填充,可以说linux说有的驱动实现都是对相应驱动数据结构的填充。具体可参考内核中相应代码。
CPUFreq的策略
CPUFreq驱动设定了CPU的频率参数,以及提供了设置频率的途径。而CPUFreq的策略则负责频率变化的调整。
在内核中,分别实现了如下CPUFreq策略,其通过cpufreq governor进行管理。
CPUFreq策略 | 策略的实现方法 |
---|---|
ondemand | 平时以低速方式运行,当系统负载提高时按需自动提高频率 |
performance | CPU以最高频率运行 |
conservative | 与cpufreq_ondemand 类似,区别在动态频率变更时采用渐进的方式 |
powersave | CPU以最低频率运行 |
userspace | 通过sys节点scaling_setspeed设置频率,同时设置scaling_governor节点为userspace |
总之,系统的状态和CPUFreq的策略共同决定了CPU频率跳变的目标,CPUFreq的核心层将目标频率传递给底层具体SoC的CPUFreq驱动,由该驱动完成CPU频率的变换。
CPUFreq的性能测试和调优
内核中存在cpuower-utils工具集(tools/power/cpupower),其中的cpufreq-bench工具帮助分析CPUFreq对系统性能的影响。
cpufreq-bench原理是模拟系统运行时的“空闲->忙->空闲->忙”等场景,从而触发系统的动态频率变化,然后分析performance策略与其它策略下完成同样运算任务时,performance策略相对的时间占比。
CPUFreq的通知
CPUFreq子系统会发出通知的情况有两种:CPUFreq的策略变化和CPU运行频率变化。当事件发生时,CPUFreq驱动会触发CPUFreq核心发出相应通知。
内核提供了如下接口方便地使用CPUFreq的通知:
1 | #define CPUFREQ_TRANSITION_NOTIFIER (0) |
CPUIdle驱动
目前ARM SoC大多支持多个不同的Idle级别,CPUIdle驱动子系统存在的目的就是对这些Idle状态进行管理,并根据系统运行状态进入不同的Idle级别。
CPUIdle驱动主要实现是提供一个类似CPUFreq驱动频率表的Idle级别表,同时实现各种不同Idle状态的进入和退出的硬件相关代码。
对于支持ACPI(Advanced Configuration and Power Interface)的Intel笔记本而言,一般有4个不同的C状态。
状态 | 功耗(mW) | 延迟(us) |
---|---|---|
C0(操作) | -1 | 0 |
C1(Halt) | 1000 | 1 |
C2(Stop-Clock) | 500 | 1 |
C3(Sleep) | 100 | 57 |
对ARM SoC而言,差异较大,但有一个最简单的WFI(等待中断发生)状态,默认会进入此状态下。
CPUIdle驱动的实现
要实现CPUIdle驱动,就是要填充cpuidle_driver结构体,具体完成可参考内核相应驱动,下面是cpuidle_driver结构体定义。
1 | struct cpuidle_driver { |
与CPUFreq类似,在CPUIdle子系统中也有对应的governor来抉择何时进入何种Idle级别的策略。
CPUIdle策略 | 策略实现方法 |
---|---|
haltpoll | 根据过去空闲时间和睡眠时间动态调整最匹配的Idle级别 |
ladder | 以步进方式进入和退出Idle级别,以过去的时间作为参考(不依赖NO_HZ配置) |
menu | 根据预期的空闲时间直接进入目标Idle级别(依赖NO_HZ配置) |
teo | 根据过去空闲时间和睡眠时间动态调整最匹配的Idle级别 |
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 yxhlfx@163.com
文章标题:Linux电源管理(1)
本文作者:红尘追风
发布时间:2017-01-09, 18:15:17
原始链接:http://www.micernel.com/2017/01/09/Linux%E7%94%B5%E6%BA%90%E7%AE%A1%E7%90%86(1)/版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。