http://yangxikun.github.io/linux%E6%80%A7%E8%83%BD%E5%88%86%E6%9E%90/2016/09/24/flame-graph.html
火焰圖的分類
壓測程序時,火焰圖能夠幫助我們直觀地瞭解到程序的性能瓶頸。本文主要是記錄下在生成火焰圖的時候的一些注意事項。以下鏈接是對每個類別的火焰圖的詳細說明。
- On-CPU:CPU Flame Graphs
- Off-CPU:Off-CPU Flame Graphs
- Memory:Memory Leak (and Growth) Flame Graphs
- Hot/Cold:Hot/Cold Flame Graphs
- Differential:Differential Flame Graphs
關於火焰圖的PPT(講解得非常詳細):Blazing Performance with Flame Graphs
如何生成火焰圖
首先是需要在程序運行時,對其進行採樣。linux下常用的有perf和systemtap,我這裏用了systemtap來做實驗,因爲已經牛人寫好了一些systemtap相應的腳本可以直接拿來用了:nginx-systemtap-toolkit。
systemtap依賴的安裝:
1、CentOS
shell> yum install yum-utils
shell> yum install kernel-devel
shell> debuginfo-install kernel
shell> yum install systemtap
在執行debuginfo-install
kernel
的時候,沒能安裝成功,於是就直接到http://debuginfo.centos.org/7下載相應的包手動安裝了。
2、Debian
shell> apt-get install systemtap linux-image-`uname -r`-dbg linux-headers-`uname -r`
systemtap的工作原理:
systemtap腳本——>翻譯爲C程序——>編譯爲內核模塊——>安裝到內核上運行,開始採樣——>結束採樣,從內核卸載
我用nginx-systemtap-toolkit提供的兩個perl腳本(它們會根據參數生成相應的systemtap腳本並執行)做了實驗:
- sample-bt:用來生成 On-CPU 火焰圖的採樣數據
- sample-bt-off-cpu:用來生成 Off-CPU 火焰圖的採樣數據
注意事項:
1、普通用戶身份無法執行systemtap。
2、什麼時候開始採樣?
當執行sample-bt
-p 50417 -t 5 -u > sample.bt
的時候,需要等到輸出類似Tracing
pid (exec_path) in kernel|user -space...
的時候才真正開始採樣。可以爲sample-bt加多一個參數-a
'-vv'
就可以看到一些debug輸出。
3、理解On-CPU採樣的工作原理
原理是定時地判斷當前cpu上運行的進程是否爲要採樣的進程,如果是的話就根據設置的採樣點進行採樣。
如果被採樣的進程一直處於就緒狀態,沒有被調度執行,那麼你將會看到sample-bt的輸出如下面這樣:
爲何沒有停止呢?這就需要從sample-bt生成的systemtap腳本看看有沒什麼線索了:
執行sample-bt
-p 114356 -t 5 -u -a '-vv' -d
,這裏多加了一個-d
參數,讓sample-bt輸出生成的systemtap腳本:
/*
target()是systemtap的函數庫Tapset提供的,用於獲取當前採樣的進程pid
*/
probe begin {
warn(sprintf("Tracing %d (/usr/sbin/mysqld) in user-space only...\n", target()))
}
global bts;
global quit = 0;
probe timer.profile {//每個一段時間被調用一次
if (pid() == target()) {//當前運行的進程與被採樣的進程是否爲同一個
if (!quit) {
bts[ubacktrace()] <<< 1;
} else {
//採樣停止
foreach (bt in bts- limit 1024) {
print_ustack(bt);
printf("\t%d\n", @count(bts[bt]));
}
exit()
}
}
}
probe timer.s(5) {//5秒後執行
nstacks = 0
foreach (bt in bts limit 1) {
nstacks++
}
if (nstacks == 0) {//沒采樣到數據直接退出
warn("No backtraces found. Quitting now...\n")
exit()
} else {//採樣到數據了,設置停止標誌
warn("Time's up. Quitting now...(it may take a while)\n")
quit = 1
}
}
所以上圖中重複的輸出了Time's
up. Quitting now...(it may take a while)
是因爲開始採樣後,timer.profile採樣到數據,timer.s設置了停止標誌之後,在timer.profile執行時一直沒遇到被採樣的進程被調度執行。此時只需要讓這個進程被調度執行就行了,比如:如果該進程是一個服務,可以發送個請求給它。
對於Off-CPU採樣的工作原理,同樣可以使用sample-bt-off-cpu
-a '-vv' -u -p 114356 -t 5 -d
查看生成的systemtap腳本。
生成火焰圖的步驟:
- 採樣:
sample-bt -p 92869 -t 10 -u -a '-vv' > a.bt
- 轉化爲火焰圖:
stackcollapse-stap.pl a.bt > a.cbt;flamegraph.pl a.cbt > a.svg
測試時生成的一個On-CPU的圖片,從圖中可看出頻繁的tcp connect和close是目前的瓶頸之一: