Linux下Power Management开发总结
本文作为一个提纲挈领的介绍性文档,后面会以此展开,逐渐丰富。
1. 前言
在 《开发流程》中介绍了PM开发的一般流程,重点是好的模型、简单有效的接口参数、可量化的测试环境以及可独性强的输出。
内核中功耗开发无论是新模型开发还是已有模型的调优,都需要了解现有的框架,遵循已有框架,简单有效的修改。这就需要了解《Android/Linux内核Power Management知识点》,关于Linux省电,从开机-->运行-->suspend-->关机这四种状态,开机/关机不太受关注,但是足够快也是省电的一种。
在进入细节之前,了解一下Linux中PM框架(PM COMMON)有助于下面学习。
suspend(SUSPEND)是一种深层次的省电,运行态情况下省电就八仙过海各显神通了。如果将电流曲线以timeline形式画出,功耗就是曲线覆盖的阴影面积了。一个任务来看,面积越小越好,当然时间也要满足需求。
suspend是系统级省电,涉及到各外设、Memory、CPU等等各种设备,总之是尽量关闭。只保留不能断电部分用于唤醒系统,以及系统恢复,比如外设唤醒中断、RAM Retention等。suspend本身也有不同种类,mem/standby/hibernation。大部分使用的还是mem,即suspend to ram。此时内核处于冻结状态(PROCESS FREEZE),系统tick停止,只有中断将其从睡眠唤醒才会去处理任务。
在系统运行过程中省电,则要复杂多变多了。对于CPU在工作是根据负载动态调频调压(CPUFREQ),没有工作处理的时候进入IDLE(CPUIDLE),更进一步在多核情况下CPU都可以被热插拔(CPU HOTPLUG);对于各种其他外设可以根据是否被使用而动态关闭(RUNTIME PM)。当然这些调节都要保证性能的输出(PM QoS)。
在系统运行过程中,高温可能导致设别损坏,因此根据温度来分配功耗也是一门必要手段(THERMAL)。
当然省电也离不开一些基础功能比如时钟控制(CLOCK)、供电开关(REGULATOR)、电源域划分(POWER DOMAIN),以及内核和应用都会用到的睡眠锁、唤醒源、唤醒事件都可以归到唤醒事件框架中(WAKEUP EVENT)。
系统的供电是使用AC还是电池,备抽象成POWER SUPPLY。
工欲善其事,必先利其器。没有一个好的工具环境,去量化,只会一抹黑,如何验证模型正确与否?如何确定参数是否调优?《开发工具介绍》中介绍了ARM开源的两款工具Workload Automation和LISA,以及一些自己开发的工具集。
在了解开发对象和有了工具之后,当然要去试一试了。《优化实战记录》中详细记录的工具的使用、优化流程和结果。
在文章的结尾,对一些其相关点进行了罗列与总结《功耗知识点补充》。
2. 开发流程
针对一个PM feature进行开发,设计模型是第一步。模型设计好之后,还要保留参数接口,可以基于这些参数针对特殊个体进行优化。
建立一个可以快速迭代、准确可靠、可量化的验证环境尤其重要。一方面可以验证设计的模型是否有效、正确;另一方面还可以调整找到最适合的参数。
针对嵌入式设备来说,最主要的是达到性能和功耗的平衡:在满足性能要求的前提下,尽量降低功耗。
这就涉及到如何去量化性能(Performance)和功耗(Power)。
量化功耗比较简单,可以通过Power Monitor在测量点获得数据(测量点的确定很重要!);量化性能就比较复杂了,针对不同的功能模块,需要不同的性能分析工具。
另外,针对不同的模块,可能需要产生特定的workload。
最后,可读性强的统计信息或者可视化图表也更有利于得出分析结果。
以LISA为例,可以使用workload rt-app产生特定调度侧率,运行时间,运行在特定CPU上的线程,保证运行环境一致。
通过devlib可以获得测试过程中的Power Monitor数据。
然后通过IPython脚本在浏览器中生成可视化图表和统计信息。
开发流程
1.设计模型:根据需求在已有框架中设计新的模型(Thermal中的IPA),或者设计一个全新的功耗模型(如EAS)。目前阶段主要是跟踪追随现有功耗模型。
2.内核实现:基于之前功耗模型,在内核中代码实现。
3.验证环境:建立验证模型的环境,一方面要有量化Performance的工具,另一方面还需要量化Power的工具。
4.模型正确与否?:通过验证环境可以查看模型是否符合预期,如果不符合就重新进行设计。
5.调整模型:根据第4步验证结果,重新调整模型缺陷。
6.优化算法:验证算法是否高效,是否更有效的提升Performance,降低Power。
3. Android/Linux内核Power Management知识点
3.1 PM COMMON
《Linux电源管理(1)_整体架构》从更高的层次介绍了电源管理,供电(PowerSupply),电池设备还需要充电(Charger),设备运行需要时钟(Clock),所在的电源域(PowerDomain),不同电压调节器(Regulator),调频调压(DVFS)以及睡眠唤醒(Suspend),保证功耗服务质量的QoS等等。
传统的粗粒度《Linux电源管理(2)_Generic PM之基本概念和软件架构》关注关机、重启、睡眠、冬眠(Hibernate)。
重启、关机有着相似的《Linux电源管理(3)_Generic PM之Reboot过程》。
设备的功耗管理遵循着统一的《Linux电源管理(4)_Power Management Interface》,bus_type/device_driver/class/device中都嵌入了dev_pm_ops 。
3.2 SUSPEND
suspend能提供最深层次的省电,对外接口是/sys/power/state,一般由用户空间触发。suspend、wakeup、hibernate、sleep、str、str等等概念容易混淆,《Linux电源管理(5)_Hibernate和Sleep功能介绍》对其进行了区分,并架构上以及sysfs进行了介绍。
往/sys/power/state写入mem可以触发《Linux电源管理(6)_Generic PM之Suspend功能》,suspend流程有着明晰的划分:PM Core-->Device PM-->syscore-->machine,同样的resume有着对应的阶段,但是顺序是反过来的。
《Linux电源管理(12)_Hibernate功能》和suspend有着明显的区别,hibernate则是将本应保存到RAM中的内容保存到了存储设备上了,可以更加省电。
对suspend的优化,因为其涉及到进程冻结、脏数据回写、各种外设的suspend、CPU等等内容,很容易引入问题,需要将其流程细分。
将suspend流程划分为不同phase,尤其Device相关需要在进行细分。而且基于Function call graph,甚至可以细节到每个函数执行时间。基本上达到了像素级的优化。
suspend的工具《Linux suspend分析优化工具——analyze_suspend.py》以及基于此的优化实例《Suspend to RAM和Suspend to Idle分析,以及在HiKey上性能对比》,详细介绍了工具和如何使用。
基于以上analyze_suspend.py思想,重新写了个简单的分析工具(TBC).
内核节点:
/sys/power/state
/sys/kernel/debug/tracing/events/power/suspend_resume
/sys/kernel/debug/suspend_stats
3.3 WAKEUP EVENT
具备唤醒功能的设备被称为wakeup source,它产生的唤醒时间被称为wakeup events。
《Linux电源管理(7)_Wakeup events framework》介绍了Linux内核wakeup events框架,它也是wakelock、wakeup count以及autosleep的基础。
《Linux电源管理(8)_Wakeup count功能》主要用于suspend同步,《Linux电源管理(9)_wakelocks》提供了内核和用户空间的wake lock。
《Linux电源管理(10)_autosleep》受用户触发将suspend操作放入有序队列autosleep_wq。
内核节点:
/sys/kernel/debug/tracing/events/power/wakeup_source_*
/sys/kernel/debug/wakeup_sources
3.4 RUNTIME PM
设备影响功耗的行为《Linux电源管理(13)_Driver的电源管理》,主要有是否具备唤醒能力,设备wakelock阻止系统进入唤醒的能力,从《Linux电源管理(14)_从设备驱动的角度看电源管理》看,驱动相关的功耗行为包括suspend/resume/shutdown/poweroff/rumtime,传统的suspend/resume逐渐被抛弃,《Linux电源管理(11)_Runtime PM之功能描述》的runtime_suspend/runtime_resume/runtime_idle更加灵活高效。
设备的RPM和cpuidle的深睡结合,功耗比较接近suspend了。
内核节点:
/sys/kernel/debug/tracing/events/rpm
3.5 CPUIDLE
CPU无事可做时会进入idle进程,cpu_idle是cpuidle进程的主循环,cpuidle_idle_call是入口点。《Linux cpuidle framework(1)_概述和软件架构》对cpuidle基本功能和架构做了介绍,然后《Linux cpuidle framework(2)_cpuidle core》从cpuidle使用者kernel sched角度进行分析,同时介绍了对cpuidle device/driver/governor是如何管理的以及sysfs节点。
cpuidle device是一种虚拟的设备,《Linux cpuidle framework(3)_ARM64 generic CPU idle driver》提供了CPU支持的不同cpuidle状态以及进入状态的驱动。cpuidle支持不同种类的状态,如何根据当前情况进入不同状态呢》《Linux cpuidle framework(4)_menu governor》就是作出这种选的主题。可以说cpuidle governor是决策机构,cpuidle driver是执行机构,cpuidle core提供了触发点以及不同参数配置接口。
那么关于CPUIDLE我们能做什么呢?
重点在于governor和driver,driver提供的状态越多,cpuidle在节省功耗和QoS之间的选择就会越丰富;
governor主要有menu和ladder,顾名思义,menu可以根据需要直接跳转状态,而ladder需要一级一级的爬。
cpuidle提供了进入不同状态的Trace,可以通过分析其timeline,查看进入的状态。
内核节点:
/sys/devices/system/cpu/cpuidle
/sys/kernel/debug/tracing/events/power/cpu_idle
3.6 CPU OPS/HOTPLUG
针对SMP,在cpuidle和cpufreq之间还存在一种低功耗技术cpu的热插拔。在《Linux CPU core的电源管理(1)_概述》中,动态关闭不需要的不需要的CPU核,也可以达到节省功耗的目的。
了解《Linux CPU core的电源管理(2)_cpu topology》才能更有针对性的进行hotplug。
在ARM体检架构下,针对CPU的suspend/idle等操作封装在《Linux CPU core的电源管理(3)_cpu ops》,CUP的状态有online/active/present/possible,每个CPU的online节点是《Linux CPU core的电源管理(5)_cpu control及cpu hotplug》的操作接口。
内核节点:
/sys/devices/system/cpu/online
/sys/devices/system/cpu/offline
/sys/kernel/debug/tracing/events/cpuhp
3.7 CPUFREQ
cpufreq也称作DVFS,《Linux电源管理(15)_PM OPP Interface》定义了不同的Voltage和Frequency的组合。
《linux cpufreq framework(1)_概述》从架构上介绍了cpufreq是如何运作过的,介绍了core/driver/governor的关系,封装了cpufreq_driver、cpufreq_policy和cpufreq_governor。《linux cpufreq framework(3)_cpufreq core》提供了driver/policy/governor三者之间框架,同时通过sysfs向上提供了接口。
《Linux cpufreq framework(2)_cpufreq driver》是调频的执行者,跟具体的架构芯片有关,特别的针对ARM的bL有《linux cpufreq framework(5)_ARM big Little driver》。
《linux cpufreq framework(4)_cpufreq governor》作为调频调压的策略制定者,有很多种(performance/powersave/userspace/ondemand/interactive),需要根据实际情况选择。
另一系列(DroidPhone)关于cpufreq的文章,
《Linux动态频率调节系统CPUFreq之二:核心(core)架构与API》
《Linux动态频率调节系统CPUFreq之三:governor》
内核节点:
/sys/devices/system/cpu/cpufreq
/sys/kernel/debug/tracing/events/power/cpu_frequency
3.8 THERMAL
高功耗会带来温度问题,在达到一定温度的时候需要降低功耗。在散热和功耗消耗量之间有一个平衡点,在此功耗量,稳定基本保持稳定,同时不会对设备造成伤害。
《Android/Linux Thermal框架分析及其Governor对比》就是用来处理这类事情的,thermal governor(IPA/stepwise)是决策者,thermal cooling是执行者。
在PC上有风扇,但是在嵌入式设备上只能通过降低功耗(主要是通过DVFS)来达到降低温度的目的。《Android/Linux Thermal Governor之IPA分析与使用》是其中一种governor,它的核心是PID控制器。
内核节点:
/sys/class/thermal
/sys/kernel/debug/tracing/events/thermal
/sys/kernel/debug/tracing/events/thermal_power_allocator
3.9 CLOCK
《Linux common clock framework(1)_概述》是用来管理Clock资源的子系统。对其它dirver提供clocks通用API;从DT中解析出clock tree关系;不同类型的clock器件;clock设置主要内容包括enable/disable clock、设置clock频率、选择clock parent等。
《Linux common clock framework(2)_clock provider》介绍了如何编写clock driver,clock分类有fixed rate clock、gate clock、divider clock、mux clock、fixed factor clock、coposite clock。
《Linux common clock framework(3)_实现逻辑分析》从clock consumer和clock provider两个角度介绍内核是如何管理clock资源的,以及driver是怎么使用clock资源的。
《Common Clock Framework系统结构》总体介绍了common clock framework,从DT中获取clock provider、consumer以及common clock framework相关配置。Clock driver作为provider,其它设备作为consumer,两者通过common clock framework联系在一起。
内核节点:
/sys/kernel/debug/clk
/sys/kernel/debug/tracing/events/clk
/sys/kernel/debug/tracing/events/power/clock_*
3.10 PM QOS
PM的主要功能就是节省功耗,同时会付出一定性能代价。PM QoS的存在就是为了保证采取功耗措施之前,保证性能(延时、吞吐量)。
《Linux PM QoS framework(1)_概述和软件架构》将整个框架分为核心QoS Framework、QoS Requestors(应用、GPU、Flash等驱动需要系统满足一定条件)、QoS Requestee(cpuidle、RPM、PM Domain获取各种限制,确保自身行为满足限制)。
限制constrain分为2类:(1)系统级,包括cpu/dma latency、network latency、network throughput、memory bandwith;(2)设备级,包括从低功耗状态的resume latency、active状态latency和一些QoS flag。
《Linux PM QoS framework(2)_PM QoS class》负责系统级QoS管理。
《Linux PM QoS framework(3)_per-device PM QoS》负责per-device的QoS管理。
内核节点:
/sys/kernel/debug/pm_qos
/sys/kernel/debug/tracing/events/power/pm_qos*
/sys/kernel/debug/tracing/events/power/dev_pm_qos*
3.11 Power Domain
《Linux PM domain framework(1)_概述和使用流程》芯片设计往往根据不同功能或者不同电压将供电分为不同区域,即电源域。
这样系统运行过程中,可以根据需求动态开关某一电源域,已达到节省功耗的目的。
电源域框架包括使用者、提供者以及框架实现。
内核节点:
/sys/kernel/debug/tracing/events/power/power_domain_target
/sys/kernel/debug/pm_genpd/pm_genpd_summary
3.12 REGULATOR
Regulator包括voltage regulator和current regulator,可以自动维持很定电压/电流的输出。
《Linux Regulator Framework(1)_概述》介绍了Regulator框架,主要进行电压/电流最大最小值设置、开关等操作。Regulator框架向内核其它driver提供API用以控制电压电流输出,同时提供了实现自身driver的接口。
《Linux Regulator Framework(2)_regulator driver》介绍了一个Regulator驱动实例。
内核节点:
/sys/class/regulator
/sys/kernel/debug/tracing/events/regulator
/sys/kernel/debug/regulator
3.13 POWER SUPPLY
Power Supply是供电设备的意思,为系统运行供电,包括电池设备、USB Charger、DC Charger。
《Linux power supply class(1)_软件架构及API汇整》对供电设备抽象形成struct power_supply,同时提供通过API用于编写不同供电设备驱动,向用户控件提供sysfs。
内核节点:
/sys/class/power_supply
3.14 PROCESS FREEZE
在进入suspend之前,需要将所有用户进程和内核线程暂停,这就需要《Linux进程冻结技术》。在对进程冻结,使其处于可控状态后才可以进行设备suspend操作以及CPU关闭等。
4. 开发工具介绍
分析了WA的框架以及其使用,重点是基于WA的框架进行二次开发。从工具名称就可以知道此工具是自动化产生负荷,然后对测试结果做post-processing。
首先为什么要有workload概念,由于测试对象不同,需要特定的用例,只有通过特殊的工具,比如rt-app能产生一定CPU load、不同数量、不同优先级、不同调度策略的进程,这种灵活性是手工无法达到的。
同时由于自动化,避免了认为带来的不确定性。WA的框架,也非常适合二次开发。不同待测设备,增加device即可;开发新的负荷,增加workload;增加测量仪表,增加instrument;需要新的手段分析数据,增加result_processor。
同时由于自动化,极大的提高了开发测试效率,更加敏捷。
《Linux Power Management Debug》
收集了网上一些关于功耗调试的方法工具,有很多开源好东东值得拥有。
由于功耗曲线和内核行为无法对应,开发测试中多靠经验判断。如果能将实际功耗和内核行为对应,那么将极大提高功耗Debug的能力。
此工具也着重于此痛点,对功耗曲线进行highlight,并且标注消耗量和平均电流。然后基于同样timeline显示内核行为irq、wakelock、cpuidle、cpufreq等等内核行为。可以方便查看异常功耗时的内核行为。
《Suspend分析工具analyze_suspend,及其WA自动化》
对测试数据进行分析,并将其可视化是Python的强项,数据分析的Pandas/NumPy,可视化的matplotlib/bokeh等等。
将这些工具用于问题分析,以及优化调试非常有效。
5. 优化实战记录
5.1 Suspend分析与优化
《Suspend to RAM和Suspend to Idle分析,以及在HiKey上性能对比》
《cpu_ops、suspend_ops、arm_idle_driver以及machine_restart/machine_power_off到底层PSCI Firmware分析》
5.2 开机时间优化
关于开机时间的优化,分为内核和用户空间两部分。内核的优化依赖于dmesg(analyze_boot.py),用户空间的优化依赖于busybox附带的bootchart(pybootchartgui.py),Ubuntu等使用systemd-analyze更加简单。
一些在Linaro WiKi上写的文档: