Динамическое отключение ядер энергосберегающим способом?
Я ищу механизм для динамического отключения ядер в Linux, чтобы минимизировать энергопотребление.
К сожалению, отключение ядер с использованием следующего простого подхода на самом деле увеличивает мощность, основываясь на показаниях ватт-ап? Pro измерения общей мощности системы:
echo 0 > /sys/devices/system/cpu/cpu7/online
Мой опыт, кажется, подтверждается другими (хотя эта ошибка была помечена как "ЗАКРЫТА PATCH_ALREADY_AVAILABLE"): https://bugzilla.kernel.org/show_bug.cgi?id=5471
Поскольку машина выгружена, я хочу, чтобы все, кроме одного, ядра (или, возможно, двух "ядер", поскольку ЦП является гиперпоточным) находились в максимально глубоком спящем состоянии. Кажется, что это не происходит само по себе, основываясь на выводе 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-состояниях.
На самом деле это сводится к двум вопросам:
- Есть ли (безопасный) способ заставить отдельные ядра перейти в определенное состояние сна (C-состояние) и заставить их оставаться там до тех пор, пока я их явно не разбуду?
- В качестве альтернативы, как я могу улучшить способность ОС автоматически более последовательно переводить ядра в более глубокие спящие состояния?
Обратите внимание, что задержка пробуждения от более глубоких состояний сна не является проблемой. FWIW, я использую Ubuntu 10.04.3 (ядро 2.6.32-38) на Intel i7 920.
1 ответ
Методы ограничения C-состояний, описанные выше, будут постоянными (до перезагрузки системы). Если вы хотите, чтобы у системы была чрезвычайно низкая задержка в определенные часы, но в другое время вы хотели бы сэкономить больше энергии, существует метод динамического контроля того, какие C-состояния используются.
Чтобы динамически управлять состояниями C, откройте файл /dev/cpu_dma_latency и запишите в него максимально допустимую задержку. Это предотвратит использование C-состояний с задержками перехода, превышающими указанное значение, при условии, что файл /dev/cpu_dma_latency остается открытым. Запись максимально допустимой задержки 0 будет держать процессоры в C0 (как при использовании параметра ядра "idle=poll"), а запись низкого значения (обычно 5 или ниже) должна заставить процессоры переходить в C1 в режиме ожидания. The exact value needed to restrict processors to the C1 state depends on various factors such as which idle driver you are using, which CPUs you are using, and possibly the ACPI tables in your system. Higher values could also be written to restrict the use of C-states with latency greater than the value written. The value used should correspond to the latency values in /sys/devices/system/cpu/cpuX/cpuidle/stateY/latency (where X is the CPU number and Y is the idle state)—CPU idle states that have a greater latency than written to /dev/cpu_dma_latency should not be used.
One simple way to do this is by compiling a simple program that will write to this file, and stay open until it is killed. An example of such a program is below, and can be compiled by cutting and pasting the code into a file called setcpulatency.c, and running “make setcpulatency”. So, to minimize latency during certain hours, say from 8AM until 5PM, a cron job could be set up to run at 8AM. This cron job could run setcpulatency in the background with an argument of 0, with a cron table entry like this:
00 08 * * * /path/to/setcpulatency 0 &
Then, at 5PM, another cron job could kill any program that's holding /dev/cpu_dma_latency open:
00 17 * * * kill -9 `lsof –t /dev/cpu_dma_latency`
Of course, this is just an example to show how C-states can be dynamically controlled... the crond service is often disabled in low latency environments, but these steps could be taken manually or run by other means.
#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;
}
}