Pull to refresh

Таблетка от пингвиньего жара своими руками

Reading time12 min
Views26K
Стал я тут недавно 'счастливым' обладателем нетбука на базе Atom N270. Windows XP, естественно для меня, был немедленно выкинут с жёсткого диска и заменён Linux'ом. И всё было хорошо… где-то минут 15, пока процессор (вообще, конечно, все вам скажут, что не процессор, а чипсет, но всякие тесты, вроде кручения бесконечных пустых циклов в bash показали, что именно процессор) не стал чрезмерно горячим в процессе установки всяких разных пакетов (я вообще не понимаю, откуда Intel взяла оценку для TDP N270 в 2.5Вт).

Другая ситуация. У моего знакомого довольно пожилой ноутбук ASUS с достаточно странными настройками ACPI, в таблицах которого записано, что включать throttling нужно при температуре системы в 89 градусов Цельсия, а отрубать систему от критического перегрева при температуре в 81 градус.

Эмс… Вы не сочтите это всё антипиаром ASUS и Intel, ибо (я уверен) на других ноут(нет)буках с другими x86-процессорами вполне появляются схожие проблемы, и этот пост о том, как их решать, а не о том, какие праАативные флагманы IT… И вообще, я фанат ARM'ов… Так что для меня, что Intel, что AMD — одинаковое x86-зло… Но просто факт остаётся фактом. В некоторых старых моделях ноутбуков от ASUS кривые таблицы ACPI, а Atom'ы греются.

Нужно как-то управлять режимами работы процессора, чтобы остужать пыл горячих кремниевых парней, дабы не разрушали они естественный прохладный микроклимат для пингвина.

Проблема только в том, что стандартные рецепты манипулирования только лишь power-уровнями процессора в Linux (при помощи подсистемы cpufreq), которые раздаются на всех форумах направо и налево, недостаточно эффективны. Тот же Atom ощутимо греется находясь и в самом 'экономном' режиме, а моему знакомому в работе периодически нужна высокая производительность процессора, однако не ценой отключения по критической температуре. И при этом сброс процессора его ноутбука в 'экономный' режим при повышении температуры от перегрева не спасал.

В общем, проблемы надо как-то решать. Собственно вот, где-то на троечку с плюсом их решить получилось, решение описываю ниже с некоторыми подробностями, о которых редко пишут на user-форумах Linux (и вообще, я даже и сам не понял, откуда я всё это решение раздобыл :).



Итак. Сперва немного теории.

1. Режимы работы процессора.

У любого уважающего себя x86-процессора режимов работы очень много. Они все описываются в жутко объёмном документе громко именуемом ACPI Specification. И кратко их можно охарактеризовать следующим образом.

Режимы процессора. Эти состояния называются CN, где N — некоторая цифирька от 0, 1, 2, 3 до фантазии разработчиков этого процессора. Кажется, Opteron'ы умеют засыпать аж в режиме C8.

Режим C0 — это рабочий режим, в котором процессор исполняет инструкции. А C1,… — режимы сна. В эти режимы ядро операционной системы переводит процессор в те моменты, когда осознаёт, что, в общем-то, никакой код она выполнять не должна (например, все нити-процессы ждут каких-то данных для продолжения работы, или пользователь сам даёт системе указание заснуть). Режимы эти отличаются несколькими параметрами. Самые главные из них это:

(1) времена входа и выхода из этого режима, latency, то есть, с какой задержкой проснётся процессор при наступлении какого-нибудь значимого аппаратного события (например, возникновения сигнала прерывания от какого-нибудь устройства);

(2) продолжает ли процессор во время сна обеспечивать какую-то функциональность. Например, продолжает ли он обеспечивать согласованность содержимого своего кэша с содержимым RAM.

Стандарт ACPI говорит нам: чем больше N в CN, тем больше задержки по входу/выходу в/из этого режима, и тем меньшую функциональность поддерживает процессор.

Обычно, в режиме C1 процессор засыпает неглубоко. Это сон, в который он впадает по исполнению инструкции hlt. Засыпает/просыпается он быстро в этом режиме, и все его системы активны. В режиме С2 он засыпает/просыпается медленней, многие подсистемы в нём отключается, а в режиме C3, он перестаёт отслеживать запросы в RAM, чтобы согласовывать содержимое своего кэша с памятью.

