性能分析工具pprof与图形展示go-torch的使用
一 准备
-
安装graphviz
# ubuntu sudo apt install graphviz # centos sudo yum install graphviz
-
将 G O P A T H / b i n 加 入 GOPATH/bin 加入 GOPATH/bin加入PATH下
-
安装go-torch
go get -u github.com/uber-archive/go-torch
下载并复制flamegraph.pl(https://github.com/brendangregg/FlameGraph)至$GOPATH/bin 路径下
二 通过文件方式输出Profile
API 文档:
http://docscn.studygolang.com/pkg/runtime/pprof/
使用 :
go tool pprof [binary] [binary.prof]
example:
func getrangeint() int {
s := rand.New(rand.NewSource(time.Now().UnixNano()))
return s.Intn(22)
}
func fillstr(s string, n int) string {
a := ""
for i := 0; i < n; i++ {
a = a + genstr(s, getrangeint())
}
return a
}
func genstr(s string, n int) string {
a := ""
for i := 0; i < n; i++ {
a = a + s
}
return a
}
func main() {
// cpu 信息
// 创建输出文件
f, err := os.Create("cpu.prof")
defer f.Close()
if err != nil {
log.Fatal("cloud not create cpu.prof file,err=", err)
}
// 获取系统信息
if err = pprof.StartCPUProfile(f); err != nil {
log.Fatal("could not start cpu profile,err=", err)
}
defer pprof.StopCPUProfile()
fmt.Println(len(fillstr("s", 50000)))
// 堆栈信息
f1, err := os.Create("mem.prof")
if err != nil {
log.Fatal("cloud not create mem.prof file,err=", err)
}
defer f1.Close()
if err = pprof.WriteHeapProfile(f1); err != nil {
log.Fatal("could not write memory profile,err=", err)
}
// 协程信息
f2, err := os.Create("goroutine.prof")
defer f2.Close()
if err != nil {
log.Fatal("cloud not create goroutine.prof file,err=", err)
}
if gProf := pprof.Lookup("goroutine"); gProf == nil {
log.Fatal("could not write goroutine profile")
} else {
gProf.WriteTo(f2, 0)
}
}
这个例子主要功能是生成随机个字符,但是由于每次都是 + 链接字符,很耗费内存
生成执行文件并运行,得到文件
go build main.go
ls
cpu.prof goroutine.prof main main.go mem.prof
- 查看cpuinfo
$ go tool pprof main cpu.prof
File: main
Type: cpu
Time: May 20, 2019 at 8:52pm (CST)
Duration: 3s, Total samples = 3.69s (122.84%)
Entering interactive mode (type "help" for commands, "o" for options)
# 查看cpu占用大小前十
(pprof) top
Showing nodes accounting for 3060ms, 82.93% of 3690ms total
Dropped 38 nodes (cum <= 18.45ms)
Showing top 10 nodes out of 112
flat flat% sum% cum cum%
1630ms 44.17% 44.17% 1630ms 44.17% runtime.memmove
460ms 12.47% 56.64% 460ms 12.47% math/rand.seedrand
240ms 6.50% 63.14% 310ms 8.40% runtime.scanobject
200ms 5.42% 68.56% 200ms 5.42% runtime.futex
150ms 4.07% 72.63% 150ms 4.07% runtime.procyield
110ms 2.98% 75.61% 110ms 2.98% runtime.memclrNoHeapPointers
110ms 2.98% 78.59% 160ms 4.34% runtime.scanblock
60ms 1.63% 80.22% 520ms 14.09% math/rand.(*rngSource).Seed
60ms 1.63% 81.84% 80ms 2.17% runtime.findObject
40ms 1.08% 82.93% 140ms 3.79% runtime.gentraceback
# 图形化显示
(pprof) svg
Generating report in profile001.svg
(pprof) exit
可以看到 大步分cpu用来进行字节拷贝,小部分用于生成随机数。
使用打开 profile001.svg
- 或者使用go-toch 生成火炬图
$ go-torch mem.prof
INFO[21:30:07] Run pprof command: go tool pprof -raw -seconds 30 mem.prof
INFO[21:30:07] Writing svg to torch.svg
三 通过HTTP 方式输出profile
- 适合持续性运行的应用
- 在应用中导入 import _ “net/http/pprof”,并启动http server
- http://<host>:<port>/debug/pprof/
- go tool pprof http://<host>:<port>/debug/pprof/profile?seconds=10(默认30s)
- go-torch -seconds 10 http://<host>:<port>/debug/pprof/profile
# example
package main
import (
"encoding/json"
"fmt"
"github.com/luslin/golang-http-funs/parse"
"net/http"
_ "net/http/pprof"
)
var P *parse.RequestParser
func init(){
P = parse.NewRequestParser()
P.AddArgument("did",true,"did error",parse.Json,parse.Post)
P.AddArgument("ssu-uid",true,"ssu-uid error",parse.Str,parse.Header)
}
func main() {
http.HandleFunc("/", IndexHandler)
_ = http.ListenAndServe("127.0.0.1:8001", nil)
}
func IndexHandler(w http.ResponseWriter, r *http.Request) {
var ret []byte
for i:= 0; i<10000;i++{
res , err := P.Parse(r)
if err != nil{
_ ,_ = fmt.Fprintln(w, err.Error())
return
}
ret ,_ = json.Marshal(res)
}
fmt.Println(ret)
_ ,_ = fmt.Fprintln(w, string(ret))
}
运行后打开网址
http://127.0.0.1:8001/debug/pprof/
或者使用命令行工具
$ go tool pprof http://127.0.0.1:8001/debug/pprof/profile?seconds=10