由于CPU能耗優化的原因,火焰圖有時并不準確。為此,我們來做一個小實驗。
(還不熟悉什么是火焰圖的可以看看文章末尾火焰圖系列文章匯總)
1.小實驗
這是一個簡單C程序,其實就是一個死循環,如下:
#include
編譯后可執行程序名為 func。接下來我開了兩個終端,分別使用 taskset將 func運行在CPU0和CPU1上:
taskset 0x1 ./functaskset 0x2 ./func
然后使用bcc+flamegraph繪制火焰圖:
/bcc/profile -I -F 99 -daf 10 > out.profile/mnt/sdb/FlameGraph/flamegraph.plout.svg
得到的火焰圖:
我的測試環境是Qemu/KVM, 32核。
我們可以看到,火焰圖顯示, func程序占用了近四分之一的CPU時間。但是由于我們把 func綁定在CPU0和1上執行,根據小學數學我們應該可以計算出來 func最多占用 2/32=6.25%的時間。
是不是有點不對?
2.原因
由于Linux會對CPU進行能耗優化,在低負載的時候,CPU并不是滿負荷工作(降頻),因此對于Idle的CPU,bcc的采樣數會減少,從而導致總采樣數減少。我們可以看到,我們的采樣頻率是99個樣本/(min*CPU)。運行了10s,那么總的樣本數應該大約為 99*10*32=31680。而實際的總采樣數只有8197。分母小了,自然 func占用的CPU時間比例增加了。
3.解決辦法
當然,我們可以修改CPUfreq強制讓所有滿負荷工作。但是這樣一來麻煩,二來我的測試環境是虛擬機,修改起來更加麻煩。我們希望用一個簡單的方法解決。
這就要提到flamegraph的隱藏功能了。為什么叫隱藏功能?因為如果你簡單地 ./flamegraph.pl--help他不會告訴你這個用法。但是實際上他已經實現了這個功能,語法是:
./flamegraph.pl --total=N < out.profile > out2.svg
其中N為用戶規定的總采樣數。在我們的示例中,應該是31680。這樣,我們繪制出來的火焰圖是這個樣子的:
嗯,的確有點丑,但是6.26%才是 func真正消耗了的CPU時間比例。
4.關于CPU時間準確性的討論
怎樣才算是繪制了準確的火焰圖呢?
考慮如下情形,如果CPU1滿負荷運轉執行 func110秒鐘,而CPU2半負荷運轉執行 func25秒鐘,剩下5s是idle。
算法1::實際上 func1和 func2一起是占用了15s的CPU時間。根據計算, func占用的時間占總時間的 15s/(10s*32)=4.69%。
算法2:如果按照上面第三節所描述的方法繪制火焰圖,采樣結果應該是 func1有大約990個樣本, func2有大約 990/2/2=248個樣本,繪制出來的火焰圖 func占比為 (990+248)/31680=3.9%
兩者不相等!筆者認為,原因在于二者算法所獲結果的含義不同。算法1計算出來的是在這種運行情形下實際 func的執行時間占比。而算法2計算出來(或者說繪制出來)的是在CPU滿負荷運轉下func的CPU時間占比。從現實來看,不同背景負載,不同情形下同一個workload的運行時間可能不同。當系統負載加重時,Linux會自動控制CPUfreq將CPU頻率增加。單單查看在某一個情形下workload的CPU執行時間意義有限。但是,對于一個workload而言,他所需要占用的計算資源量往往是相同的。因此,從程序優化角度而言,采用第三節所描述的方法計算CPU滿負載下應用程序的時間占比對于我們優化代碼更具有指導性意義。
-
cpu
+關注
關注
68文章
10854瀏覽量
211587 -
程序
+關注
關注
117文章
3785瀏覽量
81005
原文標題:火焰圖系列之使用火焰圖隱藏功能提高繪制精度
文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論