Go 效能工具小抄
- 原文地址:https://steveazz.xyz/blog/go-performance-tools-cheat-sheet
- 原文作者:
Steve Azzopardi
本文永久連結:https://github.com/gocn/translator/blob/master/2021/w23_go_performance_tools_cheat_sheet.md
譯者:Cluas
校對:Martinho0330
Go 有很多工具可以讓你瞭解你的應用程式可能在哪裡花費 CPU 時間或分配記憶體。我不是每天都使用這些工具,所以我每次都是在尋找同樣的東西。這篇文章的目的是為這些 Go 所提供的工具提供一個參考文獻。
我們將使用 https://gitlab.com/steveazz-blog/go-performance-tools-cheat-sheet 作為一個演示專案,同樣的事情有 3 種實現方式,每一種都比前一種效能更好。
基準測試 (Benchmarks)
最流行的方法之一是使用 Go 中內建的 基準測試 來看看你是否改進了什麼。
在我們的演示專案中,已經有了 可用的基準測試 我們可以用一個命令執行它們。
go test -bench=. -test.benchmem ./rand/
goos: darwin
goarch: amd64
pkg: gitlab.com/steveazz/blog/go-performance-tools-cheat-sheet/rand
cpu: Intel(R) Core(TM) i7-6820HQ CPU @ 2.70GHz
BenchmarkHitCount100-8 3020 367016 ns/op 269861 B/op 3600 allocs/op
BenchmarkHitCount1000-8 326 3737517 ns/op 2696308 B/op 36005 allocs/op
BenchmarkHitCount100000-8 3 370797178 ns/op 269406189 B/op 3600563 allocs/op
BenchmarkHitCount1000000-8 1 3857843580 ns/op 2697160640 B/op 36006111 allocs/op
PASS
ok gitlab.com/steveazz/blog/go-performance-tools-cheat-sheet/rand 8.828s
注意: -test.benchmem
是一個可選的標誌,用於顯示記憶體分配。
仔細看一下每一欄的含義:
BenchmarkHitCount100-8 3020 367016 ns/op 269861 B/op 3600 allocs/op
^------------------^ ^ ^ ^ ^ ^
| | | | | |
名稱 CPU數量 總執行次數 每次操作的納秒數 每次操作的位元組數 每次操作的記憶體分配數
比較基準測試 (Benchmarks)
Go 建立了 perf 它提供了 benchstat 這樣你就可以一起比較 benchmark 輸出,它將給你展示出它們之間的差異。
# 執行 `main` 分支的基準測試
git checkout main
go test -bench=. -test.benchmem -count=5 ./rand/ > old.txt
# 執行 `best` 分支的基準測試
git checkout best
go test -bench=. -test.benchmem -count=5 ./rand/ > new.txt
# 比較兩個基準測試結果
benchstat old.txt new.txt
name old time/op new time/op delta
HitCount100-8 366µs ± 0% 103µs ± 0% -71.89% (p=0.008 n=5+5)
HitCount1000-8 3.66ms ± 0% 1.06ms ± 5% -71.13% (p=0.008 n=5+5)
HitCount100000-8 367ms ± 0% 104ms ± 1% -71.70% (p=0.008 n=5+5)
HitCount1000000-8 3.66s ± 0% 1.03s ± 1% -71.84% (p=0.016 n=4+5)
name old alloc/op new alloc/op delta
HitCount100-8 270kB ± 0% 53kB ± 0% -80.36% (p=0.008 n=5+5)
HitCount1000-8 2.70MB ± 0% 0.53MB ± 0% -80.39% (p=0.008 n=5+5)
HitCount100000-8 270MB ± 0% 53MB ± 0% -80.38% (p=0.008 n=5+5)
HitCount1000000-8 2.70GB ± 0% 0.53GB ± 0% -80.39% (p=0.016 n=4+5)
name old allocs/op new allocs/op delta
HitCount100-8 3.60k ± 0% 1.50k ± 0% -58.33% (p=0.008 n=5+5)
HitCount1000-8 36.0k ± 0% 15.0k ± 0% -58.34% (p=0.008 n=5+5)
HitCount100000-8 3.60M ± 0% 1.50M ± 0% -58.34% (p=0.008 n=5+5)
HitCount1000000-8 36.0M ± 0% 15.0M ± 0% -58.34% (p=0.008 n=5+5)
注意,我們傳遞了 -count
標誌來多次執行基準測試,這樣它就可以得到執行的平均值。
pprof
Go 有自己的剖析器,它可以讓你更好地瞭解 CPU 時間花在哪裡,或者應用程式在哪裡分配記憶體。Go 在一段時間內對這些進行取樣,例如,它將在 X 秒內每隔 X 納秒檢視 CPU/記憶體的使用情況。
生成剖析檔案 (Profiles)
Benchmarks
你可以使用我們在演示專案中的基準來生成剖析檔案。
CPU:
go test -bench=. -cpuprofile cpu.prof ./rand/
Memory:
go test -bench=. -memprofile mem.prof ./rand/
net/http/pprof package
如果你正在編寫一個 webserver,你可以匯入 net/http/pprof
它將在 DefaultServeMux 上暴露/debug/pprof
HTTP 端點,就像我們在 示例應用 中做的那樣。
確保你的應用程式不是空閒著它需要正在執行或接收請求,以便剖析器能夠對呼叫進行取樣,否則你可能會因為應用程式是空閒的而最終得到一個空的剖析檔案。
# CPU剖析檔案
curl http://127.0.0.1:8080/debug/pprof/profile > /tmp/cpu.prof
# 堆剖析檔案
curl http://127.0.0.1:8080/debug/pprof/heap > /tmp/heap.prof
# 記憶體分配剖析檔案
curl http://127.0.0.1:8080/debug/pprof/allocs > /tmp/allocs.prof
如果你訪問/debug/pprof
,它將給出所有可用的端點的列表和它們的含義。
runtime/pprof 包
這與 net/http/pprof
類似,將它新增到你的應用程式中,但不是為所有的專案新增,你可以指定一個特定的程式碼路徑,在那個路徑生成剖析檔案。當你只對你的應用程式的某一部分感興趣,並且你只想對應用程式的那一部分進行取樣時,這就很有用。要閱讀如何使用它,請檢視 go 的參考文件 。
你也可以用這個來 給應用加上標籤 這可以幫助你更好地瞭解概況。
閱讀剖析檔案 (Profiles)
現在我們知道了如何生成剖析檔案,讓我們看看如何讀取它們以瞭解我們的應用程式正在做什麼。
我們將使用的命令是 go tool pprof
。
呼叫圖
例如,為了使用我們在演示程式中 registered 的/debug/pprof
端點,我們可以直接傳入 HTTP 端點。
# 開啟新的瀏覽器視窗,檢視30秒後的呼叫圖。
go tool pprof -http :9402 http://127.0.0.1:8080/debug/pprof/profile
另一個選擇是使用 curl
下載剖析檔案,然後使用 go tool
命令,這對於從沒有暴露在公共網際網路上的生產端點獲取剖析檔案可能很有用。
# 在伺服器上檢視。
curl http://127.0.0.1:8080/debug/pprof/profile > /tmp/cpu.prof
# 從伺服器上下載後,在本地檢視。
go tool pprof -http :9402 /tmp/cpu.prof
注意,在所有的命令中,我們都傳遞了-http
標誌,這是可選的,因為在預設情況下,這將開啟 CLI 介面。
下面你可以看到我們的演示應用程式呼叫圖。為了更好地理解它的含義,你應該閱讀 解釋呼叫圖 。
火焰圖
呼叫圖對於檢視程式正在呼叫的內容很有用,也可以幫助你瞭解應用程式正在花費的時間。瞭解 CPU 時間或記憶體分配去向的另一種方法是使用火焰圖。
使用同一個演示程式,讓我們再次執行 go tool pprof
:
# 來自HTTP端點
go tool pprof -http :9402 http://127.0.0.1:8080/debug/pprof/profile
# 來自本地的剖析檔案
go tool pprof -http :9402 /tmp/cpu.prof
然而,這一次我們將使用頂部導航欄,前往 View
> Flame Graph
然後你應該看到類似下面的東西:
為了讓你更好地瞭解如何閱讀火焰圖,你可以檢視一下 什麼是火焰圖,怎麼去讀火焰圖 (RubyConf2017 上的議題)
你也可以使用 speedscope 這是一個與語言無關的應用程式,可以從剖析檔案中生成火焰圖,它比 Go 提供的互動性更強一些。
比較剖析檔案 (Profiles)
go tool pprof
也允許你使用 比較剖析檔案 來顯示 1 個剖析檔案和另一個剖析檔案之間的差異。
再次使用我們的演示專案,我們可以為 "main" 和 "best" 分支生成剖析檔案。
# 執行 `main` 分支,生成剖析檔案。
curl http://127.0.0.1:8080/debug/pprof/profile > /tmp/main.prof
# 執行 `best` 分支,生成剖析檔案。
curl http://127.0.0.1:8080/debug/pprof/profile > /tmp/best.prof
# 比較剖析檔案。
go tool pprof -http :9402 --diff_base=/tmp/main.prof /tmp/best.prof
追蹤 (Traces)
我們需要經歷的最後一個工具是 CPU 追蹤器。這可以讓你準確地瞭解在程式執行過程中發生了什麼。它可以告訴你哪些核心是閒置的,哪些核心是忙碌的。如果你正在除錯一些沒有達到預期效能的併發程式碼,這就非常好用。
再次使用我們的演示程式,讓我們使用net/http/pprof
新增的debug/pprof/trace
端點來獲得 CPU 跟蹤。
curl http://127.0.0.1:8080/debug/pprof/trace > /tmp/best.trace
go tool trace /tmp/best.trace
關於追蹤器的更詳細的解釋可以在 go 程式設計師學院部落格 上找到。
資源
文中提到的連結
- 預設實現 -> https://gitlab.com/steveazz-blog/go-performance-tools-cheat-sheet/-/tree/main
- 效能更好的實現 -> https://gitlab.com/steveazz-blog/go-performance-tools-cheat-sheet/-/tree/better
- 效能最好的實現 -> https://gitlab.com/steveazz-blog/go-performance-tools-cheat-sheet/-/tree/best
- 基準測試 -> https://pkg.go.dev/testing#hdr-Benchmarks
- 可用的基準測試 -> https://gitlab.com/steveazz-blog/go-performance-tools-cheat-sheet/-/blob/main/rand/counter_test.go
- perf -> https://github.com/golang/perf
- benchstat -> https://github.com/golang/perf/tree/master/cmd/benchstat
- net/http/pprof -> https://pkg.go.dev/net/http/pprof
- 給應用加上標籤 -> https://rakyll.org/profiler-labels
- registered -> https://gitlab.com/steveazz-blog/go-performance-tools-cheat-sheet/-/blob/e7736e21bf1c3be7bb25e4c64b8730bb3b631b73/main.go#L7
- 解釋呼叫圖 -> https://github.com/google/pprof/blob/master/doc/README.md#interpreting-the-callgraph
- 什麼是火焰圖,怎麼去讀火焰圖 (RubyConf2017 上的議題) ->
- speedscope -> https://www.speedscope.app/
- 比較剖析檔案 -> https://github.com/google/pprof/blob/master/doc/README.md#comparing-profiles
- go 程式設計師學院部落格 -> https://blog.gopheracademy.com/advent-2017/go-execution-tracer/
- Go 高效能研究 -> https://dave.cheney.net/high-performance-go-workshop/dotgo-paris.html
- go-perf 百科 -> https://github.com/dgryski/go-perfbook
- Go 工具實戰 ->
- pprof++ -> https://eng.uber.com/pprof-go-profiler/
- 追蹤 (trace) 設計文件 -> https://docs.google.com/document/u/1/d/1FP5apqzBgr7ahCCgFO-yoVhk4YZrNIDNf9RybngBc14/pub
- 如何用 Go 編寫基準測試 -> https://dave.cheney.net/2013/06/30/how-to-write-benchmarks-in-go
- 加微信實戰群請加微信(註明:實戰群):gocnio
相關文章
- 面試小抄 - react面試React
- Go 效能壓測工具之wrk介紹與使用Go
- 名言小抄(八)--曾國藩
- Go 語言效能分析Go
- Go-For Range 效能研究Go
- Go語言效能優化- For Range 效能研究Go優化
- 《JavaScript 模式》知識點小抄本(上)JavaScript模式
- 《JavaScript 模式》知識點小抄本(下)JavaScript模式
- Go 學習、Go 進階、Go 實用工具類Go
- 效能分析工具 - pprof
- Go - 程式碼生成工具Go
- go效能調優之火焰圖Go
- 一大波開源小抄來襲
- 這份 Matplotlib 使用小抄,要多全有多全
- 效能測試工具 - Siege
- 效能壓測工具 —— wrk
- Linux 效能監控工具Linux
- 效能分析工具簡介
- CPU效能分析工具原理
- SAP OData效能分析工具
- Linux效能評估工具Linux
- android效能分析工具systraceAndroid
- Go的包管理工具(三):Go ModulesGo
- 基於 go pprof` 與 go trace 進行持續效能剖析Go
- 重試工具 — retry-goGo
- Go 編譯和工具鏈Go編譯
- 使用 GVM 工具管理 Go 版本Go
- Go的包管理工具(四):Go Module ProxyGo
- labuladong的演算法小抄官方完整版(gitee)演算法Gitee
- 28個Javascript陣列方法,開發者的小抄JavaScript陣列
- 值得收藏的27個機器學習的小抄機器學習
- 27個機器學習的小抄,助你效率翻倍機器學習
- Java 效能分析 5 大工具Java
- Linux 效能分析工具彙總Linux
- perf效能分析工具使用分享
- web效能檢測工具lighthouseWeb
- ABAP Webdynpro效能測試工具Web
- 即時效能分析工具 PyroscopeROS