以节能的方式动态禁用核心?

以节能的方式动态禁用核心?

我正在寻找一种动态禁用 Linux 中的核心的机制,以最大限度地降低功耗。

不幸的是,使用以下简单方法禁用核心实际上会增加功率,根据读数瓦特快车?专业版测量系统总功率:

echo 0 > /sys/devices/system/cpu/cpu7/online

我的经历似乎得到了其他人的证实(尽管这个错误已经被标记为“CLOSED PATCH_ALREADY_AVAILABLE”): https://bugzilla.kernel.org/show_bug.cgi?id=5471

由于机器没有负载,我希望除了一个核心之外的所有核心(或者可能是两个“核心”,因为 CPU 是超线程的)都处于尽可能深的睡眠状态。根据 acpitool 的输出,这似乎不会自动发生:

Processor ID           : 7
Bus mastering control  : no
Power management       : yes
Throttling control     : no
Limit interface        : no
Active C-state         : C0
C-states (incl. C0)    : 3
Usage of state C1      : 899 (99.3 %)
Usage of state C2      : 6 (0.7 %)

顺便说一句,让我感到困惑的一点是 acpitool 和 /proc/acpi 似乎对可用的 C 状态存在分歧,或者他们使用不同的命名方案。

$ cat /proc/acpi/processor/CPU7/power 
active state:            C0
max_cstate:              C8
maximum allowed latency: 2000000000 usec
states:
    C1:                  type[C1] promotion[--] demotion[--] latency[001] usage[00000000] duration[00000000000000000000]
    C2:                  type[C2] promotion[--] demotion[--] latency[017] usage[00001248] duration[00000000001877531423]
    C3:                  type[C3] promotion[--] demotion[--] latency[017] usage[00000006] duration[00000000000012580727]

这似乎表明有 4 个 C 状态(C0-C3),但 acpitool 仅报告 3 个 C 状态。


实际上这可以归结为两个问题:

  1. 是否有一种(安全的)方法可以强制单个核心进入特定的睡眠状态(C 状态),并强制它们保持该状态直到我明确唤醒它们?
  2. 或者,我怎样才能提高操作系统自动将核心更持续地置于更深的睡眠状态的能力?

请注意,从深度睡眠状态唤醒的延迟不是问题。FWIW,我在 Intel i7 920 上运行 Ubuntu 10.04.3(内核 2.6.32-38)。

答案1

上述限制 C 状态的方法都是永久性的(直到系统重新启动)。如果您希望系统在某些时段具有极低的延迟,但希望在其他时间节省更多电量,则有一种方法可以动态控制使用哪些 C 状态。

要动态控制 C 状态,请打开文件 /dev/cpu_dma_latency 并将最大允许延迟写入其中。只要文件 /dev/cpu_dma_latency 保持打开状态,这将阻止使用转换延迟高于指定值的 C 状态。写入最大允许延迟 0 将使处理器保持在 C0 状态(如使用内核参数“idle=poll”),而写入较低的值(通常为 5 或更低)应在空闲时强制处理器进入 C1 状态。将处理器限制为 C1 状态所需的确切值取决于各种因素,例如您正在使用哪个空闲驱动程序、您正在使用哪个 CPU,以及系统中的 ACPI 表。也可以写入更高的值来限制使用延迟大于写入值的 C 状态。使用的值应与 /sys/devices/system/cpu/cpuX/cpuidle/stateY/latency 中的延迟值相对应(其中 X 是 CPU 编号,Y 是空闲状态)——不应使用延迟比写入 /dev/cpu_dma_latency 的延迟更大的 CPU 空闲状态。

一个简单的方法是编译一个简单的程序,该程序将写入此文件,并保持打开状态直到被终止。下面是此类程序的一个示例,可以通过将代码剪切并粘贴到名为 setcpulatency.c 的文件中并运行“make setcpulatency”来编译。因此,为了最大限度地减少某些时段(例如从上午 8 点到下午 5 点)的延迟,可以设置一个 cron 作业以在上午 8 点运行。此 cron 作业可以在后台使用参数 0 运行 setcpulatency,并使用如下 cron 表条目:

00 08 * * * /path/to/setcpulatency 0 &

然后,在下午 5 点,另一个 cron 作业可以终止任何保持 /dev/cpu_dma_latency 打开的程序:

00 17 * * * kill -9 `lsof –t /dev/cpu_dma_latency`

当然,这只是一个例子,展示如何动态控制 C 状态...... crond 服务通常在低延迟环境中被禁用,但这些步骤可以手动执行或通过其他方式运行。

#include <stdio.h>
#include <fcntl.h>

int main(int argc, char **argv) {
   int32_t l;
   int fd;

   if (argc != 2) {
      fprintf(stderr, "Usage: %s <latency in us>\n", argv[0]);
      return 2;
   }

   l = atoi(argv[1]);
   printf("setting latency to %d us\n", l);

   fd = open("/dev/cpu_dma_latency", O_WRONLY);

   if (fd < 0) {
      perror("open /dev/cpu_dma_latency");
      return 1;
   }

   if (write(fd, &l, sizeof(l)) != sizeof(l)) {
      perror("write to /dev/cpu_dma_latency");
      return 1;
   }
}

相关内容