Go语言 CPU 性能、内存分析调试方法大汇总:你要的都在这( 二 )

  • 机器必须闲置
  • 注意省电模式和过热保护 , 如果突然进入这些模式 , 会导致分析数据严重不准确
  • 不要使用虚拟机、共享的云主机 , 太多干扰因素 , 分析数据会很不一致;
  • (如果承受得起 , 购买专用的性能测试分析的硬件设备 , 上架)
    • 关闭电源管理、过热管理;
    • 绝不要升级 , 以保证测试的一致性 , 以及具有可比性 。

    Go语言 CPU 性能、内存分析调试方法大汇总:你要的都在这文章插图
    如果没有这样的环境 , 那就一定要在多个环境中 , 执行多次 , 以取得可参考的、具有相对一致性的测试结果 。
    02
    CPU性能分析
    我们来用下面的代码进行测试 , 代码demo4.gopackage mainimport ("bytes""math/rand""time""log""net/http"_ "net/http/pprof")func test() {log.Println(" ===> loop begin.")for i := 0; i < 1000; i++ {log.Println(genSomeBytes())}log.Println(" ===> loop end.")}//生成一个随机字符串func genSomeBytes() *bytes.Buffer {var buff bytes.Bufferfor i := 1; i < 20000; i++ {buff.Write([]byte{'0' + byte(rand.Intn(10))})}return &buff}func main() {go func() {for {test()time.Sleep(time.Second * 1)}}()//启动pprofhttp.ListenAndServe("0.0.0.0:10000", nil)}这里面还是启动了pprof的监听,有关pprof启动的代码如下
    import ("net/http"_ "net/http/pprof")func main() {//...//...//启动pprofhttp.ListenAndServe("0.0.0.0:10000", nil)}main()里的流程很简单,启动一个goroutine去无限循环调用test()方法,休眠1s.
    test()的流程是生成1000个20000个字符的随机字符串.并且打印.
    我们将上面的代码编译成可执行的二进制文件 demo4(记住这个名字,稍后我们能用到)
    $ go build demo4.go接下来我们启动程序,程序会无限循环的打印字符串.
    接下来我们通过几种方式来查看进程的cpu性能情况.
    Web界面查看
    A
    浏览器访问我们会看到如下画面
    Go语言 CPU 性能、内存分析调试方法大汇总:你要的都在这文章插图
    这里面能够通过pprof查看包括(阻塞信息、cpu信息、内存堆信息、锁信息、goroutine信息等等), 我们这里关心的cpu的性能的profile信息.
    有关profile下面的英文解释大致如下:
    “CPU配置文件 。 您可以在秒GET参数中指定持续时间 。 获取概要文件后 , 请使用go tool pprof命令调查概要文件 。 ”
    所以我们要是想得到cpu性能,就是要获取到当前进程的profile文件,这个文件默认是30s生成一个,所以你的程序要至少运行30s以上(这个参数也可以修改,稍后我们介绍)
    我们可以直接点击网页的profile,浏览器会给我们下载一个profile文件. 记住这个文件的路径, 可以拷贝到与demo4所在的同一文件夹下.
    使用pprof工具查看
    B
    pprof 的格式如下
    go tool pprof [binary] [profile]binary: 必须指向生成这个性能分析数据的那个二进制可执行文件;
    profile: 必须是该二进制可执行文件所生成的性能分析数据文件 。
    binary 和 profile 必须严格匹配 。
    我们来查看一下:
    $ go tool pprof ./demo4 profileFile: demo4Type: cpuTime: Mar 3, 2020 at 11:18pm (CST)Duration: 30.13s, Total samples = 6.27s (20.81%)Entering interactive mode (type "help" for commands, "o" for options)(pprof)help可以查看一些指令,我么可以通过top来查看cpu的性能情况.
    (pprof) topShowing nodes accounting for 5090ms, 81.18% of 6270ms totalDropped 80 nodes (cum <= 31.35ms)Showing top 10 nodes out of 60flatflat%sum%cumcum%1060ms 16.91% 16.91%2170ms 34.61%math/rand.(*lockedSource).Int63850ms 13.56% 30.46%850ms 13.56%sync.(*Mutex).Unlock (inline)710ms 11.32% 41.79%2950ms 47.05%math/rand.(*Rand).Int31n570ms9.09% 50.88%990ms 15.79%bytes.(*Buffer).Write530ms8.45% 59.33%540ms8.61%syscall.Syscall370ms5.90% 65.23%370ms5.90%runtime.procyield270ms4.31% 69.54%4490ms 71.61%main.genSomeBytes250ms3.99% 73.52%3200ms 51.04%math/rand.(*Rand).Intn250ms3.99% 77.51%250ms3.99%runtime.memmove230ms3.67% 81.18%690ms 11.00%runtime.suspendG(pprof)这里面有几列数据,需要说明一下.
    • flat:当前函数占用CPU的耗时
    • flat::当前函数占用CPU的耗时百分比
    • sun%:函数占用CPU的耗时累计百分比
    • cum:当前函数加上调用当前函数的函数占用CPU的总耗时
    • cum%:当前函数加上调用当前函数的函数占用CPU的总耗时百分比
    • 最后一列:函数名称
    通过结果我们可以看出, 该程序的大部分cpu性能消耗在 main.getSoneBytes()方法中,其中math/rand取随机数消耗比较大.
    通过go tool pprof得到profile文件
    C
    我们上面的profile文件是通过web浏览器下载的,这个profile的经过时间是30s的,默认值我们在浏览器上修改不了,如果你想得到时间更长的cpu利用率,可以通过go tool pprof指令与程序交互来获取到