Вот тут есть некоторое дополнительное сравнение: https://github.com/yandex/perforator/discussions/14. TLDR: мы фокусировались на качественной поддержке нативных языков, и она, судя по всему, у нас реализована лучше.
Ключевое и понятное – мы целимся в AutoFDO / BOLT и более продвинутые методы оптимизации, а pyroscope скорее про https://github.com/grafana/pyroscope/discussions/2783?ysclid=m6ky5ow7l9186278470. Ещё в Pyroscope был более урезанная логика раскрутки через DWARF когда-то, но ручаться не буду: с выходом elastic/opentelemetry-ebpf-profiler и развитием eBPF все меняется слишком часто (вон коллеги из parca, которые параллельно похожую конструкцию развивали, на него переехали).
В целом, конечно, похожие решения есть. Суть в деталях и масштабе. Надо сравнивать. Но PGO развивать тут мы не бросим, самим очень нужно.
Сравнение с режимом ThinLTO. Если сравнивать с LBR-профилем от perf с одной машинки, то у нас виден эффект на единицы процентов от того, что мы можем обрабатывать прям много профилей (дни), но это уже довольно минорная штука. Ключевое тут скорее то, что вокруг perf так же придется инфру для PGO пилить, а у нас она общая с обычным профилированием.
Можно, поддерживает (масштабируем число событий на коэффициенты, которые ядро возвращает). Разве что сейчас нет поддержки записи группы событий, все независимо будут семплироваться. Ну и мы видели кучу багов с мультиплексингом в ядре (не только у нас, perf так же себя ведет). Может быть, дойдут руки в апстрим зарепортить содержательно.
Сильно зависит от приложения и вида корутин. Стекфул видно хорошо, активно внутри на такое смотрим (те же горутины). Тут вопрос скорее в правильной агрегации стеков между разными потоками.
Со стеклесс тяжелее, конечно. Самое печальное, что там стек вызовов совсем никак не материализован, так что по профилю понять можно сильно меньше. Думаем пока, есть ли варианты хорошие.
Планируется! Сейчас есть базовая поддержка для некоторых сценариев, но мы активно работаем над качественной zero-configuration поддержкой. Знаем про много смежных проектов, которые это уже хорошо делают, поэтому дело техники дальше.
Под капотом профили генерируем через AutoFDO, да. CSSPGO пока руки не дошли попробовать. Кажется, в наш пайплайн тоже должно хорошо ложиться. Завел issue подумать, спасибо!
Ещё с BOLT экспериментируем, но там пока не все так гладко, BOLT слишком уж агрессивно бинари перемалывает (появляются не встречающиеся в дикой природе несколько исполняемых секций, когда-то DWARF ломался, ещё пара нюансов).
О, звучит очень интересно. А можно почитать где-нибудь деталей? В GSYM нас немного расстроила необходимость поддерживать структуры в памяти для каждой функции, не получается сделать совсем красиво с zero-copy использованием секции, из-за этого усложняется параллельная обработка.
Трассировку используем, и Perforator умеет аннотировать семплы идентификаторами трасс. Но там много нюансов: у нас количество семплов настолько большое, что по конкретному идентфикатору трассы лукапить будет крайне дорого. Но уже сейчас внутри активно используем знание про id трассы для профилей по срезам запросов пользователей в батч-режиме.
Про ребят из Elastic знаем, как и про несколько похожих стартапов. eBPF развивается крайне активно, вот только последние годы стало возможным реализовать такого рода профилировщики, и они параллельно с нами развивались в closed source (Elastic купил стартап Optimyze и только совсем недавно выложил в open source). Мы верим, что в нашей разработке есть много полезного для сообщества (в частности, у Elastic агент, это небольшая, хоть и ключевая часть системы).
Сейчас активно думаем, как нам лучше всего проинтегрироваться с сообществом, чтоб кумулятивный эффект был от комбинации разработок.
Да. Мы внутри используем pprof (но постепенно мигрируем на новый формат из-за серьезных ограничений в масштабируемости pprof), поэтому через API и CLI можно получить сырой профиль в pprof формате. В CLI надо указать --format=pprof .
Да, с размером на диске помогает, но с трафиком в памяти – нет (на каждый семпл нужно скопировать 65К бессмысленных байт сначала из userspace в kernelspace, потом из kernelspace в userspace, потом ещё внутри perf пару раз потрогать). Memory bandwidh на современных серверах дорогой. Ну и фича довольно новая, экспериментировали пару лет наззад с -z – perf регулярно падал.
Смотрели, да. У нас основная идея – мы не требуем пересборки бинарей. Так что можно только идеями вдохновляться для построения нашей упрощенной таблицы раскрутки для eBPF программы. Но, как в соседней ветке отвечал, в мире явно назрела необходимость начать переходить на какой-то более адекватный формат для раскрутки стека.
Мы думали об этом. Скорее всего, в каком-то виде это можно сделать, с некоторой вероятностью допушим в апстрим. Основные сложности тут скорее технические: мы активно используем LLVM, код as-is переиспользовать будет сложно; ну и архитектура у perf немного отличается от нашей. Но тут очень важно то, что perforator – не только замена perf, но и инфраструктура для cluster-wide профилирования. Там тоже немало подводных камней.
Если уж мы пошли ловить мух - значит у нас всё должно быть под контролем ? А то мало ли как собрали библиотеки. В большом и сильно гетерогенном окружении это достаточно нетривиально реализовать. На масштабах Яндекса, например, есть точно разные бинарные файлы. Ну и совсем не все исполняемые файлы собираются дистрибутивами. Frame pointers везде – это хороший и правильный, но это не панацея, и так не выйдет достичь идеального качества раскрутки.
Например, есть VDSO (стеки приложения через gettimeofday не будут собиратся без DWARF), есть крайне много рукописного ассемблера в ключевых библиотеках и самых горячих местах, есть проприетарные бинарные блобы (libcuda.so), есть JIT-компилированый код и так далее. Нашей основной задачей было добиться идеального качества нативной раскрутки, потому что на масштабе perf нас не устраивал, в том числе из-за проблем на 20% стеков.
А что можете сказать по поводу ORC unwinder в ядре ? Тоже звучит очень правильно и полезно. В частности, ORC нас вдохновил подумать ещё раз, а можно ли все же DWARF раскручивать, из этого Perforator и вышел. На самом деле, мы бы очень хотели вместе с сообществом по опыту написания профилироващиков и дебаггеров сделать популярным в тулчейнах подобный компактный и простой формат таблиц раскрутки для юзерспейсных приложений. DWARF, все же, is a complex mess. Вон компиляторы значительное количество вычислительных ресурсов тратят на то, чтоб поддержвать DWARF в процессе оптимизации, а будто бы можно сильно проще, если не пытаться генерализовать все подряд.
Другое дело, что смысл Perforator в том, что он работает в рамках существующих ограничений.
B хотелось бы пример где одно и то же профилировалось с помощью perf, а потом Perforator.
Вот взял профили Hyprland на свежем Arch, собрал через perf с fp и perforator. Для воспроизведения стоит учитывать, что в Arch все бинари стрипнутые, дебагинфу для perforator достал через debuginfod автоматически, для perf пришлось руками через `perf buildid-cache -a`. Отрендерил через нашу рисовалку профилей: https://perforator.tech/static/perforator-vs-perf/perf.html vs https://perforator.tech/static/perforator-vs-perf/perforator.html. Perf не справляется с блобом от Nvidia, например, и ещё несколько похожих нюансов.
Да, так и думаем. Эвристика работать очень хорошо должна. Там оно упирается скорее в скорость дизассемблирования всех бинарей, но это решаемо.
Другое дело, что бывают совсем странные случаи, где в рукописном ассемблере сохраняют rsp в xmm регистр; тут стек вообще может не получиться восстановить. Но такого кода, надеюсь, мало
Часто рантаймы в режиме с perf-pid.map генерируют бинарный код с frame pointers, иначе perf не сможет раскрутить. Поэтому оно не слишком сильно болит. Но в любом случае есть ситуации, где нет ни DWARF, ни frame pointers (рукописный ассемблер из популярного). Для таких ситуаций мы сейчас как раз экспериментируем с анализом бинарного кода для синтеза правил раскрутки стека; есть основания надеяться, что подход сработает
Да, можно. Не экспериментировали пока сами с новым PGO в Go, но почти наверное просто должно работать.
Вот тут есть некоторое дополнительное сравнение: https://github.com/yandex/perforator/discussions/14. TLDR: мы фокусировались на качественной поддержке нативных языков, и она, судя по всему, у нас реализована лучше.
Ключевое и понятное – мы целимся в AutoFDO / BOLT и более продвинутые методы оптимизации, а pyroscope скорее про https://github.com/grafana/pyroscope/discussions/2783?ysclid=m6ky5ow7l9186278470. Ещё в Pyroscope был более урезанная логика раскрутки через DWARF когда-то, но ручаться не буду: с выходом elastic/opentelemetry-ebpf-profiler и развитием eBPF все меняется слишком часто (вон коллеги из parca, которые параллельно похожую конструкцию развивали, на него переехали).
В целом, конечно, похожие решения есть. Суть в деталях и масштабе. Надо сравнивать. Но PGO развивать тут мы не бросим, самим очень нужно.
Сравнение с режимом ThinLTO. Если сравнивать с LBR-профилем от perf с одной машинки, то у нас виден эффект на единицы процентов от того, что мы можем обрабатывать прям много профилей (дни), но это уже довольно минорная штука. Ключевое тут скорее то, что вокруг perf так же придется инфру для PGO пилить, а у нас она общая с обычным профилированием.
Можно, поддерживает (масштабируем число событий на коэффициенты, которые ядро возвращает). Разве что сейчас нет поддержки записи группы событий, все независимо будут семплироваться. Ну и мы видели кучу багов с мультиплексингом в ядре (не только у нас, perf так же себя ведет). Может быть, дойдут руки в апстрим зарепортить содержательно.
Сильно зависит от приложения и вида корутин. Стекфул видно хорошо, активно внутри на такое смотрим (те же горутины). Тут вопрос скорее в правильной агрегации стеков между разными потоками.
Со стеклесс тяжелее, конечно. Самое печальное, что там стек вызовов совсем никак не материализован, так что по профилю понять можно сильно меньше. Думаем пока, есть ли варианты хорошие.
Планируется! Сейчас есть базовая поддержка для некоторых сценариев, но мы активно работаем над качественной zero-configuration поддержкой. Знаем про много смежных проектов, которые это уже хорошо делают, поэтому дело техники дальше.
Под капотом профили генерируем через AutoFDO, да. CSSPGO пока руки не дошли попробовать. Кажется, в наш пайплайн тоже должно хорошо ложиться. Завел issue подумать, спасибо!
Ещё с BOLT экспериментируем, но там пока не все так гладко, BOLT слишком уж агрессивно бинари перемалывает (появляются не встречающиеся в дикой природе несколько исполняемых секций, когда-то DWARF ломался, ещё пара нюансов).
О, звучит очень интересно. А можно почитать где-нибудь деталей? В GSYM нас немного расстроила необходимость поддерживать структуры в памяти для каждой функции, не получается сделать совсем красиво с zero-copy использованием секции, из-за этого усложняется параллельная обработка.
Трассировку используем, и Perforator умеет аннотировать семплы идентификаторами трасс. Но там много нюансов: у нас количество семплов настолько большое, что по конкретному идентфикатору трассы лукапить будет крайне дорого. Но уже сейчас внутри активно используем знание про id трассы для профилей по срезам запросов пользователей в батч-режиме.
Про ребят из Elastic знаем, как и про несколько похожих стартапов. eBPF развивается крайне активно, вот только последние годы стало возможным реализовать такого рода профилировщики, и они параллельно с нами развивались в closed source (Elastic купил стартап Optimyze и только совсем недавно выложил в open source). Мы верим, что в нашей разработке есть много полезного для сообщества (в частности, у Elastic агент, это небольшая, хоть и ключевая часть системы).
Сейчас активно думаем, как нам лучше всего проинтегрироваться с сообществом, чтоб кумулятивный эффект был от комбинации разработок.
Да. Мы внутри используем pprof (но постепенно мигрируем на новый формат из-за серьезных ограничений в масштабируемости pprof), поэтому через API и CLI можно получить сырой профиль в pprof формате. В CLI надо указать
--format=pprof
.С xmm проблема скорее в том, что из контекста eBPF-программы их не достать, да и из ядра нетривиально. Но это совсем маргинальный сценарий, конечно, тут проще код переписать. Оригинально вот в этом коде первый раз заметили: https://www.nayuki.io/res/fast-md5-hash-implementation-in-x86-assembly/md5-fast-x8664.S
Да. Планируем в ближайшее время выпустить рисовалку профилей удобной библиотекой для JS и CLI для отрисовки произвольных pprof-совместимых профилей.
Да, с размером на диске помогает, но с трафиком в памяти – нет (на каждый семпл нужно скопировать 65К бессмысленных байт сначала из userspace в kernelspace, потом из kernelspace в userspace, потом ещё внутри perf пару раз потрогать). Memory bandwidh на современных серверах дорогой. Ну и фича довольно новая, экспериментировали пару лет наззад с -z – perf регулярно падал.
Смотрели, да. У нас основная идея – мы не требуем пересборки бинарей. Так что можно только идеями вдохновляться для построения нашей упрощенной таблицы раскрутки для eBPF программы. Но, как в соседней ветке отвечал, в мире явно назрела необходимость начать переходить на какой-то более адекватный формат для раскрутки стека.
Мы думали об этом. Скорее всего, в каком-то виде это можно сделать, с некоторой вероятностью допушим в апстрим. Основные сложности тут скорее технические: мы активно используем LLVM, код as-is переиспользовать будет сложно; ну и архитектура у perf немного отличается от нашей. Но тут очень важно то, что perforator – не только замена perf, но и инфраструктура для cluster-wide профилирования. Там тоже немало подводных камней.
Да, обязательно, над ней активно будем работать. Немного не успели до выхода.
Отличные вопросы, спасибо!
Например, есть VDSO (стеки приложения через gettimeofday не будут собиратся без DWARF), есть крайне много рукописного ассемблера в ключевых библиотеках и самых горячих местах, есть проприетарные бинарные блобы (libcuda.so), есть JIT-компилированый код и так далее. Нашей основной задачей было добиться идеального качества нативной раскрутки, потому что на масштабе perf нас не устраивал, в том числе из-за проблем на 20% стеков.
Другое дело, что смысл Perforator в том, что он работает в рамках существующих ограничений.
Вот взял профили Hyprland на свежем Arch, собрал через perf с fp и perforator. Для воспроизведения стоит учитывать, что в Arch все бинари стрипнутые, дебагинфу для perforator достал через debuginfod автоматически, для perf пришлось руками через `perf buildid-cache -a`. Отрендерил через нашу рисовалку профилей: https://perforator.tech/static/perforator-vs-perf/perf.html vs https://perforator.tech/static/perforator-vs-perf/perforator.html. Perf не справляется с блобом от Nvidia, например, и ещё несколько похожих нюансов.
Да, так и думаем. Эвристика работать очень хорошо должна. Там оно упирается скорее в скорость дизассемблирования всех бинарей, но это решаемо.
Другое дело, что бывают совсем странные случаи, где в рукописном ассемблере сохраняют rsp в xmm регистр; тут стек вообще может не получиться восстановить. Но такого кода, надеюсь, мало
Часто рантаймы в режиме с perf-pid.map генерируют бинарный код с frame pointers, иначе perf не сможет раскрутить. Поэтому оно не слишком сильно болит. Но в любом случае есть ситуации, где нет ни DWARF, ни frame pointers (рукописный ассемблер из популярного). Для таких ситуаций мы сейчас как раз экспериментируем с анализом бинарного кода для синтеза правил раскрутки стека; есть основания надеяться, что подход сработает