使用火焰圖分析CPU性能回退問題

jopen 9年前發布 | 27K 次閱讀 CPU

你能快速定位CPU性能回退的問題么? 如果你的工作環境非常復雜且變化快速,那么使用現有的工具是來定位這類問題是很具有挑戰性的。當你花掉數周時間把根因找到時,代碼已經又變更了好幾輪,新的性能問題又冒了出來。

幸虧有了CPU火焰圖(flame graphs),CPU使用率的問題一般都比較好定位。但要處理性能回退問題,就要在修改前后的火焰圖之間,不斷切換對比,來找出問題所在,這感覺就是像在太陽系中搜尋冥王星。雖然,這種方法可以解決問題,但我覺得應該會有更好的辦法。

使用火焰圖分析CPU性能回退問題

所以,下面就隆重介紹紅/藍差分火焰圖(red/blue differential flame graphs)

上面是一副交互式SVG格式圖片(鏈接)。圖中使用了兩種顏色來表示狀態,紅色表示增長藍色表示衰減

這張火焰圖中各火焰的形狀和大小都是和第二次抓取的profile文件對應的CPU火焰圖是相同的。(其中,y軸表示棧的深度,x軸表示樣本的總數,棧幀的寬度表示了profile文件中該函數出現的比例,最頂層表示正在運行的函數,再往下就是調用它的棧)

