Intel Powerclamp 驱动程序

作者:

简介

考虑这样一种情况,由于功率预算、热约束或噪声水平,必须在运行时降低系统的功耗,并且不希望使用主动冷却。必须执行软件管理的被动降功耗,以防止为灾难性场景设计的硬件操作。

目前,P 状态、T 状态(时钟调制)和 CPU 脱机用于 CPU 节流。

在 Intel CPU 上,C 状态可有效降低功耗,但到目前为止,它们仅根据工作负载机会性地使用。随着 intel_powerclamp 驱动程序的开发,引入了跨所有在线 CPU 线程同步空闲注入的方法。目标是实现强制且可控的 C 状态驻留。

在功耗、性能、可扩展性和用户体验方面进行了测试/分析。在许多情况下,与使 CPU 脱机或调制 CPU 时钟相比,显示出明显的优势。

操作理论

空闲注入

在现代 Intel 处理器(Nehalem 或更高版本)上,MSR 中提供了包级 C 状态驻留,因此内核也可以使用。

这些 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 驱动程序能够很好地扩展,实施了在线校准。进行此类校准的目标是

  1. 确定空闲注入率的有效范围

  2. 确定每个目标比率所需的补偿量

对每个目标比率的补偿包括两部分

  1. 稳态误差补偿

    这是为了抵消当系统可以在没有额外唤醒(例如外部中断)的情况下进入空闲状态时发生的错误。

  2. 动态误差补偿

    当空闲期间发生过多的唤醒时,可以通过减慢 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

校准发生在运行时。没有可用的离线方法。仅当所有相邻比率的置信度都达到令人满意的水平时才使用稳态补偿。置信度是基于运行时收集的干净数据累积的。在没有额外中断的时间段内收集的数据被认为是干净的。

为了补偿空闲期间的过多唤醒,当检测到这种情况时,会注入额外的空闲时间。目前,我们有一个简单的算法可以将注入率加倍。一个可能的增强功能可能是节流有问题的 IRQ,例如延迟级别触发中断的 EOI。但是,对调度程序或 IRQ 核心代码不具侵入性是一个挑战。

CPU 在线/脱机

每个 CPU 的内核线程在收到 CPU 热插拔活动的通知后启动/停止。intel_powerclamp 驱动程序会跟踪钳制内核线程,即使它们在 CPU 脱机事件后迁移到其他 CPU。

性能分析

本节介绍了在多个系统(包括 Westmere (80P) 和 Ivy Bridge (4P, 8P))上收集的常规性能数据。

有效性和限制

空闲注入允许的最大范围被限制在 50%。如前所述,由于强制空闲时间允许中断,过多的中断可能会导致效率降低。极端情况是执行 ping -f 以生成大量的网络中断,而 CPU 没有太多响应。在这种情况下,空闲注入线程几乎无能为力。在大多数正常情况下,例如 scp 大型文件,应用程序可以被 powerclamp 驱动程序节流,因为降低 CPU 速度也会减慢网络协议处理速度,从而减少中断。

当控制 CPU 在运行时更改控制参数时,其他 CPU 可能需要额外的时间才能赶上这些更改。在此期间,空闲注入会失去同步,因此无法按预期比例进入 package 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。