【轉載】Linux下程序的Profile工具

原文地址:http://blog.chinaunix.net/uid-9162199-id-108541.html


我們在寫程序,特別是嵌入式程序的時候,通常需要對程序的性能進行分析,以便程序能夠更快更好地運行,達到實時(real-time)的目的。如果程序很大,分析起來就很困難。如果有個工具能夠自動進行程序的性能分析,那就最好了。這裏介紹一種Linux下程序的Profiling工具----GNU profiler。


gprof的基本用法:
1. 使用 -pg 選項編譯和鏈接你的應用程序
    
    在gcc編譯程序的時候,加上-pg選項,例如:
    gcc -pg -o test test.c
    這樣就生成了可執行文件test。如果是大項目,就在makefile裏面修改編譯選項,-pg放在那裏都行。

2. 執行你的應用程序使之生成供gprof 分析的數據

    運行剛纔的程序:./test,這樣就生成了一個gmon.out文件,該文件就包含了profiling的數據。

3. 使用gprof 分析你的應用程序生成的數據

    gprof test gmon.out > profile.txt
    使用上面的命令,gprof就可以分析程序test的性能,將profiling的結果放在profile.txt文件中,打開就可以看到分析的結果。通過對結果的分析來改進我們的程序,從而達到我們的目的。

GNU gprof是個很不錯的工具,大家寫程序時可以多用用。我現在用gprof來profiling我的程序,把耗時最多的函數或運算找出來,用FPGA芯片實現,從而達到real-time的目的。

gprof編譯程序
在編譯或鏈接源程序的時候在編譯器的命令行參數中加入“-pg”選項,編譯時編譯器會自動在目標代碼中插入用於性能測試的代碼片斷,這些代碼在程序在運行時採集並記錄函數的調用關係和調用次數,以及採集並記錄函數自身執行時間和子函數的調用時間,程序運行結束後,會在程序退出的路徑下生成一個gmon.out文件。這個文件就是記錄並保存下來的監控數據。可以通過命令行方式的gprof或圖形化的Kprof來解讀這些數據並對程序的性能進行分析。另外,如果想查看庫函數的profiling,需要在編譯是再加入“-lc_p”編譯參數代替“-lc”編譯參數,這樣程序會鏈接libc_p.a庫,纔可以產生庫函數的profiling信息。如果想執行一行一行的profiling,還需要加入“-g”編譯參數。
例如如下命令行:
gcc -Wall -g -pg -lc_p example.c -o example

 

執行gprof
執行如下命令行,即可執行gprof
gprof OPTIONS EXECUTABLE-FILE gmon.out BB-DATA [YET-MORE-PROFILE-DATA -FILES...] [> OUTFILE]

 

gprof產生的信息
 %                        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.
                          
每一次調用花費在函數的時間microseconds
 total                  the average number of milliseconds spent in this
ms/call               function and its descendents per call, if this 
                          function is profiled, else blank.
                          
每一次調用,花費在函數及其衍生函數的平均時間microseconds
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.
                          
函數名


prof 實現原理
通過在編譯和鏈接你的程序的時候(使用 -pg 編譯和鏈接選項),gcc 在你應用程序的每個函數中都加入了一個名爲mcount ( or “_mcount” , or “__mcount” , 依賴於編譯器或操作系統)的函數也就是說你的應用程序裏的每一個函數都會調用mcount, mcount 會在內存中保存一張函數調用圖,並通過函數調用堆棧的形式查找子函數和父函數的地址。這張調用圖也保存了所有與函數相關的調用時間、調用次數等等的所有信息


Gprof 簡單使用:

讓我們簡單的舉個例子來看看Gprof是如何使用的。
1
.打開linux終端。新建一個test.c文件,並生用-pg 編譯和鏈接該文件。

test.c 文件內容如下:
引文:

 

       #include "stdio.h"
       #include "stdlib.h"

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(){
    printf(" main() function()\n");
    b();
}

 

命令行裏面輸入下面命令,沒加-c選項,gcc 會默認進行編譯並鏈接生成a.out:
引文:

[linux /home/test]$gcc -pg test.c

如果沒有編譯錯誤,gcc會在當前目錄下生成一個a.out文件,當然你也可以使用 –o 選項給生成的文件起一個別的名字,像 gcc –pg test.c –o test , gcc會生成一個名爲test的可執行文件,在命令行下輸入[linux /home/test]$./test ,就可以執行該程序了,記住一定要加上 ./ 否則程序看上去可能是執行,可是什麼輸出都沒有。

2
.執行你的應用程序使之生成供gprof 分析的數據。 命令行裏面輸入:
引文:

