日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

gbd 分析core文件_Go 性能分析工具 pprof 入门

發布時間:2024/4/11 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 gbd 分析core文件_Go 性能分析工具 pprof 入门 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

(給Go開發大全加星標)

來源:wudaijun

https://wudaijun.com/2018/04/go-pprof/

【導讀】pprof是golang用于性能分析的工具、可以生成圖形和文本報告。在實際項目中對高并發場景下的服務上線前必須經過pprof驗證,本文介紹了pprof的用法。

一. pprof 數據采樣

pprof 采樣數據主要有三種獲取方式:

  • runtime/pprof: 手動調用runtime.StartCPUProfile或者runtime.StopCPUProfile等 API來生成和寫入采樣文件,靈活性高

  • net/http/pprof: 通過 http 服務獲取Profile采樣文件,簡單易用,適用于對應用程序的整體監控。通過 runtime/pprof 實現

  • go test: 通過?go test -bench . -cpuprofile prof.cpu生成采樣文件 適用對函數進行針對性測試

1.1 net/http/pprof

在應用程序中導入import _ "net/http/pprof",并啟動 http server即可:

// net/http/pprof 已經在 init()函數中通過 import 副作用完成默認 Handler 的注冊go func() { log.Println(http.ListenAndServe("localhost:6060", nil))}()

之后可通過 http://localhost:6060/debug/pprof/CMD 獲取對應的采樣數據。支持的 CMD 有:

  • goroutine: 獲取程序當前所有 goroutine 的堆棧信息。

  • heap: 包含每個 goroutine 分配大小,分配堆棧等。每分配 runtime.MemProfileRate(默認為512K) 個字節進行一次數據采樣。

  • threadcreate: 獲取導致創建 OS 線程的 goroutine 堆棧

  • block: 獲取導致阻塞的 goroutine 堆棧(如 channel, mutex 等),使用前需要先調用?runtime.SetBlockProfileRate

  • mutex: 獲取導致 mutex 爭用的 goroutine 堆棧,使用前需要先調用?runtime.SetMutexProfileFraction

以上五個 CMD 都通過runtime/pprof Profile 結構體統一管理,以 Lookup 提供統一查詢接口,有相似的返回值(goroutine 堆棧),它們都支持一個 debug URL參數,默認為0,此時返回的采樣數據是不可人為解讀的函數地址列表,需要結合 pprof 工具才能還原函數名字。debug=1時,會將函數地址轉換為函數名,即脫離 pprof 在瀏覽器中直接查看。對 goroutine CMD來說,還支持 debug=2,此時將以 unrecovered panic 的格式打印堆棧,可讀性更高。如啟用net/http/pprof后,http://localhost:6060/debug/pprof/goroutine?debug=2?的響應格式為:

goroutine 18 [chan receive, 8 minutes]:ngs/core/glog.logWorker(0x18b548a, 0x4, 0x7fff5fbffb0e, 0x0, 0x3, 0xc4200e31a0, 0xc4203627c4) /Users/wudaijun/go/src/ngs/core/glog/worker.go:43 +0x19ccreated by ngs/core/glog.newLogger /Users/wudaijun/go/src/ngs/core/glog/glog.go:51 +0xe4goroutine 6 [syscall, 8 minutes]:os/signal.signal_recv(0x0) /usr/local/Cellar/go/1.9.1/libexec/src/runtime/sigqueue.go:131 +0xa7os/signal.loop() /usr/local/Cellar/go/1.9.1/libexec/src/os/signal/signal_unix.go:22 +0x22created by os/signal.init.0 /usr/local/Cellar/go/1.9.1/libexec/src/os/signal/signal_unix.go:28 +0x41goroutine 50 [select, 8 minutes]:context.propagateCancel.func1(0x1cfcee0, 0xc42017a1e0, 0x1cf3820, 0xc42005b480) /usr/local/Cellar/go/1.9.1/libexec/src/context/context.go:260 +0x113created by context.propagateCancel /usr/local/Cellar/go/1.9.1/libexec/src/context/context.go:259 +0x1da...

以上幾種 Profile 可在?http://localhost:6060/debug/pprof/?中看到,除此之外,go pprof 的 CMD 還包括:

  • cmdline: 獲取程序的命令行啟動參數

  • profile: 獲取指定時間內(從請求時開始)的cpuprof,倒計時結束后自動返回。參數: seconds, 默認值為30。cpuprofile 每秒鐘采樣100次,收集當前運行的 goroutine 堆棧信息。

  • symbol: 用于將地址列表轉換為函數名列表,地址通過’+’分隔,如 URL/debug/pprof?0x18d067f+0x17933e7

  • trace: 對應用程序進行執行追蹤,參數: seconds, 默認值1s

這幾個 CMD 因為各種原因沒有整合到 Profile 結構中去,但就使用上而言,是沒有區別的,URL格式是一致的,因此可以看做一個整體,從各個角度對系統進行數據采樣和分析。

1.2 runtime/pprof

runtime/pprof提供各種相對底層的 API 用于生成采樣數據,一般應用程序更推薦使用net/http/pprof,runtime/pprof?的 API 參考runtime/pprof或 http pprof 實現。

1.3 go test

通常用net/http/pprof或runtime/pprof對應用進行整體分析,找出熱點后,再用go test進行基準測試,進一步確定熱點加以優化并對比測試。

# 生成 test 二進制文件, pprof 工具需要用到go test -c -o tmp.test # 執行基準測試 BenchAbc,并忽略任何單元測試,test flag前面需要加上'test.'前綴tmp.test -test.bench BenchAbc -test.run XXX test.cpuprofile cpu.prof # 與上面兩條命令等價,只不過沒有保留 test 二進制文件go test -bench BenchAbc -run XXX -cpuprofile=cpu.prof .

go test可以直接加-cpuprofile?-mutexprofilefraction等參數實現prof數據的采樣和生成,更多相關參數參考?go test -h。

二. pprof 數據分析

雖然?net/http/pprof提供的數據分析可以通過設置參數后直接在瀏覽器查看,但 pprof 采樣數據主要是用于 pprof 工具的,特別針對 cpuprof, memprof, blockprof等來說,我們需要直觀地得到整個調用關系鏈以及每次調用的詳細信息,這是需要通過go tool pprof命令來分析:

go tool pprof [binary] [binary.prof]# 如果使用的 net/http/pprof 可以直接接 URLgo tool pprof http://localhost:6060/debug/pprof/profile

go pprof 采樣數據是非常豐富的,大部分情況下我們只會用到 CPU 和 內存分析,因此這里介紹下 cpu, heap, block 和 mutex 四種 pprof 數據分析。

2.1 cpuprofile

以Profiling Go Programs中的示例代碼為例:

go build -o havlak1 havlak1.go ./havlak1 --cpuprofile=havlak1.prof# of loops: 76000 (including 1 artificial root node) go tool pprof havlak1 havlak1.profFile: havlak1Type: cpuTime: Apr 3, 2018 at 3:50pm (CST)Duration: 20.40s, Total samples = 23.30s (114.24%)Entering interactive mode (type "help" for commands, "o" for options)(pprof) top5Showing nodes accounting for 9.60s, 41.20% of 23.30s totalDropped 112 nodes (cum <= 0.12s)Showing top 5 nodes out of 90 flat flat% sum% cum cum% 2.59s 11.12% 11.12% 2.78s 11.93% runtime.mapaccess1_fast64 /usr/local/Cellar/go/1.9.1/libexec/src/runtime/hashmap_fast.go 2.26s 9.70% 20.82% 4.97s 21.33% runtime.scanobject /usr/local/Cellar/go/1.9.1/libexec/src/runtime/mgcmark.go 2.06s 8.84% 29.66% 13.79s 59.18% main.FindLoops /Users/wudaijun/Code/goprof/havlak/havlak1.go 1.39s 5.97% 35.62% 1.39s 5.97% runtime.heapBitsForObject /usr/local/Cellar/go/1.9.1/libexec/src/runtime/mbitmap.go 1.30s 5.58% 41.20% 4.14s 17.77% runtime.mapassign_fast64 /usr/local/Cellar/go/1.9.1/libexec/src/runtime/hashmap_fast.go

top5用于顯示消耗 CPU 前五的函數,每一行代表一個函數,每一列為一項指標:

  • flat: 采樣時,該函數正在運行的次數*采樣頻率(10ms),即得到估算的函數運行”采樣時間”。這里不包括函數等待子函數返回。

  • flat%: flat / 總采樣時間值

  • sum%: 前面所有行的 flat% 的累加值,如第二行 sum% = 20.82% = 11.12% + 9.70%

  • cum: 采樣時,該函數出現在調用堆棧的采樣時間,包括函數等待子函數返回。因此 flat <= cum

  • cum%: cum / 總采樣時間值

