pprof性能分析

pprof 性能分析

benchmark(基准测试) 可以度量某个函数或方法的性能,也就是说,如果我们知道性能的瓶颈点在哪里,benchmark 是一个非常好的方式。但是面对一个未知的程序,如何去分析这个程序的性能,并找到瓶颈点呢?

pprof 就是用来解决这个问题的。pprof 包含两部分:

  • 编译到程序中的 runtime/pprof
  • 性能剖析工具 go tool pprof

windows本地查看腾讯云云服务器上的pprof测试结果,只需远程安装:

1
sudo yum install graphviz

一、CPU性能分析

启动 CPU 分析时,运行时(runtime) 将每隔 10ms 中断一次(为什么是10ms呢?后面会提到),记录此时正在运行的协程(goroutines) 的堆栈信息。启动 CPU 分析时,运行时(runtime) 将每隔 10ms 中断一次,记录此时正在运行的协程(goroutines) 的堆栈信息。程序运行结束后,可以分析记录的数据找到最热代码路径(hottest code paths)。

编译器热路径是编译器中的代码执行路径,大部分执行时间都花在了这些路径上,并且可能会非常频繁地执行这些路径。

一个函数在性能分析过程中出现的次数越多,说明执行该函数的代码路径(code path)花费的时间占总运行时间的比重越大。

具体实现方式

在main函数之前添加这两句,可以将性能数据输出到cpu.pprof

1
2
3
4
f, _ := os.OpenFile("cpu.pprof", os.O_CREATE|os.O_RDWR, 0644)
defer f.Close()
pprof.StartCPUProfile(f) //源码中提到:当频率大于500Hz,可能会影响本身的效率,而经过测试,最适合的频率是100Hz,不会影响且会提供有价值的数据。
defer pprof.StopCPUProfile()

对数据及进行分析:

1
$ go tool pprof -http=127.0.0.1:6060 cpu.pprof

之后会自动打开浏览器,如下,可以通过不同的方式查看结果:

image-20220731201857858

也可以直接通过命令行来分析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
[root@VM-16-2-centos pprof-test]# go tool pprof cpu.pprof
File: main
Type: cpu
Time: Jul 31, 2022 at 3:58pm (CST)
Duration: 17.34s, Total samples = 17.25s (99.46%)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) top
Showing nodes accounting for 17.18s, 99.59% of 17.25s total
Dropped 17 nodes (cum <= 0.09s)
flat flat% sum% cum cum%
17.18s 99.59% 99.59% 17.21s 99.77% main.bubbleSort (inline)
0 0% 99.59% 17.22s 99.83% main.main
0 0% 99.59% 17.22s 99.83% runtime.main
(pprof) top -cum
Showing nodes accounting for 17.18s, 99.59% of 17.25s total
Dropped 17 nodes (cum <= 0.09s)
flat flat% sum% cum cum%
0 0% 0% 17.22s 99.83% main.main
0 0% 0% 17.22s 99.83% runtime.main
17.18s 99.59% 99.59% 17.21s 99.77% main.bubbleSort (inline)
(pprof) help
Commands:
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
o/options List options and their current values
q/quit/exit/^D Exit pprof

二、内存分析

内存性能分析(Memory profiling) 记录堆内存分配时的堆栈信息,忽略栈内存分配信息。

内存性能分析启用时,默认每1000次采样1次,这个比例是可以调整的。因为内存性能分析是基于采样的,因此基于内存分析数据来判断程序所有的内存使用情况是很困难的。

具体实现方式

需要导入"github.com/pkg/profile"然后在main函数之前添加:

1
defer profile.Start(profile.MemProfile, profile.MemProfileRate(1)).Stop()

对数据及进行分析:

1
go tool pprof -http=127.0.0.1:6060 /tmp/profile2738765321/mem.pprof

image-20220731204427226

三、针对web程序

针对一直运行的后台服务,比如 web 应用或者分布式应用,我们可以使用 net/http/pprof 库,它能够在应用提供 HTTP 服务时进行分析。

pprof 采集后台服务,如果使用了默认的 http.DefaultServeMux,通常是代码直接使用http.ListenAndServe(“0.0.0.0:8000”, nil),这种情况则比较简单,只需要导入包即可。

1
2
3
import (
_ "net/http/pprof"
)

注意该包利用下划线"_"导入,意味着我们只需要该包运行其init()函数即可,如此该包将自动完成信息采集并保存在内存中。

如果你使用自定义的 ServerMux复用器,则需要手动注册一些路由规则:

1
2
3
4
5
6
r.HandleFunc("/debug/pprof/", pprof.Index)
r.HandleFunc("/debug/pprof/heap", 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)

这些路径分别表示:

  • /debug/pprof/profile:访问这个链接会自动进行 CPU profiling,持续 30s,并生成一个文件供下载,可以通过带参数?=seconds=60进行60秒的数据采集。
  • /debug/pprof/block:Goroutine阻塞事件的记录。默认每发生一次阻塞事件时取样一次。
  • /debug/pprof/goroutines:活跃Goroutine的信息的记录。仅在获取时取样一次。
  • /debug/pprof/heap: 堆内存分配情况的记录。默认每分配512K字节时取样一次。
  • /debug/pprof/mutex: 查看争用互斥锁的持有者。
  • /debug/pprof/threadcreate: 系统线程创建情况的记录。 仅在获取时取样一次。

在Gin框架中使用pprof

可以导入包go get github.com/gin-contrib/pprof,之后就可以看到一些新的接口生成:

image-20220731222053015

profile文件保存在/root/pprof/pprof.api.samples.cpu.001.pb.gz,之后直接使用上述的分析方式即可在windows界面打开:

1
2
[root@VM-16-2-centos api]# go tool pprof -http=127.0.0.1:6060 /root/pprof/pprof.api.samples.cpu.001.pb.gz
Serving web UI on http://127.0.0.1:6060

关于火焰图的基本理解方法:

image-20220731222622729

参考资料

[1] https://geektutu.com/post/hpg-pprof.html

[2] https://bbs.huaweicloud.com/blogs/289818

[3] https://bytedancecampus1.feishu.cn/docs/doccn4F3nKRdd9Uq7RGl6JPPFWg#

[4] http://liumurong.org/2019/12/gin_pprof/


pprof性能分析
https://wuhlan3.gitee.io/2022/07/31/pprof性能分析/
Author
Wuhlan3
Posted on
July 31, 2022
Licensed under