go tool trace и escape analysis
Trace показывает временную историю событий runtime: goroutine, scheduler, GC, syscalls и blocking. Escape analysis — решение компилятора о том, может ли значение жить на stack, или ему нужна heap-аллокация; это реализация, а не API-контракт.
Зачем это на интервью
Нужно уметь выбрать trace при вопросе «почему работа ждёт», а не пытаться найти эту причину только CPU profile, и не оптимизировать escapes по выводу компилятора без измерения.
Минимум для E4
- Записывать trace:
go test ./... -run '^$' -trace=trace.outилиruntime/traceв контролируемом сценарии. - Открывать
go tool trace trace.outи искать периоды runnable/running/blocked, GC и syscalls. - Запускать
go test -gcflags='-m=2' ./pkg/...для объяснений escape. - Подтверждать performance-вывод benchmark/pprof, а не только
-m.
go test ./internal/queue -run '^TestBurst$' -trace=trace.out
go tool trace trace.out
go test -gcflags='-m=2' ./internal/codecУглубление для E5/Senior
Trace полезен для scheduler latency, плохого GOMAXPROCS, долгого GC, network/syscall blocking и неравномерности goroutine. Он даёт временные связи, но артефакт может быть крупным и добавлять overhead; production-сбор согласуют, ограничивают длительностью и защищают так же, как profile. В trace сопоставляют задержку с workload, метриками и downstream-зависимостями.
Escape случается, если компилятор не может доказать безопасную stack-границу: например, адрес переживает вызов, значение помещается в interface или замыкание, размер слишком велик. Это не означает «любой pointer = heap», и конкретное решение меняется между Go releases. -m=2 даёт причины, а -gcflags следует применять к нужному пакету, избегая шума всего dependency graph. Изменение API ради одной аллокации оправдано только после профиля и оценки читаемости/безопасности.
Ключевые понятия
| Инструмент | Сигнал | Не заменяет |
|---|---|---|
| trace | timeline runtime и goroutine | агрегированный CPU/heap профиль |
-m=2 | объяснения inline/escape компилятора | измерение allocations |
| benchmark | стоимость фиксированной операции | сервисный load test |
Типовые вопросы
- Когда trace лучше pprof? — При scheduler/blocking/GC timeline; pprof лучше агрегированно ранжирует CPU или allocations.
- Escape всегда плохо? — Нет, heap необходим для корректности и часто не является bottleneck.
- Pointer всегда escape? — Нет, компилятор анализирует lifetime и может оставить объект на stack.
- Почему вывод
-mменяется? — Escape/inlining — детали оптимизатора, зависящие от версии и контекста сборки. - Можно ли снять trace в production? — Только контролируемо: короткий интервал, доступ, overhead и политика хранения должны быть определены.
Практика
- Воспроизведите goroutine blocking и снимите trace. Готово: указаны состояние, временной интервал, причина и подтверждающая метрика.
- Найдите allocation через
-m=2и pprof. Готово: показано, совпадает ли компиляторная гипотеза сalloc_space; изменение измерено benchmark.
Частые ошибки и ловушки
- Делать вывод о p99 по одной дорожке trace без workload и метрик.
- Считать escape bug или обязателным поводом переписать API.
- Снимать долгий trace в production и хранить его без контроля доступа.
Связанные темы
Инструменты Go · pprof · Производительность и память