1. 程式人生 > >【linux】Valgrind工具集詳解(十五):Callgrind(效能分析圖)

【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.