【linux】Valgrind工具集詳解(十五):Callgrind(效能分析圖)
一、概述
1、Callgrind
Callgrind用於記錄程式中函式之間的呼叫歷史資訊,對程式效能分析。預設情況下,收集的資料包括執行的指令數,它們與原始碼行的關係,函式之間的呼叫者、被呼叫者關係以及此類呼叫的數量。可選項是,對快取記憶體模擬和分支預測(類似於Cachegrind)。
2、callgrind_annotate、callgrind_control
在程式終止時將配置檔案資料寫出到檔案。為了呈現資料和互動式控制分析,提供了兩個命令列工具:
callgrind_annotate
此命令讀入配置檔案資料,並列印已排序的函式列表,可選擇使用源註釋。
對於資料的圖形視覺化可以使用 KCachegrind。
callgrind_control
使用此命令可以互動式地觀察和控制當前在Callgrind控制元件下執行的程式的狀態,而無需停止程式。
3、功能
上一篇介紹過Cachegrind,Cachegrind用於收集:事件計數(資料讀取,快取未命中等)。而Callgrind用於記錄函式成本。例如:函式foo呼叫 bar,則將成本bar加入到 foo成本中。使用callgrind_annotate或KCachegrind可以檢視從main開始的呼叫關係圖,可以檢視各個點的成本,便於優化程式碼。
Callgrind檢測函式呼叫和返回的能力取決於它執行的平臺的指令集。它最適用於x86和amd64,遺憾的是目前在PowerPC,ARM,Thumb或MIPS程式碼上執行效果不佳。這是因為這些指令集中沒有顯式的呼叫或返回指令,因此Callgrind必須依靠啟發式方法來檢測呼叫和返回。
二、使用
1、例項原始碼main.c
#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
static int g_i = 0;
static pthread_mutex_t g_lock1;
static int num=1;
static void *fun(void * arg)
{
int i;
for(i=0; i<num; ++i)
{
pthread_mutex_lock(&g_lock1) ;
printf("pthread[%d]:i=%d\n",getpid(), --g_i);
pthread_mutex_unlock(&g_lock1);
sleep(1);
}
}
int main()
{
pthread_t t;
pthread_mutex_init(&g_lock1, NULL);
if (pthread_create(&t, NULL, fun, NULL)==-1)
{
printf("pthread creat error\n");
}
int i;
for(i=0; i<num; ++i)
{
pthread_mutex_lock(&g_lock1);
printf("main[%d]:i=%d\n",getpid(), ++g_i);
pthread_mutex_unlock(&g_lock1);
sleep(1);
}
if (pthread_join(t, NULL) == -1)
{
printf("pthread_join error\n");
}
pthread_mutex_destroy(&g_lock1);
return 0;
}
2、編譯
gcc -g main.c -pthread
3、效能分析命令
valgrind --tool=callgrind ./a.out
4、檢視結果
執行完上述命令後,在當前目錄下生成 callgrind.out.<pid>檔案,使用視覺化kcachegrind檢視
kcachegrind callgrind.out.21479
5、生成流程圖
使用gprof2dot.py和dot生成圖片
python gprof2dot.py -f callgrind -n10 -s callgrind.out.21479> valgrind.dot
dot -Tpng valgrind.dot -o valgrind.png
三、命令列引數詳解
–callgrind-out-file=<file>
將配置檔案資料寫入指定檔案 file中,而不是預設輸出檔案 callgrind.out.<pid>。可以使用%p、%q格式說明符,參見–log-file;
–dump-line=<no|yes> [default: yes]
使用以原始碼行粒度執行事件計數,需要在gcc時加 -g選項;
–dump-instr=<no|yes> [default: no]
使用以指令粒度執行事件計數。結果只能在KCachegrind中顯示。
–compress-strings=<no|yes> [default: yes]
用數字代替識別符號(檔案和函式名稱);
–compress-pos=<no|yes> [default: yes]
位置表示為絕對值還是相對值;
–combine-dumps=<no|yes> [default: no]
啟用後,將結果輸出到同一檔案中。不建議啟用;
–dump-every-bb=<count> [default: 0, never]
設定配置檔案大小,超出後儲存到下一個檔案。
–dump-before=<function>
當進入到指定函式時,將資訊儲存到新的配置檔案中;
–zero-before=<function>
進入指定函式時將所有效能引數歸零;
–dump-after=<function>
當離開指定函式時,將資訊儲存到新的配置檔案中;
–instr-atstart=<yes|no> [default: yes]
指定是否希望Callgrind從程式開頭開始模擬和分析。
–collect-atstart=<yes|no> [default: yes]
指定是否在配置檔案執行開始時啟用事件收集。
–toggle-collect=
在進入/退出指定函式時切換集合。
–collect-jumps=<no|yes> [default: no]
這指定是否應該收集條件跳轉的資訊。
–collect-systime=<no|yes> [default: no]
這指定是否應收集系統呼叫時間的資訊。
–collect-bus=<no|yes> [default: no]
這指定是否應該收集執行的全域性匯流排事件的數量。
–separate-threads=<no|yes> [default: no]
是否為每個執行緒單獨生成配置檔案。如果是,則檔名將附加“-threadID”。
–separate-callers=<callers> [default: 0]
–separate-callers<number>=<function>
–separate-recs=<level> [default: 2]
–separate-recs<number>=<function>
–skip-plt=<no|yes> [default: yes]
忽略對PLT部分的呼叫。
–skip-direct-rec=<no|yes> [default: yes]
忽略直接遞迴。
–fn-skip=<function>
忽略對給定函式的呼叫。例如,如果有一個名為A> B> C的呼叫鏈,並指定要忽略的函式B,則只能看到A> C.