目錄
1、Perf介紹
2、火焰圖分類
?(1)CPU
?(2)Memory Flame Graphs
?(3)Off-CPU Flame Graphs
?(4)Hot/Cold Flame Graphs
?(5)Differential
?3、火焰圖安裝命令
(1)安裝Perf工具
(2)下載可視化工具FlameGraph
?4、火焰圖demo測試
(1)生成CPU火焰圖1
(2)火焰圖表解析
(3)當(dāng)前程序圖標(biāo)分析
a> 入口函數(shù)地址確定
b> 獲取對應(yīng)地址入口函數(shù)
?(4)生成火焰圖2
?(5)生成差分火焰圖
1、Perf介紹
perf是Linux下的一款性能分析工具,能夠進(jìn)行函數(shù)級與指令級的熱點查找。它由一個叫“Performance counters“的內(nèi)核子系統(tǒng)實現(xiàn),基于事件采樣原理,以性能事件為基礎(chǔ),支持針對處理器相關(guān)性能指標(biāo)與操作系統(tǒng)相關(guān)性能指標(biāo)的性能剖析,可用于性能瓶頸的查找與熱點代碼的定位。
Perf的主要功能和用途如下:
-
事件采樣:Perf使用硬件性能計數(shù)器來采樣事件,如CPU指令、緩存命中、緩存失效等,從而獲取系統(tǒng)在運行時的性能數(shù)據(jù)。
-
調(diào)用圖:Perf可以生成函數(shù)調(diào)用圖,顯示函數(shù)之間的調(diào)用關(guān)系和耗時,幫助識別程序的熱點和性能瓶頸。
-
火焰圖:火焰圖是Perf輸出的一種可視化圖表,它可以直觀地展示函數(shù)調(diào)用的耗時情況和函數(shù)的調(diào)用關(guān)系,以便快速準(zhǔn)確地識別最頻繁的代碼路徑,幫助快速定位性能瓶頸。
-
內(nèi)存分析:Perf可以收集內(nèi)存事件,如內(nèi)存訪問、缺頁異常等,幫助識別內(nèi)存性能問題。
-
鎖分析:Perf可以監(jiān)測鎖的使用情況,幫助發(fā)現(xiàn)多線程程序中的競爭問題。
-
Tracing支持:Perf支持Linux Trace Toolkit Next Generation (LTTng)和eBPF等跟蹤工具,用于深入分析系統(tǒng)的行為。
-
報告生成:Perf能夠生成詳細(xì)的報告和統(tǒng)計信息,方便用戶理解和分析性能數(shù)據(jù)。
2、火焰圖分類
(1)CPU
用途:檢測導(dǎo)致CPU運行繁忙的原因。
(2)Memory Flame Graphs
用途:檢測應(yīng)用程序內(nèi)存使用量增加的原因。
?(3)Off-CPU Flame Graphs
用途:有些性能問題不是CPU的性能問題,即進(jìn)程和線程不在CPU上運行時花費角度的時間,而是在程序請求期間花費了不少時間,這種情況也會成比例的影響性能。
?(4)Hot/Cold Flame Graphs
用途:將CPU和非CPU火焰圖結(jié)合在一起。它在一個圖表中顯示了所有線程的運行時間,并允許直接比較在CPU和非CPU上的代碼路徑持續(xù)時間。
?(5)Differential
? ? ? ?用途:紅藍(lán)差異火焰圖,分析不同時刻CPU性能變化的原因。
?3、火焰圖安裝命令
(1)安裝Perf工具
$ sudo apt-get install linux-tools-$(uname -r) linux-tools-generic -y //下載Perf
$ perf -v //查看安裝Perf的版本
(2)下載可視化工具FlameGraph
下載地址:GitHub - brendangregg/FlameGraph: Stack trace visualizer
?4、火焰圖demo測試
測試程序如下:
#include <stdio.h>
#define DEF_PRINT
void funcA()
{
for(int i=0; i < 10*10000;i++)
{
#ifdef DEF_PRINT
printf("funcA\n");
#endif
}
}
void funcB()
{
for(int i=0; i < 20*10000;i++)
{
#ifdef DEF_PRINT
printf("funcB\n");
#endif
}
}
void funcC()
{
for(int i=0; i < 30*10000;i++)
{
#ifdef DEF_PRINT
printf("funcC\n");
#endif
}
}
void printf1();
void printf2();
void funcD()
{
for(int i=0; i < 20*10000;i++)
{
#ifdef DEF_PRINT
printf("funcD\n");
#endif
}
printf1();
}
void printf1()
{
for(int i=0; i < 10*10000;i++)
{
#ifdef DEF_PRINT
printf("printf1\n");
#endif
}
printf2();
}
void printf2()
{
for(int i=0; i < 10*10000;i++)
{
#ifdef DEF_PRINT
printf("printf2\n");
#endif
}
}
int main()
{
while (true) {
funcA();
funcB();
funcC();
funcD();
}
return 0;
}
?程序編譯命令:
g++ -g -O0 main.cpp -o main //-g帶調(diào)試信息編譯,禁止優(yōu)化O0,
(1)生成CPU火焰圖1
生成火焰圖步驟如下:
程序運行結(jié)果如下:
//上面main程序運行時,使用top查看,進(jìn)程PID為5606,CPU為86.3%左右。
$ sudo perf record -F 99 -p 5606 -g -- sleep 30
//-F 99 表示每秒99次采樣, -p 5606 是進(jìn)程號, 即對哪個進(jìn)程進(jìn)行分析, -g 表示記錄調(diào)用棧, sleep 30 則是持續(xù)30秒。
$ sudo perf script -i perf.data &>perf.unfold
//perf script 工具對 perf.data 進(jìn)行解析,生成折疊后的調(diào)用棧。
$ ../FlameGraph/stackcollapse-perf.pl perf.unfold &>perf.folded
//下載的可視化工具FlameGraph在當(dāng)前文件上一層,用 stackcollapse-perf.pl 將 perf 解析出的內(nèi)容 perf.unfold 中的符號進(jìn)行折疊。
$ ../FlameGraph/flamegraph.pl perf.folded >perf1.svg
//生成svg圖
使用瀏覽器打開perf.svg圖,效果如下:
(2)火焰圖表解析
?上圖中每個方塊代表堆棧中的一個函數(shù),也叫堆棧幀。
y軸:表示堆棧深度,火焰越高,表示函數(shù)調(diào)用層級越深,最頂部的方塊表示當(dāng)前CPU上運行的函數(shù),每一塊的函數(shù)下方都是當(dāng)前函數(shù)的調(diào)用方。
x軸:表示當(dāng)前函數(shù)的采樣數(shù),與大多數(shù)圖表不同,它不顯示從左到右的時間流逝。左到右的排序沒有意義(它按字母順序排序以最大程度地合并幀),方框的寬度顯示了它在CPU上運行的總時間(基于采樣計數(shù))。哪個方塊的寬度比較大,就表示該函數(shù)可能存在性能問題。
注意:圖標(biāo)中顏色不具有顯著意義,通常是隨機(jī)選擇的暖色調(diào)。這種可視化稱為"火焰圖",因為它最初用于顯示CPU上的熱點,而且看起來像火焰。
它也是交互式的:將鼠標(biāo)懸停在SVG上以顯示詳細(xì)信息,并單擊進(jìn)行縮放。
(3)當(dāng)前程序圖標(biāo)分析
從(1)中火焰圖中看出,沒有demo中定義的函數(shù),這是因為printf函數(shù)占用改進(jìn)程的CPU性能較高,而for循環(huán)邏輯占用性能較低,可以點擊火焰圖上的搜索按鍵Search進(jìn)行搜索,本文搜索程序入口函數(shù)。
確定入口函數(shù)的步驟如下:
a> 入口函數(shù)地址確定
輸入下面命令
$ readelf -h main
可執(zhí)行文件信息如下:?
b> 獲取對應(yīng)地址入口函數(shù)
輸入下面命令:
$ readelf -s main
?由上圖可知入口函數(shù)為_start,所以搜索_start函數(shù)。
_start搜索結(jié)果如下:
點擊__libc_start_main函數(shù),進(jìn)入對于函數(shù)調(diào)用過程,如下:
上面火焰圖中printf函數(shù)占用該進(jìn)程CPU性能較高,printf的函數(shù)輸出內(nèi)容到顯示的過程可參考下面鏈接:
printf函數(shù)打?。ㄒ唬?過程解析篇_printf調(diào)用過程_仲夏夜之夢~的博客-CSDN博客
printf函數(shù)打?。ǘ?緩沖區(qū)篇(文件讀寫再探究)_printf flush_仲夏夜之夢~的博客-CSDN博客
?(4)生成火焰圖2
將上面的代碼中的#define DEF_PRINT? 行進(jìn)行屏蔽,這樣函數(shù)就不會打印輸出到屏幕上。重新編譯代碼,運行。
?生成火焰圖步驟跟上面(1)中一樣,只是-p參數(shù)的進(jìn)程ID號不同,生成的svg圖片如下:
由svg圖表可知,funcA在mainNoPrint進(jìn)程中,占用該進(jìn)程CPU 10%,funcB占用該進(jìn)程CPU 20%,funcC占用該進(jìn)程CPU 30%,funcD占用該進(jìn)程CPU 40%。?
?(5)生成差分火焰圖
運行mainNoPrint函數(shù),抓取系統(tǒng)所有進(jìn)程的CPU,命令如下:
$ sudo perf record -F 99 -a -g -- sleep 30 //a表示對所有進(jìn)程堆棧數(shù)據(jù)進(jìn)行抓取
$ sudo perf script -i perf.data &>perf.unfold
$ ../FlameGraph/stackcollapse-perf.pl perf.unfold &>perf.folded1
$ ../FlameGraph/flamegraph.pl perf.folded1 >perf1.svg
?生成的火焰圖如下:
?停止mainNoPrint程序,抓取系統(tǒng)所有進(jìn)程的CPU,命令如下:
$ sudo perf record -F 99 -a -g -- sleep 30
$ sudo perf script -i perf.data &>perf.unfold
$ ../FlameGraph/stackcollapse-perf.pl perf.unfold &>perf.folded2
$ ../FlameGraph/flamegraph.pl perf.folded2 >perf2.svg
生成的火焰圖如下:
以perf.folded2的為基準(zhǔn),生成差分火焰圖,命令如下:
$./FlameGraph/difffolded.pl perf.folded2 perf.folded1|../FlameGraph/flamegraph.pl >diff1.svg
?生成的差分火焰圖如下:
?由紅色部分圖可知,CPU中funcD等函數(shù)占用的CPU增加了,藍(lán)色部分相對于上次CPU減少了。
附加:
1、火焰圖的介紹也可參考:
?Linux下用火焰圖進(jìn)行性能分析_perf火焰圖分析_CHENG Jian的博客-CSDN博客
?2、可視化工具官方可參考:Flame Graphs (brendangregg.com)文章來源:http://www.zghlxwxcb.cn/news/detail-765682.html
?3、其他性能分析工具可參考:C++ performance 性能分析工具(sanitizers valgrind gprof gperftools perf)的使用_performance測試工具_(dá)超級大洋蔥806的博客-CSDN博客文章來源地址http://www.zghlxwxcb.cn/news/detail-765682.html
到了這里,關(guān)于linux下性能分析工具Perf安裝與用法的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!