现代 CPU 非常渴望转换到省电状态(称为 C 状态)。遗憾的是,从省电状态转换回满电运行状态需要时间,并且在启动组件、重新填充缓存等时可能会引起不必要的应用程序延迟。
实时应用程序可以通过阻止系统进行 C 状态转换来避免这些延迟。有两种方法可以做到这一点:
- 通过在启动时使用processor.max_cstates=1命令行选项,可以防止系统进入省电状态。
- 此外,还可以添加idle=poll选项,以便以最快的速度退出空闲状态。 不幸的是,这两个选项都会导致用电量激增。
如果需要更精细地控制省电状态,延迟敏感型应用程序可以使用电源管理服务质量 (PM QOS) 接口 /dev/cpu\_dma\_latency,以防止处理器进入深度睡眠状态并在退出深度睡眠状态时导致意外延迟。打开 /dev/cpu_dma_latency 并向其中写入零将阻止在文件描述符保持打开状态时转换到深度睡眠状态。此外,向其中写入零可模拟 idle=poll 行为。
细节:
现代处理器(例如英特尔的 Nehalem 处理器)非常积极地转换到省电状态。各种省电级别称为 C 状态,通过操作系统的空闲例程进入。C 状态有编号,从 C0(每个处理器组件都打开)开始,然后向上移动,每个级别关闭更多处理器组件,从而节省更多电量。编号较高的 C 状态也称为_更深的_C 状态。
| ode | Name | What id does | CPUs |
|---|---|---|---|
| C1 | Operating State | CPU fully turned on | All CPUs |
| C1E | Halt | Stops CPU main internal clocks via software; bus interface unit and APIC are kept running at full speed | 486DX4 and above |
| C1E | Enhanced Halt | Stops CPU main internal clocks via software and reduces CPU voltage; bus interface unit and APIC are kept running at full speed | All socket 775 CPUs |
| C1E | -- | Stops all CPU internal clocks | Turion 64, 65-nm Athlon X2 and Phenom CPUs |
| C2 | Stop Grant | Stops CPU main internal clocks via hardware; bus interface unit and APIC are kept running at full speed | 486DX4 and above |
| C2 | Stop Clock | Stops CPU internal and external clocks via hardware | Only 486DX4, Pentium, Pentium MMX, K5, K6, K6-2, K6-III |
| C2E | Extended Stop Grant | Stops CPU main internal clocks via hardware and reduces CPU voltage; bus interface unit and APIC are kept running at full speed | Core 2 Duo and above (Intel only) |
| C3 | Sleep | Stops all CPU internal clocks | Pentium II, Athlon and above, but not on Core 2 Duo E4000 and E6000 |
| C3 | Deep Sleep | Stops all CPU internal and external clocks | Pentium II and above, but not on Core 2 Duo E4000 and E6000; Turion 64 |
| C3 | AltVID | Stops all CPU internal clocks and reduces CPU voltage | AMD Turion 64 |
| C4 | Deeper Sleep | Reduces CPU voltage | Pentium M and above, but not on Core 2 Duo E4000 and E6000 series; AMD Turion 64 |
| C4E/C5 | Enhanced Deeper Sleep | Reduces CPU voltage even more and turns off the memory cache | Core Solo, Core Duo and 45-nm mobile Core 2 Duo only |
| C6 | Deep Power Down | Reduces the CPU internal voltage to any value, including 0 V | 45-nm mobile Core 2 Duo only |
每当 CPU 核心处于空闲状态时,内置的节能逻辑就会启动,并尝试将核心从当前 C 状态转换为更高的 C 状态,从而关闭各种处理器组件以节省电量。当需要 CPU 核心运行程序时,它会收到一个中断以_唤醒,并从其所处的 C 状态转换为 C0。从深度 C 状态转换回 C0 需要时间,因为必须重新打开处理器各个组件的电源。它还必须在__原子_环境中完成,以便在核心通电时没有任何东西会尝试使用核心。
在多核系统上,正在运行的工作负载会定期对齐,因此许多核心会同时处于空闲状态,从而转换到更深的 C 状态。如果它们都尝试同时唤醒,则在核心从深度睡眠状态启动时会产生大量处理器间中断 (IPI)。由于处理中断时需要锁定,系统在处理所有中断时可能会停滞相当长一段时间,这可能会导致应用程序对事件的响应出现很大的延迟(延迟)。
延迟敏感型应用程序不希望处理器转换到更深的 C 状态,因为从 C 状态返回 C0 会产生延迟。这些延迟可能从数百微秒到几毫秒不等。有两种主要方法可以防止系统转换到更深的 C 状态。
disable intel_idle
第一种方法。通过使用内核命令行参数processor.max_cstate=1和idle=poll进行启动,系统将永远不会进入除零之外的C状态,甚至不会使用MWAIT机制在空闲例程中暂时停止。虽然这将提供最快的调度程序响应时间,但它非常浪费电力,会产生需要空调系统运行的热量(并浪费更多电力)。不建议将此方法用于一般用途,但对于测试您的应用程序是否受到cstates和空闲转换延迟的影响非常方便。启动内核并添加命令行选项:
processor.max_cstate=1 idle=poll
可以快速查看应用程序的响应时间是否平滑。
disble acpi_idle
源管理功能有更细粒度的控制
第二种方法对电源管理功能有更细粒度的控制,即使用电源管理服务质量接口 (PM QOS)。文件 /dev/cpu_dma_latency 是一个接口,打开后会向操作系统注册延迟服务质量请求。程序应打开/dev/cpu_dma_latency,向其中写入一个 32 位数字,表示最大响应时间(以微秒为单位),然后在需要低延迟操作时保持文件描述符打开。写入零表示您希望获得尽可能快的响应时间
。
例如:
static int pm_qos_fd = -1;
void start_low_latency(void)
{
s32_t target = 0;
if (pm_qos_fd >= 0)
return;
pm_qos_fd = open("/dev/cpu_dma_latency", O_RDWR);
if (pm_qos_fd < 0) {
fprintf(stderr, "Failed to open PM QOS file: %s",
strerror(errno));
exit(errno);
}
write(pm_qos_fd, &target, sizeof(target));
}
void stop_low_latency(void)
{
if (pm_qos_fd >= 0)
close(pm_qos_fd);
}
或者
#!/usr/bin/perl
use FileHandle;
my $fd = open (">/dev/cpu_dma_latency");
print $fd "0";
print "Press CTRL-C to end.\n";
while (1) {
sleep 5;
}
使用上述例程,应用程序将首先调用start_low_latency(),然后执行所需的延迟敏感处理,然后调用stop_low_latency()。显然,由于打开和关闭文件是一项高开销操作,因此调用启动和停止例程之间的处理时间应该相当长。也就是说,调用启动例程,进行大量处理,然后调用停止例程。
概括:
现代处理器的电源管理功能可能会通过将处理器转换为省电的 C 状态,导致时间敏感的应用程序处理中出现不必要的延迟。
要查看您的应用程序是否受到电源管理转换的影响,请使用以下命令行选项启动您的内核:
processor.max_cstate=1 idle=poll
这将禁用系统中的电源管理(但也会消耗更多电量)。
为了对何时关闭电源管理进行更细粒度的控制,请在应用程序中使用 PM QOS 接口来告诉内核何时禁用省电状态转换。