golang-使用pprof进行性能分析

pprof是golang自带的性能分析工具,在程序运行过程中,可以记录程序的运行信息,像CPU使用情况、内存使用情况、协程的情况等等。
pprof主要有两种使用方式:

  1. 通过文件方式输出Profile
  2. 通过http方式输出Profile

通过文件方式输出profile

下面给出一个简单的示例程序(例子摘自网上):

package main

import (
	"log"
	"math/rand"
	"os"
	"runtime/pprof"
	"time"
)
                
const (
	row = 1000
	col = 1000
)

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 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 {
		log.Fatal("could not start cpu profile: ", err)
	}

	defer pprof.StopCPUProfile()
	
	//待分析代码
	x := [row][col]int{}
	fillMatrix(&x)

	f1, err := os.Create("mem.prof")
	if err != nil {
		log.Fatal("could not create memory profile: ", err)
	}
	
	//获取堆内存占用情况
	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 goroutine profile: ", err)
	}
	if gProf := pprof.Lookup("goroutine"); gProf == nil {
		log.Fatal("could not write goroutine profile")
	} else {
		gProf.WriteTo(f2, 0)
	}
	f2.Close()

}

文件名:pprof_try.go
在文件所在目录下执行:go build pprof_try.go
目录下会出现pprof_try可执行文件:./pprof_try
此时就会生成三个相应的prof文件:cpu.prof、mem.prof、goroutine.prof
这里以cpu.prof文件为例:
执行go tool pprof pprof_try cpu.prof,会进入交互模式:

Type: cpu
Time: Jul 25, 2020 at 12:07am (CST)
Duration: 206.15ms, Total samples = 10ms ( 4.85%)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) 

交互模式有很多可使用的命令(可以使用help查看简介),比较常用的是top、list、traces三个

top

Type: cpu
Time: Jul 25, 2020 at 12:07am (CST)
Duration: 206.15ms, Total samples = 10ms ( 4.85%)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) top
Showing nodes accounting for 10ms, 100% of 10ms total
      flat  flat%   sum%        cum   cum%
      10ms   100%   100%       10ms   100%  main.fillMatrix
         0     0%   100%       10ms   100%  main.main
         0     0%   100%       10ms   100%  runtime.main
(pprof) 

top命令展示函数的5个数据:

  1. flat: 函数执行时间
  2. flat%: 函数执行时间与总时间的百分比
  3. sum%: 前面每一行flat%的和
  4. cum: 累计量,加入函数调用了其它函数,其它函数的执行时间也会被记入
  5. cum%: 累计量占总量的百分比
    因此,可以看出,测试程序主要是fillMatrix函数占用了cpu时间。

list

list可以具体查看某个函数的每行代码以及每行代码的相应指标,函数名支持模糊匹配:

Type: cpu
Time: Jul 25, 2020 at 12:07am (CST)
Duration: 206.15ms, Total samples = 10ms ( 4.85%)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) top
Showing nodes accounting for 10ms, 100% of 10ms total
      flat  flat%   sum%        cum   cum%
      10ms   100%   100%       10ms   100%  main.fillMatrix
         0     0%   100%       10ms   100%  main.main
         0     0%   100%       10ms   100%  runtime.main
(pprof) list fillMatrix
Total: 10ms
ROUTINE ======================== main.fillMatrix in /Users/lcj/go_pro/src/aboutGo/pproftest/pprof_try.go
      10ms       10ms (flat, cum)   100% of Total
         .          .     23:
         .          .     24:func fillMatrix(m *[row][col]int) {
         .          .     25:   s := rand.New(rand.NewSource(time.Now().UnixNano()))
         .          .     26:
         .          .     27:   for i := 0; i < row; i++ {
      10ms       10ms     28:           for j := 0; j < col; j++ {
         .          .     29:                   m[i][j] = s.Intn(100000)
         .          .     30:           }
         .          .     31:   }
         .          .     32:}
         .          .     33:
(pprof) 

traces

traces命令可以打印所有调用栈和相应的指标信息:

File: pprof_try
Type: cpu
Time: Jul 25, 2020 at 12:07am (CST)
Duration: 206.15ms, Total samples = 10ms ( 4.85%)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) traces
File: pprof_try
Type: cpu
Time: Jul 25, 2020 at 12:07am (CST)
Duration: 206.15ms, Total samples = 10ms ( 4.85%)
-----------+-------------------------------------------------------
      10ms   main.fillMatrix
             main.main
             runtime.main
-----------+-------------------------------------------------------
(pprof) 

还有svg指令,可以将调用过程生成一个svg图,可以在浏览器进行直观查看。
如果安装了go-torch,还可以使用go-torch cpu.prof生成火炬图进行查看。

通过http方式输出Profile

分析服务器上运行的程序性能,需要使用这种方式。
在程序中导入以下包,并启动http server即可。

improt _ "net/http/pprof"

实例代码(示例摘自网上):

package main

import (
	"fmt"
	"log"
	"net/http"
	_ "net/http/pprof"
)

func GetFbSeries(n int) []int {
	res := make([]int, 2, n)
	res[0] = 1
	res[1] = 1
	for i := 2; i < n; i++ {
		res = append(res, res[i-1]+res[i-2])
	}
	return res
}

func createFBS(w http.ResponseWriter, r *http.Request) {
	var fbs []int
	for i := 0; i < 1000000; i++ {
		fbs = GetFbSeries(50)
	}
	w.Write([]byte(fmt.Sprintf("%v", fbs)))
}

func main() {
	http.HandleFunc("/fb", createFBS)
	log.Fatal(http.ListenAndServe(":8080", nil))
}

可以直接通过网页查看:
http://{host:port}/debug/pprof/

也可以在本地通过命令行查看:
go tool pprof http://{host:port}/debug/pprof/profile?seconds=10
seconds参数表述表示采样时间,默认是30s
url中的profile表示cpu,其它类目可以通过上述网页看到

如果安装了go-torch命令,可以使用以下命令生成火炬图:
go-torch -seconds 10 http://{host:port}/debug/pprof/profile
url中的profile表示cpu,其它类目可以通过上述网页看到

附:

进行内存状况分析时,有以下两个参数可以使用:

  1. -inuse_space:正在使用的内存(一般用于http查看方式)
  2. -alloc_space:已经分配的内存

**如:**go tool pprof -inuse_space http://{host:port}/debug/pprof/profile

你可能感兴趣的:(golang)