【发布时间】:2013-07-10 20:18:15
【问题描述】:
正如标题所说,我想知道这两个命令之间的区别以及它们产生的结果。
通过阅读this,我了解到 gprof 需要一个额外的标志(-g,gdb 也需要相同的标志?),但这并没有给我一个关于分析器之间差异的答案。
【问题讨论】:
正如标题所说,我想知道这两个命令之间的区别以及它们产生的结果。
通过阅读this,我了解到 gprof 需要一个额外的标志(-g,gdb 也需要相同的标志?),但这并没有给我一个关于分析器之间差异的答案。
【问题讨论】:
gprof 是专门发明的,因为prof 只给你“自我时间”。
“自我时间”告诉您在每个例程中找到程序计数器的总时间的比例。
如果您需要考虑的唯一“瓶颈”类型可以通过在调用堆栈底部减少循环来解决,那很好。
您通过减少对子例程的调用次数来解决的那种“瓶颈”呢?
这就是gprof 应该通过向呼叫者“收回”自我时间来帮助您找到的内容。
例程中的“包含时间”包括它的“自身时间”,加上从它调用的例程中冒出来的时间。
这是gprof 所做的一个简单示例:
A 调用 B 十次,B 调用 C 十次,C 执行一些 CPU 密集型循环 10 个采样时间。
请注意,没有一个样本落在 A 或 B 中,因为程序计数器几乎将所有时间都花在了 C 中。
gprof,通过计算调用次数并跟踪调用者,进行一些数学运算并向上传播时间。
所以你看,加速这个程序的一种方法是让 A 调用 B 的次数更少,或者让 B 调用 C 的次数更少,或者两者兼而有之。
prof 无法为您提供此类信息 - 您必须猜测。
如果您正在考虑使用gprof、be aware of its problems,例如不提供行级信息、对 I/O 视而不见、对递归感到困惑以及误导您认为某些事情可以帮助您发现问题,比如采样率、调用图、调用计数等。
请记住,它的作者只是声称它是一种衡量工具,而不是一种发现问题的工具,尽管大多数人认为它是后者。
【讨论】:
我的理解是,这两个命令都输出了一个类似的平面文件,看起来像:
平面轮廓:
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls us/call us/call name
37.50 0.15 0.15 48000 3.12 3.12 Life::neighbor_count(int, int)
17.50 0.22 0.07 _IO_do_write
10.00 0.26 0.04 __overflow
7.50 0.29 0.03 _IO_file_overflow
7.50 0.32 0.03 _IO_putc
5.00 0.34 0.02 12 1666.67 14166.67 Life::update(void)
5.00 0.36 0.02 stdiobuf::overflow(int)
5.00 0.38 0.02 stdiobuf::sys_write(char const *, int)
2.50 0.39 0.01 ostream::operator<<(char)
2.50 0.40 0.01 internal_mcount
0.00 0.40 0.00 12 0.00 0.00 Life::print(void)
0.00 0.40 0.00 12 0.00 0.00 to_continue(void)
0.00 0.40 0.00 1 0.00 0.00 Life::initialize(void)
0.00 0.40 0.00 1 0.00 0.00 instructions(void)
0.00 0.40 0.00 1 0.00 170000.00 main
平面配置文件显示您的程序执行每个函数所花费的总时间。
gprof 似乎又输出了一个代表 call-graph 的文件,它看起来像:
调用图:
granularity: each sample hit covers 4 byte(s) for 2.50% of 0.40 seconds
index % time self children called name
0.02 0.15 12/12 main [2]
[1] 42.5 0.02 0.15 12 Life::update(void) [1]
0.15 0.00 48000/48000 Life::neighbor_count(int, int) [4]
-----------------------------------------------
0.00 0.17 1/1 _start [3]
[2] 42.5 0.00 0.17 1 main [2]
0.02 0.15 12/12 Life::update(void) [1]
0.00 0.00 12/12 Life::print(void) [13]
0.00 0.00 12/12 to_continue(void) [14]
0.00 0.00 1/1 instructions(void) [16]
0.00 0.00 1/1 Life::initialize(void) [15]
-----------------------------------------------
[3] 42.5 0.00 0.17 _start [3]
0.00 0.17 1/1 main [2]
-----------------------------------------------
0.15 0.00 48000/48000 Life::update(void) [1]
[4] 37.5 0.15 0.00 48000 Life::neighbor_count(int, int) [4]
-----------------------------------------------
调用图显示了每个函数及其子函数花费了多少时间。从这些信息中,您可以找到虽然它们本身可能没有花费太多时间的函数,但它们调用了确实使用异常时间量的其他函数。
最后: 似乎 prof 只显示了在函数中花费的时间,而 gprof 显示了调用图以显示函数内部也花费了时间。通过它,您可以找到在函数中花费时间的例程。
【讨论】: