http://blog.csdn.net/bendanban/article/details/7742593
在網(wǎng)上找了找關(guān)于Progfile的工具,找到了這篇文章覺(jué)得不錯(cuò),轉(zhuǎn)來(lái)分享下。對(duì)原文修改了下。
本文介紹了如何使用Gnu gprof 對(duì)Linux平臺(tái)下的現(xiàn)有程序進(jìn)行優(yōu)化分析和生成程序調(diào)用圖。主要偏重于對(duì)生成和使用流程圖作介紹.
Gprof 簡(jiǎn)介:
Gprof功能:打印出程序運(yùn)行中各個(gè)函數(shù)消耗的時(shí)間,可以幫助程序員找出眾多函數(shù)中耗時(shí)最多的函數(shù)。產(chǎn)生程序運(yùn)行時(shí)候的函數(shù)調(diào)用關(guān)系,包括調(diào)用次數(shù),可以幫助程序員分析程序的運(yùn)行流程。
有了函數(shù)的調(diào)用關(guān)系,這會(huì)讓開(kāi)發(fā)人員大大提高工作效率,不用費(fèi)心地去一點(diǎn)點(diǎn)找出程序的運(yùn)行流程,這對(duì)小程序來(lái)說(shuō)可能效果不是很明顯,但對(duì)于有幾萬(wàn),幾十萬(wàn)代碼量的工程來(lái)說(shuō),效率是毋庸置疑的!而且這個(gè)功能對(duì)于維護(hù)舊代碼或者是分析Open Source來(lái)說(shuō)那是相當(dāng)誘人的,有了調(diào)用圖,對(duì)程序的運(yùn)行框架也就有了一個(gè)大體了解,知道了程序的“骨架“,分析它也就不會(huì)再那么茫然,尤其是對(duì)自己不熟悉的代碼和Open Source。費(fèi)話不多說(shuō)了,讓我們開(kāi)始我們的分析之旅吧!
Gprof 實(shí)現(xiàn)原理:
通過(guò)在編譯和鏈接你的程序的時(shí)候(使用 -pg 編譯和鏈接選項(xiàng)),gcc 在你應(yīng)用程序的每個(gè)函數(shù)中都加入了一個(gè)名為mcount ( or “_mcount” , or “__mcount” , 依賴于編譯器或操作系統(tǒng))的函數(shù),也就是說(shuō)你的應(yīng)用程序里的每一個(gè)函數(shù)都會(huì)調(diào)用mcount, 而mcount 會(huì)在內(nèi)存中保存一張函數(shù)調(diào)用圖,并通過(guò)函數(shù)調(diào)用堆棧的形式查找子函數(shù)和父函數(shù)的地址。這張調(diào)用圖也保存了所有與函數(shù)相關(guān)的調(diào)用時(shí)間,調(diào)用次數(shù)等等的所有信息。
Gprof基本用法:
1. 使用 -pg 編譯和鏈接你的應(yīng)用程序。
2. 執(zhí)行你的應(yīng)用程序使之生成供gprof 分析的數(shù)據(jù)。
3. 使用gprof 程序分析你的應(yīng)用程序生成的數(shù)據(jù)。
Gprof 簡(jiǎn)單使用:
讓我們簡(jiǎn)單的舉個(gè)例子來(lái)看看Gprof是如何使用的。
1.打開(kāi)linux終端。新建一個(gè)test.c文件,并生用-pg 編譯和鏈接該文件。 test.c 文件內(nèi)容如下:
#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();
}命令行里面輸入下面命令,沒(méi)加-c選項(xiàng),gcc 會(huì)默認(rèn)進(jìn)行編譯并鏈接生成a.out:
$gcc -pg test.c如果沒(méi)有編譯錯(cuò)誤,gcc會(huì)在當(dāng)前目錄下生成一個(gè)a.out文件,當(dāng)然你也可以使用 –o 選項(xiàng)給生成的文件起一個(gè)別的名字,像 gcc –pg test.c –o test , 則gcc會(huì)生成一個(gè)名為test的可執(zhí)行文件,在命令行下輸入[linux /home/test]$./test , 就可以執(zhí)行該程序了,記住一定要加上 ./ 否則程序看上去可能是執(zhí)行,可是什么輸出都沒(méi)有。
2.執(zhí)行你的應(yīng)用程序使之生成供gprof 分析的數(shù)據(jù)。 命令行里面輸入:
[linux /home/test]$a.out
main() function()
+--- call b() function
+---call a() function
+---call c() function
你會(huì)在當(dāng)前目錄下看到一個(gè)gmon.out 文件, 這個(gè)文件就是供gprof 分析使用的。
3.使用gprof 程序分析你的應(yīng)用程序生成的數(shù)據(jù)。
命令行里面輸入:
$ gprof -b a.out gmon.out | less
由于gprof輸出的信息比較多,這里使用了 less 命令,該命令可以讓我們通過(guò)上下方向鍵查看gprof產(chǎn)生的輸出,| 表示gprof -b a.out gmon.out 的輸出作為 less的輸入。下面是我從gprof輸出中摘抄出的與我們有關(guān)的一些詳細(xì)信息。
% 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 a [1]
0.00 0.00 1/1 c [3]
-----------------------------------------------
0.00 0.00 1/1 b [2]
[3] 0.0 0.00 0.00 1 c [3]
從上面的輸出我們能明顯的看出來(lái),main 調(diào)用了 b 函數(shù), 而b 函數(shù)分別調(diào)用了a 和 c 函數(shù)。由于我們的函數(shù)只是簡(jiǎn)單的輸出了一個(gè)字串,故每個(gè)函數(shù)的消耗時(shí)間都是0 秒。
常用的Gprof 命令選項(xiàng)解釋:
-b不再輸出統(tǒng)計(jì)圖表中每個(gè)字段的詳細(xì)描述。
-p 只輸出函數(shù)的調(diào)用圖(Call graph 的那部分信息)。
-q 只輸出函數(shù)的時(shí)間消耗列表。
-E Name不再輸出函數(shù)Name 及其子函數(shù)的調(diào)用圖,此標(biāo)志類似于 -e 標(biāo)志,但它在總時(shí)間和百分比時(shí)間的計(jì)算中排除了由函數(shù)Name 及其子函數(shù)所用的時(shí)間。
-e Name 不再輸出函數(shù)Name 及其子函數(shù)的調(diào)用圖(除非它們有未被限制的其它父函數(shù))。可以給定多個(gè) -e 標(biāo)志。一個(gè) -e 標(biāo)志只能指定一個(gè)函數(shù)。
-F Name 輸出函數(shù)Name 及其子函數(shù)的調(diào)用圖,它類似于 -f 標(biāo)志,但它在總時(shí)間和百分比時(shí)間計(jì)算中僅使用所打印的例程的時(shí)間。可以指定多個(gè) -F 標(biāo)志。一個(gè) -F 標(biāo)志只能指定一個(gè)函數(shù)。-F 標(biāo)志覆蓋 -E 標(biāo)志。
-f Name輸出函數(shù)Name 及其子函數(shù)的調(diào)用圖。可以指定多個(gè) -f 標(biāo)志。一個(gè) -f 標(biāo)志只能指定一個(gè)函數(shù)。
-z 顯示使用次數(shù)為零的例程(按照調(diào)用計(jì)數(shù)和累積時(shí)間計(jì)算)。
到這為止你可能對(duì)gprof 有了一個(gè)比較感性的認(rèn)識(shí)了,你可能會(huì)問(wèn)如何用它去分析一個(gè)真正的Open Source 呢!下面就讓我們?nèi)ビ胓prof去分析一個(gè)Open Source,看看如何去在真實(shí)的環(huán)境中使用它。
使用Gprof 分析 Cflow開(kāi)源項(xiàng)目
CFlow 是程序流程分析工具,該工具可以通過(guò)分析C源代碼,產(chǎn)生程序調(diào)用圖!有點(diǎn)跟Gprof差不多,不過(guò)CFlow是通過(guò)源代碼進(jìn)行的靜態(tài)分析并且 不能分析C++ 程序,你可以到http://www.gnu.org/software/cflow/去下載源代碼。
假設(shè)你已經(jīng)下載了該源代碼(cflow-1.1.tar.gz),并把它放置在/home目錄下,讓我們看看如何在這個(gè)應(yīng)用上使用gprof。
1. 使用 -pg 編譯和鏈接該應(yīng)用程序,請(qǐng)輸入下列命令。
[linux /home/]tar zxvf cflow-1.1.tar.gz
[linux /home/cflow-1.1/src]$./configure
[linux /home]$make CFLAGS=-pg LDFLAGS=-pg
如果沒(méi)有出錯(cuò)你會(huì)在/home/cflow-1.1/src 目錄下發(fā)行一個(gè)名為cflow的可執(zhí)行文件,這就是我們加入-pg編譯選項(xiàng)后編譯出來(lái)的可以產(chǎn)生供gprof提取信息的可執(zhí)行文件。記住一定要在編譯和鏈接的時(shí)候都使用-pg選項(xiàng),否則可能不會(huì)產(chǎn)生gmon.out文件。對(duì)于cflow項(xiàng)目,CFLAGS=-pg 是設(shè)置它的編譯選項(xiàng),LDFLAGS=-pg是設(shè)置它的鏈接選項(xiàng)。當(dāng)然你也可以直接修改它的Makefile來(lái)達(dá)到上述相同的目的,不過(guò)一定要記住編譯和鏈接都要使用-pg選項(xiàng)。
2. 運(yùn)行cflow 程序使之生成gmon.out 文件供gprof使用。
[linux /home/cflow-1.1/src]$cflow parser.c
查看/home/cflow-1.1/src目錄下有沒(méi)有產(chǎn)生gmon.out文件,如果沒(méi)有請(qǐng)重復(fù)第一步,并確認(rèn)你已經(jīng)在編譯和鏈接程序的時(shí)候使用了-pg 選項(xiàng)。Cflow的使用請(qǐng)參考http://www.gnu.org/software/cflow/manual/cflow.html。
3. 使用gprof分析程序
[linux /home/cflow-1.1/src]$gprof -b cflow gmon.out | less
恭喜你,不出意外你會(huì)在屏幕上看到gprof的輸出,函數(shù)消耗時(shí)間和函數(shù)調(diào)用圖,下面是我從我的輸出中摘抄出來(lái)的一小段。
% cumulative self self total
time seconds seconds calls Ts/call Ts/call name
0.00 0.00 0.00 118262 0.00 0.00 include_symbol
0.00 0.00 0.00 92896 0.00 0.00 is_printable
0.00 0.00 0.00 28704 0.00 0.00 set_level_mark
0.00 0.00 0.00 28703 0.00 0.00 is_last
0.00 0.00 0.00 19615 0.00 0.00 auto_processor
0.00 0.00 0.00 15494 0.00 0.00 gnu_output_handler
0.00 0.00 0.00 12286 0.00 0.00 delete_parm_processor
0.00 0.00 0.00 7728 0.00 0.00 newline
0.00 0.00 0.00 7728 0.00 0.00 print_function_name
0.00 0.00 0.00 7728 0.00 0.00 print_level
。。。。。。
。。。。。。
Call graph
granularity: each sample hit covers 4 byte(s) no time propagated
index % time self children called name
[1] 0.0 0.00 0.00 79+855 [1]
0.00 0.00 166 dcl [52]
0.00 0.00 163 parse_dcl [53]
0.00 0.00 150 dirdcl [56]
0.00 0.00 129 parse_declaration [63]
0.00 0.00 98 parse_variable_declaration [66]
0.00 0.00 63 maybe_parm_list [69]
0.00 0.00 63 parse_function_declaration [70]
0.00 0.00 39 func_body [74]
。。。。。。
。。。。。。
通過(guò)分析%time你就知道了那個(gè)函數(shù)消耗的時(shí)間最多,你可以根據(jù)這個(gè)輸出信息做有目的的優(yōu)化,不過(guò)cflow執(zhí)行的速度是在是太快了,以至%time都是0 (消耗時(shí)間是以秒為單位進(jìn)行統(tǒng)計(jì)的)。
生成圖形化的函數(shù)調(diào)用圖
1.Graphviz 工具
看到這里你也可能覺(jué)得上面的函數(shù)調(diào)用圖實(shí)在是不方便察看,也看不出來(lái)一個(gè)程序調(diào)用的整體框架。沒(méi)有關(guān)系,我再介紹一個(gè)有用的工具給你,使用 Graphviz,Graphviz or Graph Visualization 是由 AT&T 開(kāi)發(fā)的一個(gè)開(kāi)源的圖形可視化工具。它提供了多種畫(huà)圖能力,但是我們重點(diǎn)關(guān)注的是它使用 Dot 語(yǔ)言直連圖的能力。在這里,將簡(jiǎn)單介紹如何使用 Dot 來(lái)創(chuàng)建一個(gè)圖形,并展示如何將分析數(shù)據(jù)轉(zhuǎn)換成 Graphviz 可以使用的規(guī)范, Dot 使用的圖形規(guī)范。
使用 Dot 語(yǔ)言,你可以指定三種對(duì)象:圖、節(jié)點(diǎn)和邊。為了讓你理解這些對(duì)象的含義,我將構(gòu)建一個(gè)例子來(lái)展示這些元素的用法。
下圖給出了一個(gè)簡(jiǎn)單的定向圖(directed graph),其中包含 3 個(gè)節(jié)點(diǎn)。第一行聲明這個(gè)圖為 G,并且聲明了該圖的類型(digraph)。接下來(lái)的三行代碼用于創(chuàng)建該圖的節(jié)點(diǎn),這些節(jié)點(diǎn)分別名為 node1、node2 和 node3。節(jié)點(diǎn)是在它們的名字出現(xiàn)在圖規(guī)范中時(shí)創(chuàng)建的。邊是在在兩個(gè)節(jié)點(diǎn)使用邊操作(->)連接在一起時(shí)創(chuàng)建的,如第 6 行到第 8 行所示。我還對(duì)邊使用了一個(gè)可選的屬性 label,用它來(lái)表示邊在圖中的名稱。最后,在第 9 行完成對(duì)該圖規(guī)范的定義。
使用 Dot 符號(hào)表示的示例圖(test.dot)

