【go语言开发】性能分析工具pprof使用
本文主要介绍如何在项目中使用pprof工具。首先简要介绍pprof工具的作用;然后介绍pprof的应用场景,主要分为工具型应用和服务型应用。最后数据分析项目,先采集项目信息,再可视化查看
欢迎大家访问个人博客网址:https://www.maogeshuo.com,博主努力更新中…
前言
pprof是Go语言的一个性能分析库,它的名字源于**“Profile”(简称"prof")**一词。该工具最早由Google开发并用于Go语言的性能分析,它可以帮助开发者找出程序中的性能瓶颈。pprof提供了CPU分析、内存分析、阻塞分析等多种性能分析功能。
- CPU分析:
- pprof可以通过采样应用程序的运行状态来分析CPU的使用情况,找出哪些函数占用了大量的CPU时间。
- 提供CPU使用率最高的函数列表和调用关系,帮助定位程序的CPU性能瓶颈。
- 内存分析:
- 支持对应用程序的内存分配和使用情况进行分析,帮助开发人员发现内存泄漏、高内存消耗的函数等问题。
- 提供内存使用最多的函数列表和调用关系,帮助优化内存管理和减少不必要的内存分配。
- 阻塞分析:
- pprof可以分析应用程序中的阻塞情况,识别并发执行过程中可能存在的阻塞问题。
- 提供阻塞最严重的代码段和调用关系,帮助优化并发执行的性能和减少阻塞时间。
- goroutine分析:
- 支持对应用程序中goroutine的跟踪和分析,帮助理解并发执行情况。
- 提供goroutine的数量、状态和调用关系等信息,帮助优化并发编程和避免goroutine泄漏。
- 堆分析:
- pprof可以生成堆内存分配和释放的时间序列图,帮助开发人员了解程序在运行过程中的内存分配情况。
- 提供堆内存使用的趋势和波动情况,帮助优化内存管理和减少内存占用。
除了这些功能外,pprof还提供了对运行时调用图的可视化展示。pprof可以很容易地集成到任何Go程序中,只需在程序中导入net/http/pprof包,并启动一个HTTP服务器,就可以通过Web界面查看性能数据。
应用场景
pprof工具的应用场景主要分为两种:
- 服务型应用:web服务性能分析
- 工具型应用:输入命令行应用等
工具型应用
如果你想在不使用HTTP服务的情况下对应用程序进行性能分析,可以直接使用 runtime/pprof 包中提供的函数来生成性能分析数据。
package main
import (
"log"
"os"
"runtime"
"runtime/pprof"
"time"
)
func main() {
Analysis()
}
func Analysis() {
// 创建 CPU 分析文件
cpuProfile, err := os.Create("./profile/cpu.prof")
if err != nil {
log.Fatal(err)
}
defer cpuProfile.Close()
// 开始 CPU 分析
if err := pprof.StartCPUProfile(cpuProfile); err != nil {
log.Fatal(err)
}
defer pprof.StopCPUProfile()
// 模拟一些 CPU 密集型工作
for i := 0; i < 1000000; i++ {
_ = i * i
}
// 创建内存分析文件
memProfile, err := os.Create("./profile/mem.prof")
if err != nil {
log.Fatal(err)
}
defer memProfile.Close()
// 强制进行垃圾回收,以便获取准确的内存分析数据
runtime.GC()
// 开始内存分析
if err := pprof.WriteHeapProfile(memProfile); err != nil {
log.Fatal(err)
}
// 模拟一些内存使用
data := make([]byte, 1024*1024)
_ = data
time.Sleep(time.Second) // 等待一段时间以便生成分析数据
log.Println("完成性能分析")
}
服务型应用
我们这里使用gin框架,结合https://github.com/gin-contrib/pprof
package main
import (
webpprof "github.com/gin-contrib/pprof"
"github.com/gin-gonic/gin"
"log"
"net/http"
"os"
"runtime"
"runtime/pprof"
"time"
)
const Port = ":10000"
func main() {
WebAnalysis()
}
func WebAnalysis() {
g := gin.Default()
g.GET("/test", func(c *gin.Context) {
c.JSON(http.StatusOK, "测试成功")
})
webpprof.Register(g) // 注入HandlerFuncs
g.Run(Port)
}
启动后日志打印如下:
查看github.com/gin-contrib/pprof
代码,发现gin.Engine
将net/http/pprof
的函数封装成标准的HandlerFuncs
,也就是将func(w http.ResponseWriter, r *http.Request)格式函数转换为gin.HandlerFunc
package pprof
import (
"net/http/pprof"
"github.com/gin-gonic/gin"
)
const (
// DefaultPrefix url prefix of pprof
DefaultPrefix = "/debug/pprof"
)
func getPrefix(prefixOptions ...string) string {
prefix := DefaultPrefix
if len(prefixOptions) > 0 {
prefix = prefixOptions[0]
}
return prefix
}
// Register the standard HandlerFuncs from the net/http/pprof package with
// the provided gin.Engine. prefixOptions is a optional. If not prefixOptions,
// the default path prefix is used, otherwise first prefixOptions will be path prefix.
func Register(r *gin.Engine, prefixOptions ...string) {
RouteRegister(&(r.RouterGroup), prefixOptions...)
}
// RouteRegister the standard HandlerFuncs from the net/http/pprof package with
// the provided gin.GrouterGroup. prefixOptions is a optional. If not prefixOptions,
// the default path prefix is used, otherwise first prefixOptions will be path prefix.
func RouteRegister(rg *gin.RouterGroup, prefixOptions ...string) {
prefix := getPrefix(prefixOptions...)
prefixRouter := rg.Group(prefix)
{
prefixRouter.GET("/", gin.WrapF(pprof.Index))
prefixRouter.GET("/cmdline", gin.WrapF(pprof.Cmdline))
prefixRouter.GET("/profile", gin.WrapF(pprof.Profile))
prefixRouter.POST("/symbol", gin.WrapF(pprof.Symbol))
prefixRouter.GET("/symbol", gin.WrapF(pprof.Symbol))
prefixRouter.GET("/trace", gin.WrapF(pprof.Trace))
prefixRouter.GET("/allocs", gin.WrapH(pprof.Handler("allocs")))
prefixRouter.GET("/block", gin.WrapH(pprof.Handler("block")))
prefixRouter.GET("/goroutine", gin.WrapH(pprof.Handler("goroutine")))
prefixRouter.GET("/heap", gin.WrapH(pprof.Handler("heap")))
prefixRouter.GET("/mutex", gin.WrapH(pprof.Handler("mutex")))
prefixRouter.GET("/threadcreate", gin.WrapH(pprof.Handler("threadcreate")))
}
}
实际上net/http/pprof
库中已初始化的函数有Index等,并在此基础上再wrap了heap、mutex等
// Package pprof serves via its HTTP server runtime profiling data
// in the format expected by the pprof visualization tool.
//
// The package is typically only imported for the side effect of
// registering its HTTP handlers.
// The handled paths all begin with /debug/pprof/.
//
// To use pprof, link this package into your program:
//
// import _ "net/http/pprof"
//
// If your application is not already running an http server, you
// need to start one. Add "net/http" and "log" to your imports and
// the following code to your main function:
//
// go func() {
// log.Println(http.ListenAndServe("localhost:6060", nil))
// }()
//
// By default, all the profiles listed in [runtime/pprof.Profile] are
// available (via [Handler]), in addition to the [Cmdline], [Profile], [Symbol],
// and [Trace] profiles defined in this package.
// If you are not using DefaultServeMux, you will have to register handlers
// with the mux you are using.
//
// # Usage examples
//
// Use the pprof tool to look at the heap profile:
//
// go tool pprof http://localhost:6060/debug/pprof/heap
//
// Or to look at a 30-second CPU profile:
//
// go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
//
// Or to look at the goroutine blocking profile, after calling
// runtime.SetBlockProfileRate in your program:
//
// go tool pprof http://localhost:6060/debug/pprof/block
//
// Or to look at the holders of contended mutexes, after calling
// runtime.SetMutexProfileFraction in your program:
//
// go tool pprof http://localhost:6060/debug/pprof/mutex
//
// The package also exports a handler that serves execution trace data
// for the "go tool trace" command. To collect a 5-second execution trace:
//
// curl -o trace.out http://localhost:6060/debug/pprof/trace?seconds=5
// go tool trace trace.out
//
// To view all available profiles, open http://localhost:6060/debug/pprof/
// in your browser.
//
// For a study of the facility in action, visit
//
// https://blog.golang.org/2011/06/profiling-go-programs.html
package pprof
import (
"bufio"
"bytes"
"context"
"fmt"
"html"
"internal/profile"
"io"
"log"
"net/http"
"net/url"
"os"
"runtime"
"runtime/pprof"
"runtime/trace"
"sort"
"strconv"
"strings"
"time"
)
func init() {
http.HandleFunc("/debug/pprof/", Index)
http.HandleFunc("/debug/pprof/cmdline", Cmdline)
http.HandleFunc("/debug/pprof/profile", Profile)
http.HandleFunc("/debug/pprof/symbol", Symbol)
http.HandleFunc("/debug/pprof/trace", Trace)
}
浏览器输入http://localhost:10000/debug/pprof/
pprof能分析9项信息
数据分析
命令行查看
go tool pprof
usage:
Produce output in the specified format.
pprof <format> [options] [binary] <source> ...
Omit the format to get an interactive shell whose commands can be used
to generate various views of a profile
pprof [options] [binary] <source> ...
Omit the format and provide the "-http" flag to get an interactive web
interface at the specified host:port that can be used to navigate through
various views of a profile.
pprof -http [host]:[port] [options] [binary] <source> ...
Details:
Output formats (select at most one):
-callgrind Outputs a graph in callgrind format
-comments Output all profile comments
-disasm Output assembly listings annotated with samples
-dot Outputs a graph in DOT format
-eog Visualize graph through eog
-evince Visualize graph through evince
-gif Outputs a graph image in GIF format
-gv Visualize graph through gv
-kcachegrind Visualize report in KCachegrind
-list Output annotated source for functions matching regexp
-pdf Outputs a graph in PDF format
-peek Output callers/callees of functions matching regexp
-png Outputs a graph image in PNG format
-proto Outputs the profile in compressed protobuf format
-ps Outputs a graph in PS format
-raw Outputs a text representation of the raw profile
-svg Outputs a graph in SVG format
-tags Outputs all tags in the profile
-text Outputs top entries in text form
-top Outputs top entries in text form
-topproto Outputs top entries in compressed protobuf format
-traces Outputs all profile samples in text form
-tree Outputs a text rendering of call graph
-web Visualize graph through web browser
-weblist Display annotated source in a web browser
Options:
-call_tree Create a context-sensitive call tree
-compact_labels Show minimal headers
-divide_by Ratio to divide all samples before visualization
-drop_negative Ignore negative differences
-edgefraction Hide edges below <f>*total
-focus Restricts to samples going through a node matching regexp
-hide Skips nodes matching regexp
-ignore Skips paths going through any nodes matching regexp
-intel_syntax Show assembly in Intel syntax
-mean Average sample value over first value (count)
-nodecount Max number of nodes to show
-nodefraction Hide nodes below <f>*total
-noinlines Ignore inlines.
-normalize Scales profile based on the base profile.
-output Output filename for file-based outputs
-prune_from Drops any functions below the matched frame.
-relative_percentages Show percentages relative to focused subgraph
-sample_index Sample value to report (0-based index or name)
-show Only show nodes matching regexp
-show_from Drops functions above the highest matched frame.
-source_path Search path for source files
-tagfocus Restricts to samples with tags in range or matched by regexp
-taghide Skip tags matching this regexp
-tagignore Discard samples with tags in range or matched by regexp
-tagleaf Adds pseudo stack frames for labels key/value pairs at the callstack leaf.
-tagroot Adds pseudo stack frames for labels key/value pairs at the callstack root.
-tagshow Only consider tags matching this regexp
-trim Honor nodefraction/edgefraction/nodecount defaults
-trim_path Path to trim from source paths before search
-unit Measurement units to display
Option groups (only set one per group):
granularity
-functions Aggregate at the function level.
-filefunctions Aggregate at the function level.
-files Aggregate at the file level.
-lines Aggregate at the source code line level.
-addresses Aggregate at the address level.
sort
-cum Sort entries based on cumulative weight
-flat Sort entries based on own weight
Source options:
-seconds Duration for time-based profile collection
-timeout Timeout in seconds for profile collection
-buildid Override build id for main binary
-add_comment Free-form annotation to add to the profile
Displayed on some reports or with pprof -comments
-diff_base source Source of base profile for comparison
-base source Source of base profile for profile subtraction
profile.pb.gz Profile in compressed protobuf format
legacy_profile Profile in legacy pprof format
http://host/profile URL for profile handler to retrieve
-symbolize= Controls source of symbol information
none Do not attempt symbolization
local Examine only local binaries
fastlocal Only get function names from local binaries
remote Do not examine local binaries
force Force re-symbolization
Binary Local path or build id of binary for symbolization
-tls_cert TLS client certificate file for fetching profile and symbols
-tls_key TLS private key file for fetching profile and symbols
-tls_ca TLS CA certs file for fetching profile and symbols
Misc options:
-http Provide web interface at host:port.
Host is optional and 'localhost' by default.
Port is optional and a randomly available port by default.
-no_browser Skip opening a browser for the interactive web UI.
-tools Search path for object tools
Legacy convenience options:
-inuse_space Same as -sample_index=inuse_space
-inuse_objects Same as -sample_index=inuse_objects
-alloc_space Same as -sample_index=alloc_space
-alloc_objects Same as -sample_index=alloc_objects
-total_delay Same as -sample_index=delay
-contentions Same as -sample_index=contentions
-mean_delay Same as -mean -sample_index=delay
Environment Variables:
PPROF_TMPDIR Location for saved profiles (default $HOME/pprof)
PPROF_TOOLS Search path for object-level tools
PPROF_BINARY_PATH Search path for local binary files
default: $HOME/pprof/binaries
searches $buildid/$name, $buildid/*, $path/$buildid,
${buildid:0:2}/${buildid:2}.debug, $name, $path
* On Windows, %USERPROFILE% is used instead of $HOME
no profile source specified
采集数据
可以将每项数据统一采集下来,再具体分析
go tool pprof http://localhost:10000/debug/pprof/allocs
go tool pprof http://localhost:10000/debug/pprof/block
go tool pprof http://localhost:10000/debug/pprof/cmdline
go tool pprof http://localhost:10000/debug/pprof/heap
go tool pprof http://localhost:10000/debug/pprof/mutex
go tool pprof http://localhost:10000/debug/pprof/profile
go tool pprof http://localhost:10000/debug/pprof/threadcreate
go tool pprof http://localhost:10000/debug/pprof/trace
终端中运行以下命令,性能分析allocs数据:
在进入 pprof 命令行界面后,你可以输入不同的命令来查看不同类型的分析数据,比如 top 查看 CPU 使用最多的函数,list 查看某个函数的详细信息,web 可以在浏览器中打开交互式图形界面等。
查看数据
查看数据,可以选择web形式,可视化效果直观,打开收集好的pb.gz
文件
UI显示依赖graphviz
库 ,mac安装使用命令为:brew install graphviz
go tool pprof -http:127.0.0.1:port pb.gz路径 //参考截图使用
浏览器输入http://127.0.0.1:8082/ui/,UI上查看各项信息
top
查看CPU/内存占有率最高的接口