linux下的程序分析工具——gprof

来源:互联网 发布:在windows上安装spark 编辑:程序博客网 时间:2024/05/16 19:38
GNU gprof是一款linux平台上的程序分析软件(unix也有prof)。借助gprof可以获得C程序运行期间的统计数据,例如每个函数耗费的时间,函数被调用的次数以及各个函数相互之间的调用关系。gprof可以帮助我们找到程序运行的瓶颈,对占据大量CPU时间的函数进行调优(gprof统计的只是CPU的占用时间,对I/O瓶颈貌似无能为力,耗时甚久的I/O操作很可能只占据极少的CPU时间)。
gprof的使用非常简单,在编译链接的时候加上"-pg"选项,然后按照正常方式运行程序,如果程序正常退出,一个名为gmon.out将会产生。使用gprof可查看gmon.out中的统计结果:
gprof<options> [executable-file][profile-data-file(s)……] [>outfile]
可通过man gprof查看各选项含义,通常会加上"-b"选项禁止显示冗长的说明信息。
executable-file如果没有指定,则会默认为a.out。
profile-data-file可跟多个文件,若没有指定,默认gmon.out。
统计信息较多,最好重定向到outfile方便查看。
最终呈现的统计信息包括两张表:flat table和callgraph。flat table列出了各个函数的运行时间(不包括子函数)及所占总运行时间的比率,函数的调用次数;callgraph还包括函数之间的调用关系,详细列出了每个函数在它的各个子函数上所耗费的时间。
下面一个简单的例子说明一下两张表中各项的含义:
待分析的程序源码:
#define MAX 10000000void f() {long long sum = 0;for (long long i=0;i<MAX;i++)sum += i;}void g() {long long sum = 0;for (long long i=0;i<MAX;i++)sum += i;f();}int main() {long long sum = 0;for (long long i=0;i<MAX;i++)sum += i;f();g();}
       
Flat profile:Each sample counts as 0.01 seconds.  %         cumulative        self                self        total          time        seconds        seconds   calls       ms/call     ms/call      name    50.00        0.07              0.07        2      35.00      35.00        f() 28.57        0.11              0.04        1      40.00      75.00        g() 21.43        0.14              0.03                                               main% time:各个函数占用的时间比率(不包括子函数),这一列加起来应该为100%cumulative seconds:累积时间,当前行减去上一行即为当前函数耗费时间self seconds:当前函数耗费时间(不包括子函数)self calls:调用次数ms/call:调用一次耗费的平均时间(不包括子函数),单位毫秒total ms/call:同上,但包括子函数name:函数名call graph:granularity: each sample hit covers 4 byte(s) for 7.14% of0.14 secondsindex     % time    self    children   called       name                                                         <spontaneous>[1]           100.0   0.03      0.11                    main [1]                         0.04      0.04       1/1          g()[2]                         0.04      0.00       1/2          f()[3]-----------------------------------------------                         0.04      0.04        1/1        main [1][2]            53.6    0.04      0.04        1           g() [2]                         0.04      0.00        1/2        f() [3]-----------------------------------------------                         0.04      0.00        1/2        g() [2]                         0.04      0.00        1/2        main [1][3]            50.0    0.07      0.00         2          f() [3]-----------------------------------------------

每个函数都分配了一个index,index按升序排列,一个函数对应一个entry,两个entry之间用虚线隔开。
在每个entry中,以[index]起头的行称为primary line。primaryline上面的行称为caller's line,列举的是调用该函数的函数;下面的行subroutine'sline列举的是该函数调用的子函数。这三种line的各项名称虽然相同,但有着截然不同的含义。
以下都以第二个entry为例说明:
primary lineindex     % time   self    children    called      name[2]            53.6   0.04      0.04        1           g() [2]%time:g()耗费的时间比率。该比率包括了调用的f(),因此各个entry的该项数字加起来不等于100%。self:同flat table的self seconds。children:f()耗费的时间。下面的subroutines's line的self项和children项之和应等于该数值。called:只被调用了一次。subroutine's lineindex     % time     self      children      called      name                           0.04      0.00          1/2         f() [3]self:f()被g()调用过程中,f()的耗费时间0.04s。children:f()被g()调用过程中,f()中的子函数耗费时间为0。called:f()一共被调用了2次,其中有1次被g()调用。caller's lineindex     % time     self      children      called      name                          0.04      0.04          1/1          main[1]self:g()被main()调用过程中,g()的耗费时间。children:g()被main()调用过程中,g()中的子函数耗费的时间。called:g()一共被调用了1次,其中1次是被main()调用的。

gprof的基本原理
类似于gdb,gprof需要对待分析的程序做一些改动,因此在程序编译的时候需要加上"-pg"选项,如果程序的某个模块在编译的时候没有加上"-pg",则该模块的函数会被排除在统计范围之外。比如想要查看库函数的profiling,则需在链接库函数的时候用“-lc_p"代替”-lc"(gprof是各个类UNIX的标准工具,系统自带的链接库通常有两个版本,它们的区别在于编译的时候是否加上了"-pg"。用-lc_p等于告诉编译器选择加上了"-pg"的那个版本)。
加上"-pg"选项后,程序的入口会于main()之前调用monstartup(),主要是申请内存存储接下来获取的统计信息。
在每个函数中会调用_mcount(),主要是在函数的堆栈中查询父函数和子函数的地址并保存下来。
最后会在程序退出前调用_mcleanup(),将统计结果保存到gmon.out中,并完成清除工作。
gprof统计各个函数的运行时间是采用的抽样的方法,周期性的查看Programcounter指向哪一个函数的地址段,并把结果以直方图的形式保存下来。

PS:
有人建议在编译时不要加上"-g"选项,因为这样可能会影响分析结果。
通常gprof的采样周期是0.01s,统计项越接近这个值误差可能越大。若函数的运行时间低于0.01S,统计值会显示为0。

关于这一主题的有用链接:
http://www.cs.utah.edu/dept/old/texinfo/as/gprof_toc.html:关于options,flat table, call graph有更详细的论述。
http://wiki.waterlin.org/Cpp/gprof.html:对gprof的实现原理论述得很清晰。
http://sam.zoy.org/writings/programming/gprof.html:对多线程profiling。
http://linuxfocus.org/English/March2005/article371.meta.shtml:提到了perl和java的profiling方法。
        原文地址:http://blog.sina.com.cn/s/blog_6608391701013phr.html
       
0 0
原创粉丝点击