通常常規內容:html
golang 程序中:linux
上面是在 golang 程序中,性能調優的一些內容。git
好比 linux 中 cpu 性能調試,工具備 top,dstat,perf 等。github
那麼在 golang 中,有哪些分析方法?golang
golang 性能調試優化方法:web
profiling 和 trace 有啥區別?
profiling 分析沒有時間線,trace 分析有時間線。瀏覽器
在 golang 中,應用方法的工具呢?性能優化
這裏介紹 pprof 這個 golang 工具,它能夠幫助咱們調試優化程序。app
它的最原始程序是 gperftools - https://github.com/gperftools/gperftools,golang 的 pprof 是從它而來的。svg
pprof 是 golang 官方提供的性能調優分析工具,能夠對程序進行性能分析,並可視化數據,看起來至關的直觀。
當你的 go 程序遇到性能瓶頸時,可使用這個工具來進行調試並優化程序。
本文將對下面 golang 中 2 個監控性能的包 pprof 進行運用:
runtime/pprof:採集程序運行數據進行性能分析,通常用於後臺工具型應用,這種應用運行一段時間就結束。
net/http/pprof:對 runtime/pprof 的二次封裝,通常是服務型應用。好比 web server ,它一直運行。這個包對提供的 http 服務進行數據採集分析。
上面的 pprof 開啓後,每隔一段時間就會採集當前程序的堆棧信息,獲取函數的 cpu、內存等使用狀況。經過對採樣的數據進行分析,造成一個數據分析報告。
pprof 以 profile.proto 的格式保存數據,而後根據這個數據能夠生成可視化的分析報告,支持文本形式和圖形形式報告。
profile.proto 裏具體的數據格式是 protocol buffers。
那用什麼方法來對數據進行分析,從而造成文本或圖形報告?
用一個命令行工具 go tool pprof
。
Report generation:報告生成
Interactive terminal use:交互式終端
Web interface:Web 界面
調試分析 golang 程序,要開啓 profile 而後開始採樣數據。
而後安裝:go get github.com/google/pprof
,後面分析會用到。
採樣數據的方式:
// 開啓 cpu 採集分析: pprof.StartCPUProfile(w io.Writer) // 中止 cpu 採集分析: pprof.StopCPUProfile()
WriteHeapProfile 把內存 heap 相關的內容寫入到文件中
pprof.WriteHeapProfile(w io.Writer)
go test -cpuprofile cpu.prof -memprofile mem.prof -bench .
go tool pprof $host/debug/pprof/profile
go version go1.13.9
咱們用第 1 種方法,在程序中添加分析代碼,demo.go :
package main import ( "bytes" "flag" "log" "math/rand" "os" "runtime" "runtime/pprof" "sync" ) var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`") var memprofile = flag.String("memprofile", "", "write mem profile to `file`") func main() { flag.Parse() if *cpuprofile != "" { f, err := os.Create(*cpuprofile) if err != nil { log.Fatal("could not create CPU profile: ", err) } defer f.Close() if err := pprof.StartCPUProfile(f); err != nil { log.Fatal("could not start CPU profile: ", err) } defer pprof.StopCPUProfile() } var wg sync.WaitGroup wg.Add(200) for i := 0; i < 200; i++ { go cyclenum(30000, &wg) } writeBytes() wg.Wait() if *memprofile != "" { f, err := os.Create(*memprofile) if err != nil { log.Fatal("could not create memory profile: ", err) } defer f.Close() runtime.GC() if err := pprof.WriteHeapProfile(f); err != nil { log.Fatal("cound not write memory profile: ", err) } } } func cyclenum(num int, wg *sync.WaitGroup) { slice := make([]int, 0) for i := 0; i < num; i++ { for j := 0; j < num; j++ { j = i + j slice = append(slice, j) } } wg.Done() } func writeBytes() *bytes.Buffer { var buff bytes.Buffer for i := 0; i < 30000; i++ { buff.Write([]byte{'0' + byte(rand.Intn(10))}) } return &buff }
編譯程序、採集數據、分析程序:
go build demo.go
./demo.exe --cpuprofile=democpu.pprof --memprofile=demomem.pprof
說明:我是 win 系統,這個 demo 就是 demo.exe ,linux 下是 demo
go tool pprof democpu.pprof
go tool pprof 簡單的使用格式爲:go tool pprof [binary] [source]
要了解 go tool pprof 更多命令使用方法,請查看文檔:
go tool pprof --help
注意:
獲取的 Profiling 數據是動態獲取的,若是想要獲取有效的數據,須要保證應用或服務處於較大的負載中,好比正在運行工做中的服務,或者經過其餘工具模擬訪問壓力。
不然若是應用處於空閒狀態,好比 http 服務處於空閒狀態,獲得的結果可能沒有任何意義。
(後面會遇到這種問題,http 的 web 服務處於空閒狀態,採集顯示的數據爲空)
分析數據,基本的模式有 2 種:
go tool pprof democpu.pprof
字段 | 說明 |
---|---|
Type: | 分析類型,這裏是 cpu |
Duration: | 程序執行的時長 |
Duration 下面還有一行提示,這是交互模式(經過輸入 help 獲取幫助信息,輸入 o 獲取選項信息)。
能夠看出,go 的 pprof 操做還有不少其餘命令。
Commands 下有不少命令信息,text ,top 2個命令解釋相同,輸入這個 2 個看看:
top 命令:對函數的 cpu 耗時和百分比排序後輸出
top後面還能夠帶參數,好比: top15
輸出了相同的信息。
字段 | 說明 |
---|---|
flat | 當前函數佔用 cpu 耗時 |
flat % | 當前函數佔用 cpu 耗時百分比 |
sum% | 函數佔用 cpu 時間累積佔比,從小到大一直累積到 100% |
cum | 當前函數加上調用當前函數的函數佔用 cpu 的總耗時 |
%cum | 當前函數加上調用當前函數的函數佔用 cpu 的總耗時佔比 |
從字段數據咱們能夠看出哪個函數比較耗費時間,就能夠對這個函數進一步分析。
分析用到的命令是 list
。
list 命令:能夠列出函數最耗時的代碼部分,格式:list 函數名
從上面採樣數據能夠分析出總耗時最長的函數是 main.cycylenum
,用 list cyclenum
命令進行分析,以下圖:
發現最耗時的代碼是 62 行:slice = append(slice, j)
,這裏耗時有 1.47s ,能夠對這個地方進行優化。
這裏耗時的緣由,應該是 slice 的實時擴容引發的。那咱們空間換時間,固定 slice 的容量,make([]int, num * num)
在命令行直接輸出數據,基本命令格式爲:
go tool pprof <format> [options] [binary] <source>
輸入命令:go tool pprof -text democpu.pprof
,輸出:
除了上面的命令行交互分析,還能夠用圖形化來分析程序性能。
圖形化分析前,先要安裝 graphviz 軟件,
下載對應的平臺安裝包,安裝完成後,把執行文件 bin 放入 Path 環境變量中,而後在終端輸入 dot -version
命令查看是否安裝成功。
生成可視化文件:
有 2 個步驟,根據上面採集的數據文件 democpu.pprof 來進行可視化:
在命令行裏輸入 web 命令,就能夠生成一個 svg 格式的文件,用瀏覽器打開便可查看 svg 文件。
執行上面 2 個命令以下圖:
用瀏覽器查看生成的 svg 圖:
(文件太大,只截取了一小部分圖,完整的圖請自行生成查看)
關於圖形的一點說明:
運行命令:go tool pprof -http=:8080 democpu.pprof
$ go tool pprof -http=:8080 democpu.pprof Serving web UI on http://localhost:8080
命令運行完成後,會自動在瀏覽器上打開地址: http://localhost:8080/ui/
,咱們能夠在瀏覽器上查看分析數據:
這張圖就是上面用 web 命令生成的圖。
若是你在 web 瀏覽時沒有這麼多菜單可供選擇,那麼請安裝原生的 pprof 工具:
go get -u github.com/google/pprof
,而後在啓動go tool pprof -http=:8080 democpu.pprof
,就會出來菜單。
還能夠查看火焰圖, http 地址:http://localhost:8080/ui/flamegraph,可直接點擊 VIEW 菜單下的 Flame Graph 選項查看火焰圖。固然還有其餘選項可供選擇,好比 Top,Graph 等等選項。你能夠根據須要選擇。
其實上面的 web 可視化已經包含了火焰圖,把火焰圖集成到了 pprof 裏。但爲了向性能優化專家 Bredan Gregg 致敬,仍是來體會一下火焰圖生成過程。
火焰圖 (Flame Graph) 是性能優化專家 Bredan Gregg 建立的一種性能分析圖。Flame Graphs visualize profiled code。
火焰圖形狀以下:
(來自:https://github.com/brendangregg/FlameGraph)
上面用 pprof 生成的採樣數據,要把它轉換成火焰圖,就要使用一個轉換工具 go-torch,這個工具是 uber 開源,它是用 go 語言編寫的,能夠直接讀取 pprof 採集的數據,並生成一張火焰圖, svg 格式的文件。
go get -v github.com/uber/go-torch
生成火焰圖的程序 FlameGraph 是用 perl 寫的,因此先要安裝執行 perl 語言的環境。
perl -h
,輸出了幫助信息,則說明安裝成功進入到 FlameGraph 安裝目錄,執行命令,./flamegraph.pl --help
輸出信息說明安裝成功
從新進入到文件 democpu.pprof 的目錄,而後執行命令:
go-torch -b democpu.pprof
上面命令默認生成名爲 torch.svg 的文件,用瀏覽器打開查看:
自定義輸出文件名,後面加 -f
參數:
go-torch -b democpu.pprof -f cpu_flamegraph.svg
火焰圖說明:
火焰圖 svg 文件,你能夠點擊上面的每一個方塊來查看分析它上面的內容。
火焰圖的調用順序從下到上,每一個方塊表明一個函數,它上面一層表示這個函數會調用哪些函數,方塊的大小表明了佔用 CPU 使用時長長短。
go-torch 的命令格式:
go-torch [options] [binary] <profile source>
go-torch 幫助文檔:
想了解更多 go-torch 用法,請用 help 命令查看幫助文檔,
go-torch --help
。或查看 go-torch README 文檔 。