在下面這個案例展示了,在系統升級后,一個工作載荷的CPU使用率上升了。 下面是對應的CPU火焰圖(SVG格式

通常,在標準的火焰圖中棧幀和棧塔的顏色是隨機選擇的。 而在紅/藍差分火焰圖中,使用不同的顏色來表示兩個profile文件中的差異部分。

在第二個profile中deflate_slow()函數以及它后續調用的函數運行的次數要比前一次更多,所以在上圖中這個棧幀被標為了紅色。可以看出問題的原因是ZFS的壓縮功能被啟用了,而在系統升級前這項功能是關閉的。

這個例子過于簡單,我甚至可以不用差分火焰圖也能分析出來。但想象一下,如果是在分析一個微小的性能下降,比如說小于5%,而且代碼也更加復雜的時候,問題就為那么好處理了。

紅/藍差分火焰圖

這個事情我已經討論了好幾年了,最終我自己編寫了一個我個人認為有價值的實現。它的工作原理是這樣的:

  1. 抓取修改前的堆棧profile1文件
  2. 抓取修改后的堆棧profile2文件
  3. 使用profile2來生成火焰圖。(這樣棧幀的寬度就是以profile2文件為基準的)
  4. 使用“2 - 1”的差異來對火焰圖重新上色。上色的原則是,如果棧幀在profile2中出現出現的次數更多,則標為紅色,否則標為藍色。色彩是根據修改前后的差異來填充的。

這樣做的目的是,同時使用了修改前后的profile文件進行對比,在進行功能驗證測試或者評估代碼修改對性能的影響時,會非常有用。新的火焰圖是基于修改后的profile文件生成(所以棧幀的寬度仍然顯示了當前的CPU消耗),通過顏色的對比,就可以了解到系統性能差異的原因。

只有對性能產生直接影響的函數才會標注顏色(比如說,正在運行的函數),它所調用的子函數不會重復標注。

生成紅/藍差分火焰圖

我已經把一個簡單的代碼實現推送到github上(見火焰圖),其中新增了一個程序腳本,difffolded.pl。為了展示工具是如何工作的,用Linux perf_events 來演示一下操作步驟。(你也可以使用其他profiler)

抓取修改前的profile 1文件:

# perf record -F 99 -a -g -- sleep 30
# perf script > out.stacks1

一段時間后 (或者程序代碼修改后), 抓取profile 2文件:

# perf record -F 99 -a -g -- sleep 30
# perf script > out.stacks2

現在將 profile 文件進行折疊(fold), 再生成差分火焰圖:

$ git clone --depth 1 http://github.com/brendangregg/FlameGraph
$ cd FlameGraph
$ ./stackcollapse-perf.pl ../out.stacks1 > out.folded1
$ ./stackcollapse-perf.pl ../out.stacks2 > out.folded2
$ ./difffolded.pl out.folded1 out.folded2 | ./flamegraph.pl > diff2.svg

difffolded.p只能對“折疊”過的堆棧profile文件進行操作,折疊操作是由前面的stackcollapse系列腳本完成的。(見鏈接火焰圖)。 腳本共輸出3列數據,其中一列代表折疊的調用棧,另兩列為修改前后profile文件的統計數據。

func_a;func_b;func_c 31 33
[...]

在上面的例子中"funca()->funcb()->func_c()" 代表調用棧,這個調用棧在profile1文件中共出現了31次,在profile2文件中共出現了33次。然后,使用flamegraph.pl腳本處理這3列數據,會自動生成一張紅/藍差分火焰圖。

其他選項

再介紹一些有用的選項:

difffolded.pl -n:這個選項會把兩個profile文件中的數據規范化,使其能相互匹配上。如果你不這樣做,抓取到所有棧的統計值肯定會不相同,因為抓取的時間和CPU負載都不同。這樣的話,看上去要么就是一片紅(負載增加),要么就是一片藍(負載下降)。-n選項對第一個profile文件進行了平衡,這樣你就可以得到完整紅/藍圖譜。

difffolded.pl -x: 這個選項會把16進制的地址刪掉。 profiler時常會無法將地址轉換為符號,這樣的話棧里就會有16進制地址。如果這個地址在兩個profile文件中不同,這兩個棧就會認為是不同的棧,而實際上它們是相同的。遇到這樣的問題就用-x選項搞定。

flamegraph.pl --negate: 用于顛倒紅/藍配色。 在下面的章節中,會用到這個功能。

不足之處

雖然我的紅/藍差分火焰圖很有用,但實際上還是有一個問題:如果一個代碼執行路徑完全消失了,那么在火焰圖中就找不到地方來標注藍色。你只能看到當前的CPU使用情況,而不知道為什么會變成這樣。

一個辦法是,將對比順序顛倒,畫一個相反的差分火焰圖。例如:

上面的火焰圖是以修改前的profile文件為基準,顏色表達了將要發生的情況。右邊使用藍色高亮顯示的部分,從中可以看出修改后CPU Idle消耗的CPU時間會變少。(其實,我通常會把cpuidle給過濾掉,使用命令行grep -v cpuidle)

圖中把消失的代碼也突顯了出來(或者應該是說,沒有突顯),因為修改前并沒有使能壓縮功能,所以它沒有出現在修改前的profile文件了,也就沒有了被表為紅色的部分。

下面是對應的命令行:

$ ./difffolded.pl out.folded2 out.folded1 | ./flamegraph.pl --negate > diff1.svg

這樣,把前面生成diff2.svg一并使用,我們就能得到:

  • diff1.svg: 寬度是以修改前profile文件為基準,顏色表明將要發生的情況
  • diff2.svg: 寬度是以修改后profile文件為基準,顏色表明已經發生的情況

如果是在做功能驗證測試,我會同時生成這兩張圖。

CPI 火焰圖

這些腳本開始是被使用在CPI火焰圖的分析上。與比較修改前后的profile文件不同,在分析CPI火焰圖時,可以分析CPU工作周期與停頓周期的差異變化,這樣可以凸顯出CPU的工作狀態來。

其他的差分火焰圖

也有其他人做過類似的工作。Robert Mustacchi在不久前也做了一些嘗試,他使用的方法類似于代碼檢視時的標色風格:只顯示了差異的部分,紅色表示新增(上升)的代碼路徑,藍色表示刪除(下降)的代碼路徑。一個關鍵的差別是棧幀的寬度只體現了差異的樣本數。右邊是一個例子。這個是個很好的主意,但在實際使用中會感覺有點奇怪,因為缺失了完整profile文件的上下文作為背景,這張圖顯得有些難以理解。

Cor-Paul Bezemer也制作了一種差分顯示方法flamegraphdiff,他同時將3張火焰圖放在同一張圖中,修改前后的標準火焰圖各一張,下面再補充了一張差分火焰圖,但棧幀寬度也是差異的樣本數。 上圖是一個例子。在差分圖中將鼠標移到棧幀上,3張圖中同一棧幀都會被高亮顯示。這種方法中補充了兩張標準的火焰圖,因此解決了上下文的問題。

我們3人的差分火焰圖,都各有所長。三者可以結合起來使用:Cor-Paul方法中上方的兩張圖,可以用我的diff1.svg 和 diff2.svg。下方的火焰圖可以用Robert的方式。為保持一致性,下方的火焰圖可以用我的著色方式:藍->白->紅。

火焰圖正在廣泛傳播中,現在很多公司都在使用它。如果大家知道有其他的實現差分火焰圖的方式,我也不會感到驚訝。(請在評論中告訴我)

結論

如果你遇到了性能回退問題,紅/藍差分火焰圖是找到根因的最快方式。這種方式抓取了兩張普通的火焰圖,然后進行對比,并對差異部分進行標色:紅色表示上升,藍色表示下降。 差分火焰圖是以當前(“修改后”)的profile文件作為基準,形狀和大小都保持不變。因此你通過色彩的差異就能夠很直觀的找到差異部分,且可以看出為什么會有這樣的差異。

差分火焰圖可以應用到項目的每日構建中,這樣性能回退的問題就可以及時地被發現和修正。


via: http://www.brendangregg.com/blog/2014-11-09/differential-flame-graphs.html

作者:Brendan Gregg 譯者:coloka 校對:wxy

本文由 LCTT 原創翻譯,Linux中國 榮譽推出

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!