全景介绍
CPUIdle处理的是:CPU 没有可运行任务(runnable task)时,内核该选择进入哪个 idle 状态(空闲低功耗状态)。和 CPUFreq 对比:
• CPUFreq:关心 CPU 忙时 跑多快、降多少频率省电
• CPUIdle:关心 CPU 闲时 进哪个低功耗状态省电
Linux 为每个 CPU 准备了 idle 线程(idle thread),当调度器发现当前 CPU 没有可运行任务后,CPU 会进入 idle 循环(idle loop),CPUIdle 框架需要从硬件支持的 idle 状态列表中,选一个最合适的状态进入。
idle 状态本身有不同特性:
- • 深度 idle 状态:省电多,退出延迟(exit latency)也高,深度 idle 还可能涉及 local timer(本地定时器)、cache、中断控制器(interrupt controller)、CPU core、cluster 或 power domain(电源域)的硬件操作
CPUIdle 的核心问题就是:根据当前预测的空闲窗口长度,匹配退出延迟约束,选择功耗收益最大的 idle 状态。
CPUIdle 不等于 Runtime PM(运行时电源管理),也不等于系统休眠(system suspend):它处理的是系统仍处于运行(running)状态时,单个 CPU 或 CPU cluster 的局部空闲。

实际情况
工程上理解 CPUIdle,最常见的误区是直接从深度 idle 状态的usage(使用统计)下结论:
深度 idle 状态 usage 不增长,或者 CPU 明明没什么任务,功耗还是降不下去,常见的原因是:
- • 空闲窗口长度不够,高频中断或计时器不断提前唤醒 CPU
- • PM QoS(电源质量服务) latency 约束太严格,直接排除了退出延迟较大的深度 idle 状态
- • tick(时钟滴答)没有完全停止,local timer 一直唤醒 CPU
- • IRQ affinity(中断亲和性)设置不合理,中断集中打到少数 CPU 上
- • device tree(设备树)里的 idle state 参数过于保守,target residency(目标驻留时间)设置偏高
不是深度 idle 状态越多越好,也不是越深越好。一个 idle 状态如果退出延迟很高,但 CPU 很快又被中断唤醒,进入它反而得不偿失(功耗收益不够抵消退出延迟的功耗损失),governor(选择策略)会根据历史停留时间修正预测,逐渐避免选择不合适的深度 idle 状态。
所以 CPUIdle ,不能只看 sysfs 下的 usage。usage 只能说明有没有进过,不能解释为什么没进去,需要从约束、预测和平台能力三层一起分析。

抽象对象
CPUIdle 的核心对象分为 device、driver、state、governor 四类:
struct cpuidle_device:对应一个 CPU 的 CPUIdle 运行状态,它记录当前 CPU 的 idle 统计、上次进入的 state、禁用状态、latency 请求等信息。sysfs 暴露的 usage/time 统计,本质上都来自 device 侧。
struct cpuidle_driver:描述平台支持的 idle 能力,driver 内部维护一个 states 数组,每个 state 描述一个可进入的低功耗状态。ARM64 平台最常见的是PSCI(Power State Coordination Interface,电源状态协调接口) CPUIdle driver,也可能存在平台私有 driver。
struct cpuidle_state:描述单个 idle 状态,通常包含名称、描述、exit latency(退出延迟)、target residency(目标驻留时间)、flags(标志位)和 enter 回调。浅 idle 状态可能只是 WFI(Wait For Interrupt,等待中断),深度 idle 状态可能需要停止 local timer,甚至进入 core/cluster 级低功耗。
struct cpuidle_governor:定义 idle state 选择策略,它不执行硬件动作,只负责根据 next timer(下一个定时器事件)、历史 idle duration(空闲时长)、PM QoS latency、state 参数等信息,选择本次要进入哪个 state。

模型
CPUIdle 的工作模型可以拆成三层:窗口预测 → 约束裁剪 → 平台执行。
窗口预测:回答"这颗 CPU 大概还能空闲多久"。next timer event 给出一个基础参考,但设备中断、IPI(Inter-Processor Interrupt,处理器间中断)、调度事件、RCU(Read-Copy-Update,读拷贝更新锁回调都可能提前唤醒 CPU,governor 会用历史数据修正这个预测。
约束裁剪:回答"哪些 idle 状态当前不能选"。PM QoS latency 请求会排除 exit latency 过大的 state;driver state 的 exit latency 和 target residency 会进一步限制深度 idle 状态;tick/broadcast timer(广播定时器)能力也会影响 state 是否可用。
平台执行:回答"选中以后怎么真的睡下去"。浅 idle 可能只是架构 WFI,深度 idle 可能通过 PSCI CPU_SUSPEND 或固件进入 retention(保持)、power down(下电)、cluster idle。CPUIdle 核心不直接管理所有硬件细节,它通过 driver 进入平台路径。
这套模型里,governor 的选择是预测结果,不是静态规则;driver 的 state 列表是能力描述,不保证每次都能进入;sysfs 统计是结果观察,不是原因解释。

数据流
CPUIdle 的数据流从 idle loop 开始:
调度器发现当前 CPU 没有可运行任务后,进入 idle task。idle loop 准备进入 idle 前,会先处理 tick、RCU、架构 idle 等状态,再通过 CPUIdle 核心请求 governor 选择 state。
governor 读取下一次 timer event、历史 idle duration、PM QoS latency、state 的 exit latency/target residency 等信息,选出目标 state 后,核心调用 driver 的 enter() 回调。
如果目标 state 需要停止 local timer,系统需要依赖 broadcast timer(广播定时器)负责唤醒,这个能力通常由 driver state flag 或 device tree 属性描述。如果 timer/broadcast 处理不对,深度 idle 可能无法启用或者唤醒不可靠。
CPU 被 timer、中断、IPI 或其他事件唤醒后,CPUIdle 核心更新 usage/time 等统计,governor 也拿到一次实际停留时间反馈,下一次选择时,这些历史信息会继续影响预测。

运行
CPUIdle 初始化通常分成三步:governor 注册 → driver 注册 → device 注册。
governor 先把策略注册到 CPUIdle 核心。menu、teo、ladder、haltpoll 都是常见 governor,但适用场景不同,现代移动/嵌入式系统更常见的是 menu 或 TEO governor。
driver 注册平台 idle states。ARM64 平台常见做法是从 device tree 解析 CPU idle states,再结合 PSCI 或平台固件形成 driver state。state 里的 exit latency、target residency、local timer stop 等参数会直接影响选择结果。
device 注册把每个 CPU 接入框架,每个 online CPU 通常都有自己的 cpuidle device,sysfs 会暴露 state 名称、latency、residency、usage、time、disable 等信息。
运行时,CPU 进入 idle loop,governor 做选择,driver 执行进入,事件唤醒后再做反馈更新。这个反馈闭环决定了 CPUIdle 不是一张静态表,而是一个不断根据实际唤醒情况修正的选择系统。
异常路径也要纳入运行模型:
- • PM QoS 未释放会长期排除深度 idle 状态
- • 高精度定时器(hrtimer)频率太高会不断缩短 idle 窗口
- • IRQ affinity 不合理会让某个 CPU 一直被唤醒
- • device tree 参数过于保守也会让 governor 很少选择深度 idle 状态

案例:内核源码中的典型协作
我们看两个 Linux 内核源码中最常见的 CPUIdle 协作案例:
案例一:menu governor + PSCI driver + PM QoS
这是现代 ARM64 平台最标准的路径:
- 1. 预测:menu governor 读到 next timer expiry,结合历史 idle duration 预测窗口长度,得到候选 state 范围
- 2. 裁剪:PM QoS latency 请求排除 exit latency 超过约束的 state,只剩下满足 latency 要求的候选
- 3. 执行:PSCI driver 调用固件进入选中的 idle 状态,CPU 实际进入低功耗
- 4. 反馈:唤醒后 governor 更新实际停留时间,修正下一次预测
整个链路中,governor 不碰硬件,driver 不做选择,PM QoS 只提供约束,每个模块职责清晰,互不耦合。
案例二:tickless 对 CPUIdle 的影响
tickless 内核停止 local timer 会改变 CPUIdle 选择结果:
- • 如果 local tick 没有停止,下一个 tick 就是最短预测窗口,深度 idle 状态很难被选中
- • 停止 local tick 后,下一个 timer event 可能很远,预测窗口变长,深度 idle 状态机会变多
tickless 本身不是 CPUIdle 的一部分,但它通过改变 next timer expiry 这个输入,影响了 governor 预测,最终改变了 idle state 选择结果。这就是框架分层设计的体现:tick 子系统改变输入,CPUIdle 框架自动得到新结果,不需要修改核心逻辑。

总结
CPUIdle 的核心逻辑可以总结为三条线:
- • state 能力:driver 是否暴露 idle state,device tree/firmware 是否支持,state 是否处于禁用状态
- • 预测机制:next timer、历史 idle duration、governor 反馈如何影响选择,是否给深度 idle 状态留下机会
- • 约束与唤醒:PM QoS、tick、timer、中断、RCU、workqueue 有没有给 CPU 留出足够长的空闲窗口
CPUIdle 不是简单的"CPU 空了就睡"。它是在 running 系统里,围绕空闲窗口、退出延迟、平台状态和唤醒事件做选择,核心矛盾永远是:功耗收益 vs 恢复延迟,预测的窗口长度 vs 实际发生的唤醒时间。
Image