[Linux/C++] 使用 valgrind 找出程式的效能瓶頸,再用 gprof2dot 將執行歷程視覺化

[Linux/C++] 使用 valgrind 找出程式的效能瓶頸,再用 gprof2dot 將執行歷程視覺化

最近在查一個問題,我用了 lib7zip 來處理壓縮檔,

lib7zip 又會去使用 p7zip,原本運作的很正常,

但是如果遇到壓縮檔裡有許多檔案時,效能就變很差,

可是單獨跑 p7zip 附的 CLI (7z) 又沒問題…

 

嘗試修改自己程式裡的一些地方,看看對效能有無影響,

但似乎都打不中痛處,看來只能請出工具了~

用 valgrind 裡的 callgrind 功能,可以將程式內部執行函式的時間與次數都列出來,

這樣就比較容易查出來問題在哪了~

 

1. 用 valgrind 監測程式的執行歷程與時間

語法是 valgrind –tool=callgrind 程式名稱 參數…

舉例來說:

valgrind --tool=callgrind ./my7zipExtractor test.7z

 

跟平常用 valgrind 偵測 memory leak 類似,

程式會跑比較慢,因此要有點耐心…

等程式結束後,會產生 callgrind.out.<pid> 這類的檔案~

 

如果程式真的跑太久的話,其實還是可以按 Ctrl-C 中斷 valgrind,

valgrind 一樣會將已經收集到的資料輸出到 callgrind.out.<pid>。

如果程式已經有執行到效能瓶頸的位置的話,資訊還是很有參考價值的~

 

2. 用 gprof2dot 和 dot 將 callgrind 結果轉為圖片

可以用 gprof2dot 指令,將 callgrind.out 轉成 dot 格式,

再用 dot 指令,將 dot 格式檔轉成常見的影像檔格式 (如 PNG)。

這兩個指令還可以串接起來,省掉產生出 .dot 檔案這項工作。

(在 Mac 上可以直接用 brew install gprof2dot 安裝 gprof2dot)

 

舉例來說,下面這個指令會將 valgrind 輸出的 callgrind.out 檔案,

直接轉成 callgrind.png 影像檔:

gprof2dot -f callgrind callgrind.out | dot -Tpng -o callgrind.png

 

3. 比較不同狀況下的程式執行歷程

有了 PNG 檔之後,就可以來研究效能瓶頸究竟在哪了~

但有時候單靠出問題的程式產生出來的圖,不容易看出問題在哪,

這時可以再跑沒問題的程式,也產生 callgrind 圖片,

兩相比較之下,就會比較容易看出不同點了~

 

舉例來說,我將自己的程式,與執行 7z 的結果都產生出 callgrind 圖,

再用 macOS Sierra 提供的分割畫面來比較兩張圖

(用 Preview 分別開兩張圖,再長按視窗最大化鈕,

就會將目前視窗放在左半邊,這時再去選要放在右半邊的視窗),

可以看到上面四個區塊是一樣的,但後來執行的路徑不同了:

 

在這個例子裡,不同的執行路徑有可能是造成效能瓶頸的原因之一~

不過再仔細檢查,箭頭上面的數字也是很重要的資訊:

在有問題的程式裡,CodeSpec() 這個函式被呼叫了 816 次,

總共花了全部執行時間的 84.9%;

在沒問題的程式裡,CodeSpec() 函式只被呼叫了 6 次左右:

 

再去查看被呼叫很多次的函式內容,發現可能是 p7zip 設計與實作上的問題~

如果一次將壓縮檔全解開的話,很快~

但若一次一個檔案解壓縮,雖然最終一樣是將所有的檔案解出來,

但中間的歷程就會很久,因為實作上 p7zip 會需要將待解檔案的前面的檔案,

都先全部解出來,才有辦法解開待解的檔案:

  • 要解第 1 個檔案:解出檔案 1 的內容
  • 要解第 2 個檔案:解出檔案 1 和 2 的內容
  • 要解第 N 個檔案:解出檔案 1, 2, … N 的內容

這個實作的時間複雜度會是 1+2+3+…+N,也就是 O(N^2),效能很差~

找出問題的話,要修正或 workaround 掉問題,就會比較有機會了~

 

這次學到了用 valgrind 搭配 gprof2dot/dot,找出了執行很慢的原因。

感覺很不錯,以後可以好好運用這個技巧囉~

 

參考資料:

stackoverflow: How can I profile C++ code running in Linux?

stackoverflow: Interpreting callgrind data

 

(本頁面已被瀏覽過 955 次)

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料