Мы планируем обновить ОС на наших серверах с Ubuntu 10.04 LTS до Ubuntu 12.04 LTS. К сожалению, кажется, что задержка для запуска потока, который стал работоспособным, значительно увеличилась с ядра 2.6 до ядра 3.2. На самом деле в получаемые нами значения задержки трудно поверить.
Позвольте мне уточнить тест. У нас есть программа, которая запускает два потока. Первый поток получает текущее время (в тиках с использованием RDTSC), а затем сигнализирует переменной условия раз в секунду. Второй поток ожидает переменной условия и просыпается при поступлении сигнала. Затем он получает текущее время (в тиках с использованием RDTSC). Разница между временем во втором потоке и временем в первом потоке вычисляется и отображается на консоли. После этого второй поток снова ожидает переменной условия. Он снова будет сигнализирован первым потоком примерно через второй проход.
Итак, в двух словах, в результате мы получаем поток для потоковой связи через измерение задержки переменной состояния раз в секунду.
В ядре 2.6.32 эта задержка составляет порядка 2,8–3,5 мкс, что вполне разумно. В ядре 3.2.0 эта задержка увеличилась примерно до 40–100 мкс. Я исключил любые различия в оборудовании между двумя хостами. Они работают на идентичном оборудовании (процессоры X5687 {Westmere-EP} с двумя сокетами, работающие на частоте 3,6 ГГц с отключенными гиперпоточностью, ускорением и всеми состояниями C). Тестовое приложение изменяет сродство потоков, чтобы запускать их на независимых физических ядрах одного и того же сокета (т. Е. Первый поток выполняется на ядре 0, а второй поток - на ядре 1), поэтому отскока потоков на ядра или подпрыгивание / связь между сокетами.
Единственное различие между двумя хостами заключается в том, что на одном работает Ubuntu 10.04 LTS с ядром 2.6.32-28 (поле быстрого переключения контекста), а на другом - последняя версия Ubuntu 12.04 LTS с ядром 3.2.0-23 (медленный контекст распределительная коробка). Все настройки BIOS и оборудование идентичны.
Были ли какие-либо изменения в ядре, которые могли бы объяснить это нелепое замедление в том, сколько времени требуется для запланированного запуска потока?
Обновление: если вы хотите запустить тест на своем хосте и сборке Linux, я разместил код в pastebin для вашего ознакомления. Скомпилировать с помощью:
g++ -O3 -o test_latency test_latency.cpp -lpthread
Запустите (при условии, что у вас есть хотя бы двухъядерный блок):
./test_latency 0 1 # Thread 1 on Core 0 and Thread 2 on Core 1
Обновление 2 : после долгих поисков параметров ядра, сообщений об изменениях ядра и личных исследований я понял, в чем проблема, и опубликовал решение в качестве ответа на этот вопрос.
источник
/proc/sys/kernel/*
может сработать? Если вы найдете что-то, что работает, поместите эту конфигурацию/etc/sysctl.conf
или файл,/etc/sysctl.d/
чтобы она сохранялась при перезагрузках.Ответы:
Решение проблемы с производительностью пробуждения из- за плохого потока в последних ядрах связано с переключением на
intel_idle
драйвер cpuidle сacpi_idle
драйвера, который использовался в старых ядрах. К сожалению,intel_idle
драйвер игнорирует конфигурацию BIOS пользователя для C-состояний и танцует под свою собственную настройку . Другими словами, даже если вы полностью отключите все состояния C в BIOS вашего ПК (или сервера), этот драйвер все равно будет принудительно включать их во время периодов кратковременного бездействия, что почти всегда происходит, если не выполняется синтетический тест, потребляющий все ядро (например, стресс ) это работает. Вы можете отслеживать переходы состояний C, а также другую полезную информацию, связанную с частотами процессора, с помощью замечательного инструмента Google i7z на большинстве совместимого оборудования.Чтобы узнать, какой драйвер cpuidle в настоящее время активен в вашей установке, просто поместите
current_driver
файл в следующийcpuidle
раздел/sys/devices/system/cpu
:Если вы хотите, чтобы ваша современная ОС Linux имела наименьшую возможную задержку переключения контекста, добавьте следующие параметры загрузки ядра, чтобы отключить все эти функции энергосбережения:
В Ubuntu 12.04 вы можете сделать это, добавив их в
GRUB_CMDLINE_LINUX_DEFAULT
запись/etc/default/grub
и запустивupdate-grub
. Необходимо добавить следующие параметры загрузки:Вот кровавые подробности о том, что делают три варианта загрузки:
Установка
intel_idle.max_cstate
в ноль либо вернет ваш драйвер cpuidle кacpi_idle
(по крайней мере, согласно документации опции), либо полностью отключит его. На моем ящике он полностью отключен (т. Е. Отображениеcurrent_driver
файла/sys/devices/system/cpu/cpuidle
дает результатnone
). В этом случае второй вариант загрузкиprocessor.max_cstate=0
не нужен. Однако в документации указано, что установка max_cstate на ноль дляintel_idle
драйвера должна вернуть ОС кacpi_idle
драйверу. Поэтому на всякий случай поставил второй вариант загрузки.Эта
processor.max_cstate
опция устанавливает максимальное состояние C дляacpi_idle
драйвера равным нулю, надеясь, что оно также отключится. У меня нет системы, на которой я мог бы это протестировать, потому чтоintel_idle.max_cstate=0
полностью выбивает драйвер cpuidle на всем доступном мне оборудовании. Однако, если ваша установка возвращает вас изintel_idle
вacpi_idle
только с первым вариантом загрузки, сообщите мне,processor.max_cstate
сделал ли второй вариант то, что было задокументировано в комментариях, чтобы я мог обновить этот ответ.Наконец, последний из трех параметров,
idle=poll
настоящий боров власти. Он отключит C1 / C1E, что удалит последний оставшийся бит задержки за счет гораздо большего энергопотребления, поэтому используйте его только тогда, когда это действительно необходимо. Для большинства это будет излишним, поскольку задержка C1 * не так уж велика. Используя мое тестовое приложение, работающее на оборудовании, которое я описал в исходном вопросе, задержка увеличилась с 9 до 3 мкс. Это, безусловно, значительное сокращение для приложений с высокой задержкой (например, финансовая торговля, высокоточная телеметрия / отслеживание, сбор данных с высокой частотой и т. Д.), Но может не окупить потерю электроэнергии для подавляющего большинства настольные приложения. Единственный способ узнать наверняка - это профилировать улучшение производительности вашего приложения по сравнению сОбновить:
После проведения дополнительных испытаний с различными
idle=*
параметрами, я обнаружил , что установкаidle
вmwait
случае , если поддерживаются аппаратными средствами является гораздо лучшей идеей. Кажется, что использованиеMWAIT/MONITOR
инструкций позволяет процессору войти в C1E без какой-либо заметной задержки, добавляемой ко времени пробуждения потока. Благодаря этомуidle=mwait
вы получите болееidle=poll
низкие температуры процессора (по сравнению с ), меньшее потребление энергии и при этом сохраните отличные низкие задержки цикла ожидания при опросе. Поэтому мой обновленный рекомендуемый набор параметров загрузки для низкой задержки пробуждения потока ЦП на основе этих результатов:Использование
idle=mwait
вместоidle=poll
может также помочь с запуском Turbo Boost (помогая ЦП оставаться ниже его TDP [Thermal Design Power]) и гиперпоточности (для которых MWAIT является идеальным механизмом, позволяющим не использовать все физическое ядро, в то же время время избегая более высоких состояний C). Однако это еще предстоит доказать в ходе тестирования, и я буду продолжать это делать.Обновление 2:
Опция
mwait
простоя была удалена из новых ядер 3.x (спасибо пользователю ck_ за обновление). Это оставляет нам два варианта:idle=halt
- Должен работать так же хорошоmwait
, но проверьте, что это так с вашим оборудованием. ЭтаHLT
инструкция почти эквивалентнаMWAIT
подсказке с состоянием 0. Проблема заключается в том, что для выхода из состояния HLT требуется прерывание, в то время как запись в память (или прерывание) может использоваться для выхода из состояния MWAIT. В зависимости от того, что ядро Linux использует в своем цикле ожидания, это может сделать MWAIT потенциально более эффективным. Итак, как я сказал test / profile и посмотрите, соответствует ли он вашим потребностям в задержке ...и
idle=poll
- Вариант с максимальной производительностью за счет энергии и тепла.источник
Возможно, медленнее стал фьютекс, строительный блок для переменных состояния. Это прольет свет:
затем
который покажет микросекунды, затраченные на интересные системные вызовы, отсортированные по времени.
В ядре 2.6.32
В ядре 3.1.9
Я нашел этот отчет об ошибке 5-летней давности, который содержит тест производительности «пинг-понг», который сравнивает
Мне пришлось добавить
чтобы скомпилировать, что я сделал с помощью этой команды
В ядре 2.6.32
В ядре 3.1.9
Я пришел к выводу, что переключение контекста между ядром 2.6.32 и 3.1.9 действительно замедлилось, хотя и не так сильно, как в ядре 3.2. Я понимаю, что это еще не ответ на ваш вопрос, буду копать дальше.
Изменить: я обнаружил, что изменение приоритета процесса в реальном времени (оба потока) улучшает производительность 3.1.9, чтобы соответствовать 2.6.32. Однако установка того же приоритета в 2.6.32 замедляет его ... поймите, я рассмотрю это подробнее.
Вот мои результаты сейчас:
В ядре 2.6.32
В ядре 3.1.9
источник
Вы также можете увидеть щелчки процессоров в более поздних процессах и ядрах Linux из-за драйвера pstate, который отделен от c-состояний. Так что кроме того, чтобы отключить это, вам нужен следующий параметр ядра:
intel_pstate=disable
источник