[linux /home/test]$a.out
main() function()
    +--- call b() function
        +---call a() function
        +---call c() function
[linux /home/test]$

你會在當前目錄下看到一個gmon.out 文件 這個文件就是供gprof 分析使用的。

3
.使用gprof 程序分析你的應用程序生成的數據。
命令行裏面輸入:
引文:

[linux /home/test]$ gprof -b a.out gmon.out | less

由於gprof輸出的信息比較多,這裏使用了 less 命令,該命令可以讓我們通過上下方向鍵查看gprof產生的輸出,|表示gprof -b a.out gmon.out 的輸出作爲 less的輸入。下面是我從gprof輸出中摘抄出的與我們有關的一些詳細信息。
引文:

Flat profile:
 
Each sample counts as 0.01 seconds.
 no time accumulated
 
  %   cumulative   self              self     total
 time   seconds   seconds    calls  Ts/call  Ts/call  name
  0.00      0.00     0.00        1     0.00     0.00  a
  0.00      0.00     0.00        1     0.00     0.00  b
  0.00      0.00     0.00        1     0.00     0.00  c


                        Call graph
 

granularity: each sample hit covers 4 byte(s) no time propagated
 
index % time    self  children    called     name
                0.00    0.00       1/1           b [2]
[1]      0.0    0.00    0.00       1         a [1]
-----------------------------------------------
                0.00    0.00       1/1           main [10]
[2]      0.0    0.00    0.00       1         b [2]
                0.00    0.00       1/1           c [3]
                0.00    0.00       1/1           a [1]
-----------------------------------------------
                0.00    0.00       1/1           b [2]
[3]      0.0    0.00    0.00       1         c [3]
-----------------------------------------------

Index by function name
 
   [1] a                       [2] b                       [3] c

從上面的輸出我們能明顯的看出來,main 調用了 b 函數, 函數分別調用了 c 函數。由於我們的函數只是簡單的輸出了一個字串,故每個函數的消耗時間都是秒。

 

 

使用gprof分析程序

gprof介紹
gprof
是一個GNU profiler工具。可以顯示程序運行的“flat profile”,包括每個函數的調用次數,每個函數消耗的處理器時間,也可以顯示調用圖,包括函數的調用關係,每個函數調用花費了多少時間。還可以顯示註釋的源代碼--是程序源代碼的一個複本,標記有程序中每行代碼的執行次數。

基本用法:
1
.使用-pg選項編譯和鏈接你的應用程序。
2
. 執行你的應用程序,使之運行完成後生成供gprof分析的數據文件(默認是gmon.out)。
3
. 使用gprof程序分析你的應用程序生成的數據,例如:gporf a.out gmon.out

gprof 實現原理
gprof
並不神奇,在編譯和鏈接程序的時候(使用 -pg 編譯和鏈接選項),gcc 在你應用程序的每個函數中都加入了一個名爲mcountor“_mcount”, or“__mcount”)的函數,也就是說-pg編譯的應用程序裏的每一個函數都會調用mcount, mcount會在內存中保存一張函數調用圖,並通過函數調用堆棧的形式查找子函數和父函數的地址。這張調用圖也保存了所有與函數相關的調用時間,調用次數等等的所有信息。

常用的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
)一般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文件。

 

使用gprofoprofile查找性能瓶頸

有些時候,我們特別關注程序的性能,特別是底層軟件,比如驅動程序、OS等。爲了更好的優化程序性能,我們必須找到性能瓶頸點,好鋼用在刀刃上才能取得好的效果,否則可能白做工作。爲了找到關鍵路徑,我們可以使用profilng技術,在linux平臺上,我們可以使用gprofoprofile工具。

  • gprofGNU工具之一,它在編譯的時候在每個函數的出入口加入了profiling的代碼,運行時統計程序在用戶態的執行信息,可以得到每個函數的調用次數、執行時間、調用關係等信息,簡單易懂。適合於查找用戶級程序的性能瓶頸,對於很多時間都在內核態執行的程序,gprof不適合。 
  • oprofile也是一個開源的profiling工具,它使用硬件調試寄存器來統計信息,進行 profiling的開銷比較小,而且可以對內核進行profiling。它統計的信息非常的多,可以得到cache的缺失率,memory的訪存信息, 分支預測錯誤率等等,這些信息gprof是得不到的,但是對於函數調用次數,它是不能夠得到的。。 

    簡單來說,gprof簡單,適合於查找用戶級程序的瓶頸,而oprofile稍顯複雜,但是得到的信息更多,更適合調試系統軟件。
    
