profiler

簡介

各種軟件對(duì)于性能的需求可能會(huì)有很大的區(qū)別循签,但是很多應(yīng)用程序都有非常嚴(yán)格的性能需求教翩,這一點(diǎn)并不奇怪阱洪。電影播放器就是一個(gè)很好的例子:如果一個(gè)電影播放器只能以所需要速度的 75% 來播放電影,那么它幾乎就沒什么用處了槽奕。

其他應(yīng)用程序(例如視頻編碼)如果是耗時(shí)非常長的操作嘴纺,最好以 “批處理” 任務(wù)的方式運(yùn)行败晴,此時(shí)啟動(dòng)一個(gè)作業(yè),讓其一直運(yùn)行栽渴,然后我們就可以去干別的事情了尖坤。盡管這些類型的應(yīng)用程序沒有這種硬性性能指標(biāo)的限制,但是提高速度仍然會(huì)帶來很多好處闲擦,例如可以在給定的時(shí)間內(nèi)可以對(duì)更多電影進(jìn)行編碼慢味,在同樣的時(shí)間內(nèi)可以以更高的品質(zhì)進(jìn)行編碼。

通常墅冷,除了最簡單的應(yīng)用程序之外纯路,對(duì)于其他應(yīng)用程序來說,性能越好寞忿,這個(gè)應(yīng)用程序的用處就越大驰唬,也就會(huì)越流行。由于這個(gè)原因腔彰,性能考慮是(也應(yīng)該是)很多應(yīng)用程序開發(fā)人員腦袋中的第一根弦叫编。

不幸的是,很多嘗試讓應(yīng)用程序速度更快的努力都白費(fèi)了霹抛,因?yàn)殚_發(fā)人員通常都是對(duì)自己的軟件進(jìn)行一些小型的優(yōu)化宵溅,而沒有去研究程序在更大的范圍內(nèi)是如何操作的。例如上炎,我們可能會(huì)花費(fèi)大量的時(shí)間來讓某個(gè)特定函數(shù)的運(yùn)行速度達(dá)到原來的兩倍,這一點(diǎn)非常不錯(cuò),但是如果這個(gè)函數(shù)很少被調(diào)用(例如打開文件)藕施,那么將這個(gè)函數(shù)的執(zhí)行時(shí)間從 200ms 減少到 100ms寇损,對(duì)于整個(gè)軟件的總體執(zhí)行時(shí)間來說并不會(huì)有太大的影響。

有效地利用您的時(shí)間的方法是裳食,盡量優(yōu)化軟件中被頻繁調(diào)用的部分矛市。例如,假設(shè)應(yīng)用程序花了 50% 的時(shí)間在字符串處理函數(shù)上诲祸,如果可以對(duì)這些函數(shù)進(jìn)行優(yōu)化浊吏,提高 10% 的效率,那么應(yīng)用程序的總體執(zhí)行時(shí)間就會(huì)改進(jìn) 5%救氯。

因此找田,如果希望能夠有效地對(duì)程序進(jìn)行優(yōu)化,那么精確地了解時(shí)間在應(yīng)用程序中是如何花費(fèi)的着憨,以及真實(shí)的輸入數(shù)據(jù)墩衙,這一點(diǎn)非常重要。這種行為就稱為代碼剖析(code profiling)甲抖。本文將簡要介紹 GNU 編譯器工具包所提供的一種剖析工具漆改,它的名字讓人可以產(chǎn)生無限遐想,叫 GNU profiler(gprof)准谚。本文主要面向那些開放源碼軟件開發(fā)工具的新手挫剑。

gprof 來救援了

在開始介紹如何使用 gprof 之前,需要首先了解一下在整個(gè)開發(fā)周期中柱衔,剖析應(yīng)該在何處進(jìn)行樊破。通常來說,編寫代碼應(yīng)該有 3 個(gè)目標(biāo)秀存,按照重要性的次序分別如下所示:

保證軟件可以正確地工作捶码。這通常是開發(fā)過程的重點(diǎn)。通常或链,如果一個(gè)軟件根本連我們期望它做的事情都實(shí)現(xiàn)不了惫恼,那么即使它運(yùn)行速度非常快澳盐,也根本沒有任何意義祈纯!顯然,正確性在某些情況下可能并不是至關(guān)重要的叼耙;例如腕窥,如果一個(gè)電影播放器可以正確地播放 99% 的電影文件,但是偶然會(huì)有些顯示問題筛婉,那它依然可以使用簇爆。但是通常來說癞松,正確性要遠(yuǎn)遠(yuǎn)比速度更加重要。

