這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
註:本文的原文 Debugging performance issues in Go programs 由 Dmitry Vyukov 在 05/10/2014 - 07:06 編寫
註:原文太長,大家要看全部的請看原文,其他的部分,後續慢慢翻譯。
讓我們假設你想提升你的GO程式的效能。這裡有一些工具可以協助你完成這個任務。這些工具能協助你定位多種類型的熱點(CPU,IO,記憶體),你為了能夠顯著提升程式效能,你必須專註於熱點發生的地方。儘管如此,另外一個結果是可能的--這些工具能協助你確定程式中明顯的效能缺陷。例如,當你在每個程式啟動的時候,你可以在每次查詢的之前準備一個 SQL 陳述式。另外一個例子是如果一個 O(N^2) 演算法在某種程度上陷入了一個明顯存在並且期望的 O(N) 情況。為了確定這樣的情況,你需要完整性的檢查你在 profiles 中看到的。例如第一種情況下大量的時間花費在 SQL 陳述式的準備上,這已經超越了警示線了。
同樣重要的是要理解效能影響的各種邊界因素。例如,一個程式通過 100 Mbps 的頻寬串連通訊,並且它已經使用超過 90 Mbps,這裡就沒有什麼可以對這程式做的來提升它的效能了。這些類似的邊界因素包括 磁碟 IO,記憶體消耗和計算任務。
考慮到這一點,我們可以查看這些可用的工具。
注意:這些工具可能相互幹擾,例如,精確的記憶體分析可能影響CPU分析。goroutine 阻塞分析可能影響調度追蹤等等,隔離地使用這些工具以便得到更加精確的資訊。
注意:這裡所有的描述都是基於 Go1.3 版本的
CPU 分析器
Go runtime 包含了內建的 CPU 分析器,這顯示了函數消耗的 CPU 時間百分比,這裡你有3種方式訪問它:
- 最簡單的一個方式是使用
go test 命令的 -cpuprofile 標記。例如,如下命令:
$ go test -run=none -bench=ClientServerParallel4 -cpuprofile=cprof net/http
將配置給出的基準和 CPU 的概要分析寫入 cprof 檔案。
然後:
$ go tool pprof --text http.test cprof
將列印一份熱點函數列表。
這有幾個可用的輸出類型,最有用的幾個為: --text,--web 和 --list 。運行 go tool pprof 來得到最完整的列表。
這個選項最明顯的特點就是它只適用於測試。
- net/http/pprof 包。這是網路服務的理想解決方案。你僅僅只需要
import net/http/pprof 並且用如下命令收集概要檔案:
$ go tool pprof --text mybin http://myserver:6060:/debug/pprof/profile
- 手工配置收集。你需要 import runtime/pprof 並且 把如下代碼加入 main 函數中:
if *flagCpuprofile != "" { f, err := os.Create(*flagCpuprofile) if err != nil { log.Fatal(err) } pprof.StartCPUProfile(f) defer pprof.StopCPUProfile()}
這份概要檔案會被寫入指定的檔案中,想象它和第一個選項一樣的命令列方式。
這裡是一個使用 --web 選項產生的直觀的概要檔案樣本:
你可以使用 -list=funcname 選項來研究單個函數,下面的 概要檔案顯示了在 append 函數中所花費的時間:
. . 93: func (bp *buffer) WriteRune(r rune) error {. . 94: if r < utf8.RuneSelf {5 5 95: *bp = append(*bp, byte(r)). . 96: return nil. . 97: }. . 98: . . 99: b := *bp. . 100: n := len(b). . 101: for n+utf8.UTFMax > cap(b) {. . 102: b = append(b, 0). . 103: }. . 104: w := utf8.EncodeRune(b[n:n+utf8.UTFMax], r). . 105: *bp = b[:n+w]. . 106: return nil. . 107: }
你可以在這裡找到 pprof 工具的詳細資料和描述的數字圖。
當它不能解鎖堆棧的時候,這裡有關於分析器使用的3條特別條目:GC, System and ExternalCode。GC 表示記憶體記憶體回收的時間花費,見下面的記憶體分析器和垃圾收集器跟蹤最佳化建議部分。System 表示 goroutine 調度花費的時間,堆棧管理代碼以及其他輔助的 runtime 代碼。ExternalCode 表示本地動態庫花費的時間。
這裡有些提示關於如何解釋說明你在 profile 中看到的資訊。
如果很多時間花費在 runtime.mallocgc 函數,程式可能在小記憶體配置上面花費過多。 profile 會告訴你分配從哪裡來,看記憶體分析器建議如何最佳化的部分。
如果很多時間花費在 channel 操作部分,sync.Mutex 代碼和其他 synchronization primitives或者是系統組件,程式可能在承受資源競爭。考慮重構程式,以消除對共用資源的頻繁訪問。常見的技術包括分區、分區,本地緩衝/批量處理和寫時拷貝技術。
如果很多時間花費在 syscall.Read/Write 上面,程式可能在小讀寫上面花費代價太大。Bufio 封裝 os.File 或是 net.Conn 能對這種情況有協助。
如果很多時間花費在 GC 組件上面,程式不是分配了太多的臨時對象就是 heap size 設定過小導致記憶體回收頻繁發生。請看垃圾收集器跟蹤和記憶體分析器最佳化建議部分。
注意: CPU profiler 目前不能在 darwin 上工作
注意: 在 windows 伺服器上你需要安裝 Cygwin, Perl and Graphviz 來產生 svg/web 格式的概要檔案
注意: 在 Linux 上你可以嘗試 perf system profiler,它不能解鎖 GO 的堆棧,但是它能分析並且解鎖 cgo/SWIG 代碼和核心。所以它在定位分析本地/核心效能瓶頸上非常有用。