Go 程序的性能調試問題 - CPU 篇

注:本文的原文 Debugging performance issues in Go programsDmitry Vyukov 在 05/10/2014 - 07:06 編寫
注:原文太長,你們要看所有的請看原文,其餘的部分,後續慢慢翻譯。php

讓咱們假設你想提高你的GO程序的性能。這裏有一些工具能夠幫助你完成這個任務。這些工具能幫助你定位多種類型的熱點(CPU,IO,內存),你爲了可以顯著提高程序性能,你必須專一於熱點發生的地方。儘管如此,另一個結果是可能的--這些工具能幫助你肯定程序中明顯的性能缺陷。例如,當你在每一個程序啓動的時候,你能夠在每次查詢的以前準備一個 SQL 語句。另一個例子是若是一個 O(N^2) 算法在某種程度上陷入了一個明顯存在而且指望的 O(N) 狀況。爲了肯定這樣的狀況,你須要完整性的檢查你在 profiles 中看到的。例如第一種狀況下大量的時間花費在 SQL 語句的準備上,這已經超越了告警線了。html

一樣重要的是要理解性能影響的各類邊界因素。例如,一個程序經過 100 Mbps 的帶寬鏈接通信,而且它已經使用超過 90 Mbps,這裏就沒有什麼能夠對這程序作的來提高它的性能了。這些相似的邊界因素包括 磁盤 IO,內存消耗和計算任務。golang

考慮到這一點,咱們能夠查看這些可用的工具。web

注意:這些工具可能相互干擾,例如,精確的內存分析可能影響CPU分析。goroutine 阻塞分析可能影響調度追蹤等等,隔離地使用這些工具以便獲得更加精確的信息。算法

注意:這裏全部的描述都是基於 Go1.3 版本的windows

CPU 分析器

Go runtime 包含了內建的 CPU 分析器,這顯示了函數消耗的 CPU 時間百分比,這裏你有3種方式訪問它:服務器

  1. 最簡單的一個方式是使用 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 來獲得最完整的列表。
    這個選項最明顯的特色就是它只適用於測試。
  2. net/http/pprof 包。這是網絡服務的理想解決方案。你僅僅只須要 import net/http/pprof 而且用以下命令收集概要文件:
$ go tool pprof --text mybin http://myserver:6060:/debug/pprof/profile
  1. 手工配置收集。你須要 import runtime/pprof 而且 把以下代碼加入 main 函數中:
if *flagCpuprofile != "" {
    f, err := os.Create(*flagCpuprofile)
    if err != nil {
        log.Fatal(err)
    }
    pprof.StartCPUProfile(f)
    defer pprof.StopCPUProfile()
}

這份概要文件會被寫入指定的文件中,想象它和第一個選項同樣的命令行方式。網絡

這裏是一個使用 --web 選項產生的直觀的概要文件示例:
此處輸入圖片的描述app

你可使用 -list=funcname 選項來研究單個函數,下面的 概要文件顯示了在 append 函數中所花費的時間:svg

.      .   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 代碼和內核。因此它在定位分析本地/內核性能瓶頸上很是有用。

相關文章
相關標籤/搜索