go tool pprof 性能追踪[推荐]
最后更新于:2022-04-02 02:52:00
[TOC]
> [参考](https://www.jianshu.com/p/927d800021f4)
> [一看就懂系列之Golang的pprof](https://studygolang.com/articles/26918#reply0)
## 概述
性能分析执行时,需要去访问待分析的程序,莱获取分析数据
## 安装
### 1. 安装 graphviz 可视化
```
//安装图形化界面
//win
choco install -y graphviz
//mac
brew install graphviz
//centos
yum install graphviz
```
### 2. 安装 http/pprof
```
import _ "net/http/pprof"
```
demo
```
func main() {
go func() {
log.Println(http.ListenAndServe("0.0.0.0:6060", nil))
}()
//业务代码
}
```
运行程序
`go run main.go`
### 3. 安装 pprof web ui
pprof web ui 已经集成 top, svg, list, disassemble, regex search, go-torch。最方便使用
```
go get github.com/google/pprof
```
## pprof web ui 使用
**启动业务程序后**
### 查看web端报告
`http://127.0.0.1:6060/debug/pprof/`
### 快速生成 web ui
1. 方法一 [推荐]
```
pprof -seconds 60 -http 127.0.0.1:6061 http://127.0.0.1:6060/debug/pprof/profile
```
2. 方法二
```
go tool pprof http://localhost:6060/debug/pprof/profile?second=60
pprof -http 0.0.0.0:7070 binaryfile xxx.pb.gz(profile_file) //profile_file 为上条命令产生的文件,可在命令行中查看到
```
## 名词分析
### 6060/debug/pprof/ 界面
![UTOOLS1584858914381.png](http://yanxuan.nosdn.127.net/d4f4eae7e8cee23246803e5bb641e42a.png)
| 类型 | 描述 |
| --- | --- |
| allocs | **内**存分配情况的采样信息 |
| blocks | **阻塞**操作情况的采样信息 |
| cmdline | 显示程序启动**命令参数**及其参数 |
| goroutine | 显示当前所有**协程**的堆栈信息 |
| heap | **堆**上的内存分配情况的采样信息 |
| mutex | **锁**竞争情况的采样信息 |
| profile | **cpu**占用情况的采样信息,点击会下载文件 |
| threadcreate | 系统**线程**创建情况的采样信息 |
| trace | 程序**运行跟踪**信息 |
### top 指令分析
![UTOOLS1584859007089.png](http://yanxuan.nosdn.127.net/75ee4602782098c9dc083de184c76627.png)
| 类型 | 描述 | 举例 |
| --- | --- | --- |
| flat | 该函数占用CPU的耗时 | selectnbrecv占用CPU的耗时是12.29s |
| flat% | [重点关注]该函数占用CPU的耗时的百分比 | selectnbrecv耗时:12.29s,cpu总耗时:29.14,12.29/29.14=42.18 |
| sum% | top命令中排在它上面的函数以及本函数flat%之和 | chanrecv:42.18%+30.47% = 72.65% |
| cum | 当前函数加上该函数调用之前的累计CPU耗时 | chanrecv:8.88+0.54=9.42 |
| cum% | 当前函数加上该函数调用之前的累计CPU耗时的百分比 | 9.42/29.14=32.33% |
## 问题
> [参考网站](https://studygolang.com/articles/26918#reply0)
### 问题:cpu过高
![UTOOLS1583401091656.png](http://yanxuan.nosdn.127.net/a349c6fc7963341c6dbcb3180610d176.png)
1.`go tool pprof http://localhost:6060/debug/pprof/profile?second=60`
2. 输入 `top`
```
(pprof) top
flat flat% sum% cum cum%
49.75s 83.88% 83.88% 51.29s 86.48% runtime.cgocall
0.88s 1.48% 85.37% 1.04s 1.75% runtime.deferreturn
```
3. 查找 `cgocall` 进行
```
(pprof) list cgocall
Total: 59.31s
ROUTINE ======================== runtime.cgocall in C:\Go\src\runtime\cgocall.go
49.75s 51.29s (flat, cum) 86.48% of Total
. . 102:
. . 103: if raceenabled {
. . 104: racereleasemerge(unsafe.Pointer(&racecgosync))
```
### 问题:内存占用过高
```
> go tool pprof http://localhost:6060/debug/pprof/heap
(pprof) top
(pprof) list cgocall
```
### 频繁垃圾回收
```
> gc 1 @2.104s 0%: 0.018+1.3+0.076 ms clock, 0.054+0.35/1.0/3.0+0.23 ms cpu, 4->4->3 MB, 5 MB goal, 4 P
1 表示第一次执行
@2.104s 表示程序执行的总时间
0% 垃圾回收时间占用的百分比,(不知道和谁比?难道是和上面的程序执行总时间,这样比较感觉没意义)
0.018+1.3+0.076 ms clock 垃圾回收的时间,分别为STW(stop-the-world)清扫的时间, 并发标记和扫描的时间,STW标记的时间
0.054+0.35/1.0/3.0+0.23 ms cpu 垃圾回收占用cpu时间
4->4->3 MB 堆的大小,gc后堆的大小,存活堆的大小
5 MB goal 整体堆的大小
4 P 使用的处理器数量
> scvg0: inuse: 426, idle: 0, sys: 427, released: 0, consumed: 427 (MB)
426 使用多少M内存
0 剩下要清除的内存
427 系统映射的内存
0 释放的系统内存
427 申请的系统内存
```
可以查看切片所占的内存,分析内存占用最大的代码
```
//linux
GODEBUG=gctrace=1 ./xiyouji 2>&1|grep gc
//window
Set GODEBUG=gctrace=1
./xiyouji | findstr gc
> gc 1 @3.503s 0%: 0+0.99+0 ms clock, 0+0.99/0.99/1.9+0 ms cpu, 4->4->1 MB, 5 MB goal, 4 P
> go tool pprof http://localhost:6060/debug/pprof/allocs
(pprof) top
flat flat% sum% cum cum%
688.56kB 54.71% 54.71% 688.56kB 54.71% bigant/servers/login.newTcpClient
570.04kB 45.29% 100% 570.04kB 45.29% bigant/servers/login.newConList
0 0% 100% 688.56kB 54.71% bigant/servers/login.(*App).HandleCient
0 0% 100% 570.04kB 45.29% bigant/servers/login.init
0 0% 100% 570.04kB 45.29% runtime.doInit
0 0% 100% 570.04kB 45.29% runtime.main
(pprof) list newTcpClient
ROUTINE ======================== bigant/servers/login.newTcpClient in D:\go\bignat-go\servers\login\client.go
688.56kB 688.56kB (flat, cum) 54.71% of Total
. . 74: return &tcpClient{
. . 75: app: app,
. . 76: conn: conn,
. . 77: nid: uuid,
. . 78: quit: make(chan struct{}, 1),
688.56kB 688.56kB 79: sendChan: make(chan servers.Trans, 1024),
. . 80: recChan: make([]byte, 2048),
. . 81: }
```
### 协程泄露
![UTOOLS1584863420156.png](http://yanxuan.nosdn.127.net/5b5c1c7bf9b1f6246fa02a330b0ad106.png)
```
> go tool pprof http://localhost:6060/debug/pprof/goroutine
(pprof) top
Showing nodes accounting for 40, 100% of 40 total
Showing top 10 nodes out of 70
flat flat% sum% cum cum%
38 95.00% 95.00% 38 95.00% runtime.gopark
1 2.50% 97.50% 1 2.50% runtime.notetsleepg
1 2.50% 100% 1 2.50% runtime/pprof.writeRuntimeProfile
0 0% 100% 1 2.50% bigant/lib/rpc.NewRpcServer
//无异常,使用web 查看
(pprof) web
```
**提示**
通过多次使用`go tool pprof http://localhost:6060/debug/pprof/goroutine` 和`(pprof) web` 即可在UI中详细看到哪个协程增加了
### 锁的争用
```
> go tool pprof localhost:6060/debug/pprof/mutex
(prof) top
```
错误实例
![UTOOLS1584949438768.png](http://yanxuan.nosdn.127.net/65163aa4dcce7226c768a073b5a0122b.png)
### 阻塞操作
```
> go tool pprof localhost:6060/debug/pprof/block
```
![UTOOLS1584950162893.png](http://yanxuan.nosdn.127.net/86037996f4313ccc390e3fc33c389e61.png)
![UTOOLS1584950169754.png](http://yanxuan.nosdn.127.net/c8149c9982fe904b48699b0601a6d46c.png)
### 问题:访问 6060 显示 404
在入口文件中**手动**指定函数
```
func init() {
http.Handle("/debug/pprof/", http.HandlerFunc(pprof.Index))
http.Handle("/debug/pprof/cmdline", http.HandlerFunc(pprof.Cmdline))
http.Handle("/debug/pprof/profile", http.HandlerFunc(pprof.Profile))
http.Handle("/debug/pprof/symbol", http.HandlerFunc(pprof.Symbol))
http.Handle("/debug/pprof/trace", http.HandlerFunc(pprof.Trace))
}
func main() {
go func() {
log.Info(http.ListenAndServe("0.0.0.0:6060", nil))
}()
app := login.NewApp()
app.Run()
}
```
';