Development for Linux
CPU
24 October 2018

Чем заняться процессору, когда нечего делать?

Original author: Tom Yates
Translation
Разумно было бы предполагать, что для ядра довольно легко будет ничего не делать – но это не так. На конференции Kernel Recipes 2018 Рафаэль Высоцкий рассказал о том, чем занимаются процессоры, когда им нечего делать, как это обрабатывает ядро, какие у текущей стратегии есть проблемы, и как его недавняя работа над циклом бездействия улучшила ситуацию с энергопотреблением систем, которые ничего не делают.

Цикл бездействия, одна из подсистем ядра, которую поддерживает Высоцкий, управляет тем, что делает CPU, когда ему не нужно исполнять никаких процессов. Высоцкий очень точно дал все определения: CPU – это такая сущность, которая может принимать инструкции из памяти и выполнять их одновременно с другими сущностями в той же системе, занимающимися тем же самым. На простейшей однопроцессорной системе с одним ядром этим ядром является CPU. Если у процессора несколько ядер, то каждое из этих ядер – CPU. Если у каждого из ядер есть несколько интерфейсов для одновременного исполнения инструкций – Intel называет такую систему "гиперпоточностью" – тогда каждый из этих потоков будет CPU.

CPU бездействует, когда у него нет задач для выполнения. Или, точнее, у ядра Linux есть несколько внутренних классов для диспетчеризации, один из которых – особый класс бездействия (idle). Если на данном CPU ни в одном из классов, исключая класс бездействия, нет задач, то CPU считается бездействующим. Если оборудование этого не разрешает, тогда CPU придётся выполнять бесполезную инструкцию, пока не подвернётся настоящая работа. Однако это чрезвычайно неэффективное использование электричества, поэтому большинство процессоров поддерживают несколько состояний с низким потреблением энергии, в которые их переводит ядро до тех пор, пока они не потребуются для выполнения полезной работы.

В состояние бездействия нельзя просто так войти или выйти из него. На вход и выход требуется время, а кроме того, при входе в это состояние немного повышается энергопотребление текущего состояния, а при выходе из него – потребление того состояния, в которое переходит процессор. И хотя чем глубже состояние бездействия, тем меньше энергии потребляет процессор, стоимость входа и выхода в такие состояния растёт. Это значит, что в случае кратких периодов бездействия лучшим использованием ресурсов компьютера будет неглубокое бездействие; для более долгих периодов стоимость перехода в более глубокое состояние бездействия будет оправдано увеличением количества сэкономленной энергии. Поэтому в интересах ядра предсказать, как долго процессор будет бездействовать, перед тем, как решить, насколько глубокое состояние бездействия ему нужно. Это задача цикла бездействия.

В этом цикле планировщик замечает, что CPU бездействует, так как у него нет никаких задач, которые можно было бы ему поручить. Тогда планировщик вызывает регулятор, который старается выдать наилучшее предсказание подходящего состояния бездействия, в которое можно войти. Сейчас в ядре есть два регулятора, menu и ladder. Они используются в разных случаях, но оба пытаются делать примерно одно и то же: отслеживать состояние системы при переходе CPU в состояние бездействия и время, которое он провёл в бездействии. Это делается для того, чтобы предсказать, как долго вошедший в состояние бездействия CPU в нём останется, и, следовательно, какое именно состояние наилучшим образом подойдёт для данной ситуации.

Эту работу особенно усложняет таймер планировщика CPU. Планировщик запускает этот таймер для разделения времени доступа к CPU: если на одном процессоре необходимо выполнять несколько задач, каждую из них можно выполнять только по чуть-чуть, а потом периодически откладывать в пользу другой задачи. Этот таймер не нужно выполнять на бездействующем CPU, поскольку задач, между которыми нужно делить CPU, не существует. Более того, если позволить таймеру выполняться на бездействующем CPU, это не даст регулятору выбрать состояния глубокого бездействия, ограничивая промежутки, во время которых CPU находится в бездействии. Поэтому в ядрах вплоть до 4.16 планировщик отключал таймер перед вызовом регулятора. Когда CPU пробуждался по прерыванию, планировщик решал, есть ли необходимые к выполнению задачи, и в случае их наличия заново запускал таймер.

