Intel Powerclamp 驱动程序¶
- 作者:
Arjan van de Ven <arjan@linux.intel.com>
Jacob Pan <jacob.jun.pan@linux.intel.com>
简介¶
考虑这样一种情况:由于功率预算、散热限制或噪音水平,系统在运行时必须降低功耗,并且不倾向于采用主动散热。此时必须执行软件管理的被动降功耗,以防止硬件为灾难性场景而设计的动作。
目前,P-状态、T-状态(时钟调制)和 CPU 下线用于 CPU 节流。
在 Intel CPU 上,C-状态提供了有效的功耗降低,但到目前为止,它们仅根据工作负载进行机会性使用。随着 intel_powerclamp 驱动程序的开发,引入了跨所有在线 CPU 线程同步空闲注入的方法。目标是实现强制和可控的 C-状态驻留。
已在功耗、性能、可扩展性和用户体验方面进行了测试/分析。在许多情况下,与 CPU 下线或调制 CPU 时钟相比,显示出明显的优势。
操作理论¶
空闲注入¶
在现代 Intel 处理器(Nehalem 或更新版本)上,包级 C-状态驻留可在 MSR 中获得,因此内核也能获得。
这些 MSR 是:
#define MSR_PKG_C2_RESIDENCY 0x60D
#define MSR_PKG_C3_RESIDENCY 0x3F8
#define MSR_PKG_C6_RESIDENCY 0x3F9
#define MSR_PKG_C7_RESIDENCY 0x3FA
如果内核也可以向系统注入空闲时间,那么就可以建立一个管理包级 C-状态的闭环控制系统。intel_powerclamp 驱动程序被设想为这样一个控制系统,其中目标设定点是用户选择的空闲率(基于功耗降低),误差是实际包级 C-状态驻留率与目标空闲率之间的差异。
注入由为每个在线 CPU 生成的高优先级内核线程控制。
这些具有 SCHED_FIFO 类别的内核线程被创建用于执行受控占空比和持续时间的钳制操作。每个每 CPU 线程根据 jiffies 的取整同步其空闲时间和持续时间,从而可以防止累积误差以避免抖动效应。线程也绑定到 CPU,以便它们不能迁移,除非 CPU 下线。在这种情况下,属于下线 CPU 的线程将立即终止。
以 SCHED_FIFO 运行且优先级相对较高,也使得该方案适用于可抢占和不可抢占的内核。空闲时间围绕 jiffies 对齐确保了 HZ 值的可扩展性。这种效果可以通过 Perf 时间图更好地可视化。下图显示了内核线程 kidle_inject/cpu 的行为。在空闲注入期间,它运行 monitor/mwait 空闲给定的“持续时间”,然后将 CPU 让给其他任务,直到下一个时间间隔。
在空闲期间,NOHZ 调度时钟被禁用,但中断未被屏蔽。测试表明,来自调度器时钟的额外唤醒对大型系统(具有 80 个处理器的 Westmere 系统)上 powerclamp 驱动程序的效率有巨大影响。
CPU0
____________ ____________
kidle_inject/0 | sleep | mwait | sleep |
_________| |________| |_______
duration
CPU1
____________ ____________
kidle_inject/1 | sleep | mwait | sleep |
_________| |________| |_______
^
|
|
roundup(jiffies, interval)
只允许一个 CPU 收集统计数据和更新全局控制参数。这个 CPU 在本文档中被称为控制 CPU。控制 CPU 在运行时选举,策略偏向 BSP,并考虑了 CPU 热插拔的可能性。
就空闲控制系统的动态而言,包级空闲时间在很大程度上被认为是一个非因果系统,其行为不能基于过去或当前的输入。因此,intel_powerclamp 驱动程序试图根据给定输入(目标空闲率)立即强制执行所需的空闲时间。注入后,powerclamp 在给定时间窗口内监控实际空闲情况,并相应调整下一次注入,以避免过量/不足校正。
当用于因果控制系统(如温度控制)时,该驱动程序的用户需要实现将过去样本和输出纳入反馈的算法。例如,基于 PID 的温度控制器可以使用 powerclamp 驱动程序,根据过去样本的积分和微分增益来维持所需的目标温度。
校准¶
在可扩展性测试期间,观察到随着核心数量的增加,CPU 之间的同步操作变得具有挑战性。系统进入包级 C 状态的能力也是如此。
为了确保 intel_powerclamp 驱动程序能够很好地扩展,实现了在线校准。进行此类校准的目标是:
确定空闲注入比的有效范围
确定每个目标比率所需的补偿量
对每个目标比率的补偿由两部分组成:
稳态误差补偿
这是为了抵消系统在没有额外唤醒(如外部中断)的情况下进入空闲时发生的错误。
动态误差补偿
当空闲期间发生过多的唤醒时,可以通过减慢 CPU 活动来添加额外的空闲比率以抑制中断。
提供了一个 debugfs 文件供用户检查补偿进度和结果,例如在 Westmere 系统上:
[jacob@nex01 ~]$ cat
/sys/kernel/debug/intel_powerclamp/powerclamp_calib
controlling cpu: 0
pct confidence steady dynamic (compensation)
0 0 0 0
1 1 0 0
2 1 1 0
3 3 1 0
4 3 1 0
5 3 1 0
6 3 1 0
7 3 1 0
8 3 1 0
...
30 3 2 0
31 3 2 0
32 3 1 0
33 3 2 0
34 3 1 0
35 3 2 0
36 3 1 0
37 3 2 0
38 3 1 0
39 3 2 0
40 3 3 0
41 3 1 0
42 3 2 0
43 3 1 0
44 3 1 0
45 3 2 0
46 3 3 0
47 3 0 0
48 3 2 0
49 3 3 0
校准在运行时进行。没有离线方法可用。稳态补偿仅在所有相邻比率的置信水平达到满意水平时才使用。置信水平是根据运行时收集的干净数据累积的。在没有额外中断的期间收集的数据被认为是干净的。
为了补偿空闲期间过多的唤醒,当检测到此类情况时,会注入额外的空闲时间。目前,我们有一个简单的算法将注入比率加倍。一个可能的增强可能是限制触发中断,例如延迟电平触发中断的 EOI。但这对于调度器或 IRQ 核心代码来说,要做到非侵入性是一个挑战。
CPU 上线/下线¶
每 CPU 内核线程在收到 CPU 热插拔活动的通知后启动/停止。intel_powerclamp 驱动程序会跟踪钳制内核线程,即使它们在 CPU 下线事件后迁移到其他 CPU。
性能分析¶
本节描述了在多个系统上收集的一般性能数据,包括 Westmere (80P) 和 Ivy Bridge (4P, 8P)。
有效性和局限性¶
允许的空闲注入最大范围限制在 50%。如前所述,由于在强制空闲期间允许中断,过多的中断可能会导致效率降低。极端情况可能是执行 ping -f 来生成泛滥的网络中断而没有太多 CPU 确认。在这种情况下,空闲注入线程几乎无能为力。在大多数正常情况下,例如 scp 大文件时,应用程序可以通过 powerclamp 驱动程序进行节流,因为减慢 CPU 也会减慢网络协议处理,从而减少中断。
当控制 CPU 在运行时改变控制参数时,其余 CPU 可能需要额外的时间来跟上这些改变。在此期间,空闲注入会不同步,因此无法以预期的比率进入包 C 状态。但这种影响很小,因为在大多数情况下,目标比率的改变频率远低于空闲注入频率。
可扩展性¶
测试还显示,在 50% 空闲比率下,4P/8P Ivy Bridge 系统和 80P Westmere 服务器之间存在微小但可测量的差异。Westmere 需要更多的补偿才能达到相同的目标空闲比率。并且补偿随着空闲比率的增加而增加。上述原因构成了校准代码的必要性。
在 IVB 8P 系统上,与下线 CPU 相比,powerclamp 可以实现每瓦高达 40% 的更好性能。(通过对为所有运行 CPU 生成的每 CPU 计数线程求和的自旋计数器进行测量)。
使用和接口¶
powerclamp 驱动程序作为冷却设备注册到通用热层。目前,它未绑定到任何热区。
jacob@chromoly:/sys/class/thermal/cooling_device14$ grep . *
cur_state:0
max_state:50
type:intel_powerclamp
cur_state 允许用户设置所需的空闲百分比。向 cur_state 写入 0 将停止空闲注入。写入 1 到 max_state 之间的值将开始空闲注入。读取 cur_state 将返回实际和当前的空闲百分比。这可能与用户设置的值不同,因为当前空闲百分比取决于工作负载并包含自然空闲。当空闲注入被禁用时,读取 cur_state 返回值 -1 而不是 0,以避免将 100% 繁忙状态与禁用状态混淆。
使用示例
注入 25% 的空闲时间
$ sudo sh -c "echo 25 > /sys/class/thermal/cooling_device80/cur_state
如果系统不忙且已有超过 25% 的空闲时间,则 powerclamp 驱动程序将不会启动空闲注入。使用 Top 将不会显示空闲注入内核线程。
如果系统繁忙(下面的自旋测试)并且自然空闲时间少于 25%,powerclamp 内核线程将执行空闲注入。强制空闲时间被计为正常空闲,因为采用与空闲任务相同的通用代码路径。
在此示例中,显示了 24.1% 的空闲。这有助于系统管理员或用户在 powerclamp 驱动程序运行时确定性能下降的原因。
Tasks: 197 total, 1 running, 196 sleeping, 0 stopped, 0 zombie
Cpu(s): 71.2%us, 4.7%sy, 0.0%ni, 24.1%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 3943228k total, 1689632k used, 2253596k free, 74960k buffers
Swap: 4087804k total, 0k used, 4087804k free, 945336k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3352 jacob 20 0 262m 644 428 S 286 0.0 0:17.16 spin
3341 root -51 0 0 0 0 D 25 0.0 0:01.62 kidle_inject/0
3344 root -51 0 0 0 0 D 25 0.0 0:01.60 kidle_inject/3
3342 root -51 0 0 0 0 D 25 0.0 0:01.61 kidle_inject/1
3343 root -51 0 0 0 0 D 25 0.0 0:01.60 kidle_inject/2
2935 jacob 20 0 696m 125m 35m S 5 3.3 0:31.11 firefox
1546 root 20 0 158m 20m 6640 S 3 0.5 0:26.97 Xorg
2100 jacob 20 0 1223m 88m 30m S 3 2.3 0:23.68 compiz
测试表明,通过将 powerclamp 驱动程序用作冷却设备,基于 PID 的用户空间热控制器可以有效地管理 CPU 温度,前提是没有添加其他热影响。例如,Ultrabook 用户可以在特定温度(低于大多数活动跳变点)下编译内核。
模块参数¶
cpumask
(读写)一个用于注入空闲的 CPU 位掩码。位掩码的格式与 /proc/irq/*/smp_affinity 等其他子系统中使用的格式相同。掩码是逗号分隔的 32 位组。每个 CPU 对应一个位。例如,对于一个 256 CPU 系统,完整的掩码是:ffffffff,ffffffff,ffffffff,ffffffff,ffffffff,ffffffff,ffffffff,ffffffff
最右边的掩码用于 CPU 0-32。
max_idle
(读写)注入空闲时间占总 CPU 时间的最大比率,范围从 1% 到 100%。即使冷却设备的 max_state 始终为 100 (100%),此参数也允许添加最大空闲百分比限制。默认值为 50,以匹配 powerclamp 驱动程序的当前实现。如果 cpumask 包含系统中所有存在的 CPU,则不允许值超过 75。