功能:
CPU分析\内存分析\阻塞分析\互斥锁分析
pprof 采样数据主要有三种获取方式:
- runtime/pprof: 手动调用runtime.StartCPUProfile或者runtime.StopCPUProfile等 API来生成和写入采样文件,灵活性高.用于代码运行一段时间就结束.
- net/http/pprof: 通过 http 服务获取Profile采样文件,简单易用,适用于对应用程序的整体监控。用于代码持续运行的情形
- go test: 通过 go test -bench . -cpuprofile prof.cpu生成采样文件.适用对测试函数进行针对性测试
一、runtime/pprof
引入 import “runtime/pprof”,在代码中添加:
CPU采样
f, err := os.Create("cpu_profile.prof")
if err != nil {
panic(err.Error())
}
defer f.Close()
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
内存采样
f, err := os.Create("mem_profile.mprof")
if err != nil {
panic(err.Error())
}
defer f.Close()
pprof.WriteHeapProfile(f) //这一句放在程序结束时
分析
go tool pprof binary [source]
binary 是应用的二进制文件,用来解析各种符号;source 表示 profile 数据的来源,可以是本地的文件,也可以是 http 地址(在net/http/pprof模式下)。
例如
go tool pprof cpu_profile
注意: 1.程序运行时间太短,可能采样不到 2.先运行代码生成cpu_profile 3.耗时太短的代码可能不会显示
终端交互: (Total samples为0,即为采样失败)
D:\gopath\src\code>go tool pprof cpu_profile
Type: cpu
Time: Jun 6, 2020 at 11:13pm (CST)
Duration: 1.01s, Total samples = 2.76s (274.56%)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof)
top 指令
list n (列表个数,默认10)
(pprof) top
Showing nodes accounting for 2080ms, 75.36% of 2760ms total
Dropped 16 nodes (cum <= 13.80ms)
Showing top 10 nodes out of 71
flat flat% sum% cum cum%
810ms 29.35% 29.35% 810ms 29.35% runtime.procyield
390ms 14.13% 43.48% 1110ms 40.22% sync.(*Mutex).lockSlow
160ms 5.80% 49.28% 1270ms 46.01% sync.(*Mutex).Lock
150ms 5.43% 54.71% 510ms 18.48% sync.(*Mutex).Unlock
130ms 4.71% 59.42% 130ms 4.71% runtime.(*guintptr).cas
120ms 4.35% 63.77% 120ms 4.35% runtime.stdcall2
100ms 3.62% 67.39% 2160ms 78.26% main.(*list).Init_sync.func1
80ms 2.90% 70.29% 2010ms 72.83% math/rand.(*Rand).Int31n
70ms 2.54% 72.83% 100ms 3.62% main.(*list).Find_sync.func1
70ms 2.54% 75.36% 1930ms 69.93% math/rand.(*lockedSource).Int63
- flat: 函数的运行时间. 采样时,该函数正在运行的次数*采样频率(10ms),即得到估算的函数运行”采样时间”。这里不包括函数等待子函数返回。
- flat%: flat / 总采样时间值
- sum%: 前面所有行的 flat% 的累加值,如第二行 sum% = 43.48% = 29.35% + 14.45%
- cum: 采样时,该函数出现在调用堆栈的采样时间,包括函数等待子函数返回。因此 flat <= cum
- cum%: cum / 总采样时间值
list指令
list 待匹配的函数
(pprof) list Init
Total: 2.76s
ROUTINE ======================== main.(*list).Init_sync.func1 in D:\gopath\src\code\main.go
100ms 2.16s (flat, cum) 78.26% of Total
. . 56: for i := 0; i < workNum; i++ {
. . 57: go func(index int) {
. . 58: defer group.Done()
. . 59: startIndex := listLen / workNum * index
. . 60: endIndex := listLen / workNum * ( index + 1 )
20ms 20ms 61: for j:= startIndex; j < endIndex; j++ {
80ms 2.14s 62: (*l)[j] = rand.Intn(10000)
. . 63: }
. . 64: }(i)
. . 65: }
. . 66: group.Wait()
. . 67:}
web
打开调用图谱
二、go test
go test 命令有两个参数和 pprof 相关,它们分别指定生成的 CPU 和 Memory profiling 保存的文件:
- cpuprofile:cpu profiling 数据要保存的文件地址
- memprofile:memory profiling 数据要报文的文件地址
比如下面执行测试的同时,也会执行 CPU profiling,并把结果保存在 cpu.prof 文件中:
$ go test -bench . -cpuprofile=cpu.prof
执行结束之后,就会生成 main.test 和 cpu.prof 文件。要想使用 go tool pprof,需要指定的二进制文件就是 main.test。
需要注意的是,Profiling 一般和性能测试一起使用,这个原因在前文也提到过,只有应用在负载高的情况下 Profiling 才有意义。
三、net/http/pprof
引入import _ “net/http/pprof” 并加入 http.ListenAndServe(“localhost:6060”, nil) 到代码中.
gin使用pprof
引入 “github.com/gin-contrib/pprof” 添加 pprof.Register(r) // 性能
网页交互:
go tool pprof -http=:8090 http://localhost:6060/debug/pprof/profile?seconds=30
终端交互:
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
profile可调换参数:
- goroutine: 获取程序当前所有 goroutine 的堆栈信息。
- heap: 包含每个 goroutine 分配大小,分配堆栈等。每分配 runtime.MemProfileRate(默认为512K) 个字节进行一次数据采样。
- threadcreate: 获取导致创建 OS 线程的 goroutine 堆栈
- block: 获取导致阻塞的 goroutine 堆栈(如 channel, mutex 等),使用前需要先调用
runtime.SetBlockProfileRate - mutex: 获取导致 mutex 争用的 goroutine 堆栈,使用前需要先调用 runtime.SetMutexProfileFraction
- cmdline: 获取程序的命令行启动参数
- profile: 获取指定时间内(从请求时开始)的cpuprof,倒计时结束后自动返回。参数: seconds, 默认值为30。cpuprofile 每秒钟采样100次,收集当前运行的 goroutine 堆栈信息。
- symbol: 用于将地址列表转换为函数名列表,地址通过’+’分隔,如 URL/debug/pprof?0x18d067f+0x17933e7
- trace: 对应用程序进行执行追踪,参数: seconds, 默认值1s
graphviz安装
https://graphviz.org/_pages/Download/Download_windows.html
graphviz安装目录下的bin文件夹添加到Path环境变量中
http://www.cppcns.com/jiqiao/fuwuqi/273835.html
参考
https://blog.golang.org/pprof(英文)
https://github.com/hyper0x/go_command_tutorial/blob/master/0.12.md
https://lrita.github.io/2017/05/26/golang-memory-pprof/
https://segmentfault.com/a/1190000016412013
https://juejin.im/entry/5ac9cf3a518825556534c76e(CPU 分析\内存分析\阻塞分析\互斥锁分析)
https://wudaijun.com/2018/04/go-pprof/