Если регулятор предсказывает долгий период простоя, и этот период действительно оказывается долгим, то регулятор «выигрывает»: CPU переходит в состояние глубокого бездействия, и энергия экономится. Но если регулятор предсказывает долгий период простоя, а этот период оказывается коротким, то регулятор «проигрывает», поскольку стоимость входа в глубокое бездействие не окупается экономией энергии на коротком периоде бездействия. Ещё хуже, когда регулятор предсказывает короткий период простоя – тогда он «проигрывает» вне зависимости от длительности простоя: если период оказался долгим, он упустил возможность сэкономить, а если коротким, то расходы на остановку и перезапуск таймера были потрачены впустую. Или, иными словами, поскольку на остановку и запуск таймера тратятся ресурсы, нет смысла его останавливать, когда регулятор предсказывает короткий период простоя.

Высоцкий решил попробовать поменять работу регулятора, но пришёл к выводу, что основная проблема состоит в том, что таймер останавливают перед вызовом регулятора, то есть, до того, как становится известным рекомендованное состояние бездействия. Он вернул цикл бездействия в ядре 4.17, чтобы решение об остановке таймера принималось после того, как регулятор выдал свою рекомендацию. Если он предсказал долгий простой, таймер останавливается, чтобы не разбудить CPU раньше времени. Если простой предполагается коротким, таймер оставляют, чтобы не тратить ресурсы на отключения. А это значит, что таймер выполняет и функцию безопасности, пробуждая CPU, если простой оказался более длинным, чем предсказывалось, и давая регулятору второй шанс на правильное решение.

Когда бездействующий CPU пробуждается через прерывание, будь то не остановленный таймер или другое событие, планировщик сразу же принимает решение о наличии работы. Если работа есть, таймер по необходимости перезапускается. Если её нет, вызывается регулятор. Поскольку это означает, что регулятор теперь можно вызывать и когда таймер работает, и когда он не работает, регулятора необходимо вызвать, чтобы это учесть.

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


Поскольку теория игр не может служить полноценной заменой реальной ситуации, Высоцкий проверил этот подход на множестве систем. График выше характерен для всех испытанных систем; он показывает зависимость энергопотребления от времени на бездействующей системе. Зелёная линия – старый цикл бездействия, красная – новый. По новой схеме энергии потребляется меньше, кроме того, она более предсказуема. Не на всех испытанных CPU получился такой большой разрыв между линиями, однако все они показали плоскую красную линию под неровной зелёной. Как сказал Высоцкий, эта новая схема реже предсказывает короткие периоды бездействия, но чаще оказывается правой по поводу их небольшой длительности.

Отвечая на вопрос из аудитории, Высоцкий сказал, что эта работа зависит от архитектуры. В особенности от неё получат преимущество процессоры от Intel, поскольку у них имеется достаточно большой массив состояний бездействия, из которых регулятор может выбрать нужный, что даст ему наилучшие шансы на успех в случае правильного предсказания; но и процессоры ARM также получат преимущество от новой схемы.


20% падение энергопотребления в состоянии бездействия может показаться незначительным достижением, но на самом деле это не так. Любая система, желающая достаточно хорошо справляться с пиковыми нагрузками, должна обладать запасом мощности в нормальном режиме, который проявит себя во время бездействия. На графике выше показано использование процессора за год на моём сервере, который занимается почтой, передачей файлов, VPN, NTP и т.п. Жёлтый цвет означает время простое. Экономия 20% этой энергии понравилась бы моему провайдеру, да и для планеты это было бы лучше.

+26
17.8k 66
Support the author
Comments 8