性能測試工具Gprof


前段時間做產品的性能測試,用了一段時間gprof,感覺很強大。

1. gprof介紹

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

常用與Linux,默認是自帶的。如果想在windows下使用,需要安裝類似MinGw,安裝完后,即可使用。

2. 使用方法

基本用法:

1.使用-pg選項編譯和鏈接你的應用程序。

2.運行你的應用程序,使之運行完成后生成供gprof分析的數據文件(默認是gmon.out)。

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

4. (可選, 見章節4)可用python生成png圖來直觀看。

舉例(在windows下測試

     gcc -pg -o test test.c               //程序文件名稱 test.c 編譯時使用 -pg

現在我們可以再次運行生成的結果文件test ,並使用我們前面使用的測試數據。這次我們運行的時候,test運行的分析數據會被搜集並保存在'gmon.out'文件中,我們可以通過運行 ‘gprof  test gmon.out>result’到一個result文件來查看結果。

     a.exe

     gprof a.exe gmon.out>result

     gprof a.exe(直接在命令行下查看)

3. 原理分析

在所有的函數內部加入了三個函數:

.cfi_startproc負責初始化profile環境,分配內存空間

_mcount記錄每個函數代碼的callercallee的位置

.cfi_endproc清除profile環境,保存結果數據為gmon.out,供gprof分析結果

 

在編譯和鏈接程序的時候(使用 -pg 編譯和鏈接選項),gcc 在你應用程序的每個函數中都加入了一個名為mcountor_mcount, or__mcount”)的函數,也就是說-pg編譯的應用程序里的每一個函數都會調用mcount, mcount會在內存中保存一張函數調用圖,並通過函數調用堆棧的形式查找子函數和父函數的地址。這張調用圖也保存了所有與函數相關的調用時間,調用次數等等的所有信息。

程序運行結束后,會在程序退出的路徑下生成一個 gmon.out文件。這個文件就是記錄並保存下來的監控數據。可以通過命令行方式的gprof或圖形化的Kprof來解讀這些數據並對程序的性能進行分析。

4. 生成png調用關系圖

此操作需要在windows上執行,

1. 需要安裝python2.7.3graphviz

2. 需要腳本"gprof2dot.py"xdot.py

步驟:

1. gprof a.exe gmon.out>result          ---先生成result文件

2. gprof2dot.py report.txt > report.dot    --python轉為dot文件

3. dot -Tpng -oreport.png report.dot      --生成png文件

 

 

5. 命令行選項及結果參數解釋

a. 常用的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 

顯示使用次數為零的例程(按照調用計數和累積時間計算)。

b. gprof產生的結果中調用時間信息解釋

     %   cumulative   self              self     total           

    time   seconds   seconds    calls  Ts/call  Ts/call  name    

  0.00      0.00     0.00     5140     0.00     0.00  CC()

  0.00      0.00     0.00      100     0.00     0.00  AA(int)

  0.00      0.00     0.00       20     0.00     0.00  BB(int)

  0.00      0.00     0.00        1     0.00     0.00  printA(int)

  0.00      0.00     0.00        1     0.00     0.00  printB(int)

選項

解釋

%

time  

the percentage of the total running time of theprogram used by this function.

函數使用時間占所有時間的百分比。

cumulative

seconds

a running sum of the number of seconds accounted for by this function and those listed above it. 函數和上列函數累計執行的時間。

self

seconds

the number of seconds accounted for by this function alone. This is the major sort for this listing. 函數本身所執行的時間。

self

ms/call

the average number of milliseconds spent in this function per call, if this function is profiled, else blank. 每一次調用花費在函數的時間microseconds

total

ms/call

the average number of milliseconds spent in this 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. 函數名。

                           

c. 結果中Call graph (explanation follows)

index  % time    self  children    called            name

-----------------------------------------------

                0.00    0.00     190/5140        BB(int) [4]

                0.00    0.00    4950/5140        AA(int) [3]

[2]      0.0     0.00    0.00    5140             CC() [2]

-----------------------------------------------

                0.00    0.00     100/100         printA(int) [5]

[3]      0.0     0.00    0.00     100             AA(int) [3]

                0.00    0.00    4950/5140        CC() [2]

-----------------------------------------------

                0.00    0.00      20/20          printB(int) [6]

[4]      0.0     0.00    0.00      20            BB(int) [4]

                0.00    0.00     190/5140        CC() [2]

-----------------------------------------------

                0.00    0.00       1/1           main [74]

[5]      0.0    0.00    0.00       1              printA(int) [5]

                0.00    0.00     100/100         AA(int) [3]

-----------------------------------------------

                0.00    0.00       1/1           main [74]

[6]      0.0     0.00    0.00       1             printB(int) [6]

                0.00    0.00      20/20          BB(int) [4]

-----------------------------------------------   

注:按照調用時間排序,整個函數調用樹被分為很多塊。每一個用橫線包圍起來的塊是一個函數調用分支。在某個塊中,左側帶有索引的是當前關注的函數,其上方一行是調用它的函數,下方是它調用的函數。藍色表示當前函數。    

選項

解釋

index   

A unique number given to each element of the table. Index numbers are sorted numerically. The index number is printed next to every function name so it is easier to look up where the function is in the table.每個函數的index值。

% time

This is the percentage of the `total' time that was spent in this function and its children. Note that due to different viewpoints, functions excluded by options, etc, these numbers will NOT add up to 100%.這個函數和它的子函數消耗的所有時間。

self

This is the total amount of time spent in this function.這個函數自己占用的時間

children

This is the total amount of time propagated into this function by its children.這個函數的子函數所消耗的時間

called

1. 如果是它本身:沒有分號--這個函數在這個分支調用了多少次。

2. 如果是父函數:父函數調用這個函數次數/這個函數被調用的總次數。

3. 如果是子函數:這個函數調用此子函數的次數/此子函數被調用的總次數。

name 

The name of the current function. The index number is printed after it. If the function is a member of a cycle, the cycle number is printed between the function's name and the index number. 函數名。

                           

6. 使用注意

1) 一般gprof只能查看用戶函數信息。如果想查看庫函數的信息,需要在編譯是再加入“-lc_p”編譯參數代替“-lc”編譯參數,這樣程序會鏈接libc_p.a庫,才可以產生庫函數的profiling信息。

2還有一點要注意的就是當程序非正常終止時不會生成gmon.out文件,也因此就沒法查看程序運行時的信息。只有當程序從main函數中正常退出,或者通過系統調用exit()函數而退出時,才會生成gmon.out文件。而通過底層調用如_exit()等退出時不會生成gmon.out。例如:

 

    static void sighandler( int sig_no )

    {

     exit(0);

    }

    signal( SIGUSR1, sighandler );

 

當使用kill -USR1 pid 后,程序退出,生成gmon.out文件。

3) 如果沒有多少時間被花費在執行用戶空間的代碼上,因此gprof效果不好。

7. 相關資料

Graphviz 工具:http://www.graphviz.org

http://www.ibm.com/developerworks/cn/linux/l-gnuprof.html

gprof手冊:http://sourceware.org/binutils/docs-2.16/gprof/index.html

http://www.jtben.com/document/205310

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM