日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux性能评测工具之一:gprof篇

發布時間:2024/2/28 linux 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux性能评测工具之一:gprof篇 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

這些天自己試著對項目作一些壓力測試和性能優化,也對用過的測試工具作一些總結,并把相關的資料作一個匯總,以便以后信手拈來!

?

1?簡介

改進應用程序的性能是一項非常耗時耗力的工作,但是究竟程序中是哪些函數消耗掉了大部分執行時間,這通常都不是非常明顯的。GNU?編譯器工具包所提供了一種剖析工具?GNU?profiler(gprof)。gprof?可以為?Linux平臺上的程序精確分析性能瓶頸。gprof精確地給出函數被調用的時間和次數,給出函數調用關系。

gprof?用戶手冊網站?http://sourceware.org/binutils/docs-2.17/gprof/index.html

2?功能

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

1.?可以顯示“flat?profile”,包括每個函數的調用次數,每個函數消耗的處理器時間,

2.?可以顯示“Call?graph”,包括函數的調用關系,每個函數調用花費了多少時間。

3.?可以顯示“注釋的源代碼”--是程序源代碼的一個復本,標記有程序中每行代碼的執行次數。

3?原理

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

4?使用流程

1.?在編譯和鏈接時?加上-pg選項。一般我們可以加在?makefile?中。

2.?執行編譯的二進制程序。執行參數和方式同以前。

3.?在程序運行目錄下?生成?gmon.out?文件。如果原來有gmon.out?文件,將會被重寫。

4.?結束進程。這時?gmon.out?會再次被刷新。

5.?用?gprof?工具分析?gmon.out?文件。

5?參數說明

l?-b?不再輸出統計圖表中每個字段的詳細描述。

l?-p?只輸出函數的調用圖(Call?graph的那部分信息)。

l?-q?只輸出函數的時間消耗列表。

l?-e?Name?不再輸出函數Name?及其子函數的調用圖(除非它們有未被限制的其它父函數)。可以給定多個?-e?標志。一個?-e?標志只能指定一個函數。

l?-E?Name?不再輸出函數Name?及其子函數的調用圖,此標志類似于?-e?標志,但它在總時間和百分比時間的計算中排除了由函數Name?及其子函數所用的時間。

l?-f?Name?輸出函數Name?及其子函數的調用圖。可以指定多個?-f?標志。一個?-f?標志只能指定一個函數。

l?-F?Name?輸出函數Name?及其子函數的調用圖,它類似于?-f?標志,但它在總時間和百分比時間計算中僅使用所打印的例程的時間。可以指定多個?-F?標志。一個?-F?標志只能指定一個函數。-F?標志覆蓋?-E?標志。

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

一般用法:?gprof?b?二進制程序?gmon.out?>report.txt

6?報告說明

Gprof?產生的信息解釋:

??%time

Cumulative

seconds

Self?

Seconds

Calls

Self

TS/call

Total

TS/call

name

該函數消耗時間占程序所有時間百分比

程序的累積執行時間

(只是包括gprof能夠監控到的函數)

該函數本身執行時間

所有被調用次數的合共時間

函數被調用次數

函數平均執行時間

(不包括被調用時間)

函數的單次執行時間

函數平均執行時間

(包括被調用時間)

函數的單次執行時間

函數名

Call?Graph?的字段含義:

Index

%time

Self

Children

Called

Name

索引值

函數消耗時間占所有時間百分比

函數本身執行時間

執行子函數所用時間

被調用次數

函數名

注意:

程序的累積執行時間只是包括gprof能夠監控到的函數。工作在內核態的函數和沒有加-pg編譯的第三方庫函數是無法被gprof能夠監控到的,(如sleep()等)

Gprof?的具體參數可以?通過?man?gprof?查詢。

7?共享庫的支持

對于代碼剖析的支持是由編譯器增加的,因此如果希望從共享庫中獲得剖析信息,就需要使用?-pg?來編譯這些庫提供已經啟用代碼剖析支持而編譯的?C?庫版本(libc_p.a)。

如果需要分析系統函數(如libc庫),可以用?lc_p替換-lc。這樣程序會鏈接libc_p.so或libc_p.a。這非常重要,因為只有這樣才能監控到底層的c庫函數的執行時間,(例如memcpy(),memset(),sprintf()等)。

