Linux在消费电子领域的应用已经相当普遍,而对于消费电子产品来说,省电是一个重要的议题。
Linux 的电源管理非常复杂,涉及到系统级待机、频率电压转换、系统空闲处理以及各个设备驱动对系统待机的支持和各个设备运行时()的电源管理。可以说和系统中的每一个设备驱动都息息相关。
电源管理对于消费类电子产品来说非常重要,因此这部分工作往往占据了开发周期中相当一部分的比例,下图是Linux内核电源管理的整体架构,大致可以归纳为以下几类:
1)CPU在运行过程中根据系统负载动态改变电压和频率。
2)当系统空闲时,CPU根据空闲情况进入低功耗模式。
3)多核系统中CPU的热插拔支持。
4)PM QoS是系统和设备为满足特殊的时延要求而申请的,并按照特定的策略起作用。
5) 将系统暂停到RAM/硬盘的一系列设备驱动程序入口函数。
6)SoC进入挂起状态,SDRAM自刷新进入。
7)设备运行时动态电源管理,根据使用情况动态打开和关闭设备。
8) 底层时钟、电压调节器、频率/电压计(由OPP模块完成)支持可供各个驱动子系统使用。
1. 司机
该子系统位于/目录下,负责在运行时动态调整CPU的频率和电压,即DVFS( )。之所以在运行时调整CPU的电压和频率,是因为CMOS电路中的功耗与电压的平方成正比,与频率成正比,因此降低电压和频率可以降低功耗。
核心层位于//.c下,为各个SoC驱动的实现提供统一的接口,并实现了当策略和频率发生变化时通知其他模块的机制。
2. 策略
SoC驱动只是设定了CPU频率参数,提供了设置频率的方法,但是并不关心CPU本身应该运行在什么频率上,具体按照什么标准来设定频率,做哪些改变,完全由策略()决定,如表所示。
系统中增加了交互策略,适用于对延迟敏感的UI交互任务,当有UI交互任务时,该策略会更积极、更及时地调整CPU频率。
综上所述,系统状态和策略共同决定了CPU跳频的目标,核心层将目标频率传递给底层SoC驱动,由SoC驱动修改硬件完成变频,如图所示。
用户空间一般可以通过/sys///cpu/cpux/节点进行设置,比如我们要设置它采用该策略,则运行以下命令:
# echo userspace > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
# echo 700000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed
3.性能测试和调优
Linux内核3.1之后已经把-utils工具集放到了内核的tools/power/目录下,该工具集中的-bench工具可以帮助工程师分析采用该工具对系统性能的影响。
-bench工具的工作原理是在系统运行时模拟“空闲→忙→空闲→忙”的场景,从而触发系统动态的频率变化,然后通过执行与高频模式下相同的操作,同时使用诸如、、、等策略来计算完成任务的时间比例。
交叉编译工具完成后,可以将其放在目标板文件系统的/usr/sbin/目录下,运行该工具:
# cpufreq-bench -l 50000 -s 100000 -x 50000 -y 100000 -g ondemand -r 5 -n 5 -v
会输出一系列结果,我们提取出 Round n 这样的行,它表示的是 -g 选项中设置的策略相对于该策略的业绩比,假设该值为:
Round 1 - 39.74%
Round 2 - 36.35%
Round 3 - 47.91%
Round 4 - 54.22%
Round 5 - 58.64%
这显然不够理想,我们在同一个平台上采用了交互策略,得到了新的测试结果:
Round 1 - 72.95%
Round 2 - 87.20%
Round 3 - 91.21%
Round 4 - 94.10%
Round 5 - 94.93%
大致的目标是动态调整频率和电压之后,性能应该在高性能策略下的90%左右,这是理想的。
4. 司机
目前大部分 ARM SoC 都支持几种不同的 Idle 等级,驱动子系统的作用就是管理这些 Idle 状态,并根据系统的运行情况进入不同的 Idle 等级。具体 SoC 的底层驱动实现提供了类似驱动频率表的 Idle 等级表,并实现了各种 Idle 状态的进入和退出流程。
Intel系列笔记本电脑支持ACPI( and Power ,高级配置和电源接口),一般有4种不同的C状态(C0为运行状态、C1为Halt状态、C2为Stop-Clock状态、C3为Sleep状态),如表所示。
5.
它是一款用于功耗分析和电源管理诊断的开源工具,其主页位于Intel开源技术中心,维护者为Arjan van de Ven和。它可以分析系统中软件的功耗,找出耗电大户,还可以显示系统中不同C状态(对应驱动)和P状态(对应驱动)的时间占比,采用TAB式的界面风格,如图所示。
6. 司机
它是Linux系统中电源管理的基本设施之一,用于稳压电源的管理,是各个驱动子系统中设置电压的标准接口,上面介绍的驱动经常使用它来设置电压。
它能够管理系统中的电源单元,也就是电压调节器(Low,LDO,即低压差线性稳压器),并提供获取和设置这些电源单元电压的接口。一般在一块ARM电路板上,各个电压调节器及设备都会形成一个树形结构,如图所示。
Linux 子系统提供以下 API 来注册/取消注册电压调节器:
structregulator_dev * regulator_register(conststructregulator_desc
*regulator_desc, conststructregulator_config *config);
voidregulator_unregister(structregulator_dev *rdev);
7. OPP
如今的SoC一般集成了非常多的器件,系统运行时并不是所有模块都需要运行在最高频率和最高性能,SoC内部有的可以运行在较低的频率和电压,有的可以运行在较高的频率和电压,一组支持的pair被称为一个Point,简称OPP。
int opp_add(struct device *dev, unsigned long freq, unsigned long u_volt);
目前TI OMAP驱动底层采用OPP机制来获取CPU支持的频率电压列表,TI OMAP4芯片在启动过程中会为CPU设备注册OPP表(代码位于arch/arm/mach-omap2/)
8. 性能管理QoS
Linux 内核的 PM QoS 系统为内核和应用程序提供了一组接口,用户可以通过这些接口设定自己的性能期望值。一类是系统级要求,通过这些参数来设定;另一类是单个设备可以根据自己的性能要求发起 per-PM QoS 请求。
9. CPU热插拔
Linux CPU热插拔特性已经存在相当长一段时间了,在3.8之后的Linux内核中有一个小小的改进就是CPU0也可以热插拔了。
一般来说,在用户空间,可以通过/sys///cpu/cpun/节点来对某个CPU进行在线和离线操作:
# echo 0>/sys/devices/system/cpu/cpu3/online
CPU 3 is now offline
# echo 1 >/sys/devices/system/cpu/cpu3/online
当通过echo 0 >/sys///cpu/cpu3/关闭CPU3时,CPU3上的进程会被迁移到其他CPU上,保证在移除CPU3的过程中系统依然能够正常运行。一旦通过echo 1 >/sys///cpu/cpu3/再次开启CPU3,CPU3就可以参与系统的负载均衡,分担系统的任务。
在嵌入式系统中,CPU热插拔可以作为一种省电方式,当系统负载较轻时,动态关闭CPU,当系统负载增加时,再开启之前离线的CPU。目前各芯片公司可能会根据自身SoC的特点,调整内核,实现运行时的“热插拔”。
10. 暂停至 RAM
Linux支持几种形式的待机,例如挂起到RAM,挂起到硬盘,如图所示。
一般嵌入式产品只实现了 to RAM(也称s2ram,或者常称为STR),也就是将系统状态保存在内存中,并让SDRAM处于自刷新状态,在用户按下按键后再恢复系统。少数嵌入式Linux系统实现了 to disk(简称STD),与 to RAM不同,s2ram不会关闭系统,而STD会将系统状态保存到磁盘,然后关闭整个系统。
在 Linux 下,这些操作通常由用户空间触发,通过将 mem 写入 /sys/power/state 来启动挂起到 RAM 的过程。当然,许多 Linux 产品都会有一个按钮,只需按一下即可进入挂起到 RAM。
这通常是因为这个键对应的输入设备驱动上报了电源相关事件,用户空间的电源管理进程接收到这个事件,并触发s2ram。当然内核也有驱动,位于/input/apm-power.c,它可以在内核层面监听类事件,并通过()自动触发s2ram。
11. 运行时 PM
该结构体中,有三个以()、()、()开头的成员函数,协助设备完成运行时的电源管理:
PM 不同于上面介绍的系统级 to RAM PM,它是针对单个设备的。当系统不处于休眠状态时,设备可以在空闲时进入 状态,在非空闲时执行 ,使设备进入正常工作状态。这样设备运行时就会更省电。Linux PM 最早是在 .6.32 内核中合并的。
总结
Linux内核的PM框架涉及到很多组件,搞清楚这些组件之间的依赖关系,针对性的进行优化,用正确的方法编写PM,对于提升代码质量、辅助功耗、性能测试等都有很大的益处。
另外,在实际工程中,特别是在消费电子领域,超过一半的 Bug 可能都与电源管理有关。此时电源管理的很大一部分工作就是为了实现健壮性和鲁棒性。可以说,很多时候,这是一项体力活,需要工程师有足够的耐心。