Существует множество причин, по которым вы можете увидеть различия, когда вы неоднократно сравниваете то, что кажется одним и тем же кодом. Я рассмотрел некоторые причины в другом ответе , и было бы целесообразно помнить об этом.
Однако, основываясь на опыте и использовании вероятностей, мы можем устранить многие из них заранее. То, что осталось, - это наиболее вероятные причины ваших относительно больших отклонений для коротких программ с холодного старта:
- Функции энергосбережения ЦП и масштабирования частоты.
- Фактические различия в поведении во время выполнения, т. Е. Разный код, выполняемый в библиотеке времени выполнения, ВМ, ОС или другой вспомогательной инфраструктуре при каждом запуске вашей программы.
- Некоторый эффект кэширования, или эффект выравнивания кода или данных, который варьируется от запуска к запуску.
Вероятно, вы можете разделить эти три эффекта простым perf stat
без переопределения списка событий, например:
$ perf stat true
Performance counter stats for 'true':
0.258367 task-clock (msec) # 0.427 CPUs utilized
0 context-switches # 0.000 K/sec
0 cpu-migrations # 0.000 K/sec
41 page-faults # 0.159 M/sec
664,570 cycles # 2.572 GHz
486,817 instructions # 0.73 insn per cycle
92,503 branches # 358.029 M/sec
3,978 branch-misses # 4.30% of all branches
0.000605076 seconds time elapsed
Сначала посмотрите на строку 2.572 GHz
. Показывает эффективную частоту ЦП, вычисляя путем деления истинного количества циклов ЦП на значение task-clock
(время ЦП, затраченное программой). Если это изменяется от запуска к запуску, отклонение производительности настенного времени частично или полностью объясняется этим изменением, и наиболее вероятной причиной является (1) выше, т.е. масштабирование частоты ЦП, включая оба масштабирования ниже номинальной частоты (энергосбережение) ) и выше (турбонаддув или аналогичные функции).
Детали отключения масштабирования частоты зависят от аппаратного обеспечения, но наиболее распространенным, который работает в большинстве современных дистрибутивов Linux, является cpupower -c all frequency-set -g performance
, чтобы запретить масштабирование ниже номинального.
Отключение Turbo Boost является более сложным и может зависеть от аппаратной платформы и даже конкретного процессора, но для последних версий x86 некоторые параметры включают:
- Запись
0
в /sys/devices/system/cpu/intel_pstate/no_turbo
(только для Intel)
- Выполнение
wrmsr -p${core} 0x1a0 0x4000850089
для каждого ${core}
в вашей системе (хотя одного на каждый сокет, вероятно, достаточно для некоторых / большинства / всех чипов?). (Только для Intel)
- Отрегулируйте значение
/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
, чтобы установить максимальную частоту.
- Используйте регулятор
userspace
и /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed
для установки фиксированной частоты.
Другой вариант - просто несколько раз запустить тест и надеяться, что процессор быстро достигнет устойчивого состояния. perf stat
имеет встроенную поддержку для этого с опцией --repeat=N
:
-r, --repeat=<n>
repeat command and print average + stddev (max: 100). 0 means forever.
Допустим, вы заметили, что частота всегда одинакова (в пределах 1% или около того), или вы исправили проблемы с частотой, но некоторая разница остается.
Далее проверьте строку instructions
. Это приблизительный показатель того, сколько работы в целом выполняет ваша программа. Если он изменяется в одном и том же направлении и аналогичен относительной дисперсии к вашей дисперсии времени выполнения, у вас есть проблема типа (2): некоторые прогоны выполняют больше работы, чем другие. Не зная, что ваша программа, было бы трудно сказать больше, но вы можете использовать такие инструменты, как strace
, perf record + perf annotate
, чтобы отследить это.
Если instructions
не меняется, а частота фиксирована, но время выполнения меняется, у вас проблема типа (3) или «другое». Вы захотите взглянуть на большее количество счетчиков производительности, чтобы увидеть, какие из них коррелируют с более медленными запусками: у вас больше ошибок в кеше? Еще контекстные переключатели? Больше отраслевых заблуждений? Список можно продолжить. Как только вы узнаете, что вас тормозит, вы можете попытаться изолировать код, который его вызывает. Вы также можете пойти в другом направлении: используя традиционное профилирование, чтобы определить, какая часть кода замедляется при медленном запуске.
Удачи!