PS: 老的pprof版本貌似顯示的是采樣次數,比如 flat 為采樣時該函數正在運行的次數,這個次數*采樣頻率即得到采樣時間。

go tool pprof?常用命令:

  • topN: 輸入 top 命令,默認顯示 flat 前10的函數調用,可使用 -cum 以 cum 排序

  • list Func: 顯示函數名以及每行代碼的采樣分析

  • web: 生成 svg 熱點圖片,可在瀏覽器中打開,可使用 web Func 來過濾指定函數相關調用樹

通過top5命令可以看到,mapaccess1_fast64函數占用的CPU 采樣時間最多,通過?web mapaccess1_fast64?命令打開調用圖譜,查看該函數調用關系,可以看到主要在DFS 和 FindLoops 中調用的,然后再通過?list DFS查看函數代碼和關鍵調用,得到 map 結構是瓶頸點,嘗試轉換為 slice 優化,整個過程參考Profiling Go Programs。總的思路就是通過top?和web?找出關鍵函數,再通過list Func?查看函數代碼,找到關鍵代碼行并確認優化方案(輔以 go test Benchmark)。

2.2 memprofile

go build -o havlak3 havlak3.go ./havlak3 --memprofile=havlak3.mprof go tool pprof havlak3 havlak3.mprofFile: havlak3Type: inuse_spaceTime: Apr 3, 2018 at 3:44pm (CST)Entering interactive mode (type "help" for commands, "o" for options)(pprof) topShowing nodes accounting for 57.39MB, 100% of 57.39MB total flat flat% sum% cum cum% 39.60MB 69.00% 69.00% 39.60MB 69.00% main.FindLoops /Users/wudaijun/Code/goprof/havlak/havlak3.go 11.29MB 19.67% 88.67% 11.29MB 19.67% main.(*CFG).CreateNode /Users/wudaijun/Code/goprof/havlak/havlak3.go 6.50MB 11.33% 100% 17.79MB 31.00% main.NewBasicBlockEdge /Users/wudaijun/Code/goprof/havlak/havlak3.go 0 0% 100% 39.60MB 69.00% main.FindHavlakLoops /Users/wudaijun/Code/goprof/havlak/havlak3.go 0 0% 100% 17.79MB 31.00% main.buildBaseLoop /Users/wudaijun/Code/goprof/havlak/havlak3.go

memprofile 也就是 heap 采樣數據,go tool pprof 默認顯示的是使用的內存的大小,如果想要顯示使用的堆對象的個數,則通過go tool pprof --inuse_objects havlak3 havlak3.mprof,其它參數還有--alloc_objects和--alloc_space,分別是分配的堆內存大小和對象個數。在本例中,FindLoops 函數分配了39.60M 堆內存,占到69%,同樣,接下來是通過list FindLoops對函數代碼進行 review,找出關鍵數據結構,進行優化。

2.3 blockprofile

var mutex sync.Mutexfunc main() { // rate = 1 時, 統計所有的 block event, // rate <=0 時,則關閉block profiling // 參考 https://github.com/golang/go/blob/release-branch.go1.9/src/runtime/mprof.go#L397 runtime.SetBlockProfileRate(1 * 1000 * 1000) var wg sync.WaitGroup // rate > 1 時,為 ns 數,阻塞時間t>rate的event 一定會被統計 //小于rate則有t/rate 的幾率被統計 wg.Add(1) mutex.Lock() go worker(&wg) time.Sleep(2*time.Millisecond) mutex.Unlock() wg.Wait() writeProfTo("block", "block.bprof")}func worker(wg *sync.WaitGroup) { defer wg.Done() mutex.Lock() time.Sleep(1*time.Millisecond) mutex.Unlock()}func writeProfTo(name, fn string) { p := pprof.Lookup(name) if p == nil { fmt.Errorf("%s prof not found", name) return } f, err := os.Create(fn) if err != nil { fmt.Errorf("%v", err.Error()) return } defer f.Close() err = p.WriteTo(f, 0) if err != nil { fmt.Errorf("%v", err.Error()) return }}

運行程序并 pprof:

go build -o Temp tmp.gogo tool pprof Temp block.bprof(pprof) topShowing nodes accounting for 3.37ms, 100% of 3.37ms total flat flat% sum% cum cum% 2.04ms 60.52% 60.52% 2.04ms 60.52% sync.(*Mutex).Lock /usr/local/Cellar/go/1.9.1/libexec/src/sync/mutex.go 1.33ms 39.48% 100% 1.33ms 39.48% sync.(*WaitGroup).Wait /usr/local/Cellar/go/1.9.1/libexec/src/sync/waitgroup.go 0 0% 100% 1.33ms 39.48% main.main /Users/wudaijun/go/src/ngs/test/tmp/tmp.go 0 0% 100% 2.04ms 60.52% main.worker /Users/wudaijun/go/src/ngs/test/tmp/tmp.go 0 0% 100% 3.37ms 100% runtime.goexit /usr/local/Cellar/go/1.9.1/libexec/src/runtime/asm_amd64.s 0 0% 100% 1.33ms 39.48% runtime.main /usr/local/Cellar/go/1.9.1/libexec/src/runtime/proc.go

可以看到程序在 mutex.Lock 上阻塞了2.04ms(worker goroutine), 在 WaitGroup.Wait 上等待了1.33ms(main goroutine),從更上層來看,在 main 函數中一共阻塞了2.04ms,worker函數中阻塞了1.33ms(cum 列),通過?web命令生成 svg 圖片在瀏覽器查看:

可以很直觀地看到整個阻塞調用鏈,對于耗時較多的阻塞調用加以優化。

2.4 mutexprofile

仍然用2.3中的代碼,只需要改兩個地方,將?runtime.SetBlockProfileRate(1 * 1000 * 1000)?改為:

// 當 rate = 0 時,關閉 mutex prof (默認值)// 當 rate = 1 時,表示記錄所有的 mutex event// 當 rate > 1 時,記錄 1/rate 的 mutex event(隨機)runtime.SetMutexProfileFraction(1)

再將writeProfTo("block", "block.bprof")改為writeProfTo("mutex", "mutex.mprof")即可,編譯運行,并打開 pprof 工具:

go?tool?pprof?bin/Temp?mutex.mprof(pprof) topShowing nodes accounting for 2.55ms, 100% of 2.55ms total flat flat% sum% cum cum% 2.55ms 100% 100% 2.55ms 100% sync.(*Mutex).Unlock /usr/local/Cellar/go/1.9.1/libexec/src/sync/mutex.go 0 0% 100% 2.55ms 100% main.main /Users/wudaijun/go/src/ngs/test/tmp/tmp.go 0 0% 100% 2.55ms 100% runtime.goexit /usr/local/Cellar/go/1.9.1/libexec/src/runtime/asm_amd64.s 0 0% 100% 2.55ms 100% runtime.main /usr/local/Cellar/go/1.9.1/libexec/src/runtime/proc.go

查看 svg 圖:

三. 實踐 Tips

以下是一些從其它項目借鑒或者自己總結的實踐經驗,它們只是建議,而不是準則,實際項目中應該以性能分析數據來作為優化的參考,避免過早優化。

  • 對頻繁分配的小對象,使用?sync.Pool?對象池避免分配

  • 自動化的 DeepCopy 是非常耗時的,其中涉及到反射,內存分配,容器(如 map)擴展等,大概比手動拷貝慢一個數量級

  • 用 atomic.Load/StoreXXX,atomic.Value, sync.Map 等代替 Mutex。(優先級遞減)

  • 使用高效的第三方庫,如用fasthttp替代 net/http

  • 在開發環境加上-race編譯選項進行競態檢查

  • 在開發環境開啟 net/http/pprof,方便實時 pprof

  • 將所有外部IO(網絡IO,磁盤IO)做成異步

  • - EOF -推薦閱讀(點擊標題可打開)

    1、RedHat容器術語實用導論

    2、圖解 Goroutine 與搶占機制

    3、淺析 k8s 容器運行時演進

    如果覺得本文不錯,歡迎轉發推薦給更多人。

    分享、點贊和在看

    支持我們分享更多好文章,謝謝!

    總結

    以上是生活随笔為你收集整理的gbd 分析core文件_Go 性能分析工具 pprof 入门的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。