about:performance
Открыть в Telegram
Канал о performance engineering от Александра Лебедева (@alebsys). Low latency, Linux, Observability. ▸ Обо мне: alebsys.github.io ▸ Консультации: alebsys.github.io/consulting
Больше1 501
Подписчики
-124 часа
-27 дней
Нет данных30 дней
Архив постов
1 501
Про бенчмаркинг, часть 3
(части 1,2)
Ранее обсудили, что борьба с шумом (noise) процесс бесконечный.
И если поторопиться с выводами, то в шум легко записать сам bottleneck.
Важно их различать.
Шум это внешний фактор (случайный или систематический), который растягивает распределение задержек системы (см. часть 2). Лечим стабилизацией и изоляцией окружения.
Bottleneck фактор скорее внутренний: то, что напрямую ограничивает производительность системы. Лечим сменой архитектуры, алгоритмов, добавлением ресурсов и подобным.
———
Практический (анти)паттерн.
Частый способ борьбы с широким распределением (да и вообще подход на все случаи жизни): перебирать доступные параметры в надежде, что какой-то сработает. Б. Грегг поэтично назвал его "Drunk Man Anti-Method".
В генерации таких списков особенно хорош AI, у него богатая фантазия. Туда же и множество статей в интернетах из разряда "топ-10 секретов low-latency в 2026 году".
По форме это похоже на Active Benchmarking (см. часть 1): попробовал, проверил, повторил. Но пропущены ключевые шаги: наблюдение и формирование гипотезы ДО изменения. Без них цикл похож на слепой перебор.
Иногда срабатывает, но чаще отнимает время и даёт решение, которое нельзя переиспользовать (непонятно, что помогло).
Не стоит так делать.
Фреймворк, на мой взгляд, должен быть примерно таким:
* Наблюдаем за системой доступными инструментами
* Отмечаем аномалии, формируем гипотезу о том, что шумит
* Точечно вносим изменение, проверяющее гипотезу
* Повторяем
Если гипотеза верна, разброс упадёт. Если нет, идем дальше.
———
Отмечу, что bottleneck может прикидываться шумом, но таким не являться. Например:
* Lock contention
* Работа GC
* Background flushing в БД
* TCP congestion control
Все они срабатывают в случайные моменты, поэтому выглядят как шум. Хотя фактически вызваны внутренними факторами системы, а не чем-то внешним.
Соответственно лечатся не изоляцией, а изменением кода, настроек runtime или архитектуры системы.
———
В следующей части: где и когда остановиться в борьбе с шумом и bottleneck'ами.
1 501
Продублирую свой комментарий на вопрос:
Стоит задача оценки достаточности мощности оборудования по CPU. Вот уже голову сломали с методикой. Когда смотреть на среднюю, когда на p99 и p90. Пробовали коэффициент вариации(не более 5%) и что-то никуда не пришли пока…🙁Я касался этой темы в посте о среднем (https://t.me/troubleperf/110). Основная мысль в том, что начинать нужно с постановки проблемы, и держа ее в голове, искать решение (подходящую метрику). «Достаточность CPU» редко бывает самоцелью, скорее нас больше интересует справляется ли система со своей прямой обязанностью: * бекап данных заданного объема должен успеть за X (throughput) * обработка транзакции должна уложиться в Y (latency) Отсюда и метрики, за которыми хотим следить: * для первой задачи подойдет среднее над
bytes/s (не над CPU!)
* для второй p95/p99 над длительностью обработки.
И уже через их призму, мы можем смотреть на утилизацию CPU, если нужно понять отчего не пролазим в свои SLO.
Это если вдруг считаем, что виноват именно CPU (читаем про активный бенчмаркинг тут https://t.me/troubleperf/99).
———
Если интересно, не избыточно ли у нас мощностей, то и тут меряем запас по главной метрике (p99/ bytes/s): насколько она далеко от порога SLO.
И в зависимости от нужного запаса либо срезаем, либо добавляем ресурсы.1 501
А вот и ответ.
Главный момент: mean < p50 (что ловко подметил @ddpechkin)
И это при настолько высоких p99/max.
В типичном случае mean, за счёт хвостов, тянется вверх. А тут «что-то» его примагничивает вниз.
Мода!
Плюс близкие по значениям p50/p90 намекают, на наличие второй моды.
Все это в совокупе подталкивает к варианту C.
1 501
Давайте ещё разок, на этот раз чуть сложнее:
count : 44500 mean : 871 us p50 : 1081 us p90 : 1289 us p99 : 5012 us max : 11275 usЗадача всё та же: по статистике определить форму распределения. Возможные варианты: A) право-скошенная мода ~700µs
250–500 |@@@@@@ | 500–750 |@@@@@@@@@@@@@@@@@@@@@@@@| 750–1k |@@@@@@@@@@@@@@@@ | 1–1.25k |@@@@@@@@@@ | 1.25–1.5k |@@@@@@ | 1.5–2k |@@@ | 2–5k |@ | >5k |@ |B) нормальное ~1.1ms
250–500 |@ | 500–750 |@@@@@ | 750–1k |@@@@@@@@@@@@@@@@ | 1–1.25k |@@@@@@@@@@@@@@@@@@@@@@@@| 1.25–1.5k |@@@@@@@@@@@@@@@@ | 1.5–2k |@@@@@@ | 2–5k |@ | >5k |@ |C) две сопоставимые моды
250–500 |@@@@@@@@@@@@@@@@@@@@@@@@| 500–750 |@@@@@ | 750–1k |@ | 1–1.25k |@@@@@@@@@@@@@@@@@@@@@ | 1.25–1.5k |@@@@@@@ | 1.5–2k |@@ | 2–5k |@ | >5k |@ |D) Нет тут ничего! Только давайте с объяснениями;)
1 501
Ну окей, первая задачка была не сложной.
1) p50 = 160us: основная масса запросов будет где-то в районе этого числа, считай это мода
2) mean » p50: можно заподозрить, что рядом есть ещё крупная мода, но без гарантий, среднее может просто улететь из-за одного огромного выброса
3) p90 ≈ p99 и оба » p50: право-скошенности скорее нет (иначе p99 был бы кратно выше p90), а раз они рядом, то это скорее отдельная медленная мода
4) max » p99: на третью моду тянет слабо, скорее редкие выбросы, но тоже без гарантий.
И из представленных вариантов лучше всего подходит B, с мультимодальностью.
1 501
Загадка про распределение. #1
Сервис отвечает на запросы. Сняли статистику по длительности ответа:
count : 47350 mean : 1021 us p50 : 160 us p90 : 3046 us p99 : 3682 us max : 37807 usСреднее 1021 мкс, а половина запросов укладывается в 160. Вопрос: Как выглядит распределение целиком? Выбери из вариантов. A. право-скошенная мода ~150µs
0–250 |@@@@@@@@@@@@@@@@@@@@@@@@| 250–500 |@@@@@@@@@@@@ | 500–1k |@@@@@@ | 1–2k |@@@ | 2–3k |@ | 3–4k | | 4–5k | | >5k |@ |Б. доминирующая быстрая + медленная моды
0–250 |@@@@@@@@@@@@@@@@@@@@@@@@| 250–500 |@@@ | 500–1k | | 1–2k | | 2–3k |@@@@@@@@ | 3–4k |@@@@@ | 4–5k |@ | >5k |@ |C. нормальное распределение ~1.5ms
0–250 |@ | 250–500 |@@@@ | 500–1k |@@@@@@@@@@@@@@@@ | 1–2k |@@@@@@@@@@@@@@@@@@@@@@@@| 2–3k |@@@@@@@@@@@@ | 3–4k |@@@ | 4–5k | | >5k |@ |D. Все врете, нет тут правды!
1 501
Про среднее
У
avg сложилась не лучшая репутация:
* чувствителен к выбросам
* скрывает хвосты
* врёт на мультимодальных распределениях и т.д.
И всё это правда.
Но с одной оговоркой: если производительность не одно число, а распределение, то любой показатель неизбежно упрощает его, а значит может как откровенно врать, так и более-менее честно описывать действительность.
То есть все зависит от задачи, которую требуется решить, от контекста.
———
Всем нам нравятся перцентили. Но попробуйте прикинуть с их помощью throughput системы или ёмкость очереди. Вряд ли выйдет (кстати, почему?).
А вот среднее тут будет к месту.
И наоборот: среднее ничего не скажет про то, как себя чувствует худший по latency 1% запросов.
Чтобы не ошибаться в оценках, сначала стоит сформулировать вопрос, а только потом подбирать под него инструмент.
Если речь про средние и перцентили, упрощённо можем разложить так:
* сколько всего / хватит ли ёмкости? Это про сумму, то есть про среднее
* насколько плохо бывает? Тут про хвосты, то есть про перцентили
———
В итоге, чем лучше понимаем ограничения каждого инструмента, тем меньше обманываем и себя, и окружающих.1 501
В продолжение темы про AI.
Хочу порекомендовать канал моего знакомого – Azalio_tech
Миша – топ по Kubernetes и активно интересуется применением AI, как в работе, так и в повседневной жизни.
Про это и пишет в канал: наблюдения, полезные инструменты и опыт использования.
Так что, если тема близка, подписывайтесь!
Хороший контент стоит того, чтобы его поддерживать.
1 501
LLM про корректность, не про производительность
пока что
Недавние исследования (раз, два) подсвечивают "особенность" современных LLM:
«... модели хорошо чинят баги и закрывают задачи, но это умение не переносится на оптимизацию производительности. Современные LLM заточены под корректный код, а не под быстрый.»Причина не в том, что модели "не могут" в перформанс, а в том, как их обучают и оценивают. Основные бенчмарки (HumanEval, MBPP, SWE-bench) делают упор на корректность генерируемого кода (pass@k). Метрики эффективности (eff@k) существуют, но пока не стали стандартом. То есть "перформанс" сейчас не входит в KPI моделей. ——— Первая работа проверяла, насколько модели способны ускорять код: найти узкое место, внести фикс, попутно ничего не сломав. За
1.0× брали результат человека-эксперта по кодовой базе:
Top-Expert 1.000× GPT-5 0.150× Claude 4.1 Opus 0.098× Qwen3 Coder Plus 0.064× Claude 3.7 Sonnet 0.047× Claude 4.5 Sonnet 0.041× GLM-4.6 0.026× GPT-5 Mini 0.019× Kimi K2-0905 0.008× Gemini 2.5 Flash 0.008× DeepSeek V3.1 0.007× Gemini 2.5 Pro 0.007×Таким образом, лучшая модель (GPT-5) достигла лишь 15% от ускорения, которое показал человек-эксперт. А в среднем модели показывали результаты на уровне погрешности. ——— Во второй работе проверяли, можно ли снизить регрессию производительности промптингом. Сравнивали два подхода: 1)
few-shot: даём примеры эффективного кода
2) chain-of-thought: просим рассуждать пошагово
За 100% взят уровень регрессий без промпта. Если меньше, то промпт помог, если больше, то навредил. (скрин в комментах)
few-shot почти всегда уводит регрессии ниже 100%, а результаты chain-of-thought неоднозначны: где-то помогает, а где-то делает только хуже.
Как нетрудно догадаться, когда LLM дают примеры эффективного кода (мы же так и делаем, верно?🙂), результат стабильно лучше, чем когда мы просто просим её "хорошо подумать".
———
Среди основных слабостей LLM отмечают:
1) неверно идентифицируют узкое место
2) бросают на полпути, найдя любое ускорение
3) используют костыли вместо системных решений
4) подгоняют решение под тесты, периодически ломая корректность
———
В любом случае, на сегодня "человек с perf'ом" в руках остается важнейшим звеном в вопросах производительности.
А с растущим объёмом генерируемого кода эта роль только усиливается.
———
Хотя вопросы появляются:
1) 15% от "экспертного" уровня это много или мало? И сколько покажет обычный, пусть и опытный, разработчик?
2) Как скоро эффективность кода станет для LLM полноценным KPI?1 501
Упрощенно нарежем типичную функцию на две части:
1. подготовительная/служебная работа: платим каждый вызов
2. полезная работа: то, ради чего тут собрались
Мы хотим, чтобы первая часть была максимально дешёвой относительно второй (кэп).
А вот что менее очевидно: объём полезной работы далеко не всегда линейно влияет на длительность функции.
———
Наглядный пример: системный вызов sendto, для отправки UDP-датаграмм.
Зависимость длительности вызова от размера payload на скрине.
Интересно, что при минимальном объеме данных в 1 байт (плюс заголовки), время работы внутри sendto ~1.8мкс.
Но если увеличить payload до 512 байт, длительность вырастает всего в 1.25x. И дальше с ростом, почти не меняется.
(цифры на других системах могут отличаться, перепроверяйте)
Бо́льшая часть времени внутри sendto уходит не на сами данные, а на сопутствующую работу: оформить UDP/IP-заголовки, прогнать через сетевой стек, поставить в очередь на отправку.
Всё это происходит вне зависимости того, один байт ты отправляешь или тысячу.
———
И дело не в sendto. Так ведут себя многие вызовы, на которых всё держится: фикса доминирует, а объём данных почти не влияет.
Такое поведение трудно угадать без знания внутренней механики — но из этих деталей и складывается грамотный дизайн системы.
Поэтому не угадывай, замеряй.
1 501
Чего только не придумаешь в отпусках!
Например, новое название канала:
about:performance
Теперь так.1 501
О бенчмаркинге, часть 2
(первая часть тут)
Производительности в вакууме не бывает
Состояние одной и той же системы от запуска к запуску бенчмарков всегда разное. Даже если зафиксированы все статические параметры (настройки 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.
———
Выводы
- Производительность это распределение, а не число
- Шум есть всегда, и работать с ним нужно исходя из его типа
- Борьба с шумом бесконечный процесс - главное знать, где остановиться.
———
Поставить лайк на Linkedin1 501
Походил, подумал, не нужен в канале этот ранний доступ.
Добавил себе геморроя на ровном месте. Лучше откатить раньше, чем позже.
Поэтому реверт — возвращаюсь к исходному формату публикаций.
1 501
Вышла вторая часть серии про бенчмаркинг (первую ищи тут).
Ее центральная мысль: performance is a shape, not a number.
Каждый отдельный замер это всего лишь один сэмпл из полного распределения.
И чем лучше мы это распределение понимаем, тем полнее видим картину и следовательно сможем сделать более точные выводы.
В этой части:
* почему производительность это распределение, а не число
* что такое шум, откуда он берётся и каких бывает типов
* как бороться с каждым из них
* и почему борьба с ним не имеет конца
Полная версия появится здесь через 7 дней вот уже совсем скоро...
1 501
О бенчмаркинге, часть 1
Бенчмаркинг занимает значительную часть моей повседневной работы, поэтому важно понимать его основы, типы и ограничения.
По сути, это способ оценить производительность системы под нагрузкой.
Брендан Грегг в своё время ввёл наглядную терминологию:
* Passive Benchmarking
* Active Benchmarking
———
Passive Benchmarking простой и распространённый подход: настраиваешь окружение, запускаешь нагрузку, получаешь на выходе цифры и в дальнейшем ими руководствуешься.
Но это как раз тот случай, когда «просто» не значит «лучше».
Проблемы таких замеров:
* риск измерить не то, что планировалось изначально
* непонятно, что именно ограничивает производительность
* нельзя отличить систематическое отклонение от шума (об этом позже)
* остаемся без ответа, почему получены именно такие результаты
* сами бенчмарки могут содержать баги, что останется от нас скрыто
«Бенчмаркаешь A, на самом деле измеряешь B, а выводы делаешь о C». ©В итоге решения на основе таких данных могут оказаться даже хуже, чем если бы данных не было вовсе. ——— В противовес ему стоит Active Benchmarking (AB). Помимо настройки окружения требуется активное наблюдение за системой во время прогона. Задача понять: * то ли мы меряем, что планировали * что ограничивает производительность * согласуется ли наблюдаемое поведение с нашей моделью системы * что нужно изменить, чтобы улучшить результат AB способен дать более надёжный результат. Цена этого: более высокие требования к проведению эксперимента. Нужно не только уметь настроить окружение, но и верно интерпретировать наблюдаемое. Алгоритм: 1. Собрать данные о работе системы, тулинг в помощь (perf, bcc, iostat, bpftrace, tcpdump, ...) 2. Интерпретировать, как реагирует система (методологии USE, RED, off-CPU, TSA, ...) 3. Применять в цикле:
запустил
└─ пронаблюдал
└─ сформулировал гипотезу во что упираемся
└─ проверил в следующем прогоне
└─ повторил
Каждый пункт по отдельности даёт ограниченный эффект, зато вместе позволяет быстрее и увереннее продвигаться вперёд.
———
Вывод
Сырые цифры от Passive Benchmarking могут выглядеть правдоподобно и при этом вести к неверным и дорогим решениям.
Слепо доверяясь им, мы фактически надеемся, что угадали с сетапом с первого раза и учли все нюансы.
Не похоже на надёжную стратегию
Active Benchmarking напротив, позволяет избежать ловушки «бенчмаркаешь A, измеряешь B, делаешь выводы о C».
Цифры, полученные таким методом, поддаются объяснению, их можно оспорить и воспроизвести.
И на них уже можно опираться при принятии инженерных решений.
———
Что почитать
- Active Benchmarking
- CPU Benchmarks and Bad Tinder Dates
- Performance Methodologies
- Producing Wrong Data Without Doing Anything Obviously Wrong (тут может помочь заметка о чтении white paper)
To be continued...
———
Поддержать лайком на Linkedin.