根据网上信息整理所成。
功能与优劣
gprof实际上只是一个用于读取profile结果文件的工具。gprof采用混合方法来收集程序的统计信息,它使用检测方法,在编译过程中在函数入口处插入计数器用于收集每个函数的被调用情况和被调用次数;也使用采样方法,在运行时按一定间隔去检查程序计数器并在分析时找出程序计数器对应的函数来统计函数占用的时间。需要注意的是,gprof统计的只是CPU的占用时间,对I/O瓶颈貌似无能为力,耗时甚久的I/O操作很可能只占据极少的CPU时间。
使用
正常运行编译好的程序,程序正常结束后会在当前目录生成统计信息文件gmon.out,也就是说,程序必须正常退出(调用exit或从main中返回)才能生成统计信息。
当前目录下如果有另外叫gmon.out的文件,内容将被本次运行生成的统计信息覆盖,多次运行统计程序前需要将前几次的gmon.out改名。
$ g++ main.cpp -pg -o main
$ ./main # 会生成gmon.out性能分析文件
$ gprof -b main gmon.out > report.txt
这是基本使用方法,更加详细的参见info gprof
。最终呈现的统计信息包括两张表:flat table和call graph。flat table列出了各个函数的运行时间(不包括子函数)及所占总运行时间的比率,函数的调用次数;call graph还包括函数之间的调用关系,详细列出了每个函数在它的各个子函数上所耗费的时间。
生成的信息与解释
Flat Profile的数据解释:
%time | Cumulative seconds | Self seconds | Calls | Self ms/call | Total ms/call | name |
---|---|---|---|---|---|---|
该函数消耗时间占程序所有时间百分比 | 函数和上列函数累计执行时间(仅包括gprof能够监控到的函数) | 该函数本身执行时间(所有被调用次数的总共时间) | 函数被调用次数 | 函数平均执行时间 | 函数平均执行时间,包括其衍生函数 | 函数名 |
如何分析呢?
1) 看%time列, 或者 "self ms/call"列, 这里消耗时间最多的函数就是最耗费CPU的函数了. 也是最值得优化的函数了. (消耗仅统计函数自身的代码消耗, 不统计子函数的消耗)
2) 看"total ms/call"列, 找到包含子函数在内最耗时间的函数
3) 从"self ms/call"列和"total ms/call"列对比可知, 如果self ms/call列的值很小,就可以推测子函数消耗时间很多
一般Flat Profile的数据就够算法竞赛或者日常的小项目的分析了。如果需要Call Graph的分析,参考网上其他的文章。
一些注意事项
- 通常gprof的采样周期是0.01s,统计项越接近这个值误差可能越大。若函数的运行时间低于0.01S,统计值会显示为0。
- 多线程下,gprof只能采集主线程性能数据。原因是gprof采用ITIMER_PROF信号,在多线程内,只有主线程才能响应该信号。解决的关键是让各个线程响应ITIMER_PROF信号,就是重写pthread_create函数。
- 一般gprof只能查看用户函数信息。如果想查看库函数的信息,需要在编译是再加入"-lc_p"编译参数代替"-lc"编译参数,这样程序会链接libc_p.a库,才可以产生库函数的profiling信息。
其他的一些工具
见https://blog.csdn.net/chdhust/article/details/41073885与https://blog.csdn.net/feilengcui008/article/details/51306894。