Управляем частотой CPU в ОС FreeBSD

FreeBSD
В интернете можно найти все, ну почти все. Проблема в том — что просто не знаешь чего искать то.
Так и с этой темой.

Как то обратил внимание сколько потребляется кВт/ч в месяц, сумма не очень понравилась, и решил с этим хоть как-то бороться. Жесткие диски работают постоянно, Westeng Digital серия Green, как заявлено производителем — с пониженным энергопотреблением. В общем — за счет них не особо сэкономишь. Видео-карта ..., тоже нет механизмов регулирования. Сетевая — такая же беда. И вот добираемся до процессора. Как известно, все достаточно современные процессоры позволяют регулировать свою частоту, как следствие при понижении частоты — энергопотребление уменьшается, при увеличении — соответственно увеличивается.
В ОС FreeBSD существует драйвер, для управления частотой процессора — это cpufreq.

Бегло окидываем взглядом man по нему и получаем след. средства управления этим драйвером через sysctl:

     dev.cpu.%d.freq
             Current active CPU frequency in MHz.

     dev.cpu.%d.freq_levels
             Currently available levels for the CPU (frequency/power usage).
             Values are in units of MHz and milliwatts.

     dev.DEVICE.%d.freq_settings
             Currently available settings for the driver (frequency/power
             usage).  Values are in units of MHz and milliwatts.  This is
             helpful for understanding which settings are offered by which
             driver for debugging purposes.

     debug.cpufreq.lowest
             Lowest CPU frequency in MHz to offer to users.  This setting is
             also accessible via a tunable with the same name.  This can be
             used to disable very low levels that may be unusable on some sys‐
             tems.

     debug.cpufreq.verbose
             Print verbose messages.  This setting is also accessible via a
             tunable with the same name.


Ага, что же мы получили:
dev.cpu.%d.freq — текущая частота процессора;
dev.cpu.%d.freq_levels — доступные настройки для драйвера (частота/мощность). Частота в МГЦ, мощность в мВт;
dev.DEVICE.%d.freq_settings, debug.cpufreq.lowest, debug.cpufreq.verbose — отладочные параметры, про них позже.

Если верить описанию — на процессору можно установить любую частоту из списка dev.cpu.%d.freq_levels. Частота устанавливается через системную переменную dev.cpu.%d.freq, так же она отображает текущую частоту процессора.
Ну что ж, это функционал устраивает, приступаем к настройке.

Установка драйвера

Здесь все элементарно, устанавливаем модуль ядра и подгружаем его:
[18:08 dk@mira ~]> cd /usr/src/sys/modules/cpufreq/
[18:13 dk@mira /usr/src/sys/modules/cpufreq]> sudo make
...
[18:13 dk@mira /usr/src/sys/modules/cpufreq]> sudo make install cleandir
install -o root -g wheel -m 555   cpufreq.ko /boot/kernel
kldxref /boot/kernel
rm -f export_syms cpufreq.ko cpufreq.kld ichss.o est.o hwpstate.o p4tcc.o powernow.o opt_acpi.h acpi_if.h pci_if.h bus_if.h cpufreq_if.h device_if.h
rm -f @ machine
rm -f .depend GPATH GRTAGS GSYMS GTAGS


Загружаем модуль и проверяем настройки драйвера:
[18:14 dk@mira /usr/src/sys/modules/cpufreq]> sudo kldload cpufreq
[18:15 dk@mira /usr/src/sys/modules/cpufreq]> kldstat -v | grep cpufreq
                151 cpu/cpufreq
10    1 0xffffffff8090f000 e7d8     cpufreq.ko (/boot/kernel/cpufreq.ko)

[18:15 dk@mira /usr/src/sys/modules/cpufreq]> sysctl -a|grep freq
kern.acct_chkfreq: 15
kern.timecounter.tc.i8254.frequency: 1193182
kern.timecounter.tc.ACPI-fast.frequency: 3579545
kern.timecounter.tc.HPET.frequency: 14318180
kern.timecounter.tc.TSC.frequency: 1866677939
debug.cpufreq.lowest: 0
debug.cpufreq.verbose: 0
machdep.acpi_timer_freq: 3579545
machdep.tsc_freq: 1866677939
machdep.i8254_freq: 1193182
dev.cpu.0.freq: 1867
dev.cpu.0.freq_levels: 1867/22464 1633/19656 1600/22464 1400/19656 1200/16848 1000/14040 800/11232 600/8424 400/5616 200/2808
dev.acpi_perf.0.freq_settings: 1867/22464 1600/22464
dev.cpufreq.0.%driver: cpufreq
dev.cpufreq.0.%parent: cpu0
dev.cpufreq.1.%driver: cpufreq
dev.cpufreq.1.%parent: cpu1
dev.p4tcc.0.freq_settings: 10000/-1 8750/-1 7500/-1 6250/-1 5000/-1 3750/-1 2500/-1 1250/-1
dev.p4tcc.1.freq_settings: 10000/-1 8750/-1 7500/-1 6250/-1 5000/-1 3750/-1 2500/-1 1250/-1

