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

Linux主要的性能有哪些?

基于RV1126開發(fā)板的火焰檢測(cè)算法開發(fā)

BNC接頭技術(shù)原理與工程應(yīng)用剖析:從結(jié)構(gòu)到性能優(yōu)化

思特威推出高性能智能交通應(yīng)用全局快門圖像傳感器產(chǎn)品
多光譜火焰檢測(cè)攝像頭

使用Arthas火焰圖工具的Java應(yīng)用性能分析和優(yōu)化經(jīng)驗(yàn)

迅為瑞芯微RK3588開發(fā)板深度剖析丨首選的性能
如何優(yōu)化Linux服務(wù)器的性能
迅為RK3588開發(fā)板深度剖析丨首選的性能
Linux服務(wù)器性能查看方法
探索巔峰性能 |迅為 RK3588開發(fā)板深度剖析
多光譜火焰智能監(jiān)測(cè)攝像機(jī)

評(píng)論