Ядра 1 и 2 сорта под Linux
Процессоры с P и E ядрами появились сравнительно недавно и как с ними уживаться все еще ломают голову разработчики.
Однако на самом деле эта дискриминация на первоклассные и второсортные ядра процессора появилась еще раньше. И пришлось изобретать свои костыли, чтобы важное запускалось на быстрых, а неважное на медленных ядрах.
Речь идет о турбо частоте. Суть в том, что практически у любого процессора базовая частота не имеет никакого значения. В режиме энергосбережения частота может быть сильно ниже базовой, а под полной загрузкой всех ядер частота также немного выше базовой (all core turbo). И конечно же, при условии отсутствия нагрузки на других, одно или несколько ядер могут повышать частоту еще выше до значения turbo.
Однако есть линейки процессоров (в частности это Xeon E5 v4), у которых определенные ядра ни при каких условиях не могут поднять частоту выше all core turbo. Будем называть их «медленными».
Все испытания провожу на домашнем роутере под ОС Debian и Xeon E5–1630v4 (4 ядра, 8 потоков, 3.7 Ггц базовая, 4.0 Ггц турбо)
apt install linux-cpupower
По-умолчанию скорей всего (если специально не менять ничего в BIOS) будут включены все C-states процессора:
watch -n0.5 «cpupower monitor -c»
В кратце: это уровни энергосбережения. Чем выше уровень, тем в более глубоком сне находится ядро и тем дольше оно из него выходит. Поэтому там где нужна больше скорость работы, а не энергосбережение, то рекомендуется держать ядра не глубже C3. А где нужна самая максимальная отзывчивость — C1, однако в этом режиме уже не будет никаких turbo частот. Поэтому ограничить на сервере до C3 — оптимальное решение, когда и хорошая отзывчивость и ядра могут повышать частоту до turbo. Помимо C-states есть также другие параметры, которыми можно смещать работу процессора либо в сторону скорости, либо в сторону экономии энергии (governor, performance bias… и все эти изменения делаются/не_делаются как в ОС, так и в BIOS — нужно рассматривать конкретный процессор и конкретную мат. плату), но здесь не об этом.
Подчеркну лишь, что в большинстве случаев по-умолчанию баланс смещен именно в сторону экономии энергии. И без ручного вмешательства процессор может не быть таким быстрым как мог бы, хотелось бы…
Проверяем теорию о медленных ядрах. Отключаем у всех ядер C1E и C3:
cpupower -c all idle-set -d2
cpupower -c all idle-set -d3
И дальше поочередно отключаем C6 у каждого из ядер, загоняя принудительно только это ядро в C1
cpupower -c 0 idle-set -d4
Видим, что ядро 0 теперь 99% времени простаивает в C1, т.е. полностью готово к работе. Хотя и работы на нем никакой не выполняется. Но главное, видим что частота его не выше 3.8 Ггц
Включаем обратно cpupower -c 0 idle-set -e4
И отключаем C6 у следующего:
cpupower -c 4 idle-set -d4
Виртуальное ядро 4 также у нас не подымается выше 3.8 Ггц
cpupower -c 1 idle-set -d4
А вот и первое ядро здорового человека, которое может подняться под 4 Ггц. Не совсем т.к. помимо этой программной настройки есть еще аппаратное управление в самом процессоре, на которое никак не повлиять. До самого максимума ядро сможет разогнаться только если на нем еще и нагрузка хоть какая-то будет.
Также мы видим, что следующее ядро 5 тоже подскочило в частоте. Т.е. виртуальные ядра 1 и 5 — это одно физическое ядро и частоты у них связаны.
cpupower -c 5 idle-set -d4
Соответственно разгоняя ядро 5, поднимается частота и у ядра 1
cpupower -c 2 idle-set -d4
cpupower -c 6 idle-set -d4
Выяснили, что ядра 2 и 6 также могут, если захотят.
cpupower -c 3 idle-set -d4
cpupower -c 7 idle-set -d4
А ядра 3/7 как и 0/4 тоже не выше 3.8 Ггц.
Итого расклад по максимальным частотам у нас получился такой:
0 — 3.8
4 — 3.8
1 — 4.0
5 — 4.0
2 — 4.0
6 — 4.0
3 — 3.8
7 — 3.8
Так в чем же проблема?
Обычно процессы запускаются на первом попавшем случайном ядре. Конечно это не доставляет неудобств в большинстве случаев и никто вообще не заморачивается такими мелочами. Особенно если задачи многопоточные и малотребовательные к CPU — типа Nginx например. Однако есть случаи, когда запускаемый процесс точно лишь однопоточный и внутренняя жаба начинает душить от осознания того что этот процесс в 50% случаев (на данном процессоре) запускается на медленных ядрах и выполняется хоть немного, но медленней чем мог бы…
На помощь приходит комманда taskset
Ею мы можем ограничивать какие конкретно ядра будут доступны для запускаемого процесса.
Для примера запакуем в 1 поток полугигабайтный каталог /usr/share на ядре 0:
и потом на ядре 1:
Отличие в 5 сек. Да, разница не такая большая как была бы с современными P и E ядрами, но она есть.
Еще примечательно, что даже подымая частоту лишь на 1 из ядер, все остальные также подтягиваются к 3.8, хоть они и находятся в C6 режиме энергосбережения. И если просто поднять частоту на всех быстрых ядрах, то итоговая максимальная частота каждого будет заметно не дотягивать до 4.0 Ггц.
Запустим архивирование в 1 поток на одном из быстрых ядер:
Видим, что при условии когда все остальные ядра находятся в покое, частота этого загруженного ядра увеличивается практически до самого верхнего потолка в 4.0 Ггц.
Загрузим все 4 быстрых ядра 4-х поточным архивированием:
Все еще хорошо конечно, однако заметно как максимальная частота каждого отдалилась от отметки 4.0 Ггц.
Ну и загрузим по максимуму все 8 ядер:
Получили all core turbo в 3.8 Ггц.
Раскрасив на графике мониторинга (collectd + rrdtool) ядра 1,5,2,6 красным, а остальные зеленым (не смотрим на подпись под графиком), наглядно видим как зеленые никогда не выходят выше, куда могут красные:
Как это использовать на практике? Каждый решит для себя. На своем хостинге к примеру, я ограничил малозначимые процессы только медленными ядрами. Ни к чему чтобы FTP, DNS и подобные задачи вообще присутствовали на быстрых ядрах. Чтобы на этих быстрых исполнялось лишь то, что действительно важно — MySQL и PHP. В файле службы добавляем все тот же taskset и список медленных ядер (в данном случае процессор E5–1650v4):
Можно конечно сделать обратное ограничение, повесить определенные задачи только на быстрые ядра:
MySQL будет работать замечательно и максимально возможно быстро…, но лишь до поры пока нагрузка не большая и в основном однопоточная. Нужно быть осторожным т.к. если к базам будут приходить больше 4 параллельных запросов, то суммарная производительность конечно же наоборот уменьшится, ведь мы по-сути ограничили этот процесс лишь 4 мя ядрами.
В целом конечно же подобные процессоры очень неудобны и гораздо лучше когда все ядра равны.
Особенно печально если ваш VPS хостер использует подобные процессоры и вас поселят именно на подобные медленные ядра, которые никогда, ни при каких условиях не смогут приблизиться к турбо-частоте (За которую вы наверняка заплатили, поверив рекламе). И вы врядли сможете подобрать слова, чтоб объяснить/доказать проблему поддержке.