1.3.7 gprof:性能分析工具
gprof是GNU profile工具,可以運行于linux、AIX、Sun等操作系統進行C、C++、Pascal、Fortran程序的性能分析,用于程序的性能優化以及程序瓶頸問題的查找和解決。通過分析應用程序運行時產生的 'flat profile',可以得到每個函數的調用次數,每個函數消耗的處理器時間,也可以得到函數的 '調用關系圖' ,包括函數調用的層次關系,每個函數調用花費了多少時間。
Gprof具有以下優缺點:
需要編譯選項支持:
調試多線程程序只能統計主線程的信息(所以不能用于 kingbase)。
例如:gcc -pg -o test test.cpp ,編譯器會自動在目標代碼中插入用于性能測試的代碼片斷,這些代碼在程序運行時采集并記錄函數的調用關系和調用次數,并記錄函數自身執行時間和被調用函數的執行時間。
執行編譯后的可執行程序,如:./test。該步驟運行程序的時間會稍慢于正常編譯的可執行程序的運行時間。程序運行結束后,會在程序所在路徑下生成一個缺省文件名為 gmon.out 的文件,這個文件就是記錄程序運行的性能、調用關系、調用次數等信息的數據文件。
使用 gprof 命令來分析記錄程序運行信息的 gmon.out 文件,如:gprof test gmon.out 則可以在顯示器上看到函數調用相關的統計、分析信息。上述信息也可以采用 gprof test gmon.out > gprofresult.txt 重定向到文本文件以便于后續分析。
使用 gcc/cc 或 g++ 編譯和鏈接時需要加入 -pg 選項;
使用 ld 鏈接時需要用 /lib/gcrt0.o 代替 crt0.o 作為第一個 input 文件
如果要調試 libc 庫需要使用 -lc_p代替 -lc 參數
GNU工具,人手一個;
混合方法采集信息。
優點:
缺點:
命令行選項如下:
選項 | 描述 |
-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 | 顯示使用次數為零的例程(按照調用計數和累積時間計算)。 |
例子:
1 #include 2 #include 3 int a(void) 4 { 5 int i=0,g=0; 6 while(i++ < 100000) 7 { 8 g+=i; 9 } 10 11 return g; 12 } 13 14 int b(void) 15 { 16 int i=0,g=0; 17 18 while(i++ < 400000) 19 { 20 g +=i; 21 } 22 23 return g; 24 } 25 26 int main(int argc, char** argv) 27 { 28 int iterations; 29 30 if(argc != 2) 31 { 32 printf('Usage %s 33 exit(-1); 34 } 35 else 36 iterations = atoi(argv[1]); 37 printf('No of iterations = %dn', iterations); 38 39 while(iterations--) 40 { 41 a(); 42 b(); 43 } 44 } 應用程序包括兩個函數:a 和 b,它們通過運行不同次數的循環來消耗不同的CPU時間。 main 函數中采用了一個循環來反復調用這兩個函數。函數 b 中循環的次數是 a 函數的 4 倍,因此我們期望通過 gprof 的分析結果可以觀察到大概有 20% 的時間花在了 a 函數中,而 80% 的時間花在了 b 函數中。 編譯程序:gcc test.c -pg -o test -O2 -lc 運行并傳入參數:./test 50000 程序運行完之后,會在目錄下生成一個 gmon.out 文件: 使用 gprof 命令分析分析 gmon.out 文件gprof test gmon.out -p 程序運行時間太短,所以 gprof 無效,若是大程序即可使用此來分析。 上面那些參數得含義如下: 名稱 含義 %time 函數以及衍生函數(函數內部再次調用的子函數)所占的總運行時間的百分比 cumulative seconds 函數累計執行的時間 self seconds 函數執行占用的時間 calls 函數的調用次數 self ms/call 每一次調用函數花費的時間microseconds,不包括衍生函數的運行時間 total ms/call 每一次調用函數花費的時間microseconds,包括衍生函數的運行時間 name 函數名稱 ld 是 GNU 工具鏈中的一個軟件,主要用于將 obj 文件鏈接成可執行文件。同時可以使用自己的腳本來控制 ld 的行為,可以通過 -T 選項選擇自己的腳本而不是默認的。 選項 描述 -static 靜態鏈接 -l 指定鏈接某個庫 -e name 指定 name 為程序入口 -r 合并目標文件,不進行最終鏈接 -L 指定鏈接時查找路徑,多個路徑之間用冒號隔開 -M 將鏈接時的符號和地址輸出成一個映射文件 -o 指定輸出的文件名 -s 清除輸出文件中的符號信息 -shared 鏈接器生成一個 Linux 上使用的動態庫 -S 清除輸出文件中的調試信息 -T 指定鏈接腳本文件 -Ttext 指定 text 段的地址 -version-script 指定符號版本腳本文件 -soname 指定輸出動態庫的 SONAME -export-dynamic 將全局符號全部導出 -verbose 鏈接時輸出詳細信息 -rpath 指定鏈接時庫查找路徑 --help 查看鏈接器的幫助信息 libbfd 工具不會在安裝 binutils 的時候自動安裝,需要在 binutils 安裝包的 bfd 文件夾下單獨安裝。 在安裝完 binutils 工具之后就可以看到此工具。安裝完成后,會生成如下文件: /usr/local/include/bfd.h /usr/local/lib/libbfd.a 可以利用此工具獲取 elf 可執行文件的 section(節) 及 symbol(符號) 信息。 使用此工具需要注意的地方: 頭文件包含 采用GNU autotools的項目,在編譯前一般都會執行一下 configure 腳本,生成 Makefile 及 config.h文 件。 對于沒有使用 GNU autotools 的應用,可以采用如下格式得到 config.h 文件,這個文件的內容,相當于是使用 GNU autotools 開發一個 hello world 項目而得到的 config.h,下面就是 config.h 文件的模板 程序使用bfd,需要包含bfd.h頭文件。但是,在包含 bfd.h 之前,還需要包含 config.h。即代碼中需要有如下形式的文件包含: #include 'config.h' config.h 不是系統的頭文件,也不是bfd庫的頭文件,而是應用程序自己的頭文件。 1 /* config.h. Generated from config.h.in by configure. */ 2 /* config.h.in. Generated from configure.ac by autoheader. */ 3 4 /* Name of package */ 5 #define PACKAGE 'hello' 6 7 /* Define to the address where bug reports for this package should be sent. */ 8 #define PACKAGE_BUGREPORT 'bug-report@address' 9 10 /* Define to the full name of this package. */ 11 #define PACKAGE_NAME 'hello' 12 13 /* Define to the full name and version of this package. */ 14 #define PACKAGE_STRING 'hello 1.0' 15 16 /* Define to the one symbol short name of this package. */ 17 #define PACKAGE_TARNAME 'hello' 18 19 /* Define to the home page for this package. */ 20 #define PACKAGE_URL '' 21 22 /* Define to the version of this package. */ 23 #define PACKAGE_VERSION '1.0' 24 25 /* Version number of package */ 26 #define VERSION '1.0' 鏈接 鏈接的時候需要帶上這幾個庫:bfd iberty dl z 例如,假設 hello.c 是一個完整的使用 bfd 庫的程序,則他的編譯方法如:gcc hello.c -lbfd -liberty -ldl -lz 例子如下: 1 #include 2 #include 3 #include 'config.h' 4 #include 5 #include 6 #include 7 #include 8 #include 9 10 /* 11 這里定義 3 個 static 變量,并把他們放到一個單獨的 section 中。 12 后面,我們通過 bfd 找出這個 section,并得到這 3 個變量的內容。 13 同時,我們還通過符號查找操作,找到 a_haha 這個 static 變量的信息。 14 */ 15 static uint64_t a_haha __attribute__((section ('my_test_sec'))) =3; 16 static uint64_t b __attribute__((section ('my_test_sec'))) =7; 17 static uint64_t c __attribute__((section ('my_test_sec'))) =8; 18 19 /* 獲取當前進程自己的elf文件路徑 */ 20 int get_self_path(char *buf, int buf_len) 21 { 22 int ret = readlink('/proc/self/exe', buf, buf_len); 23 buf[ret]='
主站蜘蛛池模板:
浙江省|
龙胜|
宁夏|
侯马市|
临沂市|
延庆县|
朔州市|
绥宁县|
将乐县|
余江县|
中卫市|
和林格尔县|
七台河市|
韶关市|
紫阳县|
万载县|
博白县|
馆陶县|
沅江市|
囊谦县|
柯坪县|
景谷|
鞍山市|
肥东县|
合肥市|
崇明县|
烟台市|
钟山县|
济南市|
临泉县|
鄂托克旗|
蛟河市|
华池县|
山丹县|
民乐县|
安化县|
浦江县|
陈巴尔虎旗|
诸暨市|
邯郸市|
湘阴县|
1.3.8 ld:GNU 鏈接器
1.3.9 libbfd:二進制文件描述器
#include