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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

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

(給Go開發(fā)大全加星標(biāo))

來源:wudaijun

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

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

一. pprof 數(shù)據(jù)采樣

pprof 采樣數(shù)據(jù)主要有三種獲取方式:

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

  • net/http/pprof: 通過 http 服務(wù)獲取Profile采樣文件,簡單易用,適用于對應(yīng)用程序的整體監(jiān)控。通過 runtime/pprof 實現(xiàn)

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

1.1 net/http/pprof

在應(yīng)用程序中導(dǎo)入import _ "net/http/pprof",并啟動 http server即可:

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

之后可通過 http://localhost:6060/debug/pprof/CMD 獲取對應(yīng)的采樣數(shù)據(jù)。支持的 CMD 有:

  • goroutine: 獲取程序當(dāng)前所有 goroutine 的堆棧信息。

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

  • threadcreate: 獲取導(dǎo)致創(chuàng)建 OS 線程的 goroutine 堆棧

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

  • mutex: 獲取導(dǎo)致 mutex 爭用的 goroutine 堆棧,使用前需要先調(diào)用?runtime.SetMutexProfileFraction

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

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: 獲取程序的命令行啟動參數(shù)

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

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

  • trace: 對應(yīng)用程序進(jìn)行執(zhí)行追蹤,參數(shù): seconds, 默認(rèn)值1s

這幾個 CMD 因為各種原因沒有整合到 Profile 結(jié)構(gòu)中去,但就使用上而言,是沒有區(qū)別的,URL格式是一致的,因此可以看做一個整體,從各個角度對系統(tǒng)進(jìn)行數(shù)據(jù)采樣和分析。

1.2 runtime/pprof

runtime/pprof提供各種相對底層的 API 用于生成采樣數(shù)據(jù),一般應(yīng)用程序更推薦使用net/http/pprof,runtime/pprof?的 API 參考runtime/pprof或 http pprof 實現(xiàn)。

1.3 go test

通常用net/http/pprof或runtime/pprof對應(yīng)用進(jìn)行整體分析,找出熱點后,再用go test進(jìn)行基準(zhǔn)測試,進(jìn)一步確定熱點加以優(yōu)化并對比測試。

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

go test可以直接加-cpuprofile?-mutexprofilefraction等參數(shù)實現(xiàn)prof數(shù)據(jù)的采樣和生成,更多相關(guān)參數(shù)參考?go test -h。

二. pprof 數(shù)據(jù)分析

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

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

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

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 前五的函數(shù),每一行代表一個函數(shù),每一列為一項指標(biāo):

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

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

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

  • cum: 采樣時,該函數(shù)出現(xiàn)在調(diào)用堆棧的采樣時間,包括函數(shù)等待子函數(shù)返回。因此 flat <= cum

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

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

go tool pprof?常用命令:

  • topN: 輸入 top 命令,默認(rèn)顯示 flat 前10的函數(shù)調(diào)用,可使用 -cum 以 cum 排序

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

  • web: 生成 svg 熱點圖片,可在瀏覽器中打開,可使用 web Func 來過濾指定函數(shù)相關(guān)調(diào)用樹

通過top5命令可以看到,mapaccess1_fast64函數(shù)占用的CPU 采樣時間最多,通過?web mapaccess1_fast64?命令打開調(diào)用圖譜,查看該函數(shù)調(diào)用關(guān)系,可以看到主要在DFS 和 FindLoops 中調(diào)用的,然后再通過?list DFS查看函數(shù)代碼和關(guān)鍵調(diào)用,得到 map 結(jié)構(gòu)是瓶頸點,嘗試轉(zhuǎn)換為 slice 優(yōu)化,整個過程參考Profiling Go Programs。總的思路就是通過top?和web?找出關(guān)鍵函數(shù),再通過list Func?查看函數(shù)代碼,找到關(guān)鍵代碼行并確認(rèn)優(yōu)化方案(輔以 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 采樣數(shù)據(jù),go tool pprof 默認(rèn)顯示的是使用的內(nèi)存的大小,如果想要顯示使用的堆對象的個數(shù),則通過go tool pprof --inuse_objects havlak3 havlak3.mprof,其它參數(shù)還有--alloc_objects和--alloc_space,分別是分配的堆內(nèi)存大小和對象個數(shù)。在本例中,FindLoops 函數(shù)分配了39.60M 堆內(nèi)存,占到69%,同樣,接下來是通過list FindLoops對函數(shù)代碼進(jìn)行 review,找出關(guān)鍵數(shù)據(jù)結(jié)構(gòu),進(jìn)行優(yōu)化。

2.3 blockprofile

var mutex sync.Mutexfunc main() { // rate = 1 時, 統(tǒng)計所有的 block event, // rate <=0 時,則關(guān)閉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 數(shù),阻塞時間t>rate的event 一定會被統(tǒng)計 //小于rate則有t/rate 的幾率被統(tǒng)計 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 函數(shù)中一共阻塞了2.04ms,worker函數(shù)中阻塞了1.33ms(cum 列),通過?web命令生成 svg 圖片在瀏覽器查看:

可以很直觀地看到整個阻塞調(diào)用鏈,對于耗時較多的阻塞調(diào)用加以優(yōu)化。

2.4 mutexprofile

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

// 當(dāng) rate = 0 時,關(guān)閉 mutex prof (默認(rèn)值)// 當(dāng) rate = 1 時,表示記錄所有的 mutex event// 當(dāng) rate > 1 時,記錄 1/rate 的 mutex event(隨機(jī))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

以下是一些從其它項目借鑒或者自己總結(jié)的實踐經(jīng)驗,它們只是建議,而不是準(zhǔn)則,實際項目中應(yīng)該以性能分析數(shù)據(jù)來作為優(yōu)化的參考,避免過早優(yōu)化。

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

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

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

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

  • 在開發(fā)環(huán)境加上-race編譯選項進(jìn)行競態(tài)檢查

  • 在開發(fā)環(huán)境開啟 net/http/pprof,方便實時 pprof

  • 將所有外部IO(網(wǎng)絡(luò)IO,磁盤IO)做成異步

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

    1、RedHat容器術(shù)語實用導(dǎo)論

    2、圖解 Goroutine 與搶占機(jī)制

    3、淺析 k8s 容器運行時演進(jìn)

    如果覺得本文不錯,歡迎轉(zhuǎn)發(fā)推薦給更多人。

    分享、點贊和在看

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

    總結(jié)

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

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。