火焰圖(Flame Graphs)
一、概述:
火焰圖(flame graph)是性能分析的利器,通過它可以快速定位性能瓶頸點。
perf 命令(performance 的縮寫)是 Linux 系統原生提供的性能分析工具,會返回 CPU 正在執行的函數名以及調用棧(stack)。
本文介紹它的安裝和基本用法。
二、安裝perf和可視化生成器
# yum install perf -y //yum方式安裝perf
# git clone https://github.com/brendangregg/FlameGraph.git //選擇好火焰圖文件存放路徑后執行該條命令,從github上獲取火焰圖的相關文件,獲取完成后會有一個FlameGraph的文件夾,如下圖
說明:打開文件夾,里面大部分是perf語言寫的腳本,生成火焰圖后續會用到,如下圖,右圖為各pl文件用途釋義
到此,安裝完成。
三、perf 采集數據
# perf record -F 99 -a -g -- sleep 60 //對CPU所有進程以99Hz采集,它的執行頻率是 99Hz(每秒99次),如果99次都返回同一個函數名,那就說明 CPU 這一秒鍾都在執行同一個函數,可能存在性能問題。執行60秒后會彈出如下圖提示表示采集完成,在當前目錄會生成一個perf.data的文件


# perf record -F 99 -p 181 -g -- sleep 60 //對進程ID為181的進程進行采集,采集時間為60秒,執行期間不要退出
上述代碼中perf record
表示記錄,-F 99
表示每秒99次,-p 13204
是進程號,即對哪個進程進行分析,-g
表示記錄調用棧,sleep 30
則是持續30秒,-a 表示記錄所有cpu調用。更多參數可以執行perf --help查看。
perf.data文件生成后,表示采集完成。最好是在火焰圖的目錄下進行采集,方便轉換成SVG圖形。
四、生成火焰圖
# perf script -i perf.data &> perf.unfold //生成腳本文件
# ./FlameGraph/stackcollapse-perf.pl perf.unfold &> perf.folded
# ./FlameGraph/flamegraph.pl perf.folded > perf.svg //執行完成后生成perf.svg圖片,可以下載到本地,用瀏覽器打開 perf.svg,如下圖
五、火焰圖的含義
火焰圖是基於 perf 結果產生的 SVG 圖片,用來展示 CPU 的調用棧。
y 軸表示調用棧,每一層都是一個函數。調用棧越深,火焰就越高,頂部就是正在執行的函數,下方都是它的父函數。
x 軸表示抽樣數,如果一個函數在 x 軸占據的寬度越寬,就表示它被抽到的次數多,即執行的時間長。注意,x 軸不代表時間,而是所有的調用棧合並后,按字母順序排列的。
火焰圖就是看頂層的哪個函數占據的寬度最大。只要有"平頂"(plateaus),就表示該函數可能存在性能問題。
顏色沒有特殊含義,因為火焰圖表示的是 CPU 的繁忙程度,所以一般選擇暖色調。
六、互動性
火焰圖是 SVG 圖片,可以與用戶互動。
(1)鼠標懸浮
火焰的每一層都會標注函數名,鼠標懸浮時會顯示完整的函數名、抽樣抽中的次數、占據總抽樣次數的百分比。下面是一個例子。
mysqld'JOIN::exec (272,959 samples, 78.34 percent)
(2)點擊放大
在某一層點擊,火焰圖會水平放大,該層會占據所有寬度,顯示詳細信息。
左上角會同時顯示"Reset Zoom",點擊該鏈接,圖片就會恢復原樣。
(3)搜索
按下 Ctrl + F 會顯示一個搜索框,用戶可以輸入關鍵詞或正則表達式,所有符合條件的函數名會高亮顯示。
七、火焰圖示例
下面是一個簡化的火焰圖例子。
首先,CPU 抽樣得到了三個調用棧。
func_c func_b func_a start_thread func_d func_a start_thread func_d func_a start_thread
上面代碼中,start_thread
是啟動線程,調用了func_a
。后者又調用了func_b
和func_d
,而func_b
又調用了func_c
。
經過合並處理后,得到了下面的結果,即存在兩個調用棧,第一個調用棧抽中1次,第二個抽中2次。
start_thread;func_a;func_b;func_c 1 start_thread;func_a;func_d 2
有了這個調用棧統計,火焰圖工具就能生成 SVG 圖片。
上面圖片中,最頂層的函數g()
占用 CPU 時間最多。d()
的寬度最大,但是它直接耗用 CPU 的部分很少。b()
和c()
沒有直接消耗 CPU。因此,如果要調查性能問題,首先應該調查g()
,其次是i()
。
另外,從圖中可知a()
有兩個分支b()
和h()
,這表明a()
里面可能有一個條件語句,而b()
分支消耗的 CPU 大大高於h()
。
八、局限
兩種情況下,無法畫出火焰圖,需要修正系統行為。
(1)調用棧不完整
當調用棧過深時,某些系統只返回前面的一部分(比如前10層)。
(2)函數名缺失
有些函數沒有名字,編譯器只用內存地址來表示(比如匿名函數)。
九、常見應用的火焰圖
Node 應用的火焰圖
Node 應用的火焰圖就是對 Node 進程進行性能抽樣,與其他應用的操作是一樣的。
$ perf record -F 99 -p `pgrep -n node` -g -- sleep 30
詳細的操作可以看這篇文章。
Chrome 瀏覽器的火焰圖
Chrome 瀏覽器可以生成頁面腳本的火焰圖,用來進行 CPU 分析。
打開開發者工具,切換到 Performance 面板。然后,點擊"錄制"按鈕,開始記錄數據。這時,可以在頁面進行各種操作,然后停止"錄制"。
這時,開發者工具會顯示一個時間軸。它的下方就是火焰圖。
瀏覽器的火焰圖與標准火焰圖有兩點差異:它是倒置的(即調用棧最頂端的函數在最下方);x 軸是時間軸,而不是抽樣次數。
參考資料:
https://github.com/brendangregg/FlameGraph
http://www.brendangregg.com/flamegraphs.html
https://www.jianshu.com/p/492218c163d9
http://www.ruanyifeng.com/blog/2017/09/flame-graph.html
--------------------------------------------------------------------------------------------------------------------------------------------------------
歡迎從事性能測試的小伙伴加入性能測試Q群: