簡介
產生程式運行時候的函式調用關係,包括調用次數,可以幫助程式設計師分析程式的運行流程。
有了函式的調用關係,這會讓開發人員大大提高工作效率,不用費心地去一點點找出程式的運行流程,這對小程式來說可能效果不是很明顯,但對於有幾萬,幾十萬代碼量的工程來說,效率是毋庸置疑的!而且這個功能對於維護舊代碼或者是分析Open Source來說那是相當誘人的,有了調用圖,對程式的運行框架也就有了一個大體了解,知道了程式的"骨架",分析它也就不會再那么茫然,尤其是對自己不熟悉的代碼和Open Source。費話不多說了,讓我們開始我們的分析之旅吧!
優缺點
Gprof具有以下優缺點:
1) 優點:
a) GNU工具,人手一個;
b) 混合方法採集信息。
2) 缺點:
a) 需要編譯選項支持:
i. 使用gcc/cc編譯和連結時需要加入-pg選項
ii. 使用ld連結時需要用/lib/gcrt0.o代替crt0.o作為第一個input檔案
iii. 如果要調試libc庫需要使用-lc_p代替-lc參數
b) 調試多執行緒程式只能統計主執行緒的信息(所以不能用於kingbase)。
原理
通過在編譯和連結你的程式的時候(使用 -pg 編譯和連結選項),gcc 在你應用程式的每個函式中都加入了一個名為mcount ( or "_mcount" , or "__mcount" , 依賴於編譯器或作業系統)的函式,也就是說你的應用程式里的每一個函式都會調用mcount, 而mcount 會在記憶體中保存一張函式調用圖,並通過函式調用堆疊的形式查找子函式和父函式的地址。這張調用圖也保存了所有與函式相關的調用時間,調用次數等等的所有信息。
命令
-b 不再輸出統計圖表中每個欄位的詳細描述。
-q 只輸出函式的調用圖(Call graph的那部分信息)。
-p 只輸出函式的時間消耗列表。
-e Name 不再輸出函式Name 及其子函式的調用圖(除非它們有未被限制的其它父函式)。可以給定多個 -e 標誌。一個 -e 標誌只能指定一個函式。
-E Name 不再輸出函式Name 及其子函式的調用圖,此標誌類似於 -e 標誌,但它在總時間和百分比時間的計算中排除了由函式Name 及其子函式所用的時間。
-f Name 輸出函式Name 及其子函式的調用圖。可以指定多個 -f 標誌。一個 -f 標誌只能指定一個函式。
-F Name 輸出函式Name 及其子函式的調用圖,它類似於 -f 標誌,但它在總時間和百分比時間計算中僅使用所列印的例程的時間。可以指定多個 -F 標誌。一個 -F 標誌只能指定一個函式。-F 標誌覆蓋 -E 標誌。
-z 顯示使用次數為零的例程(按照調用計數和累積時間計算)。
示例
Test.c
#include <stdio.h>
int prime(int n)
{
int i;
for (i=2; i<n; i++)
{
if (n%i == 0)
return 0;
return 1;
}
}
void main(void)
{
int i, n;
n = 1000;
for (i=2; i<=n; i++)
{
if (prime(i))
printf("%d\n", i);
}
}
Gcc -pg -o test test.c
./test
gprof -b test gmon.out |less
Flat profile:
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls Ts/call Ts/call name
100.00 0.02 0.02 main
0.00 0.02 0.00 999 0.00 0.00 prime
^L
Call graph
granularity: each sample hit covers 4 byte(s) for 50.00% of 0.02 seconds
index % time self children called name
<spontaneous>
[1] 100.0 0.02 0.00 main [1]
0.00 0.00 999/999 prime [2]
-----------------------------------------------
0.00 0.00 999/999 main [1]
[2] 0.0 0.00 0.00 999 prime [2]
-----------------------------------------------
^L
Index by function name
[1] main [2] prime
注意
1) 一般gprof只能查看用戶函式信息。如果想查看庫函式的信息,需要在編譯時再加入"-lc_p"編譯參數代替"-lc"編譯參數,這樣程式會連結libc_p.a庫,才可以產生庫函式的profiling信息。
2) gprof只能在程式正常結束退出之後才能生成程式測評報告,原因是gprof通過在atexit()里註冊了一個函式來產生結果信息,任何非正常退出都不會執行atexit()的動作,所以不會產生gmon.out檔案。如果你的程式是一個不會退出的服務程式,那就只有修改代碼來達到目的。如果不想改變程式的運行方式,可以添加一個信號處理函式解決問題(這樣對代碼修改最少),例如:
static void sighandler( int sig_no )
{
exit(0);
}
signal( SIGUSR1, sighandler );
當使用kill -USR1 pid 後,程式退出,生成gmon.out檔案。
信息
% the percentage of the total running time of the
time program used by this function.
函式使用時間占所有時間的百分比。
cumulative a running sum of the number of seconds accounted
seconds for by this function and those listed above it.
函式和上列函式累計執行的時間。
self the number of seconds accounted for by this
seconds function alone. This is the major sort for this listing.
函式本身所執行的時間。
calls the number of times this function was invoked, if
this function is profiled, else blank.
函式被調用的次數
self the average number of milliseconds spent in this
ms/call function per call, if this function is profiled,else blank.
每一次調用花費在函式的時間(毫秒)。
total the average number of milliseconds spent in this
ms/call function and its descendents per call, if this
function is profiled, else blank.
每一次調用,花費在函式及其衍生函式的平均時間(毫秒)。
name the name of the function. This is the minor sort
for this listing. The index shows the location of
the function in the gprof listing. If the index is
in parenthesis it shows where it would appear in
the gprof listing if it were to be printed.
函式名