这个更界面化:http://www.cnblogs.com/rocketfan/archive/2009/11/15/1603465.html
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和call graph。flat table列出了各个函数的运行时间(不包括子函数)及所占总运行时间的比率,函数的调用次数;call graph还包括函数之间的调用关系,详细列出了每个函数在它的各个子函数上所耗费的时间。
下面一个简单的例子说明一下两张表中各项的含义:
待分析的程序源码:
#define MAX 10000000
void 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% of 0.14 seconds
index % 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。primary line上面的行称为caller's line,列举的是调用该函数的函数;下面的行subroutine's line列举的是该函数调用的子函数。这三种line的各项名称虽然相同,但有着截然不同的含义。
以下都以第二个entry为例说明:
primary line
index % 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 line
index % 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 line
index % 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统计各个函数的运行时间是采用的抽样的方法,周期性的查看Program counter指向哪一个函数的地址段,并把结果以直方图的形式保存下来。
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
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和call graph。flat table列出了各个函数的运行时间(不包括子函数)及所占总运行时间的比率,函数的调用次数;call graph还包括函数之间的调用关系,详细列出了每个函数在它的各个子函数上所耗费的时间。
下面一个简单的例子说明一下两张表中各项的含义:
待分析的程序源码:
#define MAX 10000000
void 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% of 0.14 seconds
index % 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。primary line上面的行称为caller's line,列举的是调用该函数的函数;下面的行subroutine's line列举的是该函数调用的子函数。这三种line的各项名称虽然相同,但有着截然不同的含义。
以下都以第二个entry为例说明:
primary line
index % 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 line
index % 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 line
index % 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统计各个函数的运行时间是采用的抽样的方法,周期性的查看Program counter指向哪一个函数的地址段,并把结果以直方图的形式保存下来。
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
作者:jackxiang@向东博客 专注WEB应用 构架之美 --- 构架之美,在于尽态极妍 | 应用之美,在于药到病除
地址:https://jackxiang.com/post/6581/
版权所有。转载时必须以链接形式注明作者和原始出处及本声明!
最后编辑: jackxiang 编辑于2013-8-13 18:28
评论列表