gcc?example1.c?–pg?-lc_p?-o?example1

注意要用ldd?./example?|?grep?libc來查看程序鏈接的是libc.so還是libc_p.so

8?用戶時間與內核時間

gprof?的最大缺陷:它只能分析應用程序在運行過程中所消耗掉的用戶時間,無法得到程序內核空間的運行時間。通常來說,應用程序在運行時既要花費一些時間來運行用戶代碼,也要花費一些時間來運行?“系統代碼”,例如內核系統調用sleep()。

有一個方法可以查看應用程序的運行時間組成,在?time?命令下面執行程序。這個命令會顯示一個應用程序的實際運行時間、用戶空間運行時間、內核空間運行時間

如?time?./program

輸出:

real????2m30.295s

user????0m0.000s

sys?????0m0.004s

9?注意事項

1.?g++在編譯和鏈接兩個過程,都要使用-pg選項。

2.?只能使用靜態連接libc庫,否則在初始化*.so之前就調用profile代碼會引起“segmentation?fault,解決辦法是編譯時加上-static-libgcc或-static。

3.?如果不用g++而使用ld直接鏈接程序,要加上鏈接文件/lib/gcrt0.o,如ld?-o?myprog?/lib/gcrt0.o?myprog.o?utils.o?-lc_p。也可能是gcrt1.o

4.?要監控到第三方庫函數的執行時間,第三方庫也必須是添加?pg?選項編譯的。

5.?gprof只能分析應用程序所消耗掉的用戶時間.

6.?程序不能以demon方式運行。否則采集不到時間。(可采集到調用次數)

7.?首先使用?time?來運行程序從而判斷?gprof?是否能產生有用信息是個好方法。

8.?如果?gprof?不適合您的剖析需要,那么還有其他一些工具可以克服?gprof?部分缺陷,包括?OProfile?和?Sysprof。

9.?gprof對于代碼大部分是用戶空間的CPU密集型的程序用處明顯。對于大部分時間運行在內核空間或者由于外部因素(例如操作系統的?I/O?子系統過載)而運行得非常慢的程序難以進行優化。

10.?gprof?不支持多線程應用,多線程下只能采集主線程性能數據。原因是gprof采用ITIMER_PROF信號,在多線程內只有主線程才能響應該信號。但是有一個簡單的方法可以解決這一問題:http://sam.zoy.org/writings/programming/gprof.html

11.?gprof只能在程序正常結束退出之后才能生成報告(gmon.out)。

a)?原因:?gprof通過在atexit()里注冊了一個函數來產生結果信息,任何非正常退出都不會執行atexit()的動作,所以不會產生gmon.out文件。

b)?程序可從main函數中正常退出,或者通過系統調用exit()函數退出。

10?多線程應用

gprof?不支持多線程應用,多線程下只能采集主線程性能數據。原因是gprof采用ITIMER_PROF信號,在多線程內只有主線程才能響應該信號。

采用什么方法才能夠分析所有線程呢?關鍵是能夠讓各個線程都響應ITIMER_PROF信號。可以通過樁子函數來實現,重寫pthread_create函數

?gprof-helper.c

#define?_GNU_SOURCE

#include?<sys/time.h>

#include?<stdio.h>

#include?<stdlib.h>

#include?<dlfcn.h>

#include?<pthread.h>

static?void?*?wrapper_routine(void?*);

/*?Original?pthread?function?*/

static?int?(*pthread_create_orig)(pthread_t?*__restrict,

??????????????????????????????????__const?pthread_attr_t?*__restrict,

??????????????????????????????????void?*(*)(void?*),

??????????????????????????????????void?*__restrict)?=?NULL;

/*?Library?initialization?function?*/

void?wooinit(void)?__attribute__((constructor));

void?wooinit(void)

{

????pthread_create_orig?=?dlsym(RTLD_NEXT,?"pthread_create");

????fprintf(stderr,?"pthreads:?using?profiling?hooks?for?gprof/n");

????if(pthread_create_orig?==?NULL)

????{

????????char?*error?=?dlerror();

????????if(error?==?NULL)

????????{

????????????error?=?"pthread_create?is?NULL";

????????}

????????fprintf(stderr,?"%s/n",?error);

????????exit(EXIT_FAILURE);

????}

}

