Perfetto + dotnet-trace: практический цикл профилирования для .NET 9/.NET 10
Практический цикл профилирования для .NET 9 и .NET 10: захватывайте трассировки с помощью dotnet-trace, визуализируйте их в Perfetto и итеративно разбирайтесь с проблемами CPU, GC и пула потоков.
Самый быстрый способ выйти из тупика “оно тормозит” в .NET - перестать гадать и начать смотреть на временную шкалу. Статья, которая ходит по рукам на этой неделе, показывает чистый рабочий процесс: захват трассировок с помощью dotnet-trace, а затем их анализ в Perfetto (та же экосистема просмотрщика трассировок, которую многие знают по миру Android и Chromium): Using dotnet-trace with Perfetto.
Почему стоит добавить Perfetto в свой инструментарий
Если вы уже используете dotnet-counters или профилировщик, Perfetto его не заменяет. Он его дополняет:
- Вы получаете визуальную временную шкалу, которая значительно облегчает анализ проблем конкурентности (всплески пула потоков, симптомы конкуренции за блокировки, асинхронные водопады).
- Вы можете поделиться файлом трассировки с другим инженером, не прося его установить вашу IDE или коммерческий профилировщик.
Для приложений .NET 9 и .NET 10 это особенно полезно, когда вы пытаетесь убедиться, что “небольшое” изменение случайно не привнесло лишние аллокации, лишние потоки или новое узкое место синхронизации.
Цикл захвата (сначала воспроизведение, потом трассировка)
Хитрость в том, чтобы относиться к трассировке как к циклу, а не к разовой операции:
- Сделайте замедление воспроизводимым (тот же endpoint, та же нагрузка, тот же набор данных).
- Захватите 10-30 секунд вокруг интересующего окна.
- Анализируйте, формируйте гипотезу, меняйте одну вещь, повторяйте.
Вот минимальная последовательность захвата с использованием глобального инструмента:
dotnet tool install --global dotnet-trace
# Find the PID of the target process (pick one)
dotnet-trace ps
# Capture an EventPipe trace (default providers are usually a good starting point)
dotnet-trace collect --process-id 12345 --duration 00:00:15 --output app.nettrace
В итоге вы получите app.nettrace. Дальше следуйте шагам преобразования/открытия из исходной статьи (точный путь “открыть в Perfetto” зависит от того, какой Perfetto UI вы используете и какой шаг преобразования выберете).
На что смотреть, открыв трассировку
Начните с вопросов, на которые можно ответить за минуты:
- Загрузка CPU: вы CPU-bound (горячие методы) или ожидаете (блокировка, sleep, I/O)?
- Поведение пула потоков: видите ли вы всплески рабочих потоков, коррелирующие с пиками задержки?
- Корреляция с GC: совпадают ли окна пауз с медленным запросом или только с фоновой активностью?
Найдя подозрительное окно, вернитесь к коду и внесите точечное изменение (например: уменьшить аллокации, избежать sync-over-async, убрать блокировку с горячего пути запроса или сгруппировать дорогие вызовы).
Один прагматичный шаблон: трассировка в Release без потери символов
Если можете, запускайте медленный путь в Release (ближе к продакшену), но сохраняйте достаточно информации, чтобы рассуждать о фреймах. В SDK-style проектах PDB генерируются по умолчанию; для сеанса профилирования обычно нужны предсказуемые пути вывода:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Configuration>Release</Configuration>
<DebugType>portable</DebugType>
</PropertyGroup>
</Project>
Держите всё скучным: стабильный вход, стабильная конфигурация, короткие трассировки, повторение.
Если хотите детальные шаги по Perfetto и скриншоты, исходная статья - лучшая ссылка, которую стоит держать открытой во время прогона цикла: Using dotnet-trace with Perfetto.
Comments
Sign in with GitHub to comment. Reactions and replies thread back to the comments repo.