В области отладки производительности компьютера профилирование относится к профилированию приложения, а профилирование — к использованию ЦП и памяти приложением. Язык Go уделяет особое внимание производительности, поэтому язык поставляется с библиотекой профилирования.В этой статье объясняется, как выполнять профилирование в golang.
Оптимизация производительности
Оптимизация производительности в проекте языка Go в основном включает следующие аспекты:
- Профиль ЦП: отчет об использовании ЦП программой и сбор данных приложения на ЦП и регистры в соответствии с определенной частотой.
- Профиль памяти (профиль кучи): сообщает об использовании памяти программой.
- Профилирование блоков: сообщает, когда горутины не запущены, что можно использовать для анализа и поиска узких мест в производительности, таких как взаимоблокировки.
- Профилирование горутины: отчет об использовании горутин, какие горутины есть и каковы их отношения вызова
Собирайте данные о производительности
Язык Go имеет встроенные инструменты для получения текущих данных программы, включая следующие две стандартные библиотеки:
-
runtime/pprof
: сбор данных о работе приложения типа инструмента для анализа. -
net/http/pprof
: сбор данных о времени выполнения приложения-службы для анализа.
После включения pprof текущая информация о стеке будет собираться через регулярные промежутки времени (10 мс) для получения сведений о ресурсах ЦП и памяти, занимаемых каждой функцией; наконец, на основе анализа выборочных данных будет сформирован отчет об анализе производительности.
Обратите внимание, что мы должны включать pprof в наш код только для тестирования производительности.
применение инструмента
Тип выхода, если ваше приложение работает какое-то время. Тогда лучше всего сохранить отчет о профилировании в файл для анализа при выходе из приложения. Для этого случая вы можете использоватьruntime/pprof
библиотека. Первый импорт в кодеruntime/pprof
инструмент:
import "runtime/pprof"
Анализ производительности процессора
Включить анализ производительности процессора:
pprof.StartCPUProfile(w io.Writer)
Остановить профилирование ЦП:
pprof.StopCPUProfile()
После завершения выполнения приложения создается файл, в котором сохраняются данные профилирования нашего ЦП. После получения выборочных данных используйтеgo tool pprof
Инструмент для анализа производительности процессора.
Оптимизация производительности памяти
Запишите информацию о стеке программы
pprof.WriteHeapProfile(w io.Writer)
После получения выборочных данных используйтеgo tool pprof
Инструменты для анализа производительности памяти.
go tool pprof
По умолчанию используется-inuse_space
Для статистики можно также использовать-inuse-objects
Просмотрите количество выделенных объектов.
сервисное приложение
Если ваше приложение работает постоянно, например, веб-приложение, вы можете использоватьnet/http/pprof
Библиотеки, способные предоставлять HTTP-сервисы для анализа.
Если по умолчаниюhttp.DefaultServeMux
(Обычно код напрямую использует http.ListenAndServe("0.0.0.0:8000", nil)), просто импортируйте его следующим образом в код вашего веб-сервераnet/http/pprof
import _ "net/http/pprof"
Если вы используете собственный Mux, вам необходимо вручную зарегистрировать некоторые правила маршрутизации:
r.HandleFunc("/debug/pprof/", pprof.Index)
r.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
r.HandleFunc("/debug/pprof/profile", pprof.Profile)
r.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
r.HandleFunc("/debug/pprof/trace", pprof.Trace)
Если вы используете gin framework, рекомендуется использоватьGitHub.com/gin-contJapan…, зарегистрируйте маршруты, связанные с pprof, в коде с помощью следующих команд.
pprof.Register(router)
В любом случае, ваш HTTP-сервис будет более/debug/pprof
конечная точка, доступ к ней дает что-то вроде этого:По этому пути есть несколько подстраниц:
- /debug/pprof/profile: при переходе по этой ссылке автоматически выполняется профилирование ЦП на 30 секунд и создается файл для загрузки.
- /debug/pprof/heap: Путь профилирования памяти, по этой ссылке вы получите файл с результатами профилирования памяти.
- /debug/pprof/block: Путь к блоку Профилирование
- /debug/pprof/goroutines: список запущенных горутин и отношения вызова.
команда go tool pprof
Будь то инструментальное приложение или сервисное приложение, после того, как мы используем соответствующую библиотеку pprof для получения данных, следующим шагом будет анализ данных, мы можем использоватьgo tool pprof
инструмент командной строки.
go tool pprof
Самый простой способ его использования:
go tool pprof [binary] [source]
в:
- бинарный — бинарный файл приложения, используемый для разбора различных символов;
- source указывает источник данных профиля, который может быть локальным файлом или http-адресом.
Меры предосторожности:Полученные данные профилирования являются динамическими. Чтобы получить достоверные данные, убедитесь, что приложение находится под большой нагрузкой (например, сервис создается и работает, или моделируется давление доступа с помощью других инструментов). В противном случае, если приложение простаивает, результат может быть бессмысленным.
конкретный пример
Сначала напишем проблемный код:
// runtime_pprof/main.go
package main
import (
"flag"
"fmt"
"os"
"runtime/pprof"
"time"
)
// 一段有问题的代码
func logicCode() {
var c chan int
for {
select {
case v := <-c:
fmt.Printf("recv from chan, value:%v\n", v)
default:
}
}
}
func main() {
var isCPUPprof bool
var isMemPprof bool
flag.BoolVar(&isCPUPprof, "cpu", false, "turn cpu pprof on")
flag.BoolVar(&isMemPprof, "mem", false, "turn mem pprof on")
flag.Parse()
if isCPUPprof {
file, err := os.Create("./cpu.pprof")
if err != nil {
fmt.Printf("create cpu pprof failed, err:%v\n", err)
return
}
pprof.StartCPUProfile(file)
defer pprof.StopCPUProfile()
}
for i := 0; i < 8; i++ {
go logicCode()
}
time.Sleep(20 * time.Second)
if isMemPprof {
file, err := os.Create("./mem.pprof")
if err != nil {
fmt.Printf("create mem pprof failed, err:%v\n", err)
return
}
pprof.WriteHeapProfile(file)
file.Close()
}
}
С помощью флага мы можем контролировать, включать ли анализ производительности ЦП и памяти в командной строке. Сохраните и скомпилируйте приведенный выше код какruntime_pprof
Исполняемый файл, который добавляется при выполнении-cpu
Параметры командной строки следующие:
./runtime_pprof -cpu
После ожидания в течение 30 секунд в текущем каталоге будет создан файл.cpu.pprof
документ.
Интерфейс командной строки
Мы используем набор инструментов gopprof
Давайте проанализируем это.
go tool pprof cpu.pprof
Выполнение приведенного выше кода войдет в интерактивный интерфейс следующим образом:
runtime_pprof $ go tool pprof cpu.pprof
Type: cpu
Time: Jun 28, 2019 at 11:28am (CST)
Duration: 20.13s, Total samples = 1.91mins (568.60%)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof)
Можем войти в интерактивный интерфейсtop3
Давайте рассмотрим функции, которые занимают 3 старших бита процессора в программе:
(pprof) top3
Showing nodes accounting for 100.37s, 87.68% of 114.47s total
Dropped 17 nodes (cum <= 0.57s)
Showing top 3 nodes out of 4
flat flat% sum% cum cum%
42.52s 37.15% 37.15% 91.73s 80.13% runtime.selectnbrecv
35.21s 30.76% 67.90% 39.49s 34.50% runtime.chanrecv
22.64s 19.78% 87.68% 114.37s 99.91% main.logicCode
в:
- flat: время, затраченное текущей функцией на загрузку ЦП
- flat: процент времени, в течение которого текущая функция занимает ЦП.
- sun%: кумулятивный процент времени, в течение которого функция занимает ЦП.
- cum: текущая функция плюс общее время процессора, затраченное функцией, вызывающей текущую функцию.
- cum%: общий процент затрат времени на текущую функцию плюс функция, которая вызывает текущую функцию, занимающую ЦП.
- Последний столбец: имя функции
В большинстве случаев мы можем проанализировать работу приложения и оптимизировать программу, проанализировав эти пять столбцов.
мы также можем использоватьlist 函数名
команда для просмотра анализа конкретных функций, таких как выполнениеlist logicCode
Ознакомьтесь с подробным анализом функций, которые мы написали.
(pprof) list logicCode
Total: 1.91mins
ROUTINE ================ main.logicCode in .../runtime_pprof/main.go
22.64s 1.91mins (flat, cum) 99.91% of Total
. . 12:func logicCode() {
. . 13: var c chan int
. . 14: for {
. . 15: select {
. . 16: case v := <-c:
22.64s 1.91mins 17: fmt.Printf("recv from chan, value:%v\n", v)
. . 18: default:
. . 19:
. . 20: }
. . 21: }
. . 22:}
В результате анализа обнаружено, что большую часть ресурсов ЦП занимают строки 17. Мы анализируем, что содержимое по умолчанию в операторе выбора вызовет вышеуказанноеcase v:=<-c:
Всегда выполнять. Добавляем строчку в ветку по умолчаниюtime.Sleep(time.Second)
Вот и все.
Графический
Или вы можете напрямую войти в Интернет и просмотреть подробное использование ЦП в программе через диаграмму svg. Для просмотра графического интерфейса сначала необходимо установитьgraphvizГрафические инструменты.
Мак:
brew install graphviz
Windows: СкачатьgraphvizБудуgraphviz
Добавьте папку bin в каталоге установки в переменную среды Path. Введите в терминалеdot -version
Проверьте, прошла ли установка успешно.
Примечания к графикам: Каждое поле представляет собой функцию.Теоретически, чем больше поле, тем больше ресурсов процессора оно занимает. Линии между прямоугольниками представляют отношения вызова между функциями. Цифры в строках представляют количество вызовов функций. Первая строка чисел в поле представляет собой процент ЦП, занятых текущей функцией, а вторая строка чисел представляет совокупный процент ЦП, занятых текущей функцией.
Помимо анализа данных о производительности ЦП, pprof также поддерживает анализ данных о производительности памяти. Например, используйте следующие команды для анализа данных о производительности кучи службы http и просмотра использования памяти текущей программой и использования объектов горячей памяти.
# 查看内存占用数据
go tool pprof -inuse_space http://127.0.0.1:8080/debug/pprof/heap
go tool pprof -inuse_objects http://127.0.0.1:8080/debug/pprof/heap
# 查看临时内存分配数据
go tool pprof -alloc_space http://127.0.0.1:8080/debug/pprof/heap
go tool pprof -alloc_objects http://127.0.0.1:8080/debug/pprof/heap
горящие и пламенные графики
Пламенный график (Flame Graph) — это своего рода график анализа производительности, созданный Бреданом Греггом, названный так потому, что он похож на 🔥. Приведенные выше результаты профилирования также преобразуются в пламенные графы.Если вы лучше разбираетесь в пламенных графах, вы можете сделать это вручную, но здесь мы представим инструмент:go-torch
. Это инструмент Uber с открытым исходным кодом, который может напрямую считывать данные профилирования Golang и генерировать SVG-файл Flame Graph.
Установить факел
go get -v github.com/uber/go-torch
SVG-файл Flame Graph можно открыть в браузере, и самое лучшее в нем для графиков вызовов — это то, что он динамичен: вы можете увеличивать масштаб каждого квадрата, чтобы проанализировать, что на нем изображено.
Последовательность вызовов на графике пламени идет снизу вверх. Каждый квадрат представляет функцию, а слой над ним указывает, какие функции будут вызываться этой функцией. Размер квадрата представляет продолжительность использования ЦП. Соответствие цветов карты пламени не имеет особого значения, сопоставление красного и желтого цветов по умолчанию должно быть больше похоже на пламя.
Инструмент go-torch очень прост в использовании, без каких-либо аргументов он попытаетсяhttp://localhost:8080/debug/pprof/profile
Получить данные профилирования. Он имеет три часто используемых параметра, которые можно настроить:
- -u --url: URL-адрес для посещения, здесь только часть хоста и порта
- -s –suffix: путь к профилю pprof, по умолчанию /debug/pprof/profile
- --seconds: продолжительность профилирования, по умолчанию 30 с.
Установить FlameGraph
Для генерации флейм-графа необходимо заранее установить инструмент FlameGraph, установка этого инструмента очень проста (требуется поддержка среды perl), главное добавить в переменную окружения соответствующий исполняемый файл.
-
Скачайте и установите перл:www.perl.org/get.html
-
Скачать FlameGraph:
git clone https://github.com/brendangregg/FlameGraph.git
-
Буду
FlameGraph
Каталог добавляется в переменные окружения операционной системы. -
Учащимся на платформе Windows необходимо поставить
go-torch/render/flamegraph.go
в файлеGenerateFlameGraph
Измените следующим образом, затем вgo-torch
Выполнить в каталогеgo install
Вот и все.// GenerateFlameGraph runs the flamegraph script to generate a flame graph SVG. func GenerateFlameGraph(graphInput []byte, args ...string) ([]byte, error) { flameGraph := findInPath(flameGraphScripts) if flameGraph == "" { return nil, errNoPerlScript } if runtime.GOOS == "windows" { return runScript("perl", append([]string{flameGraph}, args...), graphInput) } return runScript(flameGraph, args, graphInput) }
Инструмент измерения давления рабочий
Рекомендуемое использование:github.com/wg/wrkилиGitHub.com/adjust/go — я…
Используйте фонарик
Используйте wrk для стресс-тестирования:
go-wrk -n 50000 http://127.0.0.1:8080/book/list
Пока идет вышеуказанный стресс-тест, откройте другой терминал и выполните:
go-torch -u http://127.0.0.1:8080 -t 30
Через 30 секунд терминал подскажет следующий запрос в начале лета:Writing svg to torch.svg
Затем мы используем браузер, чтобы открытьtorch.svg
Вы можете увидеть график пламени ниже.Ось Y графика пламени представляет порядок, в котором ЦП вызывает метод, а ось X представляет процент времени, занимаемый методом в каждом времени вызова выборки.Чем шире метод, тем больше времени ЦП он занимает. . Благодаря графику пламени мы можем более четко определить трудоемкие вызовы функций, а затем постоянно исправлять код, передискретизировать и постоянно оптимизировать.
Кроме того, данные о производительности памяти можно анализировать с помощью графиков пламени:
go-torch -inuse_space http://127.0.0.1:8080/debug/pprof/heap
go-torch -inuse_objects http://127.0.0.1:8080/debug/pprof/heap
go-torch -alloc_space http://127.0.0.1:8080/debug/pprof/heap
go-torch -alloc_objects http://127.0.0.1:8080/debug/pprof/heap
pprof в сочетании с тестированием производительности
go test
Команда имеет два параметра, связанных с pprof, которые определяют сгенерированные файлы профилирования ЦП и памяти соответственно:
- -cpuprofile: адрес файла, в котором должны быть сохранены данные профилирования процессора.
- -memprofile: адрес файла данных профилирования памяти для отправки сообщения
Мы также можем объединить pprof с тестированием производительности, например:
Например, при выполнении теста ниже также будет выполнено профилирование ЦП, а результаты будут сохранены в файле cpu.prof:
go test -bench . -cpuprofile=cpu.prof
Например, при выполнении теста ниже будет также выполнено профилирование памяти, а результаты будут сохранены в файле cpu.prof:
go test -bench . -memprofile=./mem.prof
Следует отметить, что профилирование обычно используется вместе с тестированием производительности, по этой причине также упоминалось ранее, профилирование имеет смысл только тогда, когда приложение находится под высокой нагрузкой.
Вышеизложенное касаетсяНастройка производительности pprof языка GoЕсли хотите узнать больше, подписывайтесь"Перейти клавишный воин"Официальный аккаунт, давайте общаться и учиться вместе!
рекомендуемая статья: