(первая часть тут)
Производительности в вакууме не бывает
Состояние одной и той же системы от запуска к запуску бенчмарков всегда разное. Даже если зафиксированы все статические параметры (настройки OS и рантайма, CPU affinity, etc), то температура процессоров, состояние кешей, layout кода в памяти всё равно плавают. Что уж говорить про внешне схожие окружения - там различий может быть еще больше.
Следовательно результаты на выходе всегда различаются.
Так какой из них нам взять за основу?
———
Помогает формулировка от Ben Sigelman: «Performance is a shape, not a number».
Производительность это всегда распределение, а не одно конкретное число. Не существует одного единственного, правильного значения.
И каждый отдельный прогон бенчмарка это просто один сэмпл из всего распределения, полученный при конкретных условиях.
Если углубить, то и внутри одного запуска мы всегда получаем распределение:
$ funclatency-bpfcc __sys_sendto -d 10 -u
usecs : count distribution
0 -> 1 : 12433 |************ |
2 -> 3 : 20394 |******************* |
4 -> 7 : 20540 |********************|
8 -> 15 : 1962 |** |
16 -> 31 : 237 | |
32 -> 63 : 19 | |
64 -> 127 : 8500 |******** |
128 -> 255 : 12 | |
256 -> 511 : 0 | |
512 -> 1023 : 4 | |
1024 -> 2047 : 5 | |
2048 -> 4095 : 1 | |
4096 -> 8191 : 2 | |
———
Задача перформанс-инженера сводится к двум вещам:
1. сужать это распределение
2. объяснять, почему оно именно такое
На ширину распределения влияет шум: переключение контекста, прерывания, соседи, и т.д. И чем шум больше, тем шире хвосты распределения.
Важный момент: шум может быть случайным, а может быть систематическим. Бороться с ними нужно по-разному.
———
Случайный шум (random noise) это то, что возникает непредсказуемо, без видимой системы. Например, фоновый процесс случайно попал на наше ядро в одних прогонах и не попал в других. Или соседнее ядро внезапно дало всплеск нагрузки на общий L3.
Лечится количеством прогонов: чем их больше, тем сильнее усредняем случайные отклонения, и тем точнее итоговая оценка.
Систематический шум (systematic bias), уже другое явление. Какой-то фактор стабильно сдвигает измерения в одну и туже сторону. Например IRQ, прибитый к нашему ядру, просыпается через равные промежутки. Такой тип шумов (или отклонений) не лечится количеством прогонов, из раза в раз будем получать искаженный результат.
В "Producing Wrong Data Without Doing Anything Obviously Wrong", авторы показали, что даже размер переменных окружения может вносить существенные искажения в итоговый результат.
С систематическим шумом борются наблюдением и рандомизацией факторов, см. Stabilizer.
———
Это объясняет, почему Passive Benchmarking плох, даже при тысяче прогонов: он не отличает один тип шума от другого. Active Benchmarking, помимо прочего, как раз про то, чтобы такие смещения находить.
Ранее мы говорили о цикле в Active Benchmarking: запустил → пронаблюдал → сформулировал гипотезу → проверил → повторил.
Это как раз про то, что борьба с шумом процесс бесконечный: зафиксировали частоту, получили распределение уже, в следующем прогоне в топ выходят прерывания, вынесли их с ядра, получили еще более стабильный результат.
Далее поднимают голову соседи по L3 кешу...
По своей природе это похоже на дрейфующее бутылочное горлышко в производительности: всегда что-то будет в топ-1.
Следующим возникает естественный вопрос: "где и когда остановиться?" To be continued.
———
Выводы
- Производительность это распределение, а не число
- Шум есть всегда, и работать с ним нужно исходя из его типа
- Борьба с шумом бесконечный процесс - главное знать, где остановиться.
———
Поставить лайк на Linkedin