Задержки здесь важны, чтобы ядро ОС могло правильно программировать таймеры, чтобы процессор проснулся как раз к моменту окончания sleep-интервала, запрошенного какими-нибудь процессами: если процесс запросил sleep в одну секунду, а задержка для входа и выхода из состояния C2 у процессора занимает .1 секунду, то ядро должно запрограммировать таймер на тик и генерацию прерывания через .9 секунд. Примитивный пример, но, надеюсь, достаточно иллюстративный.

Во время активности системы (хабрачеловек на отправил свой компьютер в с suspend) процессор отправляют спать максимум в режим С2 (согласование кэшей — штука серьёзная). А в состояние C3 его переводят только при нажатии пользователем кнопочки sleep или запуском им команды
pm-suspend.

Полюбоваться тем, как спится ядрам вашего процессора можно командой

$ cat /proc/acpi/processor/CPU0/power 
active state:            C0
max_cstate:              C8
maximum allowed latency: 16000 usec
states:
    C1:                  type[C1] promotion[--] demotion[--] latency[000] usage[00000000] duration[00000000000000000000]


Естественно, CPU0 нужно заменить на номер того процессора, состояние которого вы хотите узнать.

Ок. Режимы производительности. Когда процессор не спит (находится в режиме C0), он работает (вот он идеал, победивший лень). Но работать процессор может с разным энергопотреблением и с разной частотой. Чем ниже частота, тем меньше можно ему потреблять энергии, меньше греться и вообще всего меньше, в том числе и производительности.

В общем, вот. Больше тут сказать нечего. Режимы эти обозначаются обычно PN, где N от 0 до… и чем больше N, тем меньше частота и энергопотребление. Посмотреть же возможные P-состояния можно так:

$ cpufreq-info 
cpufrequtils 006: cpufreq-info (C) Dominik Brodowski 2004-2009
Report errors and bugs to cpufreq@vger.kernel.org, please.
analyzing CPU 0:
  driver: powernow-k8
  CPUs which run at the same hardware frequency: 0
  CPUs which need to have their frequency coordinated by software: 0
  maximum transition latency: 8.0 us.
  hardware limits: 800 MHz - 3.00 GHz
  available frequency steps: 3.00 GHz, 2.30 GHz, 1.80 GHz, 800 MHz
  available cpufreq governors: conservative, performance
  current policy: frequency should be within 800 MHz and 3.00 GHz.
                  The governor "conservative" may decide which speed to use
                  within this range.
  current CPU frequency is 800 MHz.
  cpufreq stats: 3.00 GHz:5.81%, 2.30 GHz:3.70%, 1.80 GHz:10.42%, 800 MHz:80.07%  (1425)
analyzing CPU 1:
  driver: powernow-k8
  CPUs which run at the same hardware frequency: 1
  CPUs which need to have their frequency coordinated by software: 1
  maximum transition latency: 8.0 us.
  hardware limits: 800 MHz - 3.00 GHz
  available frequency steps: 3.00 GHz, 2.30 GHz, 1.80 GHz, 800 MHz
  available cpufreq governors: conservative, performance
  current policy: frequency should be within 800 MHz and 3.00 GHz.
                  The governor "conservative" may decide which speed to use
                  within this range.
  current CPU frequency is 800 MHz.
  cpufreq stats: 3.00 GHz:0.52%, 2.30 GHz:1.21%, 1.80 GHz:5.99%, 800 MHz:92.28%  (651)


На самом деле частоту у современного процессора можно варьировать более плавно. Например, у данного вот Athlon II X2 её можно менять с шагом в 100MHz, но Linux показывает здесь и использует именно P-состояния, описанные в таблицах ACPI, то есть точки, в которых меняется и напряжение на ядре. Может быть, это будет изменено в будущих версиях ядра.

Но это ещё не всё. Работая в некотором режиме производительности процессор может находится в режиме пропуска тактов — T-состоянии. Опять же, режим T0 означает, что такты процессор не пропускает, а Т7, означает, что процессор использует только каждый 8 такт тактового генератора для своей работы.

Понятно, что чем больше тактов процессор пропускает, тем меньше он греется. Throttle-режимы появились в процессоре Pentium4 и активно там использовались для того, чтобы не допускать перегрева сего чрезмерно горячего произведения инженерного гения (или безумия… кому как больше нравится :) одна система replay'я чего стоит. Ну да ладно, то дела минувших лет).

Посмотреть на возможные T-состояния можно так:

$ cat /proc/acpi/processor/CPU0/throttling 
not supported


2. Cpufreq.

Если в режимы С1, С2, С3 ядро переводит процессор вполне самостоятельно, как только обнаруживает в таблицах ACPI описание способности процессора к такому переходу (для этого должен быть загружен драйвер processor.ko), то для перевода процессора между P-состояниями ему нужны модули подсистемы Cpufreq.

Здесь есть два основных компонента — драйверы для процессоров, которые могут распознавать допустимые P-режимы и водить процессор между ними, и управляющие. Драйверы они и в cpufreq драйверы, а вот управляющие — занятные зверушки.

Управляющий — это модуль ядра, который реализуют некоторую политику перевода процессора из одного P-режима, в другой. Например, управляющий powersave держит процессор на самом экономном из возможных P-режимов (минимум и максимум ограничены возможностями оборудования, настройками cpufreq и интерфейсом ограничений). Или вот, например, управляющий ondemand при обнаружении того, что загрузка процессора достигла некоторого порога (который можно задать через настройки) сразу же отправляет его в самое производительное из допустимых P-режимов и держит его там пока нагрузка на процессор не снизится ниже некого порогового значения (пока этот порог менять нельзя, впрочем, есть более гибкий управляющий conservative).

Вот… Тут тоже, вероятно, нечего больше сказать. Разве только сообщить, что утилита cpufreq-info выдаёт всю статистику о том, какие управляющие в системе доступны, и какие ограничения для частот установлены, и какая частота текущая. И т.д. Если же какие-то управляющие недоступны, это означает, что у вас не загружены соответствующие модули ядра. Поправить ситуацию можно командой подобной такой: modprobe cpufreq-conservative. Или вставив соответствующие модули в список автозагрузки в вашем дистрибутиве.

Вручную по-переключать различные режимы работы процессора можно утилитой cpufreq-set. Например, # cpufreq-set --min 800MHz --governor powersave переведёт процессор в

А за более подробной информацией желающие могут посмотреть в директорию:

# ls /sys/devices/system/cpu/cpu0/cpufreq/ | cat
affected_cpus
conservative
cpuinfo_cur_freq
cpuinfo_max_freq
cpuinfo_min_freq
cpuinfo_transition_latency
related_cpus
scaling_available_frequencies
scaling_available_governors
scaling_cur_freq
scaling_driver
scaling_governor
scaling_max_freq
scaling_min_freq
scaling_setspeed
stats


3. Cpufreqd.

Эта занятная зверушка умеет делать вот что. Она может отслеживать некоторые параметры системы, в том числе и важные для решаемой задачи: (1) уровень температуры в различных температурных зонах компьютера и (2) уровень загрузки процессора вычислениями. А на основании полученных данных она может поменять настройки подсистемы cpufreq в ядре, или выполнить некую команду.

Руководствуется cpufreqd в своей нелёгкой жизни описанием профилей и правил, взятых из конфигурационного файла. Профили — это описания неких действий, например: выбрать управляющего powersave и минимальную частоту выставить в 30% от максимально доступной, и выполнить команду 'echo Hello World' в оболочке.

Правила — это списки условий, которые cpufreqd периодически проверяет и оценивает, выставляет им баллы за соответствие текущей ситуации, а потом применяет то правило, которое получает наивысшую оценку. Выполнение правила — это исполнение указаний в связанном с правилом профиле.

Собственно вот. Всё просто. И уже вырисовывается план действий: нужно настроить cpufreqd так, чтобы при повышении температуры за какой-то порог он переводил процессор в самое экономичное из P-состояний, и заставлял CPU экономить, экономить и ещё раз экономить.

А при нормальной температуре, он держал бы CPU при политике ondemand, например, чтобы и производительности хватало, и грелось бы не очень сильно всё при простое системы.

4. Немного лирики.

