Думаю, многие слышали историю «Тора 3» об оптимизации производительности. В исходном коде движка 3D-игры Джон Кармак будет1/sqrt(x)
Эффективность выполнения этой функции максимально оптимизирована.
Обычно мы используем метод деления пополам или метод итерации Ньютона для вычисления квадратного корня из числа с плавающей запятой. Но в этой функции автор использует «магическое число», итерации нет вообще, а квадратный корень вычисляется напрямую в два шага. Захватывающий!
Поскольку это функция самого низкого уровня, а игра включает в себя большое количество таких операций, игра может работать гладко в эпоху DOS, где вычислительные ресурсы чрезвычайно ограничены. В этом вся прелесть оптимизации производительности!
На работе, когда объем бизнеса относительно невелик, используется меньше машин, и преимущества оптимизации производительности не могут быть реализованы. Когда бизнес использует тысячи машин и оптимизирует производительность на 20 %, он может сэкономить сотни машин и миллионы долларов в год. Сэкономленные деньги дадут сотрудникам премии в конце года, так много счастья!
Вообще говоря, анализ производительности можно рассматривать на трех уровнях: уровень приложения, уровень системы и уровень кода.
Прикладной уровень предназначен в основном для того, чтобы разобраться с использованием бизнес-стороны, позволить им использовать его более разумно и сократить количество бессмысленных вызовов, исходя из предпосылки удовлетворения потребностей пользователя; системный уровень обращает внимание на архитектуру службы, например как добавление уровня кеша; уровень кода заботится об эффективности выполнения функции, например, об использовании более эффективного алгоритма квадратного корня и т. д.
Чтобы сделать что-либо, вы должны обратить внимание на метод. Во многих случаях быстрое выполнение самой важной части задач может принести большую часть преимуществ. Некоторые другие края и углы можно сшивать медленно. Как только вы захотите выполнить на 100%, вы часто будете попадать в ситуацию, когда приложили много усилий и мало достигли.
То же самое верно и для оптимизации производительности: выявление узких мест производительности позволит нам заплатить наименьшие усилия и получить наибольшую награду.
В языке Go pprof — это такой инструмент, который помогает нам быстро находить узкие места в производительности, а затем выполнять целевые оптимизации.
что такое ппроф
Перед запуском кода мы можем получить производительность системы посредством нагрузочного тестирования, например, количество запросов, которые можно обработать в секунду, среднее время отклика, процент ошибок и другие показатели. Таким образом, мы получаем итоговую оценку эффективности наших услуг.
Но измерение стресса — это смоделированный трафик в автономном режиме, что, если он выйдет в онлайн? Будут такие сценарии, как высокий параллелизм, большой трафик, ненадежность восходящего и нисходящего потоков, внезапный пиковый трафик и т. д., которые непредсказуемы.
В сети внезапно появляется большое количество алармов, таймаут интерфейса, количество ошибок увеличивается.Помимо просмотра логов и мониторинга, вы можете использовать инструменты анализа производительности, чтобы проанализировать производительность программы и найти узкое место. Конечно, вообще эта ситуация не даст вам возможности проанализировать, даунгрейд, текущий лимит, откат - это первое, что нужно сделать, сначала нужно остановить лосс. После восстановления нормальной работы используйте онлайн-воспроизведение трафика или стресс-тестирование, чтобы создать проблемы с производительностью, а затем используйте инструменты для анализа узких мест системы.
Вообще говоря, анализ производительности в основном фокусируется на таких показателях, как ЦП, память, дисковый ввод-вывод и сеть.
Profiling
Это относится к набору данных, которые могут отражать состояние выполнения программы во время выполнения программы. В разработке программного обеспечения анализ производительности (также называемый профилированием) — это метод анализа, который изучает поведение программы путем сбора информации о времени выполнения программы, а также метод динамического анализа программы.
Библиотека pprof, входящая в состав языка Go, может анализировать работу программы и предоставлять функции визуализации. Он содержит две связанные библиотеки:
-
время выполнения/pprof Для программ, которые запускаются только один раз, например автономных программ предварительной обработки, которые запускаются только один раз в день, вызовите функции, предоставляемые пакетом pprof, чтобы вручную включить сбор данных о производительности.
-
сеть/http/pprof Для онлайн-сервисов, для HTTP-сервера, получите доступ к HTTP-интерфейсу, предоставляемому pprof, для получения данных о производительности. Конечно, на самом деле нижним уровнем также является функция, предоставляемая исполняемой средой/pprof, которая инкапсулируется в интерфейс для обеспечения доступа к внешней сети.
Роль pprof
pprof
Это инструмент для анализа производительности программ на языке Go, который может предоставлять различные данные о производительности:
allocs
иheap
Информация о выборке такая же, но первая — это выделение памяти для всех объектов, а куча — это выделение памяти для активных объектов.
The difference between the two is the way the pprof tool reads there at start time. Allocs profile will start pprof in a mode which displays the total number of bytes allocated since the program began (including garbage-collected bytes).
Изображение выше взято из практической статьи pprof в справочнике [wolfogre], в которой приводится пример программы для устранения неполадок, анализа и решения проблем с производительностью с помощью pprof, что очень интересно.
- Когда анализ производительности ЦП включен, среда выполнения Go будет приостанавливаться каждые 10 мс, чтобы записать стек вызовов и связанные данные текущей запущенной горутины. После сохранения данных анализа производительности на жесткий диск мы можем проанализировать горячие точки в коде.
- Анализ производительности памяти заключается в записи стека вызовов при выделении кучи. По умолчанию выборка выполняется каждые 1000 выделений, это значение можно изменить. Выделения стека не записываются анализом памяти, поскольку они освобождаются в любое время. Потому что профилирование памяти — это выборка, а также потому, что оно записывает выделение памяти, а не использование памяти. Поэтому трудно использовать инструменты анализа производительности памяти, чтобы точно оценить конкретное использование памяти программой.
- Анализ блокировки — это очень уникальный анализ, он чем-то похож на анализ производительности ЦП, но фиксирует время, затрачиваемое горутинами на ожидание ресурсов. Анализ блокировки очень полезен для анализа узких мест параллелизма программы.Анализ производительности блокировки может показать, когда заблокировано большое количество горутин. Блокирующее профилирование — это специальный инструмент профилирования, который не следует использовать для профилирования, пока не будут устранены узкие места ЦП и памяти.
Как использовать ппроф
мы можем пройти
报告生成
,Web 可视化界面
,交互式终端
три способа использованияpprof
.
—— Жареная рыба «Анализ производительности Golang Killer PProf»
runtime/pprof
Возьмите в качестве примера профилирование ЦП, добавьте две строки кода, вызовитеpprof.StartCPUProfile
Запустить профилирование процессора, позвонитьpprof.StopCPUProfile()
Сбросить данные в файл:
import "runtime/pprof"
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
func main() {
// …………
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
// …………
}
net/http/pprof
Запустите порт (отличный от порта, который обычно предоставляет бизнес-услуги) для прослушивания запросов pprof:
import _ "net/http/pprof"
func initPprofMonitor() error {
pPort := global.Conf.MustInt("http_server", "pprofport", 8080)
var err error
addr := ":" + strconv.Itoa(pPort)
go func() {
err = http.ListenAndServe(addr, nil)
if err != nil {
logger.Error("funcRetErr=http.ListenAndServe||err=%s", err.Error())
}
}()
return err
}
pprof
Пакет автоматически зарегистрирует обработчики для обработки связанных запросов:
// src/net/http/pprof/pprof.go:71
func init() {
http.Handle("/debug/pprof/", http.HandlerFunc(Index))
http.Handle("/debug/pprof/cmdline", http.HandlerFunc(Cmdline))
http.Handle("/debug/pprof/profile", http.HandlerFunc(Profile))
http.Handle("/debug/pprof/symbol", http.HandlerFunc(Symbol))
http.Handle("/debug/pprof/trace", http.HandlerFunc(Trace))
}
первый путь/debug/pprof/
На самом деле есть 5 подпутей ниже:
goroutine threadcreate heap block mutex
Запустив сервис, получите к нему доступ прямо в браузере:
Вы можете получить сводную страницу:
Вы можете напрямую щелкнуть ссылку выше, чтобы перейти на подстраницу для просмотра соответствующей сводной информации.
Есть две ссылки для получения информации о горутинах,goroutine
иfull goroutine stack dump
, первое представляет собой сводное сообщение, вы можете просмотреть общую ситуацию с горутинами, а второе — статус каждой горутины. Для интерпретации конкретного содержания страницы, пожалуйста, обратитесь к статье [Да Бин].
нажмитеprofile
иtrace
Выборка данных будет выполняться в фоновом режиме в течение определенного периода времени. После завершения выборки файл профиля будет возвращен в браузер, а затем передан локально.go tool pprof
инструменты для анализа.
Когда скачаем и получим файл профиля, выполняем команду:
go tool pprof ~/Downloads/profile
Вы можете войти в интерактивный режим использования командной строки. воплощать в жизньgo tool pprof -help
Справочную информацию можно просмотреть.
Вы можете войти в интерактивный режим командной строки, не щелкая ссылку в браузере, напрямую используя следующую команду:
go tool pprof http://47.93.238.9:8080/debug/pprof/profile
Конечно, также необходимо собирать данные в фоновом режиме в течение определенного периода времени, затем загружать файл данных на локальный компьютер и, наконец, анализировать его. За приведенным выше URL также может следовать параметр времени:?seconds=60
, чтобы настроить продолжительность профилирования ЦП.
Аналогичные команды:
# 下载 cpu profile,默认从当前开始收集 30s 的 cpu 使用情况,需要等待 30s
go tool pprof http://47.93.238.9:8080/debug/pprof/profile
# wait 120s
go tool pprof http://47.93.238.9:8080/debug/pprof/profile?seconds=120
# 下载 heap profile
go tool pprof http://47.93.238.9:8080/debug/pprof/heap
# 下载 goroutine profile
go tool pprof http://47.93.238.9:8080/debug/pprof/goroutine
# 下载 block profile
go tool pprof http://47.93.238.9:8080/debug/pprof/block
# 下载 mutex profile
go tool pprof http://47.93.238.9:8080/debug/pprof/mutex
После входа в интерактивный режим наиболее часто используемыеtop
,list
,web
и так далее.
воплощать в жизньtop
:
Получите четыре столбца данных:
имя столбца | значение |
---|---|
flat | Время выполнения этой функции |
flat% | Flat в процентах от общего времени процессора. Общее время программы составило 16,22 с, а 16,19 с Eat составили 99,82 %. |
sum% | Сумма плоских пропорций каждой предыдущей строки |
cum | накопительная сумма. Относится к общему времени, затраченному функцией, плюс функции, вызываемые функцией. |
cum% | cum в процентах от общего времени процессора |
Другие типы, такие как heap's flat, sum и cum, аналогичны по смыслу вышеприведенным, но вычисления отличаются: один — это процессорное время, а другой — размер памяти.
воплощать в жизньlist
,использовать正则
Сопоставьте, найдите соответствующий код:
list Eat
Непосредственно найдите соответствующий код, отнимающий много времени:
воплощать в жизньweb
(Вам необходимо установить graphviz, pprof может использовать grapgviz для генерации графа вызовов программы), он сгенерирует файл формата svg и откроет его прямо в браузере (возможно, вам потребуется установить метод открытия файла .svg по умолчанию). формат):
Линия на рисунке представляет вызов метода, а метка на линии представляет выборочное значение указанного вызова метода (например, время, размер выделения памяти и т. д.), а размер поля связан с размером выборочное значение выполняемого метода.
Каждое поле состоит из двух меток: в профиле процессора одна — это доля времени, в течение которого выполняется метод, а другая — доля времени, в течение которой он появляется в выборочном стеке (первое — фиксированное время, второе — кумулятивное время). пропорциональное соотношение); чем больше поле, тем больше времени или больше памяти выделяется.
Кроме того,traces
Команда также может отображать стек вызовов функции:
Помимо двух упомянутых выше способов (генерация отчета, взаимодействие с командной строкой), вы также можете взаимодействовать в браузере. Сначала создайте файл профиля, а затем выполните команду:
go tool pprof --http=:8080 ~/Downloads/profile
Войдите в визуальный рабочий интерфейс:
Нажмите на строку меню, чтобы переключиться между: Top/Graph/Peek/Source и даже увидеть Flame Graph:
По сравнению с общим графиком пламени он просто перевернут, и отношения вызова отображаются сверху вниз. Чем длиннее форма, тем дольше время выполнения. Примечание. Используемая здесь версия go — 1.13, а более старые версии инструмента pprof не поддерживаются.-http
параметр. Конечно, вы можете скачать и другие библиотеки для просмотра флейм-графа, например:
go get -u github.com/google/pprof
或者
go get github.com/uber/go-torch
ппроф продвинутый
Я дал несколько практических статей по использованию инструмента pprof для анализа производительности в разделе «Ссылки», вы можете попрактиковаться в нем, а затем использовать его в своей обычной работе.
Расс Кокс в действии
Основное содержание этой части взято из справочного материала [Росс Кокс] и посвящено идеям Дэниела по оптимизации.
Причина этого в том, что кто-то опубликовал статью, в которой реализован алгоритм на разных языках, и программа, написанная на go, была очень медленной, а C++ — самой быстрой. А потом Расс Кокс разозлился, как он мог это выдержать? Теперь включите pprof killer для оптимизации. В конце концов, программа не только быстрее, но и использует меньше памяти!
Во-первых, добавьте код для профилирования процессора:
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
func main() {
flag.Parse()
if *cpuprofile != "" {
f, err := os.Create(*cpuprofile)
if err != nil {
log.Fatal(err)
}
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
}
...
}
Наблюдение за прошедшим временем с помощью pproftop5
, и обнаружил, что функция, считывающая карту, занимает больше всего времени:mapaccess1_fast64
, в то время как он появляется в рекурсивной функции.
С первого взгляда вы можете увидеть самую большую рамкуmapacess1_fast64
функция. воплощать в жизньweb mapaccess1
Команда, более сосредоточенная:
перечислитьmapaccess1_fast64
Больше всего функций main.FindLoops и main.DFS, пора найти конкретный код и выполнить команду:list DFS
, найдите соответствующий код.
Метод оптимизации состоит в том, чтобы изменить карту на срез, Причина этого, конечно, в том, что тип ключа - int и он не слишком разреженный.
Вывод будет заключаться в том, что для небольших наборов данных вам не следует использовать карты, где было бы достаточно срезов, поскольку карты имеют большие накладные расходы.
После модификации, снова путем профилирования процессора, обнаружено, что рекурсивные функции, отнимающие много времени, больше не входят в топ-5. Однако добавлена долгая по времени функция: runtime.mallocgc, на долю которой приходится 54,2%, что связано с выделением памяти и сборкой мусора.
Затем добавьте код для сбора данных памяти:
var memprofile = flag.String("memprofile", "", "write memory profile to this file")
func main() {
// …………
FindHavlakLoops(cfgraph, lsgraph)
if *memprofile != "" {
f, err := os.Create(*memprofile)
if err != nil {
log.Fatal(err)
}
pprof.WriteHeapProfile(f)
f.Close()
return
}
// …………
}
продолжить черезtop5
,list
Команда находит участок кода, который выделяет больше всего памяти, и обнаруживает, что на этот раз при вставке элементов в карту используется больше памяти. Метод улучшения также заключается в использовании среза вместо карты, но еще одна особенность карты заключается в том, что элементы могут быть вставлены повторно, поэтому написана новая функция для вставки элементов в срез:
func appendUnique(a []int, x int) []int {
for _, y := range a {
if x == y {
return a
}
}
return append(a, x)
}
Что ж, теперь программа работает в 2,1 раза быстрее, чем была изначально. Проверьте данные профиля процессора еще раз и найдите, чтоruntime.mallocgc
Он немного снизился, но по-прежнему составляет 50,9%.
Another way to look at why the system is garbage collecting is to look at the allocations that are causing the collections, the ones that spend most of the time in mallocgc.
Следовательно, необходимо видеть, что перерабатывается при сборке мусора, что является «виновником», вызывающим частую сборку мусора.
использоватьweb mallocgc
команда для отображения функций, связанных с mallocgc, в виде векторной диаграммы, но слишком много узлов с малым размером выборки, которые влияют на наблюдение, добавьте команду фильтра:
go tool pprof --nodefraction=0.1 profile
будет меньше, чем10%
Точки выборки , отфильтровываются, и новую векторную диаграмму можно увидеть интуитивно,FindLoops
Инициировано наибольшее количество операций по сбору мусора. продолжайте использовать командуlist FindLoops
Найдите местоположение кода напрямую.
Получается, что каждый раз, когда вы выполняетеFindLoops
функции, обаmake
Некоторые временные переменные, которые будут облагать налогом сборщик мусора. Улучшение заключается в добавлении кэша глобальных переменных, который можно использовать повторно. Недостатком является то, что теперь он не является потокобезопасным.
На этом оптимизация с помощью инструмента pprof завершается. Конечный результат очень хорош, в основном достигается та же скорость и тот же размер выделения памяти, что и в C++.
Вдохновение, которое мы можем получить, состоит в том, чтобы сначала использовать профиль процессора, чтобы найти наиболее трудоемкие функции и оптимизировать их. Если вы обнаружите, что gc выполняет много, найдите код, который выделяет больше всего памяти, и функцию, которая вызывает выделение памяти, и оптимизируйте ее.
Оригинальный текст отличный, и хотя он был написан давно (изначально написан в 2011 году), его все же стоит посмотреть. Кроме того, реальная боевая статья из справочного материала [wolfogre] также очень интересна, и используемые движения аналогичны этой статье, но вы можете запустить пример программы, представленный в статье, чтобы шаг за шагом решить проблему с производительностью, очень интересный!
Найдите утечки памяти
Выделение памяти может происходить либо в куче, либо в стеке. Память, выделенная в куче, требует сборки мусора или ручной сборки (для языков без сборки мусора, таких как C++), память в стеке обычно освобождается автоматически после выхода из функции.
Язык Go использует escape-анализ для размещения в стеке как можно большего количества объектов, чтобы программа могла работать быстрее.
Здесь, чтобы объяснить, есть две стратегии анализа памяти: одна - это текущая (на этот раз получение) память или выделение объекта, называемоеinuse
; другой — это все выделения памяти с момента запуска программы, независимо от того, была ли это сборка мусора или нет, вызываемаяalloc
.
As mentioned above, there are two main memory analysis strategies with pprof. One is around looking at the current allocations (bytes or object count), called inuse. The other is looking at all the allocated bytes or object count throughout the run-time of the program, called alloc. This means regardless if it was gc-ed, a summation of everything sampled.
плюс-sample_index
После параметра можно переключить тип анализа памяти:
go tool pprof -sample_index=alloc_space http://47.93.238.9:8080/debug/pprof/heap
Есть 4 типа:
тип | значение |
---|---|
inuse_space | amount of memory allocated and not released yet |
inuse_objects | amount of objects allocated and not released yet |
alloc_space | total amount of memory allocated (regardless of released) |
alloc_objects | total amount of objects allocated (regardless of released) |
В справочном материале [Dabin Actual Memory Leakage] описывается, как найти дополнительные горутины в два момента до и после с помощью метода, аналогичного diff, а затем найти причину утечки горутины и не использовать напрямую профиль кучи или горутины. файлы. Также рекомендуется к прочтению!
Суммировать
pprof
Это мощный инструмент для анализа производительности программ Go, который создает файлы профилей путем выборки и сбора данных, связанных с производительностью запущенных программ Go. После этого предоставляются три различные формы представления, чтобы мы могли более интуитивно видеть соответствующие данные о производительности.
После получения данных о производительности вы можете использоватьtop
,web
,list
Подождите, пока команда быстро найдет соответствующий код и оптимизирует его.
«Преждевременная оптимизация — корень всех зол». В реальной работе мало кто обращает внимание на производительность, но когда программа, которую вы пишете, имеет узкие места в производительности, и qps не может подняться во время стресс-теста qa, чтобы продемонстрировать техническую силу, вам все равно нужно наблюдать узкие места в производительности через pprof, и выполнять соответствующую оптимизацию производительности.
использованная литература
[Процесс оптимизации Расса Кокса с прикрепленным кодом]blog.golang.org/profiling-a…
【гугл ппроф】GitHub.com/Google/BubbleRO…
[Отладка приложений golang с помощью графиков pprof и flame]secondchildstudent.com/2017/09/11/…
【Сбор ресурсов】Добавь V и ты готов.ru/blog/2017/0…
【Профилирование вашего приложения Golang за 3 шага】coder.today/специальности/2018-1…
[Кейс, стресс-тест, удаленное профилирование Golang и пламенные графы]МА на ski.com/article/ Иди сюда…
【Жареная рыба ппроф】сегмент fault.com/ah/119000001…
【Птичье гнездо ппроф】коло not.com/2017/03/02/…
[7 методов профилирования для Go]blog.horn99.org/post/go wave…
[pprof более полный]nuggets.capable/post/684490…
[Объясните процесс анализа и оптимизации на примерах]арт эм. Гостей все меньше и меньше. V.com/blog/2017/0…
[Переход от Дмитрия Вьюкова]GitHub.com/gowaves/go/me…
[Очень замечательная практическая статья Вольфогре]blog.wolf ogre.com/posts/go-brand…
【Дэйв Чейни】Dave.Cheney.net/high-per для…
【Реальный случай】блог woo woo woo.cn on.com/loss может быть 303/afraid…
[Настоящая утечка памяти Дабина]сегмент fault.com/ah/119000001…
【Найти утечку памяти】Woohoo.бесплатный код camp.org/news/how-i-…
【Оптимизация производительности Thor 3】Imperial Capital coder.com/so попробуйте-о…