Go
性能优化
-
CPU profile
:报告程序CPU
使用情况,按照一定频率去采集应用程序CPU
和寄存器上面的数据 -
Memory Profile (Heap Profile)
:报告内存使用情况 -
Block Profiling
:报告goroutines
不在运行状况情况下,可以用来分析和查找死锁等性能瓶颈 -
Goroutine Profiling
:报告goroutine
的使用情况,有哪些goroutine
它们调用关系是怎样的
package main
import (
"flag"
"fmt"
"os"
"runtime/pprof"
"time"
)
// 一段有问题的代码
func logicCode() {
var c chan int
for {
select {
case v := <- c:
fmt.Printf("recv from chan, value:%v", v)
default:
time.Sleep(time.Second) // 耗费CPU的时候注释这行
}
}
}
func main() {
var isCPUPprof bool
var isMemPprof bool
flag.BoolVar(&isCPUPprof, "cpu", false, "turn cpu pprof on")
flag.BoolVar(&isMemPprof, "mem", false, "turn mem pprof on")
flag.Parse()
if isCPUPprof {
file, err := os.Create("./cpu.pprof") // 在当前文件夹下创建一个文件
if err != nil {
fmt.Printf("creat cpu pprof failed, err : %v", err)
return
}
_ = pprof.StartCPUProfile(file)
defer pprof.StopCPUProfile()
}
for i:=0; i < 8; i++ {
go logicCode()
}
time.Sleep(6 * time.Second)
if isMemPprof {
file, err := os.Create("./mem.pprof")
if err != nil {
fmt.Printf("create mem pprof failed, err : %v", err)
return
}
_ = pprof.WriteHeapProfile(file)
file.Close()
}
}
编译:
andrew@andrew-G3-3590:~/go/src/basic/pprof_demo$ go build pprofile_demo.go
andrew@andrew-G3-3590:~/go/src/basic/pprof_demo$ ./pprofile_demo -cpu=true
andrew@andrew-G3-3590:~/go/src/basic/pprof_demo$ go tool pprof cpu.pprof
File: pprofile_demo
Type: cpu
Time: Dec 21, 2020 at 11:08pm (CST)
Duration: 20.17s, Total samples = 58.35s (289.35%)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) top 5
Showing nodes accounting for 58.25s, 99.83% of 58.35s total
Dropped 14 nodes (cum <= 0.29s)
flat flat% sum% cum cum%
27.16s 46.55% 46.55% 46.38s 79.49% runtime.selectnbrecv
19.22s 32.94% 79.49% 19.22s 32.94% runtime.chanrecv
11.87s 20.34% 99.83% 58.25s 99.83% main.logicCode
(pprof) quit
-
flat
当前函数占用CPU
的耗时 -
flat%
当前函数占用CPU
的耗时百分比 -
sum%
函数占用CPU
耗时累计百分比 -
cum
当前函数加上调用当前函数的函数占用CPU
的总耗时 -
cum%
当前函数加上调用当前函数的函数占用CPU
的总耗时百分比 - 最后一列:函数名称
使用命令查看,具体哪个函数浪费了比较多的时间
andrew@andrew-G3-3590:~/go/src/basic/pprof_demo$ go build pprofile_demo.go
andrew@andrew-G3-3590:~/go/src/basic/pprof_demo$ ./pprofile_demo -cpu=true
andrew@andrew-G3-3590:~/go/src/basic/pprof_demo$ go tool pprof cpu.pprof
File: pprofile_demo
Type: cpu
Time: Dec 21, 2020 at 11:23pm (CST)
Duration: 6.15s, Total samples = 17.10s (277.95%)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) top 3
Showing nodes accounting for 17.10s, 100% of 17.10s total
flat flat% sum% cum cum%
7.79s 45.56% 45.56% 13.18s 77.08% runtime.selectnbrecv
5.39s 31.52% 77.08% 5.39s 31.52% runtime.chanrecv
3.92s 22.92% 100% 17.10s 100% main.logicCode
(pprof) list logicCode
Total: 17.10s
ROUTINE ======================== main.logicCode in /home/andrew/go/src/basic/pprof_demo/pprofile_demo.go
3.92s 17.10s (flat, cum) 100% of Total
. . 11:// 一段有问题的代码
. . 12:func logicCode() {
. . 13: var c chan int
. . 14: for {
. . 15: select {
3.92s 17.10s 16: case v := <- c:
. . 17: fmt.Printf("recv from chan, value:%v", v)
. . 18: default:
. . 19: //time.Sleep(time.Second)
. . 20:
. . 21: }
(pprof) web # 如果装的有graphviz工具,这里会在浏览器打开一个svg图片如下:
使用go绘制火焰图
讲到这里就不得不说下,使用go
绘制火焰图分析代码性能:
- 第一步安装
pprof
go get github.com/google/pprof
要是遇到提示没有权限,参考: go get提示没有 权限解决
直接使用pprof
分析:
pprof -http=:8080 cpu.prof
执行之后会在浏览器中打开,并显示对程序的分析图
- 安装
FlameGraph
git clone https://github.com/brendangregg/FlameGraph.git
export PATH=$PATH:home/FlameGraph #换成自己的路径
- 安装
graphviz
sudo apt-get install graphviz
- 安装
go-torch
go get github.com/uber/go-torch
go-torch 工具的使用非常简单,没有任何参数的话,它会尝试从 http://localhost:8080/debug/pprof/profile 获取 profiling 数据。它有三个常用的参数可以调整:
-u --url:要访问的 URL,这里只是主机和端口部分
-s --suffix:pprof profile 的路径,默认为 /debug/pprof/profile
-t --seconds:要执行 profiling 的时间长度,默认为 30s
火焰图的调用顺序从下到上,每个方块代表一个函数,它上面一层表示这个函数会调用哪些函数,方块的大小代表了占用 CPU 使用的长短,火焰图的配色并没有特殊的意义。