[go学习笔记]四十五、性能分析工具

270 阅读1分钟

示例代码请访问:github.com/wenjianzhan…

准备工作

  • 安装 graphviz
    • brew install graphviz
  • GOPATH/bin 加入PATH
    • Mac OS:在 .bash_profile 中修改路径
  • 安装 go-torch
    • go get github.com/uber/go-torch
    • 下载并复制 flamegraph.pl (github.com/brendangreg…) 至 $GOPATH/bin 路径下
    • GOPATH/bin 加入PATH

通过文件方式输出Profile

  • 灵活性高,属用语特定代码段的分析
  • 通过手动调用 runtime/pprof 的API
  • API 相关文档 studygolang.com/static/pkgd…
  • go tool pprof [binary] [binary.prof]

flamegraph.pl 下载下来 是需要给他是这一下执行权限

 chmod +x flamegraph.pl    

示例代码 prof.go

package main

import (
	"log"
	"math/rand"
	"os"
	"runtime/pprof"
	"time"
)

const (
	col = 10000
	row = 10000
)

func fillMatrix(m *[row][col]int) {
	s := rand.New(rand.NewSource(time.Now().UnixNano()))

	for i := 0; i < row; i++ {
		for j := 0; j < col; j++ {
			m[i][j] = s.Intn(100000)
		}
	}
}

func calculate(m *[row][col]int) {
	for i := 0; i < row; i++ {
		tmp := 0
		for j := 0; j < col; j++ {
			tmp += m[i][j]
		}
	}
}

func main() {
	//创建输出文件
	f, err := os.Create("cpu.prof")
	if err != nil {
		log.Fatal("could not create CPU profile: ", err)
	}

	// 获取系统信息
	if err := pprof.StartCPUProfile(f); err != nil { //监控cpu
		log.Fatal("could not start CPU profile: ", err)
	}
	defer pprof.StopCPUProfile()

	// 主逻辑区,进行一些简单的代码运算
	x := [row][col]int{}
	fillMatrix(&x)
	calculate(&x)

	f1, err := os.Create("mem.prof")
	if err != nil {
		log.Fatal("could not create memory profile: ", err)
	}
	//runtime.GC()                                       // GC,获取最新的数据信息
	if err := pprof.WriteHeapProfile(f1); err != nil { // 写入内存信息
		log.Fatal("could not write memory profile: ", err)
	}
	f1.Close()

	f2, err := os.Create("goroutine.prof")
	if err != nil {
		log.Fatal("could not create groutine profile: ", err)
	}

	if gProf := pprof.Lookup("goroutine"); gProf == nil {
		log.Fatal("could not write groutine profile: ")
	} else {
		gProf.WriteTo(f2, 0)
	}
	f2.Close()

}

调试

// 第一步、编译项目
$ go build prof.go

ls
// 第二步、启动程序
$ ./prof

// 再次编译程序
$ go build prof.go

// 查看目录文件
$ ls          
cpu.prof       mem.prof       prof.go        goroutine.prof prof           

// 执行 go tool pprof 命令
$ go tool pprof prof cpu.prof  

// 可以看到下面这样的一个交互式的控制台
File: prof
Type: cpu
Time: Nov 16, 2019 at 12:23am (CST)
Duration: 1.66s, Total samples = 1.37s (82.53%)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) 

// 可以使用 top 命令,看到top cpu 的情况
// cum 表示总体加和的时间

(pprof) top
Showing nodes accounting for 1.37s, 100% of 1.37s total
      flat  flat%   sum%        cum   cum%
     1.29s 94.16% 94.16%      1.32s 96.35%  main.fillMatrix
     0.05s  3.65% 97.81%      0.05s  3.65%  main.calculate
     0.02s  1.46% 99.27%      0.02s  1.46%  math/rand.(*Rand).Int31n
     0.01s  0.73%   100%      0.03s  2.19%  math/rand.(*Rand).Intn
         0     0%   100%      1.37s   100%  main.main
         0     0%   100%      1.37s   100%  runtime.main
(pprof) 

// 上述输出 可以体现出来 fillMatrix 耗时还是挺长的,我们可以使用list命令进行详细分析
// list 命令可以根据输入新的的名字进行最大匹配,不一定输入全部

(pprof) list fill  
Total: 1.37s
ROUTINE ======================== main.fillMatrix in /Users/zhangwenjian/Code/golearning/src/ch44/tools/file/prof.go
     1.29s      1.32s (flat, cum) 96.35% of Total
         .          .     16:func fillMatrix(m *[row][col]int) {
         .          .     17:   s := rand.New(rand.NewSource(time.Now().UnixNano()))
         .          .     18:
         .          .     19:   for i := 0; i < row; i++ {
         .          .     20:           for j := 0; j < col; j++ {
     1.29s      1.32s     21:                   m[i][j] = s.Intn(100000)
         .          .     22:           }
         .          .     23:   }
         .          .     24:}
         .          .     25:
         .          .     26:func calculate(m *[row][col]int) {
(pprof) 

// 输出结果可以看出 所有的耗时都在 m[i][j] = s.Intn(100000)

// 也可以通过图形化的方式进行查看
// 可以通过 svg 命令 来生成 svg 图
(pprof) svg
Generating report in profile001.svg
(pprof)

// 使用浏览器打开之后也可以查看;

cpu

示例代码请访问:github.com/wenjianzhan…