idle
CPU是用来计算的,如果CPU没事可干的话,Linux Kernel中称cpu这种状态为idle,而内核中的
cpuidle framework就是为了管理这种状态。
idle进程
CPU任何时候都是要执行进程的,把idle做成进程就可以和内核中当前的任务调度系统很自然的链接起来。
系统初始化之后,就会把第一个init进程变为idle进程,并把优先级设置成最低。
当idle进程被调用的时候,说明cpu已经没事可干了。
这样的话,如果要设置CPU状态的话,只需要在idle进程里面操作就可以了。
所以idle的整个逻辑就拆成了这么几步:
- CPU支持哪些状态,这些状态通过什么途径上报给操作系统
- 操作系统基于什么策略选择让CPU进入什么状态
- 这些CPU状态的进入和退出,需要怎么执行
下面就围绕这个逻辑来展开。
CPU idle状态
cpu core根据功耗有不同的状态,ACPI定义了processor state,称为c state。
功耗越低唤醒延时越大。C0代表运行态,C1、C2、CX是具体的硬件实现,数字越大,睡眠程度越深。
后面ACPI又引入了Low Power Idle扩展,idle的状态不仅和core相关,也可以和系统中其它组件相关。
ARM64 cpu idle
ARM上cpu idle最初是通过WFI和WFE指令来实现的。
但是随着对时延要求的提高,CX state的引入,多级idle就自然而然产生了。
16年Linux Kernel也支持了ACPI LPI扩展。
linux kernel cpuidle framework
内核中的cpuidle框架逻辑视图如下:
开发视图如下:
整体逻辑
boot阶段
系统启动后,创建idle线程
runtime阶段
判断是否有任务调度
a. 如果有的话,就去做schedule调度判断core有没有被offline,
a. 如果被offline,则执行cpu die相关流程判断有没有使用cpuidle framework
a. 如果没有使用,则直接走default idle函数,执行wfi如果使用了cpuidle framework,那接下来要调用cpuidle_select(),获取target state
a.cpuidle_select()
,根据当前使用的governor,根据系统的pm qos,预期驻留时间/唤醒延时,判断target statecall_cpuidle()
调用注册的driver进入target state
a. driver主要做的事情是,在初始化时,从ACPI/DTS中获取c state信息;调用psci、pcc等协议和通信接口driver根据target state进入低功耗状态,有可能是idle、retention、shutdown等状态
a. 如果是retention,会处于wfi,上下文不丢失,唤醒后执行下一条指令
b. 如果是shutdown,会重新走resume流程
对于支持ACPI Low power idle的arm64来说,最后会调用acpi_idle_lpi_ender
进入相应的idle状态,进而调用PSIC规范相关的函数psci_ops.cpu_suspend
,
之后通过SMC指令调用UEFI中ARM TrustFirmware中的psci_cpu_suspend
函数,从而进入厂商的plat_psci_ops_t
中定义的相关函数。
完整调用栈如下:
linux kernel:
do_idle
cpuidle_idle_call
cpuidle_select
cpuidle_enter
acpi_idle_lpi_enter
acpi_processor_ffh_lpi_enter
psci_cpu_suspend_enter
psci_ops->cpu_suspend
psci_0_2_cpu_suspend
smc CPU_SUSPEND
trust firmware:
psci_smc_handler
psci_cpu_suspend
cpu_standby
plat_psci_ops_t->cpu_standby
测试验证
可以通过sysfs接口查看当前支持idle方式:
root@localhost:~# grep "" /sys/devices/system/cpu/cpuidle/*
/sys/devices/system/cpu/cpuidle/available_governors:ladder menu teo
/sys/devices/system/cpu/cpuidle/current_driver:none
/sys/devices/system/cpu/cpuidle/current_governor:menu
/sys/devices/system/cpu/cpuidle/current_governor_ro:menu
如果支持了LPI,则会看到:
sys/devices/system/cpu/cpuidle/low_power_idle_cpu_residency_us
sys/devices/system/cpu/cpuidle/low_power_idle_system_residency_us
负载测试
带负载的测试,可以参考ARM Neoverse平台的LPI测试方法。
参考
- cpuidle overview
- Linux cpuidle framework(1)_概述和软件架构
- Linux Cpuidle介绍
- Low Power Idle Table
- CPU idle power saving methods for real-time workloads
- cpuidle framework in Linux Kernel(2)what’s idle state
- ACPI / processor_idle: Add ACPI v6.0 LPI support
- Processor P-states and C-states
- Arm Neoverse Reference Design Platform Software documentation-ACPI Low Power Idle
- Arm Neoverse N2 reference design Technical Overview
- 一文搞懂ARM SoC功耗控制架构