通常常规内容:html
golang 程序中:linux
上面是在 golang 程序中,性能调优的一些内容。git
好比 linux 中 cpu 性能调试,工具备 top,dstat,perf 等。github
那么在 golang 中,有哪些分析方法?golang
golang 性能调试优化方法:web
profiling 和 trace 有啥区别?
profiling 分析没有时间线,trace 分析有时间线。浏览器
在 golang 中,应用方法的工具呢?性能优化
这里介绍 pprof 这个 golang 工具,它能够帮助咱们调试优化程序。app
它的最原始程序是 gperftools - https://github.com/gperftools/gperftools,golang 的 pprof 是从它而来的。svg
pprof 是 golang 官方提供的性能调优分析工具,能够对程序进行性能分析,并可视化数据,看起来至关的直观。
当你的 go 程序遇到性能瓶颈时,可使用这个工具来进行调试并优化程序。
本文将对下面 golang 中 2 个监控性能的包 pprof 进行运用:
runtime/pprof:采集程序运行数据进行性能分析,通常用于后台工具型应用,这种应用运行一段时间就结束。
net/http/pprof:对 runtime/pprof 的二次封装,通常是服务型应用。好比 web server ,它一直运行。这个包对提供的 http 服务进行数据采集分析。
上面的 pprof 开启后,每隔一段时间就会采集当前程序的堆栈信息,获取函数的 cpu、内存等使用状况。经过对采样的数据进行分析,造成一个数据分析报告。
pprof 以 profile.proto 的格式保存数据,而后根据这个数据能够生成可视化的分析报告,支持文本形式和图形形式报告。
profile.proto 里具体的数据格式是 protocol buffers。
那用什么方法来对数据进行分析,从而造成文本或图形报告?
用一个命令行工具 go tool pprof
。
Report generation:报告生成
Interactive terminal use:交互式终端
Web interface:Web 界面
调试分析 golang 程序,要开启 profile 而后开始采样数据。
而后安装:go get github.com/google/pprof
,后面分析会用到。
采样数据的方式:
// 开启 cpu 采集分析: pprof.StartCPUProfile(w io.Writer) // 中止 cpu 采集分析: pprof.StopCPUProfile()
WriteHeapProfile 把内存 heap 相关的内容写入到文件中
pprof.WriteHeapProfile(w io.Writer)
go test -cpuprofile cpu.prof -memprofile mem.prof -bench .
go tool pprof $host/debug/pprof/profile
go version go1.13.9
咱们用第 1 种方法,在程序中添加分析代码,demo.go :
package main import ( "bytes" "flag" "log" "math/rand" "os" "runtime" "runtime/pprof" "sync" ) var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`") var memprofile = flag.String("memprofile", "", "write mem profile to `file`") func main() { flag.Parse() if *cpuprofile != "" { f, err := os.Create(*cpuprofile) if err != nil { log.Fatal("could not create CPU profile: ", err) } defer f.Close() if err := pprof.StartCPUProfile(f); err != nil { log.Fatal("could not start CPU profile: ", err) } defer pprof.StopCPUProfile() } var wg sync.WaitGroup wg.Add(200) for i := 0; i < 200; i++ { go cyclenum(30000, &wg) } writeBytes() wg.Wait() if *memprofile != "" { f, err := os.Create(*memprofile) if err != nil { log.Fatal("could not create memory profile: ", err) } defer f.Close() runtime.GC() if err := pprof.WriteHeapProfile(f); err != nil { log.Fatal("cound not write memory profile: ", err) } } } func cyclenum(num int, wg *sync.WaitGroup) { slice := make([]int, 0) for i := 0; i < num; i++ { for j := 0; j < num; j++ { j = i + j slice = append(slice, j) } } wg.Done() } func writeBytes() *bytes.Buffer { var buff bytes.Buffer for i := 0; i < 30000; i++ { buff.Write([]byte{'0' + byte(rand.Intn(10))}) } return &buff }
编译程序、采集数据、分析程序:
go build demo.go
./demo.exe --cpuprofile=democpu.pprof --memprofile=demomem.pprof
说明:我是 win 系统,这个 demo 就是 demo.exe ,linux 下是 demo
go tool pprof democpu.pprof
go tool pprof 简单的使用格式为:go tool pprof [binary] [source]
要了解 go tool pprof 更多命令使用方法,请查看文档:
go tool pprof --help
注意:
获取的 Profiling 数据是动态获取的,若是想要获取有效的数据,须要保证应用或服务处于较大的负载中,好比正在运行工做中的服务,或者经过其余工具模拟访问压力。
不然若是应用处于空闲状态,好比 http 服务处于空闲状态,获得的结果可能没有任何意义。
(后面会遇到这种问题,http 的 web 服务处于空闲状态,采集显示的数据为空)
分析数据,基本的模式有 2 种:
go tool pprof democpu.pprof
字段 | 说明 |
---|---|
Type: | 分析类型,这里是 cpu |
Duration: | 程序执行的时长 |
Duration 下面还有一行提示,这是交互模式(经过输入 help 获取帮助信息,输入 o 获取选项信息)。
能够看出,go 的 pprof 操做还有不少其余命令。
Commands 下有不少命令信息,text ,top 2个命令解释相同,输入这个 2 个看看:
top 命令:对函数的 cpu 耗时和百分比排序后输出
top后面还能够带参数,好比: top15
输出了相同的信息。
字段 | 说明 |
---|---|
flat | 当前函数占用 cpu 耗时 |
flat % | 当前函数占用 cpu 耗时百分比 |
sum% | 函数占用 cpu 时间累积占比,从小到大一直累积到 100% |
cum | 当前函数加上调用当前函数的函数占用 cpu 的总耗时 |
%cum | 当前函数加上调用当前函数的函数占用 cpu 的总耗时占比 |
从字段数据咱们能够看出哪个函数比较耗费时间,就能够对这个函数进一步分析。
分析用到的命令是 list
。
list 命令:能够列出函数最耗时的代码部分,格式:list 函数名
从上面采样数据能够分析出总耗时最长的函数是 main.cycylenum
,用 list cyclenum
命令进行分析,以下图:
发现最耗时的代码是 62 行:slice = append(slice, j)
,这里耗时有 1.47s ,能够对这个地方进行优化。
这里耗时的缘由,应该是 slice 的实时扩容引发的。那咱们空间换时间,固定 slice 的容量,make([]int, num * num)
在命令行直接输出数据,基本命令格式为:
go tool pprof <format> [options] [binary] <source>
输入命令:go tool pprof -text democpu.pprof
,输出:
除了上面的命令行交互分析,还能够用图形化来分析程序性能。
图形化分析前,先要安装 graphviz 软件,
下载对应的平台安装包,安装完成后,把执行文件 bin 放入 Path 环境变量中,而后在终端输入 dot -version
命令查看是否安装成功。
生成可视化文件:
有 2 个步骤,根据上面采集的数据文件 democpu.pprof 来进行可视化:
在命令行里输入 web 命令,就能够生成一个 svg 格式的文件,用浏览器打开便可查看 svg 文件。
执行上面 2 个命令以下图:
用浏览器查看生成的 svg 图:
(文件太大,只截取了一小部分图,完整的图请自行生成查看)
关于图形的一点说明:
运行命令:go tool pprof -http=:8080 democpu.pprof
$ go tool pprof -http=:8080 democpu.pprof Serving web UI on http://localhost:8080
命令运行完成后,会自动在浏览器上打开地址: http://localhost:8080/ui/
,咱们能够在浏览器上查看分析数据:
这张图就是上面用 web 命令生成的图。
若是你在 web 浏览时没有这么多菜单可供选择,那么请安装原生的 pprof 工具:
go get -u github.com/google/pprof
,而后在启动go tool pprof -http=:8080 democpu.pprof
,就会出来菜单。
还能够查看火焰图, http 地址:http://localhost:8080/ui/flamegraph,可直接点击 VIEW 菜单下的 Flame Graph 选项查看火焰图。固然还有其余选项可供选择,好比 Top,Graph 等等选项。你能够根据须要选择。
其实上面的 web 可视化已经包含了火焰图,把火焰图集成到了 pprof 里。但为了向性能优化专家 Bredan Gregg 致敬,仍是来体会一下火焰图生成过程。
火焰图 (Flame Graph) 是性能优化专家 Bredan Gregg 建立的一种性能分析图。Flame Graphs visualize profiled code。
火焰图形状以下:
(来自:https://github.com/brendangregg/FlameGraph)
上面用 pprof 生成的采样数据,要把它转换成火焰图,就要使用一个转换工具 go-torch,这个工具是 uber 开源,它是用 go 语言编写的,能够直接读取 pprof 采集的数据,并生成一张火焰图, svg 格式的文件。
go get -v github.com/uber/go-torch
生成火焰图的程序 FlameGraph 是用 perl 写的,因此先要安装执行 perl 语言的环境。
perl -h
,输出了帮助信息,则说明安装成功进入到 FlameGraph 安装目录,执行命令,./flamegraph.pl --help
输出信息说明安装成功
从新进入到文件 democpu.pprof 的目录,而后执行命令:
go-torch -b democpu.pprof
上面命令默认生成名为 torch.svg 的文件,用浏览器打开查看:
自定义输出文件名,后面加 -f
参数:
go-torch -b democpu.pprof -f cpu_flamegraph.svg
火焰图说明:
火焰图 svg 文件,你能够点击上面的每一个方块来查看分析它上面的内容。
火焰图的调用顺序从下到上,每一个方块表明一个函数,它上面一层表示这个函数会调用哪些函数,方块的大小表明了占用 CPU 使用时长长短。
go-torch 的命令格式:
go-torch [options] [binary] <profile source>
go-torch 帮助文档:
想了解更多 go-torch 用法,请用 help 命令查看帮助文档,
go-torch --help
。或查看 go-torch README 文档 。