/*?Our?data?structure?passed?to?the?wrapper?*/

typedef?struct?wrapper_s

{

????void?*?(*start_routine)(void?*);

????void?*?arg;

????pthread_mutex_t?lock;

????pthread_cond_t??wait;

????struct?itimerval?itimer;

}?wrapper_t;

/*?The?wrapper?function?in?charge?for?setting?the?itimer?value?*/

static?void?*?wrapper_routine(void?*?data)

{

????/*?Put?user?data?in?thread-local?variables?*/

????void?*?(*start_routine)(void?*)?=?((wrapper_t*)data)->;start_routine;

????void?*?arg?=?((wrapper_t*)data)->;arg;

????/*?Set?the?profile?timer?value?*/

????setitimer(ITIMER_PROF,?&((wrapper_t*)data)->;itimer,?NULL);

????/*?Tell?the?calling?thread?that?we?don't?need?its?data?anymore?*/

????pthread_mutex_lock(&((wrapper_t*)data)->;lock);

????pthread_cond_signal(&((wrapper_t*)data)->;wait);

????pthread_mutex_unlock(&((wrapper_t*)data)->;lock);

????/*?Call?the?real?function?*/

????return?start_routine(arg);

}

/*?Our?wrapper?function?for?the?real?pthread_create()?*/

int?pthread_create(pthread_t?*__restrict?thread,

???????????????????__const?pthread_attr_t?*__restrict?attr,

???????????????????void?*?(*start_routine)(void?*),

???????????????????void?*__restrict?arg)

{

????wrapper_t?wrapper_data;

????int?i_return;

????/*?Initialize?the?wrapper?structure?*/

????wrapper_data.start_routine?=?start_routine;

????wrapper_data.arg?=?arg;

????getitimer(ITIMER_PROF,?&wrapper_data.itimer);

????pthread_cond_init(&wrapper_data.wait,?NULL);

????pthread_mutex_init(&wrapper_data.lock,?NULL);

????pthread_mutex_lock(&wrapper_data.lock);

????/*?The?real?pthread_create?call?*/

????i_return?=?pthread_create_orig(thread,

???????????????????????????????????attr,

???????????????????????????????????&wrapper_routine,

???????????????????????????????????&wrapper_data);

????/*?If?the?thread?was?successfully?spawned,?wait?for?the?data

?????*?to?be?released?*/

????if(i_return?==?0)

????{

????????pthread_cond_wait(&wrapper_data.wait,?&wrapper_data.lock);

????}

????pthread_mutex_unlock(&wrapper_data.lock);

????pthread_mutex_destroy(&wrapper_data.lock);

????pthread_cond_destroy(&wrapper_data.wait);

????return?i_return;

}

///

然后編譯成動態庫?gcc?-shared?-fPIC?gprof-helper.c?-o?gprof-helper.so?-lpthread?-ldl?

使用例子:

/a.c/

#include?<stdio.h>;

#include?<stdlib.h>;

#include?<unistd.h>;

#include?<pthread.h>;

#include?<string.h>;

void?fun1();

void?fun2();

void*?fun(void?*?argv);

int?main()

{

????????int?i?=0;

????????int?id;

????????pthread_t????thread[100];

????????for(i?=0?;i<?100;?i++)

????????{

????????????????id?=?pthread_create(&thread[i],?NULL,?fun,?NULL);

????????????????printf("thread?=%d/n",i);

????????}

????????printf("dsfsd/n");

????????return?0;

}

void*??fun(void?*?argv)

{

????????fun1();

????????fun2();

????????return?NULL;

}

void?fun1()

{

????????int?i?=?0;

????????while(i<100)

????????{

????????????????i++;????????

????????????????printf("fun1/n");

????????}????????

}

void?fun2()

{

????????int?i?=?0;

????????int?b;

????????while(i<50)

????????{

????????????????i++;

????????????????printf("fun2/n");

????????????????//b+=i;????????

????????}????????

}

///

gcc?-pg?a.c??gprof-helper.so

運行程序:

./a.out

分析gmon.out:

gprof?-b?a.out?gmon.out

總結

以上是生活随笔為你收集整理的Linux性能评测工具之一:gprof篇的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。