gprof是一個GNU profiler工具,可以採集程序中每個函數的調用次數、每個函數消耗的CPU時間、以及顯示調用關係圖包括每個函數調用花費了多少時間。要查看gprof的官方詳細信息請點擊這裏,也可以參看這裏。
一、原理
在編譯和鏈接程序的時候,使用-pg選項,這樣gcc/g++就會在應用程序的每個函數中都加入一個名爲mcount/_mcount/__mcount的函數,即用-pg編譯的應用程序裏的每個函數都會調用mcount函數,而mcount函數會在內存中保存一張函數調用圖,並通過函數調用堆棧的形式查找子函數和父函數的地址,這張調用圖也保存了所有與函數相關的調用時間、調用次數等所有信息。
二、用法
運行用-pg編譯和鏈接後生成的應用程序,在程序退出時會在當前路徑生成一個gmon.out文件,這個文件會記錄下採集的監控數據,可以通過命令行方式的gprof或圖形化方式的Kprof來解析監控數據以分析應用程序的性能。
gprof常用命令選項如下:
-b:不再輸出統計圖表中每個字段的詳細描述
-p:只輸出函數的調用圖(Call graph的那部分信息)
-q:只輸出函數的時間消耗列表
-e Name:不再輸出函數Name及其子函數的調用圖(除非它們有未被限制的其它父函數)。一個-e標誌只能指定一個函數,但是可以給定多個-e標誌。
-E Name:不再輸出函數Name及其子函數的調用圖,此標誌類似於-e標誌,但它在總時間和百分比時間的計算中排除了由函數Name及其子函數所用的時間。
-f Name:輸出函數Name及其子函數的調用圖。一個-f標誌只能指定一個函數,但是可以指定多個-f標誌。
-F Name:輸出函數Name及其子函數的調用圖,它類似於-f標誌,但它在總時間和百分比時間計算中僅使用所打印的例程的時間。一個-F標誌只能指定一個函數,但是可以指定多個-F標誌,-F標誌覆蓋-E標誌。
-z:顯示使用次數爲零的例程(按照調用計數和累積時間計算)。
需要注意如下兩點:
(1)如果要查看庫函數的profiling,需要在編譯時再加入-lc_p編譯參數,這樣程序會鏈接libc_p庫,從而產生庫函數的profiling信息。
(2)gprof只能在應用程序正常結束退出後才能生產gmon.out文件,這是因爲gprof通過在atexit()裏註冊了一個函數來產生結果信息,任何非正常退出都不會執行atexit(),也就不會產生gmon.out文件。通常爲了達到這個效果會爲應用程序註冊一個信號處理函數以優雅解決此問題,比如:
1
2
3
4
5
6
7
8
9
|
static void sighandler( int sig_no) { exit (0); } int main( int argc, char **argv) { signal (SIGUSR1,
sighandler); ... } |
當使用kill -USER1 pid後,應用程序會退出並生成gmon.out文件。
三、實例
下面以簡單實例來說明如何使用gprof,具體代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
#include
<stdio.h> #include
<stdlib.h> #include
<unistd.h> #include
<signal.h> static void sighandler( int sig_no
) { printf ( "hello
exit\n" ); exit (0); } void a() { printf ( "\t\t+---call
a() function\n" ); } void c() { printf ( "\t\t+---call
c() function\n" ); } int b() { printf ( "\t+---
call b() function\n" ); a(); c(); return 0; } int main() { signal (SIGUSR1,
sighandler); printf ( "
main() function()\n" ); b(); while ( true ) { sleep(5); } return 0; } |
(1)使用-pg選項編譯和鏈接應用程序。
gcc -pg -o test test.c
(2)執行應用程序,使之運行完成後生成供gprof分析的數據文件(默認是gmon.out)。
由於本程序是一個永不退出的後臺程序,所以就不僅僅是./test了,而需要如下來退出:
#kill -USR1 pid
這樣在應用程序所在目錄就會產生gmon.out文件。
(3)使用gprof分析應用程序生成的數據文件。
gprof test gmon.out
使用上面命令就能分析test的性能了,找出耗時最多的函數或者運算不是夢。
通常profiling結果都比較多,這樣可以使用管道或者重定向將結果分頁顯示或者輸出到文件中,再具體分析,比如:
gprof test gmon.out | less
gprof test gmon.out > profiling.txt
gprof分析結果會產生如下一些信息:
%time:函數使用時間佔所有時間的百分比
cumulative seconds:函數和上列函數累計執行的時間
self seconds:函數本身所執行的時間
calls:函數被調用的次數
self ms/call:每一次調用花費在函數的時間(單位微秒)
total ms/call:每一次調用花費在函數及其衍生函數的平均時間(單位微秒)
name:函數名
簡單地用-b參數分析下性能,其結果輸出如下:
從上面的輸出能看出main調用了b,而b又分別調用了a和c,由於函數很簡單,所以每個函數的時間消耗都是0秒。
四、附註
一般來說,gprof用於查找用戶態層次性能瓶頸,如果你需要查找內核態的性能瓶頸,請使用另一個款開源的profiling工具——oprofile,其使用硬件調試寄存器來統計信息,可以對內核進行profiling,採集cache缺失率、memory訪存信息、分支預測錯誤率等,具體可以參考oprofile官網,也可以參考這裏。