К сожалению, с процессорами от Intel сей фокус не проходит :(. Просто наболело (сколько сражался со своим Atom и с P3 знакомого), поэтому напишу. Вот, например, с официально 25Ваттным Turion X2 у меня вообще никаких проблем не возникало. Я включал управляющего conservative для обоих ядер процессора и спокойно себе работал. Замечая существенный нагрев ноутбука только при действительно серьёзных нагрузках вроде кодирования видео.

Управляющий conservative похож на ondemand. Только он более плавный. Когда conservative обнаруживает, что вычислительная нагрузка на процессор возросла за некий период наблюдения до некого порогового значения (80% по-умолчанию) он переводит процессор в более производительный P-режим. Когда он замечает, что она упала ниже другого порога (20%), то он переводит процессор в менее производительны P-режим. Это упрощённое описание, но в целом адекватное. Так вот, очень удобно и в случае с моим Turion'ом работало всё это замечательно.

А вот Atom повёл себя существенно хуже. Естественно, я попытался, проделать с ним тот же самый фокус и с ним. Но Atom начал греться даже в самом малопроизводительном P-состоянии. А потом ещё знакомый появился со своим Dothan'ом, с которым тоже этот conservative-фокус не сработал. Ноутбук перегревался и вырубался.

5. Давайте будем throttle'ить.

Но, не будем отчаиваться, и вспомним, что у процессоров есть ещё одна крутилка — T-состояния. И крутить этой крутилкой можно через так называемый limit-интерфейс. Штука это хоть и страшно называется, является очень простой по смыслу: можно ограничить минимальные по номеру, то есть, максимальные по производительности P и T состояния. Если посмотреть так:

$ cat /proc/acpi/processor/CPU0/limit 
active limit:            P0:T6
user limit:              P0:T6
thermal limit:           P0:T0


(это уже другой процессор, T2050)

то можно увидеть, что эти самые ограничения. active — это текущий, user — это установленный со стороны операционной системы, а thermal — это тот, который должен устанавливать BIOS или аппаратура при обнаружении перегрева.

Если через этот limit-интерфейс установить ограничения на T-состояния то процессор впадёт в throttle'инг и начнёт существенно меньше греться. В коде выше у меня процессор находится по причине своего безделья в состоянии T6, и это означает что он работает только на каждый 4-тый такт.

6. ОК. Всё вместе или конфиг для cpufreqd.

[General]
        pidfile=/var/run/cpufreqd.pid
        poll_interval=0.5
[/General]

[Profile]
        name=idle

        minfreq=0%
        maxfreq=100%
        policy=powersave

        exec_post=echo -n 0:6 | tee /proc/acpi/processor/CPU[01]/limit > /dev/null
[/Profile]

[Profile]
        name=basic

        minfreq=0%
        maxfreq=100%
        policy=conservative

        up_threshold=75
        down_threshold=25
        ignore_nice_load=1

        exec_post=echo -n 0:0 | tee /proc/acpi/processor/CPU[01]/limit > /dev/null
[/Profile]

[Profile]
        name=too_hot

        minfreq=0%
        maxfreq=100%
        policy=powersave

        exec_post=echo -n 0:7 | tee /proc/acpi/processor/CPU[01]/limit > /dev/null
[/Profile]

[Rule]
        name=idle
        profile=idle
        acpi_temperature=0-55
        cpu_interval=0-6.25
[/Rule]

[Rule]
        name=basic
        profile=basic
        acpi_temperature=0-55
        cpu_interval=75-100
[/Rule]

[Rule]
        name=too_hot
        profile=too_hot
        acpi_temperature=55-100
[/Rule]


Собственно вот. Всё просто. Логика этого конфигурационного файла такова.

A. cpureqd опрашивает состояние системы каждые 0.5 секунды.

B. Когда в системе обнаруживается низкая вычислительная активность, она переходит в наименее производительное P-состояние и в достаточно глубокий throttle'инг (вообще-то он фанатский тут выбран, комфортнее работать когда опрос происходит через каждые 0.25 секунд, а в состоянии idle процессор уходит в T4).

С. В режиме нагрузки процессор управляется по политике conservative с минимальными ограничениями. И с немного подкрученными порогами для перехода по режиму производительности вверх и вниз. Вверх conservative пойдёт, когда в текущем состоянии загрузка процессора превысит 75%, а вниз, когда упадёт ниже 25%.

D. Когда же температура поднимется выше 55 процентов (да-да, cpufreqd он странный) от максимальной, то это приведёт к выполнению профиля too_hot, который переведёт процессор в максимальный throttling и минимальное по производительности из P-состояний.

Небольшой хитростью тут является использования условия cpu_interval в правилах. Нагрузкой idle считается нагрузка на CPU от 0 до 6.5 процентов за предыдущий интервал наблюдения. А basic нагрузкой — нагрузка от 75 до 100.

Логика здесь такая. Если помните, то я написал, что cpufreqd в ходе своей работы анализирует набор своих правил и выставляет каждому оценку — насколько оно соответствует текущей ситуации. И если оценка у правила достаточно высока и превосходит все достаточно высокие оценки, то cpufreqd применяет соответствующий этому правилу профиль (профили, на самом деле, но не важно). Поэтому, когда cpufreqd видит, что загрузка процессора не попадает в интервалы [0, 6.25] или [75, 100], при нормальной температуре системы, он просто ничего не делает.

Так вот. Нам же нужно переключаться из состояния basic в состояние idle и обратно. Когда процессор находится в состоянии basic из-за настроек conservative при загрузке меньше 25% он будет переводить процессор в более низкое (тут и далее по производительности) P-состояние, тем самым повышая загрузку процессора в процентном выражении текущими вычислениями — просто все задачи начинают выполняться медленней, следовательно, требуют больше процессорного времени, следовательно, процессор загружается сильнее.

Но из самого низкого P-состояния процессор должен перепрыгнуть в состояние idle, когда он работает в 4 раза медленней, чем в самом низком P-состоянии. И прыгнуть он туда должен при достаточно низкой нагрузке. Я выбрал этот параметр равным 25 / 4, но на самом деле можно было бы
выбрать любую цифру меньшую, скажем, 60 / 4, чтобы при прыжке в idle нагрузка на процессор не возросла настолько, чтобы сработало правило basic, которое должно срабатывать при высокой загрузке (больше 75%) в состоянии idle. При этом 60 / 4 всё ещё меньше 25, поэтому режим idle не включится при работе под управляющим conservative, который при обнаружении загрузки процессора меньше 25 переключит его в более низкий P-режим, чем повысит нагрузку на процессор. И, поэтому, состояние idle не будет включаться, пока нагрузка на процессор не начнёт падать в самом низком P-режиме. ЧТД.

Вот. Всё достаточно просто. Напоследок напишу, что параметры 0.5, 0:6 и 6.25 — фанатские, и могут быть не комфортными при работе в KDE или GNOME, изменение режимов работы системы раз в .5 секунды заметно для пользователя. Лучше поэтому использовать значения 0.25, 0:4, 12.5 соответственно. Кроме этого, естественно, вам придётся самостоятельно последить за температурой вашей системы и выставить комфортные именно для вас температурные интервалы. Тут только следует помнить, что тепловых зон в компьютере много, а в той форме, в которой в конфигурации выше используется критерий acpi_temperature температура берётся средней по всем этим зонам. Вообще, cpufreqd позволяет указывать конкретную температурную зону для наблюдения, и можно попробовать указать термозону процессора, но пока эта фича скорее похожа на баг :) там есть ошибки в коде. А понаблюдать за изменением температуры в термозонах можно при помощи команды $ watch cat /proc/acpi/thermal_zone/*/temperature

Надеюсь, это было полезно.

P.S. А вообще, мне жутко не хватает в cpufreqd возможности работать с состояниями. То есть, возможности использовать в правилах нечто вроде: если я в состоянии 'иду вверх', или 'я в состоянии жестокий троттлинг'. Потому что, понятно, что если мы идём вверх, и на следующем шаге переключения частоты у нас нагрузка с 50 процентов упала до 25, это ещё не означает, что пора идти вниз. А в системе правил cpufreqd такое выразить непонятно, как. Поэтому, если бы кто прикрутил к cpufreqd такой вот statefull плагин — было бы замечательно. У меня самого на это нет времени и сил, к сожалению.

Tags:
Hubs:
Total votes 122: ↑100 and ↓22+78
Comments55

Articles