Пакет pprof
Обзор
Пакет pprof записывает данные профилирования во время выполнения в формате, ожидаемом инструментом визуализации pprof.
Профилирование программы на Go
Первый шаг к профилированию программы на Go — включить профилирование. Поддержка профилирования тестов производительности, созданных с помощью стандартного пакета testing, встроена в go test. Например, следующая команда запускает тесты производительности в текущем каталоге и записывает профили CPU и памяти в файлы cpu.prof и mem.prof:
go test -cpuprofile cpu.prof -memprofile mem.prof -bench .
Чтобы добавить аналогичную поддержку профилирования в автономную программу, добавьте в функцию main следующий код:
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`")
var memprofile = flag.String("memprofile", "", "write memory profile to `file`")
func main() {
flag.Parse()
if *cpuprofile != "" {
f, err := os.Create(*cpuprofile)
if err != nil {
log.Fatal("could not create CPU profile: ", err)
}
defer f.Close() // error handling omitted for example
if err := pprof.StartCPUProfile(f); err != nil {
log.Fatal("could not start CPU profile: ", err)
}
defer pprof.StopCPUProfile()
}
// ... rest of the program ...
if *memprofile != "" {
f, err := os.Create(*memprofile)
if err != nil {
log.Fatal("could not create memory profile: ", err)
}
defer f.Close() // error handling omitted for example
runtime.GC() // get up-to-date statistics
// Lookup("allocs") creates a profile similar to go test -memprofile.
// Alternatively, use Lookup("heap") for a profile
// that has inuse_space as the default index.
if err := pprof.Lookup("allocs").WriteTo(f, 0); err != nil {
log.Fatal("could not write memory profile: ", err)
}
}
}
Также существует стандартный HTTP-интерфейс для доступа к данным профилирования. Следующая строка установит обработчики по адресу /debug/pprof/ для загрузки профилей в реальном времени:
import _ "net/http/pprof"
Дополнительные сведения см. в пакете net/http/pprof.
Затем профили можно визуализировать с помощью инструмента pprof:
go tool pprof cpu.prof
В командной строке pprof доступно множество команд. Часто используемые команды включают "top", которая выводит сводку самых ресурсоёмких участков программы, и "web", которая открывает интерактивный график этих участков и графов вызовов. Используйте команду "help", чтобы получить сведения обо всех командах pprof.
Дополнительные сведения о pprof см. по адресу https://github.com/google/pprof/blob/main/doc/README.md.
Указатель
Файлы пакета
elf.go label.go map.go pe.go pprof.go pprof_rusage.go proto.go proto_other.go protobuf.go protomem.go runtime.go
func Do 1.9
func Do(ctx context.Context, labels LabelSet, f func(context.Context))
Do вызывает f с копией родительского контекста, в карту меток которого добавлены указанные метки. Горoutines, запущенные во время выполнения f, унаследуют расширенный набор меток. Каждая пара ключ/значение из labels добавляется в карту меток в указанном порядке, заменяя предыдущее значение для того же ключа. Расширенная карта меток будет установлена на время вызова f и восстановлена после его возврата.
func ForLabels 1.9
func ForLabels(ctx context.Context, f func(key, value string) bool)
ForLabels вызывает f для каждой метки, заданной в контексте. Функция f должна возвращать true для продолжения обхода или false для его досрочного завершения.
func Label 1.9
func Label(ctx context.Context, key string) (string, bool)
Label возвращает значение метки с указанным ключом в ctx и логическое значение, указывающее, существует ли эта метка.
func SetGoroutineLabels 1.9
func SetGoroutineLabels(ctx context.Context)
SetGoroutineLabels устанавливает метки текущей горутины в соответствии с ctx. Новая горутина наследует метки горутины, которая её создала. Это API более низкого уровня, чем Do; по возможности следует использовать именно Do.
func StartCPUProfile
func StartCPUProfile(w io.Writer) error
StartCPUProfile включает профилирование CPU для текущего процесса. Во время профилирования данные профиля буферизуются и записываются в w. StartCPUProfile возвращает ошибку, если профилирование уже включено.
В Unix-подобных системах StartCPUProfile по умолчанию не работает для кода Go, собранного с помощью -buildmode=c-archive или -buildmode=c-shared. StartCPUProfile использует сигнал SIGPROF, но этот сигнал будет доставлен обработчику SIGPROF основной программы (если он есть), а не обработчику, используемому Go. Чтобы это заработало, вызовите os/signal.Notify для syscall.SIGPROF, но учтите, что это может нарушить профилирование, выполняемое основной программой.
func StopCPUProfile
func StopCPUProfile()
StopCPUProfile останавливает текущее профилирование CPU, если оно выполняется. StopCPUProfile возвращает управление только после завершения всех операций записи профиля.
func WithLabels 1.9
func WithLabels(ctx context.Context, labels LabelSet) context.Context
WithLabels возвращает новый context.Context с добавленными указанными метками. Метка заменяет предыдущую метку с тем же ключом.
func WriteHeapProfile
func WriteHeapProfile(w io.Writer) error
WriteHeapProfile — это сокращённая запись для Lookup("heap").WriteTo(w, 0). Функция сохранена для обратной совместимости.
type LabelSet 1.9
LabelSet — это набор меток.
type LabelSet struct {
// contains filtered or unexported fields
}
func Labels 1.9
func Labels(args ...string) LabelSet
Labels принимает чётное число строк, представляющих пары ключ-значение, и создаёт содержащий их LabelSet. Метка заменяет предыдущую метку с тем же ключом. В настоящее время метки используются только в профилях CPU и горутин. Подробности см. в https://golang.org/issue/23458.
type Profile
Profile — это набор трассировок стека, показывающих последовательности вызовов, приведшие к возникновению определённого события, например выделения памяти. Пакеты могут создавать и поддерживать собственные профили; чаще всего они используются для отслеживания ресурсов, которые необходимо явно закрывать, например файлов или сетевых соединений.
Методы Profile можно одновременно вызывать из нескольких горутин.
У каждого Profile уникальное имя. Несколько профилей определены заранее:
goroutine - stack traces of all current goroutines goroutineleak - stack traces of all leaked goroutines allocs - a sampling of all past memory allocations heap - a sampling of memory allocations of live objects threadcreate - stack traces that led to the creation of new OS threads block - stack traces that led to blocking on synchronization primitives mutex - stack traces of holders of contended mutexes
Эти предопределённые профили управляют своим состоянием самостоятельно и вызывают панику при явном вызове методов Profile.Add или Profile.Remove.
Профиль CPU недоступен как Profile. Для него предусмотрен специальный API — функции StartCPUProfile и StopCPUProfile, поскольку во время профилирования они передают данные в поток записи.
Профиль кучи
Профиль кучи содержит статистику по состоянию на момент последнего завершённого сборщика мусора; более поздние выделения памяти в нём не учитываются, чтобы не смещать профиль от живых данных в сторону мусора. Если сборка мусора ещё ни разу не выполнялась, профиль кучи содержит сведения обо всех известных выделениях памяти. Это исключение особенно полезно для программ, работающих без включённой сборки мусора, обычно в целях отладки.
Профиль кучи отслеживает места выделения памяти как для всех живых объектов в памяти приложения, так и для всех объектов, выделенных с момента запуска программы. Флаги pprof -inuse_space, -inuse_objects, -alloc_space и -alloc_objects позволяют выбрать отображаемые данные; по умолчанию используется -inuse_space (живые объекты с учётом их размера).
Профиль выделений памяти
Профиль allocs совпадает с профилем кучи, но по умолчанию pprof отображает -alloc_space — общее количество байтов, выделенных с момента запуска программы (включая байты, освобождённые сборщиком мусора).
Профиль блокировок
Профиль блокировок отслеживает время, проведённое в ожидании примитивов синхронизации, таких как sync.Mutex, sync.RWMutex, sync.WaitGroup, sync.Cond, а также при отправке, получении и выборе каналов.
Трассировки стека соответствуют месту, где произошло блокирование (например, sync.Mutex.Lock).
Значения выборок соответствуют суммарному времени блокировки на данной трассировке стека с учётом выборки по времени, задаваемой функцией runtime.SetBlockProfileRate.
Профиль конкуренции за мьютексы
Профиль мьютексов отслеживает конкуренцию за мьютексы, такие как sync.Mutex, sync.RWMutex, и внутренние блокировки среды выполнения.
Трассировки стека соответствуют концу критической секции, вызвавшей конкуренцию. Например, если блокировка удерживается долго, пока другие горутины ждут возможности её получить, конкуренция будет зарегистрирована, когда блокировка наконец будет снята (то есть при вызове sync.Mutex.Unlock).
Значения выборок соответствуют приблизительному суммарному времени, которое другие горутины провели в ожидании блокировки, с учётом выборки по событиям, задаваемой функцией runtime.SetMutexProfileFraction. Например, если вызывающая горутина удерживает блокировку в течение 1s, а ещё 5 горутин ждут возможности получить её всё это время, трассировка стека вызова снятия блокировки покажет 5s конкуренции.
type Profile struct {
// contains filtered or unexported fields
}
func Lookup
func Lookup(name string) *Profile
Lookup возвращает профиль с указанным именем или nil, если такого профиля нет.
func NewProfile
func NewProfile(name string) *Profile
NewProfile создаёт профиль с указанным именем. Если профиль с таким именем уже существует, NewProfile вызывает panic. Принято использовать префикс 'import/path.' для создания отдельных пространств имён для каждого пакета. Для совместимости с различными инструментами, читающими данные pprof, имена профилей не должны содержать пробелы.
func Profiles
func Profiles() []*Profile
Profiles возвращает срез всех известных профилей, отсортированных по имени.
func (*Profile) Add
func (p *Profile) Add(value any, skip int)
Add добавляет в профиль текущий стек вызовов, связанный со значением value. Add сохраняет value во внутренней карте, поэтому value должно подходить для использования в качестве ключа карты и не будет собрано сборщиком мусора до соответствующего вызова Profile.Remove. Add вызывает panic, если профиль уже содержит стек для value.
Параметр skip имеет то же значение, что и skip в runtime.Caller, и определяет, с какого места начинается трассировка стека. Значение skip=0 начинает трассировку с функции, вызывающей Add. Например, для следующего стека вызовов:
Add called from rpc.NewClient called from mypkg.Run called from main.main
При значении skip=0 трассировка стека начинается с вызова Add внутри rpc.NewClient. При значении skip=1 трассировка стека начинается с вызова NewClient внутри mypkg.Run.
func (*Profile) Count
func (p *Profile) Count() int
Count возвращает количество стеков вызовов, содержащихся в профиле в данный момент.
func (*Profile) Name
func (p *Profile) Name() string
Name возвращает имя этого профиля, которое можно передать в Lookup, чтобы получить профиль повторно.
func (*Profile) Remove
func (p *Profile) Remove(value any)
Remove удаляет из профиля стек вызовов, связанный со значением value. Ничего не делает, если value отсутствует в профиле.
func (*Profile) WriteTo
func (p *Profile) WriteTo(w io.Writer, debug int) error
WriteTo записывает снимок профиля в формате pprof в w. Если при записи в w возникает ошибка, WriteTo возвращает эту ошибку. В противном случае WriteTo возвращает nil.
Параметр debug включает дополнительный вывод. При значении debug=0 записывается сжатый gzip буфер протокола, описанный в https://github.com/google/pprof/tree/main/proto#overview. При значении debug=1 записывается устаревший текстовый формат с комментариями, сопоставляющими адреса именам функций и номерам строк, чтобы программист мог прочитать профиль без инструментов.
Для предопределённых профилей другие значения debug могут иметь особый смысл; например, при выводе профиля "goroutine" значение debug=2 означает, что стеки горутин будут выведены в том же формате, который использует программа на Go при завершении из-за необработанной паники.
Ошибки
- ☞
Качество профилей зависит от поддержки со стороны ядра, используемой для их создания. Подробности об известных проблемах см. в разделе https://golang.org/issue/13841.
© Google, Inc.
Licensed under the Creative Commons Attribution License 3.0.
http://golang.org/pkg/runtime/pprof/