var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`") var memprofile = flag.String("memprofile", "", "write mem profile to `file`")
funcmain() { flag.Parse()
if *cpuprofile != "" { f, err := os.Create(*cpuprofile) if err != nil { log.Fatal("could not create CPU profile: ", err) } defer f.Close() // error handling omitted for example if err := pprof.StartCPUProfile(f); err != nil { log.Fatal("could not start CPU profile: ", err) } defer pprof.StopCPUProfile() }
// ... rest of the program ... 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() // error handling omitted for example runtime.GC() // get up-to-date statistics if err := pprof.WriteHeapProfile(f); err != nil { log.Fatal("could not write memory profile: ", err) } } } funccyclenum(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() } funcwriteBytes() *bytes.Buffer { var buff bytes.Buffer for i := 0; i < 30000; i++ { buff.Write([]byte{'0' + byte(rand.Intn(10))}) } return &buff }
1 2 3 4
go build test.go ./test.exe --cpuprofile=cpu.pprof --memprofile=mem.pprof
go tool pprof cpu.pprof
程序退出时会生成两个profile,一个是cpu.pprof的,一个是mem.pprof。
go tool pprof 简单的使用格式为: go tool pprof [binary] [source]
# -run=none 只进行基准测试 go test -v -run=none -bench=. -blockprofile block.out -cpuprofile cpu.out -memprofile mem.out -mutexprofile mutex.out -trace trace.out
分析
1 2 3 4 5 6
go tool pprof block.out go tool pprof cpu.out go tool pprof mem.out go tool pprof mutex
go tool trace trace.out
分析数据
命令行交互分析
1 2
go tool pprof cpu.pprof go tool pprof test.exe cpu.pprof
1 2 3 4 5 6
$ go tool pprof cpu.pprof Type: cpu Time: Jun 11, 2022 at 8:07pm (CST) Duration: 515.79ms, Total samples = 1.47s (285.00%) Entering interactive mode (type "help" for commands, "o" for options) (pprof)
Type: 分析类型,这里是 cpu
Duration: 程序执行的时长
Duration 下面还有一行提示,这是交互模式(通过输入 help 获取帮助信息,输入 o 获取选项信息)。
(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
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. 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 : Clear focus/ignore/hide/tagfocus/tagignore
type "help <cmd|option>" for more information
常用命令
top
top 默认查看程序中占用cpu前10位的函数。 top 3 可以查看程序中占用CPU前三位的函数。
在命令行里输入 web 命令,就可以生成一个 svg 格式的文件,用浏览器打开即可查看 svg 文件。
每个框代表一个函数,理论上框越大表示占用的 cpu 资源越多
每个框之间的线条代表函数之间的调用关系,线条上的数字表示函数调用的次数
每个框中第一行数字表示当前函数占用 cpu 的百分比,第二行数字表示当前函数累计占用 cpu 的百分比
1 2 3 4 5 6
$ go tool pprof cpu.pprof Type: cpu Time: Jun 11, 2022 at 8:07pm (CST) Duration: 515.79ms, Total samples = 1.47s (285.00%) Entering interactive mode (type "help" for commands, "o" for options) (pprof) web
生成pdf
1 2 3 4 5 6
$ go tool pprof cpu.pprof Type: cpu Time: Jun 11, 2022 at 8:07pm (CST) Duration: 515.79ms, Total samples = 1.47s (285.00%) Entering interactive mode (type "help" for commands, "o" for options) (pprof) pdf
火焰图每个方块代表一个函数,它下面一层表示这个函数会调用哪些函数,方块的大小代表了占用 CPU 使用的长短。 火焰图的配色并没有特殊的意义,默认的红、黄配色是为了更像火焰而已。
测试覆盖率
语句的覆盖率是指在测试中至少被运行一次的代码占总代码数的比例。 go test -run=Converage 标志参数通过在测试代码中插入生成钩子来统计覆盖率数据。在运行每个测试前,它将待测代码拷贝一份并做修改,在每个词法块都会设置一个布尔标志变量。当被修改后的被测试代码运行退出时,将统计日志数据写入c.out文件,并打印一部分执行的语句的一个总结。
1 2 3 4
# 用-coverprofile标志参数,生成覆盖率文件c.out go test -run=Coverage -coverprofile=cover.out # 测试覆盖率工具,打印了测试日志,生成一个HTML报告 go tool cover -html=cover.out