例子 gist 來自以前的 Trie 的實現, Ruby vs Go.ruby
main
函數加上了下面幾行:網絡
1 2 3 4 5 6 |
import "runtime/pprof" // ... cpuProfile, _ := os.Create("cpu_profile") pprof.StartCPUProfile(cpuProfile) defer pprof.StopCPUProfile() // ... |
這裏 os.Create("cpu_profile")
指定生成的數據文件, 而後 pprof.StartCPUProfile
看名字就知道是開始對 CPU 的使用進行監控. 有開始就有結束, 通常直接跟着 defer pprof.StopCPUProfile()
省的後面忘了. 編譯執行一次之後會在目錄下生成監控數據並記錄到 cpu_profile. 接着就可使用 pprof 來解讀分析這些監控生成的數據.
When CPU profiling is enabled, the Go program stops about 100 times per second and records a sample consisting of the program counters on the currently executing goroutine’s stack.
CPU Profiling
1 2 3 4 5 6 |
$ go tool pprof cpu_profile Type: cpu Time: Jan 22, 2019 at 3:02pm (CST) Duration: 518.52ms, Total samples = 570ms (109.93%) Entering interactive mode (type "help" for commands, "o" for options) (pprof) |
由於是在多核環境, 因此, 取樣時間(Total samples) 佔比大於 100% 也屬於正常的. 交互操做模式提供了一大票的命令, 執行一下 help
就有相應的文檔了. 好比輸出報告到各類格式(pdf, png, gif), 方塊越大個表示消耗越大.
又或者列出 CPU 佔比最高的一些(默認十個)運行結點的 top
命令, 也能夠加上須要的結點數好比 top15
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
(pprof) top Showing nodes accounting for 480ms, 84.21% of 570ms total Showing top 10 nodes out of 67 flat flat% sum% cum cum% 200ms 35.09% 35.09% 210ms 36.84% main.NewNode (inline) 70ms 12.28% 47.37% 170ms 29.82% runtime.scanobject 60ms 10.53% 57.89% 70ms 12.28% runtime.greyobject 30ms 5.26% 63.16% 30ms 5.26% runtime.memclrNoHeapPointers 30ms 5.26% 68.42% 30ms 5.26% runtime.memmove 20ms 3.51% 71.93% 250ms 43.86% main.(*Node).insert 20ms 3.51% 75.44% 20ms 3.51% runtime.findObject 20ms 3.51% 78.95% 230ms 40.35% runtime.gcDrain 20ms 3.51% 82.46% 20ms 3.51% runtime.pthread_cond_wait 10ms 1.75% 84.21% 10ms 1.75% runtime.(*gcWork).tryGetFast (inline) |
- flat: 是指該函數執行耗時, 程序總耗時 570ms,
main.NewNode
的 200ms 佔了 35.09% - sum: 當前函數與排在它上面的其餘函數的 flat 佔比總和, 好比
35.09% + 12.28% = 47.37%
- cum: 是指該函數加上在該函數調用以前累計的總耗時, 這個看圖片格式的話會更清晰一些.
能夠看到, 這裏最耗 CPU 時間的是 main.NewNode
這個操做.
除此外還有 list
命令能夠根據匹配的參數列出指定的函數相關數據, 好比:
Memory Profiling
1 2 3 |
// ... memProfile, _ := os.Create("mem_profile") pprof.WriteHeapProfile(memProfile) |
相似 CPU 的監控, 要監控內存的分配回收使用狀況, 只要調用 pprof.WriteHeapProfile(memProfile)
而後是跟上面同樣的生成圖片:
Type: inuse_space 是監控內存的默認選項, 還能夠選 -alloc_space, -inuse_objects, -alloc_objects
inuse_space 是正在使用的內存大小, alloc_space是從頭至尾一共分配了的內存大小(包括已經回收了的), 後綴爲 _objects
的是相應的對象數
net/http/pprof
對於 http 服務的監控有一些些的不一樣, 不過 Go 已經對 pprof 作了一些封裝在 net/http/pprof
例子 gist 來自從 net/http 入門到 Gin 源碼梳理
引入多一行 _ "net/http/pprof"
, 啓用服務之後就能夠在路徑 /debug/pprof/
看到相應的監控數據. 相似下面(已經很貼心的把各自的描述信息寫在下邊了):
用 wrk (brew install wrk) 模擬測試
wrk -c 200 -t 4 -d 3m http://localhost:8080/hello
仍是沒有前面的那些可視化圖形 UI 直觀, 不過能夠經過 http://localhost:8080/debug/pprof/profile (其餘幾個指標也差很少, heap, alloc…)生成一個相似前面的 CPU profile 文件監控 30s 內的數據. 而後就能夠用 go tool pprof
來解讀了.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
Type: cpu Time: Jan 22, 2019 at 4:22pm (CST) Duration: 30.13s, Total samples = 1.62mins (321.66%) Entering interactive mode (type "help" for commands, "o" for options) (pprof) top Showing nodes accounting for 93.78s, 96.76% of 96.92s total Dropped 270 nodes (cum <= 0.48s) Showing top 10 nodes out of 52 flat flat% sum% cum cum% 81.42s 84.01% 84.01% 81.45s 84.04% syscall.Syscall 3.45s 3.56% 87.57% 3.45s 3.56% runtime.kevent 2.31s 2.38% 89.95% 2.31s 2.38% runtime.pthread_cond_wait 2.06s 2.13% 92.08% 2.07s 2.14% runtime.usleep 1.93s 1.99% 94.07% 1.93s 1.99% runtime.pthread_cond_signal 1.10s 1.13% 95.20% 1.10s 1.13% runtime.freedefer 0.85s 0.88% 96.08% 0.87s 0.9% runtime.nanotime 0.59s 0.61% 96.69% 4.07s 4.20% runtime.netpoll 0.04s 0.041% 96.73% 0.67s 0.69% runtime.newproc1 0.03s 0.031% 96.76% 44.18s 45.58% net/http.(*conn).readRequest (pprof) Type: alloc_space Time: Jan 22, 2019 at 4:26pm (CST) Entering interactive |