什么是火焰圖
火焰圖(Flame Graph)是由Linux性能優化大師Brendan Gregg發明的,和所有其他的trace和profiling方法不同的是,Flame Graph以一個全局的視野來看待時間分布,它從底部往頂部,列出所有可能的調用棧。其他的呈現方法,一般只能列出單一的調用?;蛘叻菍哟位臅r間分布。
我最快樂的童年時代,每逢冬天,尤其是春節的時候,和一家人圍坐在火堆旁邊烤火。這已經成為最美好的回憶,其實人生追求的快樂非常簡單?;鹧鎴D的火焰首先來自于根,然后以火苗的形式往上面竄??梢园褟目拷孛娴母巾斏系拿總€火苗,想想成一個調用棧。由于火苗有很多根,這正好也和現實生活中程序的執行邏輯相似。
以典型的分析CPU時間花費到哪個函數的on-cpu火焰圖為例來展開。
CPU火焰圖中的每一個方框是一個函數,方框的長度,代表了它的執行時間,所以越寬的函數,執行越久。火焰圖的樓層每高一層,就是更深一級的函數被調用,最頂層的函數,是葉子函數。
火焰圖的生成過程是:
先trace系統,獲取系統的profiling數據
用腳本來繪制
系統的profiling數據獲取,可以選擇最流行的perf record,而后把采集的數據進行加工處理,繪制為火焰圖。其中第二步的繪制火焰圖的腳本程序,通過如下方式獲取:
gitclone https://github.com/brendangregg/FlameGraph
火焰圖案例
廢話不多說,直接從最簡單的例子開始說起。talk is cheap, show you the cde,代碼如下:
c()
{
for(int i=0;i<1000;i++);
}
b()
{
for(int i=0;i<1000;i++);
c();
}
a()
{
for(int i=0;i<1000;i++);
b();
}
則這三個函數,在火焰圖中呈現的樣子為:
a()的2/3的時間花在b()上面,而b()的1/3的時間花在c()上面。很多個這樣的a->b->c的火苗堆在一起,就構成了火焰圖。
進一步理解火焰圖的最好方法仍然是通過一個實際的案例,下面的程序創建2個線程,兩個線程的handler都是thread_fun(),之后thread_fun()調用fun_a()、fun_b()、fun_c(),而fun_a()又會調用fun_d():
/*
* One example to demo flamegraph
*
* Copyright (c) Barry Song
*
* Licensed under GPLv2
*/
#include
func_d()
{
int i;
for(i=0;i<50000;i++);
}
func_a()
{
int i;
for(i=0;i<100000;i++);
func_d();
}
func_b()
{
int i;
for(i=0;i<200000;i++);
}
func_c()
{
int i;
for(i=0;i<300000;i++);
}
void* thread_fun(void* param)
{
while(1) {
int i;
for(i=0;i<100000;i++);
func_a();
func_b();
func_c();
}
}
int main(void)
{
pthread_t tid1,tid2;
int ret;
ret=pthread_create(&tid1,NULL,thread_fun,NULL);
if(ret==-1){
...
}
ret=pthread_create(&tid2,NULL,thread_fun,NULL);
...
if(pthread_join(tid1,NULL)!=0){
...
}
if(pthread_join(tid2,NULL)!=0){
...
}
return 0;
}
先看看不用火焰圖的缺點在哪里。
如果不用火焰圖,我們也可以用類似perf top這樣的工具分析出來CPU時間主要花費在哪里了:
$gcc exam.c -pthread
$./a.out&
$sudo perf top
perf top的顯示結果如下:
perf top提示出來了fun_a()、fun_b()、fun_c(), fun_d(),thread_func()這些函數內部的代碼是CPU消耗大戶,但是它缺乏一個全局的視野,我們無法看出全局的調用棧,也弄不清楚這些函數之間的關系?;鹧鎴D則不然,我們用下面的命令可以生成火焰圖(以root權限運行):
perf record -F 99 -a -g -- sleep 60
perf script | ./stackcollapse-perf.pl > out.perf-folded
./flamegraph.pl out.perf-folded > perf-kernel.svg
上述程序捕獲系統的行為60秒鐘,最后調用flamegraph.pl生成一個火焰圖perf-kernel.svg,用看圖片的工具就可以打開這個svg。
上述火焰圖顯示出了a.out中,thread_func()、func_a()、func_b()、fun_c()和func_d()的時間分布。
從上述火焰圖可以看出,雖然thread_func()被兩個線程調用,但是由于thread_func()之前的調用棧是一樣的,所以2個線程的thread_func()調用是合并為同一個方框的。
更深閱讀
除了on-cpu的火焰圖以外,off-cpu的火焰圖,對于分析系統堵在IO、SWAP、取得鎖方面的幫助很大,有利于分析系統在運行的時候究竟在等待什么,系統資源之間的彼此伊伴。
比如,下面的火焰圖顯示,nginx的吞吐能力上不來的很多程度原因在于sem_wait()等待信號量。
上圖摘自Yichun Zhang (agentzh)的《Introduction to offCPU Time Flame Graphs》。
關于火焰圖的更多細節和更多種火焰圖各自的功能,可以訪問:
http://www.brendangregg.com/flamegraphs.html
-
Linux
+關注
關注
87文章
11229瀏覽量
208927 -
函數
+關注
關注
3文章
4306瀏覽量
62431
原文標題:火焰圖:全局視野的Linux性能剖析
文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論