Диапазон частот от 1867МГц до 200МГц, при этом потребляемая мощность может меняться от 22,464Вт до 2,808Вт. При максимальной частоте в 1867 МГц потребляемая мощность составит 22,464Вт, а при минимальной частоте 200МГц всего 2,808Вт — что почти в 10 раз меньше!!!
Разрешаем драйверу загружаться вместе с системой, для этого в файл /boot/loader.conf добавляем следующею строку:
cpufreq_load="yes"


Пробуем драйвер

Драйвер загружен в память, список частот есть — теперь самое время его опробовать. Поменяем частоту процессора с максимальной до минимальной и обратно:
[18:23 root@mira ~]# sysctl dev.cpu.0.freq=200
dev.cpu.0.freq: 1867 -> 200
[18:23 root@mira ~]# sysctl  dev.cpu.0.freq
dev.cpu.0.freq: 200
[18:24 root@mira ~]# sysctl dev.cpu.0.freq=1867
dev.cpu.0.freq: 200 -> 1867
[18:24 root@mira ~]# sysctl dev.cpu.0.freq
dev.cpu.0.freq: 1867

Вроде работает, можно двигаться дальше.

Управляем частотой процессора в зависимости от нагрузки

Первая мысль, которая пришла в голову — это написать свой скрипт, который в течении промежутка времени будет собирать статистику по загрузке процессора, и если загрузки нет — то просто понижать частоту до следующей ступени. А если загрузка есть, и активная — то наоборот, повышать до следующей ступени.
Но после детального прочтения документации по cpufreq вышел на службу powerd, которая занимается именно этим. Итак, какие параметры есть у этой службы:

DESCRIPTION
     The powerd utility monitors the system state and sets various power con‐
     trol options accordingly.  It offers four modes (maximum, minimum, adap‐
     tive and hiadaptive) that can be individually selected while on AC power
     or batteries.  The modes maximum, minimum, adaptive and hiadaptive may be
     abbreviated max, min, adp, hadp.

     Maximum mode chooses the highest performance values.  Minimum mode
     selects the lowest performance values to get the most power savings.
     Adaptive mode attempts to strike a balance by degrading performance when
     the system appears idle and increasing it when the system is busy.  It
     offers a good balance between a small performance loss for greatly
     increased power savings.  Hiadaptive mode is like adaptive mode, but
     tuned for systems where performance and interactivity are more important
     than power consumption.  It increases frequency faster, reduces the fre‐
     quency less aggressively and will maintain full frequency for longer.
     The default mode is adaptive for battery power and hiadaptive for the
     rest.

The powerd utility recognizes the following runtime options:

     -a mode     Selects the mode to use while on AC power.

     -b mode     Selects the mode to use while on battery power.

     -i percent  Specifies the CPU load percent level when adaptive mode
                 should begin to degrade performance to save power.  The
                 default is 50% or lower.

     -n mode     Selects the mode to use normally when the AC line state is
                 unknown.

     -p ival     Specifies a different polling interval (in milliseconds) for
                 AC line state and system idle levels.  The default is 250 ms.

     -P pidfile  Specifies an alternative file in which the process ID should
                 be stored.  The default is /var/run/powerd.pid.

     -r percent  Specifies the CPU load percent level where adaptive mode
                 should consider the CPU running and increase performance.
                 The default is 75% or higher.

     -v          Verbose mode.  Messages about power changes will be printed
                 to stdout and powerd will operate in the foreground.

Как следует из описания — поддерживается 4 режима работы:
— max (maximum) — выбираются максимальные настройки производительности (установит макс. частоту процессора);
— min (minimum) — выбираются минимальные настройки производительности (установит минимальную частоту процессора);
— adp(adaptive) — адаптивный, понижает частоту при простое, и увеличивает при появлении нагрузки;
— hadp (hiadaptive) — аналогичен адаптивному режиму, но упор делается на производительность, в ущерб энергопотреблению. Частоту процессора увеличивает быстрее чем понижает.
Первые два режима нам не интересны, ибо max — это и без драйвера включен, min — все время держать минимальную частоту совсем не интересно.
Остается два режима, adp и hadp. Вот их и посмотрим, для это запускаем powerd по очереди в каждом режиме:
[18:38 root@mira ~]# powerd -v -a adp
powerd: unable to determine AC line status
load  16%, current freq 1867 MHz ( 0), wanted freq 1633 MHz
changing clock speed from 1867 MHz to 1633 MHz
load  14%, current freq 1633 MHz ( 1), wanted freq 1428 MHz
changing clock speed from 1633 MHz to 1600 MHz
powerd: error setting CPU frequency 1600: Invalid argument
load  18%, current freq 1600 MHz ( 2), wanted freq 1249 MHz
changing clock speed from 1600 MHz to 1400 MHz
load  26%, current freq 1400 MHz ( 3), wanted freq 1092 MHz
changing clock speed from 1400 MHz to 1200 MHz
powerd: error setting CPU frequency 1200: Invalid argument
load  24%, current freq 1200 MHz ( 4), wanted freq  955 MHz
changing clock speed from 1200 MHz to 1000 MHz
powerd: error setting CPU frequency 1000: Invalid argument
load  26%, current freq 1000 MHz ( 5), wanted freq  835 MHz
load  30%, current freq 1000 MHz ( 5), wanted freq  730 MHz
changing clock speed from 1000 MHz to 800 MHz
powerd: error setting CPU frequency 800: Invalid argument
load  29%, current freq  800 MHz ( 6), wanted freq  638 MHz
load  26%, current freq  800 MHz ( 6), wanted freq  558 MHz
changing clock speed from 800 MHz to 600 MHz
powerd: error setting CPU frequency 600: Invalid argument
load  45%, current freq  600 MHz ( 7), wanted freq  488 MHz
load  20%, current freq  600 MHz ( 7), wanted freq  427 MHz
load   9%, current freq  600 MHz ( 7), wanted freq  373 MHz
changing clock speed from 600 MHz to 400 MHz
powerd: error setting CPU frequency 400: Invalid argument
load  38%, current freq  400 MHz ( 8), wanted freq  326 MHz
load  30%, current freq  400 MHz ( 8), wanted freq  285 MHz
load  35%, current freq  400 MHz ( 8), wanted freq  249 MHz
load  17%, current freq  400 MHz ( 8), wanted freq  217 MHz
load  30%, current freq  400 MHz ( 8), wanted freq  200 MHz
changing clock speed from 400 MHz to 200 MHz
powerd: error setting CPU frequency 200: Invalid argument
load  45%, current freq  200 MHz ( 9), wanted freq  200 MHz
^Ctotal joules used: 51.948

[18:40 root@mira ~]# powerd -v -a hadp
powerd: unable to determine AC line status
load  12%, current freq 1867 MHz ( 0), wanted freq 1808 MHz
load  11%, current freq 1867 MHz ( 0), wanted freq 1751 MHz
load   4%, current freq 1867 MHz ( 0), wanted freq 1696 MHz
load  15%, current freq 1867 MHz ( 0), wanted freq 1643 MHz
load  11%, current freq 1867 MHz ( 0), wanted freq 1591 MHz
changing clock speed from 1867 MHz to 1600 MHz
powerd: error setting CPU frequency 1600: Invalid argument
load  15%, current freq 1600 MHz ( 2), wanted freq 1541 MHz
load  17%, current freq 1600 MHz ( 2), wanted freq 1492 MHz
load  17%, current freq 1600 MHz ( 2), wanted freq 1445 MHz
load  22%, current freq 1600 MHz ( 2), wanted freq 1399 MHz
changing clock speed from 1600 MHz to 1400 MHz
load  19%, current freq 1400 MHz ( 3), wanted freq 1355 MHz
load  20%, current freq 1400 MHz ( 3), wanted freq 1312 MHz
load   9%, current freq 1400 MHz ( 3), wanted freq 1271 MHz
load  23%, current freq 1400 MHz ( 3), wanted freq 1231 MHz
load  23%, current freq 1400 MHz ( 3), wanted freq 1192 MHz
changing clock speed from 1400 MHz to 1200 MHz
powerd: error setting CPU frequency 1200: Invalid argument
load  18%, current freq 1200 MHz ( 4), wanted freq 1154 MHz
load  26%, current freq 1200 MHz ( 4), wanted freq 1154 MHz
load  15%, current freq 1200 MHz ( 4), wanted freq 1117 MHz
^Ctotal joules used: 87.750

Как и следовало из описания — hadp стремиться занять максимальную частоту, но при простое уменьшает. adp — симметричный баланс, растет также как и падает. Что из этого следует? А следует вот что: в режиме hadp — процессор максимально быстро выйдет на рабочую частоту, т.е. фактические одиночный всплеск нагрузки заставит ворочаться процессор на максимальной частоте, в то время как частота процессора при простое будет понижаться не так оперативно. В режиме adp — будет симметричное понижение/повышение частоты процессора — т.е. он одинаково медленно будет опускать частоту и поднимать частоту.
Выбор режима должен каждый выбирать для себя, это дело вкуса. Хотите чтобы процессор выходил на максимальную частоту предельно быстро — то это hadp, но потребление будет выше. Если не обломаться, и подождать несколько секунд до выхода на максимальную частоту — то это режим adp.
Лично для моих нужд adp хватает за глаза.
Добавочно можно регулировать переключение частот параметрами -r и -i:
-r — указывает порог нагрузки, при котором следует повышать частоту. По умолчанию — 75% и больше. Т.е. при нагрузке в 75% и выше частота процессора будет повышаться;
-i — указывает порог нагрузки, при котором следует понижать частоту. По умолчанию — 50% и меньше. Т.е. при нагрузке 50% и ниже — частота процессора будет понижаться.
Под мои нужды, как я и указывал выше — реактивной реакции не надо, могу и подождать некоторое время. Для этого указываю — что увеличивать частоту при нагрузке в 90% и выше.
Проверяем:
[18:51 root@mira ~]# powerd -a adp -r 90 -v
...
load  26%, current freq  200 MHz ( 9), wanted freq  200 MHz
load  70%, current freq  200 MHz ( 9), wanted freq  200 MHz
load 150%, current freq  200 MHz ( 9), wanted freq  400 MHz
changing clock speed from 200 MHz to 400 MHz
powerd: error setting CPU frequency 400: Invalid argument
load 129%, current freq  400 MHz ( 8), wanted freq  800 MHz
changing clock speed from 400 MHz to 800 MHz
powerd: error setting CPU frequency 800: Invalid argument
load  73%, current freq  800 MHz ( 6), wanted freq  800 MHz
load  33%, current freq  800 MHz ( 6), wanted freq  700 MHz
load 113%, current freq  800 MHz ( 6), wanted freq 1400 MHz
changing clock speed from 800 MHz to 1400 MHz
load  69%, current freq 1400 MHz ( 3), wanted freq 1400 MHz
load  29%, current freq 1400 MHz ( 3), wanted freq 1225 MHz
load  35%, current freq 1400 MHz ( 3), wanted freq 1071 MHz
changing clock speed from 1400 MHz to 1200 MHz
powerd: error setting CPU frequency 1200: Invalid argument
load  12%, current freq 1200 MHz ( 4), wanted freq  937 MHz
changing clock speed from 1200 MHz to 1000 MHz
powerd: error setting CPU frequency 1000: Invalid argument
load  20%, current freq 1000 MHz ( 5), wanted freq  819 MHz
load  39%, current freq 1000 MHz ( 5), wanted freq  716 MHz
changing clock speed from 1000 MHz to 800 MHz
powerd: error setting CPU frequency 800: Invalid argument
load  26%, current freq  800 MHz ( 6), wanted freq  626 MHz
load  25%, current freq  800 MHz ( 6), wanted freq  547 MHz
changing clock speed from 800 MHz to 600 MHz
powerd: error setting CPU frequency 600: Invalid argument
load  25%, current freq  600 MHz ( 7), wanted freq  478 MHz
...

