NOTE

4.2 pprof

1. pprof是什么 Golang的性能分析工具。 2. 如何使用pprof 有两个库: runtime/pprof :采集工具型应用运行数据进行分析 net/http/pprof :采集web应用运行时数据进行分析 benchmark :压测 2.1. runtime/pprof 2.1.1.

Go创建于 更新于 historical

这是历史学习笔记,可能存在过时或不完整的理解。

1. pprof是什么

Golang的性能分析工具。

2. 如何使用pprof

有两个库: runtime/pprof:采集工具型应用运行数据进行分析 net/http/pprof:采集web应用运行时数据进行分析 benchmark:压测

2.1. runtime/pprof

2.1.1. CPU分析

假设应用如下:

import (
	"fmt"
	"time"
)

// 一段有问题的代码
func logicCode() {
	var c chan int
	for {
		select {
		case v := <-c:
			fmt.Printf("recv from chan, value:%v\n", v)
		default:
		}
	}
}

func main() {
	for i := 0; i < 8; i++ {
		go logicCode()
	}
	time.Sleep(20 * time.Second)
}

如果要开启CPU分析,那么步骤如下:

  1. 导入包import "runtime/pprof"
  2. 开启CPU性能分析:pprof.StartCPUProfile(w io.Writer)+停止CPU性能分析:pprof.StopCPUProfile() 代码如下
import (
	"fmt"
	"os"
	"runtime/pprof"
	"time"
)

// 一段有问题的代码
func logicCode() {
	var c chan int
	for {
		select {
		case v := <-c:
			fmt.Printf("recv from chan, value:%v\n", v)
		default:
		}
	}
}

func main() {
	//开启CPU分析
	file, err := os.Create("./cpu.pprof")
	if err != nil {
		fmt.Printf("create cpu pprof failed, err:%v\n", err)
		return
	}
	pprof.StartCPUProfile(file)
	defer pprof.StopCPUProfile()

	for i := 0; i < 8; i++ {
		go logicCode()
	}
	time.Sleep(20 * time.Second)
}
  1. 运行代码生成报告
  2. 命令行分析
    • go tool pprof cpu.pprof
    • 几个比较重要的命令:
      • top:找出我们写的代码中占用CPU高的函数
          • flat:当前函数占用CPU的耗时。举例来说,runtime.selectnbrecv这个函数的耗时占用了56.08s,不包括调用子函数
          • flat%::当前函数占用CPU的耗时百分比。举例来说,runtime.selectnbrecv这个函数的耗时占用了CPU48.75%的时间,不包括调用子函数
          • sum%:该函数及以上函数占用CPU的耗时累计百分比,即flat%的累加。举例来说,mainlogicCode及以上的函数占用了48.75+34.60+16.06=99.41%的时间
          • cum:当前函数加上当前函数调用的函数占用CPU的总耗时。举例来说,runtime.selectnbrecv这个函数的耗时占用了96.02s,包括调用子函数。可以使用top -cum按照cum排序
          • cum%:当前函数加上调用当前函数的函数占用CPU的总耗时百分比。举例来说,runtime.selectnbrecv这个函数的耗时占用了CPU83.47%的时间,包括调用子函数
          • 最后一列:函数名称
      • list函数名:查看源代码
      • web:图形化方式查看报告(需要安装graphviz)
          • Edge:调用
            • 代表A调用B,其中虚线表示省略了中间一些不重要的函数调用
            • 连线上的值表示该子函数耗时
          • Node:函数
            • CPU占用时间越多那么图形越大越红
            • main.logicCode函数本身占用了18.47s,占比16.06%,该函数以及子函数占用了114.49s,占比99.52%
  3. 浏览器分析
    • go tool pprof -http=:9090 cpu.pprof
    • 其中的火焰图.md(关联笔记尚未公开)特别有用
  4. 修改代码
func logicCode() {
	var c chan int
	for {
		select {
		case v := <-c:
			fmt.Printf("recv from chan, value:%v\n", v)
		default:
			time.Sleep(time.Second)
		}
	}
}
  1. 重新运行分析
    • 可以看出没有我们写的代码占用高的情况了

2.1.2. 内存分析

步骤如下

  1. 导入包:import "runtime/pprof"
  2. 记录程序的堆栈信息:pprof.WriteHeapProfile(w io.Writer) 代码如下:
port (
	"fmt"
	"os"
	"runtime/pprof"
	"time"
)

func main() {
	//开启内存分析
	file, err := os.Create("./memory.pprof")
	if err != nil {
		fmt.Printf("create cpu pprof failed, err:%v\n", err)
		return
	}
	pprof.WriteHeapProfile(file)

	for i := 0; i < 8; i++ {
		go logicCode()
	}
	time.Sleep(20 * time.Second)
}
  1. 运行代码生成报告
  2. 命令行分析
    • go tool pprof -inuse_space memory.pprof
    • go tool pprof -inuse_objects memory.pprof

Golang内存泄露.md

2.1.3. 阻塞分析

In the Go programming language, what happens when a goroutine blocks? - Quora

2.2. net/http/pprof

假设Web应用如下:

func main() {
	go func() {
		http.ListenAndServe("0.0.0.0:9999", nil)
	}()
}

如果要开启分析,那么步骤如下:

  1. 导入包:import _ "net/http/pprof"
import _ "net/http/pprof"
func main() {
	go func() {
		http.ListenAndServe("0.0.0.0:9999", nil)
	}()
}
  1. 使用浏览器访问http://127.0.0.1:9999/debug/pprof/
    • 点击不同端点查看
      • 内存:allocsheap
      • CPU:profile
      • 线程:threadcreate
      • 协程:goroutine
  2. 除了用浏览器实时查看外,也可以用go tool pprof查看不同端点
go tool pprof http://localhost:9999/debug/pprof/allocs
go tool pprof http://localhost:9999/debug/pprof/heap
go tool pprof http://localhost:9999/debug/pprof/goroutine
go tool pprof http://localhost:9999/debug/pprof/threadcreate
go tool pprof http://localhost:9999/debug/pprof/profile
  1. 也可以保存当时的快照以便以后分析
curl http://localhost:9999/debug/pprof/allocs > allocs.out
curl http://localhost:9999/debug/pprof/heap > heap.out
curl http://localhost:9999/debug/pprof/goroutine > goroutine.out
curl http://localhost:9999/debug/pprof/threadcreate > threadcreate.out
curl http://localhost:9999/debug/pprof/profile > profile.out

然后用go tool pprof分析,同工具型应用

2.3. benchmark

benchmark.md

3. pprof原理

采样:开启之后每隔一段时间(10ms)收集堆栈信息,获取每个函数占用的CPU和内存等资源, 分析:通过对这些采样数据进行分析,形成一个性能分析报告

4. 参考