保證軟件是可維護(hù)的入蛆。這實(shí)際上是第一個(gè)目標(biāo)的一個(gè)子項(xiàng)响蓉。通常,如果軟件編寫得可維護(hù)性不好哨毁,那么即使它最開始時(shí)可以很好地工作枫甲,很快您(或其他人)在修正 bug 或添加新特性時(shí)可能也會(huì)破壞程序的正確性。

讓軟件可以快速運(yùn)行扼褪。這就是剖析的用武之地想幻。當(dāng)軟件可以正確運(yùn)行之后,我們就可以開始剖析的過程來幫助它更快地運(yùn)行了话浇。

假設(shè)我們現(xiàn)在已經(jīng)有了一個(gè)可以工作的應(yīng)用程序脏毯,接下來讓我們來看一下如何使用 gprof 來精確測(cè)量應(yīng)用程序執(zhí)行過程中時(shí)間都花費(fèi)到什么地方去了,這樣做的目的是了解一下在什么地方進(jìn)行優(yōu)化效果最佳凳枝。

gprof 可以對(duì) C抄沮、C++、Pascal 和 Fortran 77 應(yīng)用程序進(jìn)行剖析岖瑰。本文中的例子使用的是 C叛买。

清單 1. 耗時(shí)的應(yīng)用程序示例

#include

int a(void) {

int i=0,g=0;

while(i++<100000)

{

g+=i;

}

return g;

}

int b(void) {

int i=0,g=0;

while(i++<400000)

{

g+=i;

}

return g;

}

int main(int argc, char** argv)

{

int iterations;

if(argc != 2)

{

printf("Usage %s \\n", argv[0]);

exit(-1);

}

else

iterations = atoi(argv[1]);

printf("No of iterations = %d\\n", iterations);

while(iterations--)

{

a();

b();

}

}

正如我們從代碼中可以看到的,這個(gè)非常簡單的應(yīng)用程序包括兩個(gè)函數(shù):a和b蹋订,它們都處于一個(gè)繁忙的循環(huán)中消耗 CPU 周期率挣。main函數(shù)中采用了一個(gè)循環(huán)來反復(fù)調(diào)用這兩個(gè)函數(shù)。第二個(gè)函數(shù)b循環(huán)的次數(shù)是a函數(shù)的 4 倍露戒,因此我們期望在對(duì)代碼分析完之后椒功,可以看出大概有 20% 的時(shí)間花在了a函數(shù)中,而 80% 的時(shí)間花在了b函數(shù)中智什。下面就開始剖析代碼动漾,并看一下我們的這些期望是否正確。

啟用剖析非常簡單荠锭,只需要在 gcc 編譯標(biāo)志中加上-pg即可旱眯。編譯方法如下:

gcc example1.c -pg -o example1 -O2 -lc

在編譯好這個(gè)應(yīng)用程序之后,可以按照普通方式運(yùn)行這個(gè)程序:

./example1 50000

當(dāng)這個(gè)程序運(yùn)行完之后证九,應(yīng)該會(huì)看到在當(dāng)前目錄中新創(chuàng)建了一個(gè)文件 gmon.out删豺。

使用輸出結(jié)果

首先看一下 “flat profile”,我們可以使用gprof命令獲得它愧怜,這需要為其傳遞可執(zhí)行文件和 gmon.out 文件作為參數(shù)呀页,如下所示:

gprof example1 gmon.out -p

這會(huì)輸出以下內(nèi)容:

清單 2. flat profile 的結(jié)果

Flat profile:

Each sample counts as 0.01 seconds.

% ? cumulative ? self ? ? ? ? ? ? ?self ? ? total

time ? seconds ? seconds ? ?calls ?ms/call ?ms/call ?name

80.24 ? ? 63.85 ? ?63.85 ? ?50000 ? ? 1.28 ? ? 1.28 ?b

20.26 ? ? 79.97 ? ?16.12 ? ?50000 ? ? 0.32 ? ? 0.32 ?a

從這個(gè)輸出結(jié)果中可以看到,正如我們期望的一樣拥坛,b函數(shù)所花費(fèi)的時(shí)間大概是a函數(shù)所花費(fèi)的時(shí)間的 4 倍蓬蝶。真正的數(shù)字并不是十分有用尘分;由于取整舍入錯(cuò)誤,這些數(shù)字可能并不是非常精確丸氛。

聰明的讀者可能會(huì)注意到音诫,很多函數(shù)調(diào)用(例如printf)在這個(gè)輸出中都沒有出現(xiàn)。這是因?yàn)檫@些函數(shù)都是在 C 運(yùn)行時(shí)庫(libc.so)中的雪位,(在本例中)它們都沒有使用-pg進(jìn)行編譯,因此就沒有對(duì)這個(gè)庫中的函數(shù)收集剖析信息梨撞。稍后我們會(huì)回到這個(gè)問題上來雹洗。

接下來我們希望了解的是 “call graph”,這可以通過下面的方式獲得:

gprof example1 gmon.out -q

這會(huì)輸出下面的結(jié)果卧波。

清單 3. Call graph

Call graph (explanation follows)

granularity: each sample hit covers 2 byte(s) for 0.01% of 79.97 seconds

index % time ? ?self ?children ? ?called ? ? name

[1] ? ?100.0 ? ?0.00 ? 79.97 ? ? ? ? ? ? ? ? main [1]

63.85 ? ?0.00 ? 50000/50000 ? ? ? b [2]

16.12 ? ?0.00 ? 50000/50000 ? ? ? a [3]

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

63.85 ? ?0.00 ? 50000/50000 ? ? ? main [1]

[2] ? ? 79.8 ? 63.85 ? ?0.00 ? 50000 ? ? ? ? b [2]

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

16.12 ? ?0.00 ? 50000/50000 ? ? ? main [1]

[3] ? ? 20.2 ? 16.12 ? ?0.00 ? 50000 ? ? ? ? a [3]

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

最后时肿,我們可能會(huì)希望獲得一個(gè) “帶注解的源代碼” 清單,它會(huì)將源代碼輸出到應(yīng)用程序中港粱,并加上每個(gè)函數(shù)被調(diào)用了多少次的注釋螃成。

要使用這種功能,請(qǐng)使用啟用調(diào)試功能的標(biāo)志來編譯源代碼查坪,這樣源代碼就會(huì)被加入可執(zhí)行程序中:

gcc example1.c -g -pg -o example1 -O2 -lc

像以前一樣重新運(yùn)行這個(gè)應(yīng)用程序:

./example1 50000

gprof命令現(xiàn)在應(yīng)該是:

gprof example1 gmon.out -A

這會(huì)輸出下面的結(jié)果:

清單 4. 帶注釋的源代碼

*** File /home/martynh/profarticle/example1.c:

#include

50000 -> int a(void) {

int i=0,g=0;

while(i++<100000)

{

g+=i;

}

return g;

}

50000 -> int b(void) {

int i=0,g=0;

while(i++<400000)

{

g+=i;

}

return g;

}

int main(int argc, char** argv)

##### -> {

int iterations;

if(argc != 2)

{

printf("Usage %s \\n", argv[0]);

exit(-1);

}

else

iterations = atoi(argv[1]);

printf("No of iterations = %d\\n", iterations);

while(iterations--)

{

a();

b();

}

}

Top 10 Lines:

Line ? ? ?Count

3 ? ? ?50000

11 ? ? ?50000

Execution Summary:

3 ? Executable lines in this file

3 ? Lines executed

100.00 ? Percent of the file executed

100000 ? Total number of line executions

33333.33 ? Average executions per line

共享庫的支持

正如在前面曾經(jīng)介紹的寸宏,對(duì)于代碼剖析的支持是由編譯器增加的,因此如果希望從共享庫(包括 C 庫 libc.a)中獲得剖析信息偿曙,就需要使用-pg來編譯這些庫氮凝。幸運(yùn)的是,很多發(fā)行版都提供了已經(jīng)啟用代碼剖析支持而編譯的 C 庫版本(libc_p.a)望忆。

在我使用的發(fā)行版 gentoo 中罩阵,需要將 “profile” 添加到 USE 標(biāo)志中,并重新執(zhí)行emergeglibc启摄。當(dāng)這個(gè)過程完成之后稿壁,就會(huì)看到 /usr/lib/libc_p.a 文件已經(jīng)創(chuàng)建好了。對(duì)于沒有按照標(biāo)準(zhǔn)提供 libc_p 的發(fā)行版本來說歉备,需要檢查它是否可以單獨(dú)安裝傅是,或者可能需要自己下載 glibc 的源代碼并進(jìn)行編譯。

在獲得 libc_p.a 文件之后威创,就可以簡單地重新編譯前面的例子了落午,方法如下:

gcc example1.c -g -pg -o example1 -O2 -lc_p

然后,可以像以前一樣運(yùn)行這個(gè)應(yīng)用程序肚豺,并獲得 flat profile 或 call graph溃斋,應(yīng)該會(huì)看到很多 C 運(yùn)行函數(shù),包括printf(這些函數(shù)在我們的測(cè)試函數(shù)中并不是太重要)吸申。

用戶時(shí)間與內(nèi)核時(shí)間

現(xiàn)在我們已經(jīng)知道如何使用 gprof 了梗劫,接下來可以簡單且有效地對(duì)應(yīng)用程序進(jìn)行分析了享甸,希望可以消除性能瓶頸。

不過現(xiàn)在您可能已經(jīng)注意到了 gprof 的最大缺陷:它只能分析應(yīng)用程序在運(yùn)行過程中所消耗掉的用戶時(shí)間梳侨。通常來說蛉威,應(yīng)用程序在運(yùn)行時(shí)既要花費(fèi)一些時(shí)間來運(yùn)行用戶代碼,也要花費(fèi)一些時(shí)間來運(yùn)行 “系統(tǒng)代碼”走哺,例如內(nèi)核系統(tǒng)調(diào)用蚯嫌。

如果對(duì)清單 1 稍加修改,就可以清楚地看出這個(gè)問題:

清單 5. 為清單 1 添加系統(tǒng)調(diào)用分析功能

#include

int a(void) {

sleep(1);

return 0;

}

int b(void) {

sleep(4);

return 0;

}

int main(int argc, char** argv)

{

int iterations;

if(argc != 2)

{

printf("Usage %s \\n", argv[0]);

exit(-1);

}

else

iterations = atoi(argv[1]);

printf("No of iterations = %d\\n", iterations);

while(iterations--)

{

a();

b();

}

}

正如您可以看到的丙躏,我們對(duì)清單 1 中的代碼進(jìn)行了修改择示,現(xiàn)在a函數(shù)和b函數(shù)不再只處理繁忙的循環(huán)了,而是分別調(diào)用 C 運(yùn)行時(shí)函數(shù)sleep來掛起執(zhí)行 1 秒和 4 秒晒旅。

像以前一樣編譯這個(gè)應(yīng)用程序:

gcc example2.c -g -pg -o example2 -O2 -lc_p

并讓這個(gè)程序循環(huán) 30 次:

./example2 30

所生成的 flat profile 如下所示:

清單 6. flat profile 顯示了系統(tǒng)調(diào)用的結(jié)果

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 ? ? ?120 ? ? 0.00 ? ? 0.00 ?sigprocmask

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? 61 ? ? 0.00 ? ? 0.00 ?__libc_sigaction

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? 61 ? ? 0.00 ? ? 0.00 ?sigaction

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? 60 ? ? 0.00 ? ? 0.00 ?nanosleep

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? 60 ? ? 0.00 ? ? 0.00 ?sleep

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? 30 ? ? 0.00 ? ? 0.00 ?a

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? 30 ? ? 0.00 ? ? 0.00 ?b

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? 21 ? ? 0.00 ? ? 0.00 ?_IO_file_overflow

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? ?3 ? ? 0.00 ? ? 0.00 ?_IO_new_file_xsputn

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? ?2 ? ? 0.00 ? ? 0.00 ?_IO_new_do_write

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? ?2 ? ? 0.00 ? ? 0.00 ?__find_specmb

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? ?2 ? ? 0.00 ? ? 0.00 ?__guard_setup

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? ?1 ? ? 0.00 ? ? 0.00 ?_IO_default_xsputn

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? ?1 ? ? 0.00 ? ? 0.00 ?_IO_doallocbuf

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? ?1 ? ? 0.00 ? ? 0.00 ?_IO_file_doallocate

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? ?1 ? ? 0.00 ? ? 0.00 ?_IO_file_stat

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? ?1 ? ? 0.00 ? ? 0.00 ?_IO_file_write

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? ?1 ? ? 0.00 ? ? 0.00 ?_IO_setb

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? ?1 ? ? 0.00 ? ? 0.00 ?____strtol_l_internal

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? ?1 ? ? 0.00 ? ? 0.00 ?___fxstat64

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? ?1 ? ? 0.00 ? ? 0.00 ?__cxa_atexit

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? ?1 ? ? 0.00 ? ? 0.00 ?__errno_location

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? ?1 ? ? 0.00 ? ? 0.00 ?__new_exitfn

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? ?1 ? ? 0.00 ? ? 0.00 ?__strtol_internal

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? ?1 ? ? 0.00 ? ? 0.00 ?_itoa_word

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? ?1 ? ? 0.00 ? ? 0.00 ?_mcleanup

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? ?1 ? ? 0.00 ? ? 0.00 ?atexit

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? ?1 ? ? 0.00 ? ? 0.00 ?atoi

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? ?1 ? ? 0.00 ? ? 0.00 ?exit

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? ?1 ? ? 0.00 ? ? 0.00 ?flockfile

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? ?1 ? ? 0.00 ? ? 0.00 ?funlockfile

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? ?1 ? ? 0.00 ? ? 0.00 ?main

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? ?1 ? ? 0.00 ? ? 0.00 ?mmap

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? ?1 ? ? 0.00 ? ? 0.00 ?moncontrol

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? ?1 ? ? 0.00 ? ? 0.00 ?new_do_write

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? ?1 ? ? 0.00 ? ? 0.00 ?printf

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? ?1 ? ? 0.00 ? ? 0.00 ?setitimer

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? ?1 ? ? 0.00 ? ? 0.00 ?vfprintf