我們以編譯運行hello.c爲例,來說明如何使用這兩個工具,這裏不解釋具體結果的含義,要想詳細瞭解每個結果代表什麼意思,可以看一下參考資料中官方站點上的doc信息,裏面會給你詳盡的解釋。

gprof Quick Start

    gprofgnu binutils工具之一,默認情況下linux系統當中都帶有這個工具。

  1. 使用 -pg 選項來編譯hello.c,如果要得到帶註釋的源碼清單,則需要增加 -g 選項。運行: gcc -pg -g -o hello hello.c 
  2. 運行應用程序: ./hello  會在當前目錄下產生gmon.out文件 
  3. 使用gprof來分析gmon.out文件,需要把它和產生它的應用程序關聯起來: 
    1. gprof hello gmon.out -p 得到每個函數佔用的執行時間 
    2. gprof hello gmon.out -q 得到call graph,包含了每個函數的調用關係,調用次數,執行時間等信息。 
    3. gprof hello gmon.out -A 得到一個帶註釋的源代碼清單,它會註釋源碼,指出每個函數的執行次數。這需要在編譯的時候增加 -g選項。 

oprofile Quick Start

    oprofilesourceforge上面的一個開源項目,在2.6內核上帶有這個工具,好像只有smp系統纔有。比較老的系統,需要自己安裝,重新編譯內核。
    oprofile是一套工具,分別完成不同的事情。

op_help  列出所有支持的事件。
opcontrol
:設置需要收集的事件。
opreport
 對結果進行統計輸出。
opannaotate
:產生帶註釋的源/彙編文件,源語言級的註釋需要編譯源文件時的支持。
opstack
    產生調用圖profile,但要求x86/2.6的平臺,並且linux2.6安裝了call-graph patch
opgprof
    產生如gprof相似的結果。
oparchive
  將所有的原始數據文件收集打包,可以到另一臺機器上進行分析。
op_import
  將採樣的數據庫文件從另一種abi轉化成本地格式。

    運行oprofile需要root權限,因爲它要加載profile模塊,啓動oprofiled後臺程序等。所以在運行之前,就需要切換到root

  1. opcontrol --init  加載模塊,mout /dev/oprofile 創建必需的文件和目錄 
  2. opcontrol --no-vmlinux 或者 opcontrol --vmlinux=/boot/vmlinux-`uname -r` 決定是否對kernel進行profiling 
  3. opcontrol --reset 清楚當前會話中的數據 
  4. opcontrol --start 開始profiling 
  5. ./hello 運行應用程序,oprofile會對它進行profiling 
  6. opcontrol --dump 把收集到的數據寫入文件 
  7. opcontrol --stop 停止profiling 
  8. opcotrol -h 關閉守護進程oprofiled 
  9. opcontrol --shutdown 停止oprofiled
  10. opcontrol --deinit 卸載模塊 

常用的是3→7這幾個過程,得到性能數據之後,可以使用opreport, opstack, opgprof, opannotate幾個工具進行分析,我常用的是opreport, opannotate進行分析。

  1. opreport使 http://oprofile.sourceforge.net/doc/opreport.html 
  2. opannotate使用 http://oprofile.sourceforge.net/doc/opannotate.html 
  3. opgprof使用 http://oprofile.sourceforge.net/doc/opgprof.html 

最常用的是opreport,這個可以給出imagesymbols的信息,比如我想得到每個函數的執行時間佔用比例等信息,用來發現系統性能瓶頸。opannotate可以對源碼進行註釋,指出哪個地方佔用時間比較多。常用命令如下:

  • opreport -l /bin/bash --exclude-dependent --threshold 1 , 用來發現系統瓶頸。
    指定查看/bin/bashprofiling信息,佔用總體執行時間1%以上的函數列表
  • opannotate --source --output-dir=annotated /usr/local/oprofile-pp/bin/oprofiled 
  • opannotate --source --base-dirs=/tmp/build/libfoo/ --search-dirs=/home/user/libfoo/ --output-dir=annotated/ /lib/libfoo.so 

網絡資源

  1. gprof 用戶手冊 http://sourceware.org/binutils/docs-2.17/gprof/index.html 
  2. oprofile官方站點 http://oprofile.sourceforge.net/ 
  3. 使用 GNU profiler 來提高代碼運行速度 http://www-128.ibm.com/developerworks/cn/linux/l-gnuprof.html 
  4. 使用 OProfile for Linux on POWER 識別性能瓶頸  http://www-128.ibm.com/developerworks/cn/linux/l-pow-oprofile/

發佈了167 篇原創文章 · 獲贊 65 · 訪問量 71萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章