Вполне приемлемый результат. Что показывают эти цифры: после выхода процессора на минимальную частоту в 200МГц была дана нагрузка в течении секунды, что видно в плавном повышении до 1400МГц, а после исчезновения нагрузки — плавное понижение. Каждая строчка — это период в 250мс, который, кстати, тоже можно менять с помощью параметра -p. Попробуем уменьшить период до 100мс:
[18:57 root@mira ~]# powerd -a adp -r 90 -p 100 -v
..
load  67%, current freq  200 MHz ( 9), wanted freq  200 MHz
load  38%, current freq  200 MHz ( 9), wanted freq  200 MHz
load 148%, current freq  200 MHz ( 9), wanted freq  400 MHz
changing clock speed from 200 MHz to 400 MHz
powerd: error setting CPU frequency 400: Invalid argument
load 130%, current freq  400 MHz ( 8), wanted freq  800 MHz
changing clock speed from 400 MHz to 800 MHz
powerd: error setting CPU frequency 800: Invalid argument
load 116%, current freq  800 MHz ( 6), wanted freq 1600 MHz
changing clock speed from 800 MHz to 1600 MHz
powerd: error setting CPU frequency 1600: Invalid argument
load 124%, current freq 1600 MHz ( 2), wanted freq 1867 MHz
changing clock speed from 1600 MHz to 1867 MHz
load  58%, current freq 1867 MHz ( 0), wanted freq 1867 MHz
load  32%, current freq 1867 MHz ( 0), wanted freq 1633 MHz
changing clock speed from 1867 MHz to 1633 MHz
load 108%, current freq 1633 MHz ( 1), wanted freq 1867 MHz
changing clock speed from 1633 MHz to 1867 MHz
load 112%, current freq 1867 MHz ( 0), wanted freq 1867 MHz
load   8%, current freq 1867 MHz ( 0), wanted freq 1633 MHz
changing clock speed from 1867 MHz to 1633 MHz
load   8%, current freq 1633 MHz ( 1), wanted freq 1428 MHz
changing clock speed from 1633 MHz to 1600 MHz
powerd: error setting CPU frequency 1600: Invalid argument
load  22%, current freq 1600 MHz ( 2), wanted freq 1249 MHz
changing clock speed from 1600 MHz to 1400 MHz
load  16%, current freq 1400 MHz ( 3), wanted freq 1092 MHz
changing clock speed from 1400 MHz to 1200 MHz
powerd: error setting CPU frequency 1200: Invalid argument
load  31%, current freq 1200 MHz ( 4), wanted freq  955 MHz
changing clock speed from 1200 MHz to 1000 MHz
powerd: error setting CPU frequency 1000: Invalid argument
load  22%, current freq 1000 MHz ( 5), wanted freq  835 MHz
load   8%, current freq 1000 MHz ( 5), wanted freq  730 MHz
changing clock speed from 1000 MHz to 800 MHz
powerd: error setting CPU frequency 800: Invalid argument
load  24%, current freq  800 MHz ( 6), wanted freq  638 MHz
load  24%, current freq  800 MHz ( 6), wanted freq  558 MHz
changing clock speed from 800 MHz to 600 MHz
powerd: error setting CPU frequency 600: Invalid argument
load  53%, current freq  600 MHz ( 7), wanted freq  558 MHz
load  31%, current freq  600 MHz ( 7), wanted freq  488 MHz
load   8%, current freq  600 MHz ( 7), wanted freq  427 MHz
load   0%, current freq  600 MHz ( 7), wanted freq  373 MHz
changing clock speed from 600 MHz to 400 MHz
powerd: error setting CPU frequency 400: Invalid argument
load  16%, current freq  400 MHz ( 8), wanted freq  326 MHz
load  24%, current freq  400 MHz ( 8), wanted freq  285 MHz
load  29%, current freq  400 MHz ( 8), wanted freq  249 MHz
load  16%, current freq  400 MHz ( 8), wanted freq  217 MHz
load  32%, current freq  400 MHz ( 8), wanted freq  200 MHz
changing clock speed from 400 MHz to 200 MHz
powerd: error setting CPU frequency 200: Invalid argument
load  58%, current freq  200 MHz ( 9), wanted freq  200 MHz
load  31%, current freq  200 MHz ( 9), wanted freq  200 MHz

Видно, что тестовой нагрузки в одну секунду хватило чтоб вывести процессор на максимальную частоту, причем довольно быстро — за 700мс (количество строк после 200МГц * 100мс). В то время как при интервале в 250мс потребовалась 9 строк и выход был на частоту в 1400МГц.
Пожалуй, эти настройки и оставлю. Но, эти параметры должен каждый подбирать под свои задачи!
Добавляем в /etc/rc.conf запуск powerd и параметры для запуска:
powerd_enable="yes"
powerd_flags="-a adp -p 100 -r 90"

Ну и запускаем его:
[19:02 root@mira /etc]# /etc/rc.d/powerd start
Starting powerd.


Все! Об эффективности этого метода можно будет теперь по следующему счету за электричество.

16 комментариев

avatar
Отлично! Надо попробовать.
avatar
о результатах в счете напиши потом плиз :)
avatar
напишу :) хп прокурву сейчас поставил — чуть попозже отчет по ней будет
avatar
Ну как, есть эффект?
avatar
ммм, не фонтан, где-то на 10кВт сократилось потребление
avatar
Видео-карта ..., тоже нет механизмов регулирования.
В Nvidia прекрасно работает PowerMizer сбрасывает частоту, когда нужно.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.