性能分析

Go程序的性能分析整体可以分为两步:

  1. 生成性能数据文件
  2. 对性能数据文件进行分析

生成性能数据文件

性能数据文件的生成有三种方式。

通过命令行生成性能数据文件

可以在go test进行性能测试的时候生成性能数据文件,因为我们关注cpu和内存数据,所以我们添加参数来生成这两者的数据文件。
例如

$ go test -bench=".*" -cpuprofile cpu.profile -memprofile mem.profile

执行上述命令会生成3个文件:

  • v1.test:测试生成的二进制文件,在性能分析的时候解析各种符号。
  • cpu.profile:cpu性能数据文件
  • mem.profile:内存性能数据文件

通过代码来生成性能数据文件

利用runtime/pprof包,编写代码生成性能数据文件。


package main

import (
  "os"
  "runtime/pprof"
)

func main() {
  // 生成cpu性能数据文件
  cpuOut, _ := os.Create("cpu.out")
  defer cpuOut.Close()
  pprof.StartCPUProfile(cpuOut)
  defer pprof.StopCPUProfile()
  
  // 生成内存性能数据文件
  memOut, _ := os.Create("mem.out")
  defer memOut.Close()
  defer pprof.WriteHeapProfile(memOut)

  Sum(3, 5)
}

func Sum(a, b int) int {
  return a + b
}

运行之后就会在当前目录生成cpu.profile和mem.profile数据文件。

通过net/http/pprof生成性能数据文件

对于http server,如何使用的是net/http包的默认ServerMux,那么直接匿名导入包即可。

import _ "net/http/pprof"

因为在包下存在init函数注册了对应的handler

func init() {
	http.HandleFunc("/debug/pprof/", Index)
	http.HandleFunc("/debug/pprof/cmdline", Cmdline)
	http.HandleFunc("/debug/pprof/profile", Profile)
	http.HandleFunc("/debug/pprof/symbol", Symbol)
	http.HandleFunc("/debug/pprof/trace", Trace)
}

如果使用的不是默认的ServerMux,或者使用的不是官方的net/http包的话,只需要按照上面init函数的形式,将这几个handler进行封装注册路由即可。
然后启动http服务,访问对应的路由即可收集到数据。

执行

$ curl http://127.0.0.1:8080/debug/pprof/profile -o cpu.profile

访问/debug/pprof/profile路由,pprof就会采集这30s内的cpu性能数据,生成cpu.profile数据文件。

同样的,生成内存性能数据文件可以执行下面的命令

$ curl http://127.0.0.1:8080/debug/pprof/heap -o mem.profile

具体的ip和端口根据实际启动的服务为准。

性能分析

在进行性能分析时,我们可以采取不同的手段来分析性能,比如分析采样图、分析火焰图,还可以使用go tool pprof交互模式来查看函数CPU和内存消耗数据。

cpu性能分析

默认情况下,Go语言的运行时会以100Hz(每秒100次,每10ms一次)的频率对CPU使用情况进行采样。每次采样,会记录正在运行的函数,并统计其运行时间,从而生成CPU性能数据。

分析采样图

首先,确保系统安装了graphviz

$ sudo yum -y install graphviz.x86_64

然后,执行go tool pprof生成调用图,可以生成不同格式的图片

$ go tool pprof -svg cpu.profile > cpu.svg  # svg 格式
$ go tool pprof -pdf cpu.profile > cpu.pdf # pdf 格式
$ go tool pprof -png cpu.profile > cpu.png # png 格式

图片中的有向线段标识调用关系,由没有箭头的一端调用有箭头的一端。而线段上的数字就是采样周期内调用这个函数的耗时。

矩形方框内则包含如下数据

  • 函数名/方法名。包括包名、结构体名、函数名/方法名,方便快速定位到函数/方法。
  • 本地采样时间,以及在采样总数中所占比例。本地采样时间时指采样点落在该函数中的总时间。
  • 累积采样时间,以及在采样总数中所占比例。累积采样时间是指采样点落在该函数,以及被它直接或者间接调用的函数中的总时间。

累积采样时间越长,矩形就越大,但是这并不意味着这个函数本身有问题,可能是其调用的函数存在问题。不过本地采样时间很大,那么就是这个函数本身有问题了。

无论如果,大矩形都是值得我们关注的地方。

分析火焰图

火焰图可以更加直观地让我们观察到性能瓶颈。
go tool pprof提供的-http参数,可以使我们通过浏览器浏览采样图和火焰图,执行如下命令

$ go tool pprof -http="0.0.0.0:8081" v1.test cpu.profile

就可以访问命令中的地址在浏览器中查看数据了。

ui界面提供了不同的采样数据视图,火焰图选择Flame Graph。火焰图有如下特征:

  • 每一列代表一个调用栈,每个格式代表一个函数。
  • 纵轴展示了栈的深度,调用关系按照从上到下排列。最下面的格子代表采样时,正在占用CPU的函数。
  • 调用栈在横向会按照字母排序,并且相同的调用栈会合并,所以一个格子的宽度越大,说明这个函数越可能时瓶颈

查看火焰图时,重点关注的就是横向越宽的格子。

用go tool pprof交互模式查看数据

执行如下命令可以进行交互模式来查看性能数据

$ go tool pprof v1.test cpu.profile
File: v1.test
Type: cpu
Time: Aug 17, 2021 at 2:17pm (CST)
Duration: 56.48s, Total samples = 440ms ( 0.78%)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof)

可以数据指令来查看想要的数据,不过这里就进行过多的介绍了,还是更加推荐火焰图的方式,要更加直观一些。

内存性能分析

内存性能分析与cpu性能分析的方法比较类似,将前面的cpu性能文件替换为内存数据文件即可。

posted @   三尺山  阅读(59)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示