Настройка производительности pprof на языке Go «сухая»

Go
Настройка производительности pprof на языке Go «сухая»

В области отладки производительности компьютера профилирование относится к профилированию приложения, а профилирование — к использованию ЦП и памяти приложением. Язык 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По этому пути есть несколько подстраниц:

  • /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Проверьте, прошла ли установка успешно.

CPU占比图Примечания к графикам: Каждое поле представляет собой функцию.Теоретически, чем больше поле, тем больше ресурсов процессора оно занимает. Линии между прямоугольниками представляют отношения вызова между функциями. Цифры в строках представляют количество вызовов функций. Первая строка чисел в поле представляет собой процент ЦП, занятых текущей функцией, а вторая строка чисел представляет совокупный процент ЦП, занятых текущей функцией.

Помимо анализа данных о производительности ЦП, 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), главное добавить в переменную окружения соответствующий исполняемый файл.

  1. Скачайте и установите перл:www.perl.org/get.html

  2. Скачать FlameGraph:git clone https://github.com/brendangregg/FlameGraph.git

  3. БудуFlameGraphКаталог добавляется в переменные окружения операционной системы.

  4. Учащимся на платформе 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Если хотите узнать больше, подписывайтесь"Перейти клавишный воин"Официальный аккаунт, давайте общаться и учиться вместе!

рекомендуемая статья:

Опционный режим Голанга