0.00 ? ? ?0.00 ? ? 0.00 ? ? ? ?1 ? ? 0.00 ? ? 0.00 ?write

如果對(duì)這個(gè)輸出結(jié)果進(jìn)行分析栅盲,我們就會(huì)看到,盡管 profiler 已經(jīng)記錄了每個(gè)函數(shù)被調(diào)用的確切次數(shù)废恋,但是為這些函數(shù)記錄的時(shí)間(實(shí)際上是所有函數(shù))都是 0.00谈秫。這是因?yàn)閟leep函數(shù)實(shí)際上是執(zhí)行了一次對(duì)內(nèi)核空間的調(diào)用,從而將應(yīng)用程序的執(zhí)行掛起了鱼鼓,然后有效地暫停執(zhí)行拟烫,并等待內(nèi)核再次將其喚醒。由于花在用戶空間執(zhí)行的時(shí)間與花在內(nèi)核中睡眠的時(shí)間相比非常小蚓哩,因此就被取整成零了构灸。其原因是 gprof 僅僅是通過以固定的周期對(duì)程序運(yùn)行時(shí)間進(jìn)行采樣測(cè)量來工作的。因此岸梨,當(dāng)程序不運(yùn)行時(shí)喜颁,就不會(huì)對(duì)程序進(jìn)行采樣測(cè)量。

這實(shí)際上是一把雙刃劍曹阔。從一個(gè)方面來說半开,這使得有些程序非常難以進(jìn)行優(yōu)化,例如花費(fèi)大部分時(shí)間在內(nèi)核空間的程序赃份,或者由于外部因素(例如操作系統(tǒng)的 I/O 子系統(tǒng)過載)而運(yùn)行得非常慢的程序寂拆。從另一個(gè)方面來說,這意味著剖析不會(huì)受到系統(tǒng)中其他事件的影響(例如另外一個(gè)用戶使用了大量的 CPU 時(shí)間)抓韩。

通常纠永,有一個(gè)很好的基準(zhǔn)測(cè)試可以用來查看 gprof 對(duì)于幫助對(duì)應(yīng)用程序進(jìn)行優(yōu)化是多么有用,方法是在time命令下面執(zhí)行它谒拴。這個(gè)命令會(huì)顯示一個(gè)應(yīng)用程序運(yùn)行完成需要多少時(shí)間尝江,并可以測(cè)量它在用戶空間和內(nèi)核空間各花費(fèi)了多少時(shí)間。

如果查看一下清單 2 中的例子:

time ./example2 30

輸出結(jié)果應(yīng)該如下所示:

清單 7. time 命令的輸出結(jié)果

No of iterations = 30

real ? ?2m30.295s

user ? ?0m0.000s

sys ? ? 0m0.004s

我們可以看出幾乎沒有多少時(shí)間被花費(fèi)在執(zhí)行用戶空間的代碼上英上,因此 gprof 在此處不會(huì)非常有用炭序。

結(jié)束語

盡管 gprof 存在上面的限制啤覆,但是它對(duì)于優(yōu)化代碼來說依然是個(gè)非常有用的工具,如果您的代碼大部分是用戶空間 CPU 密集型的惭聂,它的用處就更加明顯窗声。首先使用time來運(yùn)行程序從而判斷 gprof 是否能產(chǎn)生有用信息是個(gè)好主意。

如果 gprof 不適合您的剖析需要辜纲,那么還有其他一些工具可以克服 gprof 部分缺陷笨觅,包括 OProfile 和 Sysprof (請(qǐng)參看參考資料中有關(guān)這些工具信息的鏈接)。

從另一個(gè)方面來說耕腾,假設(shè)我們已經(jīng)安裝了 gcc屋摇,gprof 相對(duì)于其他工具來說,一個(gè)主要的優(yōu)點(diǎn)是很可能早已在 Linux 機(jī)器上安裝了需要使用的工具幽邓。



Gprof產(chǎn)生的信息解釋:

%time ? ?

該函數(shù)消耗時(shí)間占程序所有時(shí)間百分比

Cumulative Seconds

程序的累積執(zhí)行時(shí)間 (只是包括gprof能夠監(jiān)控到的函數(shù))

Self seconds

該函數(shù)本身執(zhí)行時(shí)間(所有被調(diào)用次數(shù)的合共時(shí)間)

Calls

函數(shù)被調(diào)用次數(shù)

Self ?TS/call

函數(shù)平均執(zhí)行時(shí)間(不包括被調(diào)用時(shí)間)(函數(shù)的單次執(zhí)行時(shí)間)

TotalTS/call

函數(shù)平均執(zhí)行時(shí)間(包括被調(diào)用時(shí)間)

name

(函數(shù)的單次執(zhí)行時(shí)間)函數(shù)名



Call Graph的字段含義:

Index ?

索引值

%time

函數(shù)消耗時(shí)間占所有時(shí)間百分比

Self

函數(shù)本身執(zhí)行時(shí)間

Children

執(zhí)行子函數(shù)所用時(shí)間

Called

被調(diào)用次數(shù)

Name

函數(shù)名

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市火脉,隨后出現(xiàn)的幾起案子牵舵,更是在濱河造成了極大的恐慌,老刑警劉巖倦挂,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件畸颅,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡方援,警方通過查閱死者的電腦和手機(jī)没炒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來犯戏,“玉大人送火,你說我怎么就攤上這事∠确耍” “怎么了种吸?”我有些...
    開封第一講書人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長呀非。 經(jīng)常有香客問我坚俗,道長,這世上最難降的妖魔是什么岸裙? 我笑而不...
    開封第一講書人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任猖败,我火速辦了婚禮,結(jié)果婚禮上降允,老公的妹妹穿的比我還像新娘恩闻。我一直安慰自己,他們只是感情好拟糕,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開白布判呕。 她就那樣靜靜地躺著倦踢,像睡著了一般。 火紅的嫁衣襯著肌膚如雪侠草。 梳的紋絲不亂的頭發(fā)上辱挥,一...
    開封第一講書人閱讀 51,598評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音边涕,去河邊找鬼晤碘。 笑死,一個(gè)胖子當(dāng)著我的面吹牛功蜓,可吹牛的內(nèi)容都是我干的园爷。 我是一名探鬼主播,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼式撼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼童社!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起著隆,我...
    開封第一講書人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤扰楼,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后美浦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體弦赖,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年浦辨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蹬竖。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡流酬,死狀恐怖币厕,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情芽腾,我是刑警寧澤劈榨,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站晦嵌,受9級(jí)特大地震影響同辣,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜惭载,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一旱函、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧描滔,春花似錦棒妨、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽伏穆。三九已至,卻和暖如春纷纫,著一層夾襖步出監(jiān)牢的瞬間枕扫,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來泰國打工辱魁, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留烟瞧,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓染簇,卻偏偏與公主長得像参滴,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子锻弓,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法砾赔,類相關(guān)的語法,內(nèi)部類的語法青灼,繼承相關(guān)的語法过蹂,異常的語法,線程的語...
    子非魚_t_閱讀 31,634評(píng)論 18 399
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理聚至,服務(wù)發(fā)現(xiàn),斷路器本橙,智...
    卡卡羅2017閱讀 134,657評(píng)論 18 139
  • *面試心聲:其實(shí)這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個(gè)offer,總結(jié)起來就是把...
    Dove_iOS閱讀 27,145評(píng)論 30 470
  • 使用SQLServer Profiler監(jiān)視系統(tǒng)的一些基本概念和各種事件的監(jiān)視 這兩天需要搞一份我們某個(gè)系統(tǒng)的夜間...
    oo水桶oo閱讀 1,564評(píng)論 0 1
  • 她說甚亭,最近跟你交流都不怎么愉快贷币,感覺不在一個(gè)頻道上。 我看著那些字眼亏狰,突然就紅了眼眶役纹。我一直知道我們之間有問題,我...
    54小愈閱讀 624評(píng)論 0 0