digraph G
{
node1;
node2;
node3;

node1 -> node2 [label="edge_1_2"];
node1 -> node3 [label="edge_1_3"];
node2 -> node3 [label="edge_2_3"];
}
要將這個(gè) .dot 文件轉(zhuǎn)換成一個(gè)圖形映像,則需要使用 Dot 工具,這個(gè)工具是在 Graphviz 包中提供的。清單 6 介紹了這種轉(zhuǎn)換。
清單 6. 使用 Dot 來(lái)創(chuàng)建 JPG 映像
[linux /home]$ dot -Tjpg test.dot -o test.jpg
在這段代碼中,我告訴 Dot 使用 test.dot 圖形規(guī)范,并生成一個(gè) JPG 圖像,將其保存在文件 test.jpg 中。所生成的圖像如圖1所示。在此處,我使用了 JPG 格式,但是 Dot 工具也可以支持其他格式,其中包括 GIF、PNG 和 postscript等等。

Dot創(chuàng)建的實(shí)例圖
Dot 語(yǔ)言還可以支持其他一些選項(xiàng),包括外形、顏色和很多屬性。有興趣可以查看graphviz相關(guān)文檔。
2.從gprof的輸出中提取調(diào)用圖信息,產(chǎn)生可供Graphviz使用的dot文件。
這樣的腳本有人已經(jīng)實(shí)現(xiàn)了,我們只要下載一個(gè)現(xiàn)成的就可以了,首先從http://www.ioplex.com/~miallen/ 網(wǎng)站下載一個(gè)mkgraph腳本。解壓該腳本到包含gmon.out文件的目錄下。使用mkgraph0.sh產(chǎn)生調(diào)用的jpg圖像文件。例如:使用上面的例子,生成cflow的調(diào)用圖。
[linux /home/cflow-1.1/src]$ mkgraph0.sh cflow gmon.out
部分調(diào)用圖如下,有了這個(gè)圖是不是對(duì)程序整體框架有了個(gè)清晰地了解,如果你對(duì)生成的調(diào)用圖效果不滿意,你還可以通過(guò)修改mkgraph0腳本使之產(chǎn)生合適的dot文件即可:
總結(jié):
使用gprof , Graphviz , mkgraph 生成函數(shù)調(diào)用圖
1. 使用 -pg 編譯和鏈接你的應(yīng)用程序。
2. 執(zhí)行你的應(yīng)用程序使之生成供gprof 分析的數(shù)據(jù)。
3. 使用mkgraph腳本生成圖形化的函數(shù)調(diào)用圖。
相關(guān)資料:
文檔:用 Graphviz 可視化函數(shù)調(diào)用
文檔:Speed your code with the GNU profiler
文檔:gropf 幫助文件
Mkgraph 腳本:http://www.ioplex.com/~miallen/
Graphviz 工具:http://www.graphviz.org
Cflow :http://www.gnu.org/software/cflow/
(責(zé)任編輯:城塵 68476636-8003)
原文地址:點(diǎn)擊打開(kāi)鏈接http://os.51cto.com/art/200703/41426_2.htm