about:performance
СтатистикаКанал о performance engineering от Александра Лебедева (@alebsys). Low latency, Linux, Observability. ▸ Обо мне: alebsys.github.io ▸ Консультации: alebsys.github.io/consulting
- Последний пост
- 14 авг.
- Последнее чтение
- 21:57
- Постов за неделю
- 1
- Всего постов
- 32
- Тип
- открытый
- Язык
- русский
- Категория
- Технологии (по похожим)
- В каталоге с
- 13 авг.
- 1/24сутки в ленте
- 440
- 1/48двое суток
- 504
- 1/72трое суток
- 543
Оценка по просмотрам недавних постов: пост набирает почти всё за первые сутки.
Посты
видео или голосовое, без подписи
about:performance pinned «»
видео или голосовое, без подписи
видео или голосовое, без подписи
Про бенчмаркинг, часть 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'ами.
Продублирую свой комментарий на вопрос: Стоит задача оценки достаточности мощности оборудования по 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. И в зависимости от нужного запаса либо срезаем, либо добавляем ресурсы.
Давайте ещё разок, на этот раз чуть сложнее: count : 44500 mean : 871 us p50 : 1081 us p90 : 1289 us p99 : 5012 us max : 11275 us Задача всё та же: по статистике определить форму распределения. Возможные варианты: A) право-скошенная…
видео или голосовое, без подписи
Загадка про распределение. #1 Сервис отвечает на запросы. Сняли статистику по длительности ответа: count : 47350 mean : 1021 us p50 : 160 us p90 : 3046 us p99 : 3682 us max : 37807 us Среднее 1021 мкс, а половина запросов укладывается…
видео или голосовое, без подписи
Про среднее У avg сложилась не лучшая репутация: * чувствителен к выбросам * скрывает хвосты * врёт на мультимодальных распределениях и т.д. И всё это правда. Но с одной оговоркой: если производительность не одно число, а распределение, то любой показатель неизбежно упрощает его, а значит может как откровенно врать, так и более-менее честно описывать действительность. То есть все зависит от задачи, которую требуется решить, от контекста. ——— Всем нам нравятся перцентили. Но попробуйте прикинуть с их помощью throughput системы или ёмкость очереди. Вряд ли выйдет (кстати, почему?). А вот среднее тут будет к месту. И наоборот: среднее ничего не скажет про то, как себя чувствует худший по latency 1% запросов. Чтобы не ошибаться в оценках, сначала стоит сформулировать вопрос, а только потом подбирать под него инструмент. Если речь про средние и перцентили, упрощённо можем разложить так: * сколько всего / хватит ли ёмкости? Это про сумму, то есть про среднее * насколько плохо бывает? Тут про хвосты, то есть про перцентили ——— В итоге, чем лучше понимаем ограничения каждого инструмента, тем меньше обманываем и себя, и окружающих.
В продолжение темы про AI. Хочу порекомендовать канал моего знакомого – Azalio_tech Миша – топ по Kubernetes и активно интересуется применением AI, как в работе, так и в повседневной жизни. Про это и пишет в канал: наблюдения, полезные инструменты и опыт использования. Так что, если тема близка, подписывайтесь! Хороший контент стоит того, чтобы его поддерживать.
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. подготовительная/служебная работа: платим каждый вызов 2. полезная работа: то, ради чего тут собрались Мы хотим, чтобы первая часть была максимально дешёвой относительно второй (кэп). А вот что менее очевидно: объём полезной работы далеко не всегда линейно влияет на длительность функции. ——— Наглядный пример: системный вызов sendto, для отправки UDP-датаграмм. Зависимость длительности вызова от размера payload на скрине. Интересно, что при минимальном объеме данных в 1 байт (плюс заголовки), время работы внутри sendto ~1.8мкс. Но если увеличить payload до 512 байт, длительность вырастает всего в 1.25x. И дальше с ростом, почти не меняется. (цифры на других системах могут отличаться, перепроверяйте) Бо́льшая часть времени внутри sendto уходит не на сами данные, а на сопутствующую работу: оформить UDP/IP-заголовки, прогнать через сетевой стек, поставить в очередь на отправку. Всё это происходит вне зависимости того, один байт ты отправляешь или тысячу. ——— И дело не в sendto. Так ведут себя многие вызовы, на которых всё держится: фикса доминирует, а объём данных почти не влияет. Такое поведение трудно угадать без знания внутренней механики — но из этих деталей и складывается грамотный дизайн системы. Поэтому не угадывай, замеряй.
Чего только не придумаешь в отпусках! Например, новое название канала: about:performance Теперь так.
Channel name was changed to «about:performance»
О бенчмаркинге, часть 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. ——— Выводы - Производительность это распределение, а не число - Шум есть всегда, и работать с ним нужно исходя из его типа - Борьба с шумом бесконечный процесс - главное знать, где остановиться. ——— Поставить лайк на Linkedin
Походил, подумал, не нужен в канале этот ранний доступ. Добавил себе геморроя на ровном месте. Лучше откатить раньше, чем позже. Поэтому реверт — возвращаюсь к исходному формату публикаций.
Вышла вторая часть серии про бенчмаркинг (первую ищи тут). Ее центральная мысль: performance is a shape, not a number. Каждый отдельный замер это всего лишь один сэмпл из полного распределения. И чем лучше мы это распределение понимаем, тем полнее видим картину и следовательно сможем сделать более точные выводы. В этой части: * почему производительность это распределение, а не число * что такое шум, откуда он берётся и каких бывает типов * как бороться с каждым из них * и почему борьба с ним не имеет конца Полная версия появится здесь через 7 дней вот уже совсем скоро...
О бенчмаркинге, часть 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.