正如标题所说,我想知道这两个命令之间的区别以及它们产生的结果。
通过阅读本文,我了解到 gprof 需要一个额外的标志(-g,gdb 也需要相同的标志?),但这并没有给我关于分析器之间差异的答案。
gprof
是专门发明的,因为prof
只给你“自我时间”。“自我时间”告诉您在每个例程中找到程序计数器的总时间的比例。如果您需要考虑的唯一类型的“瓶颈”可以通过在调用堆栈底部减少周期来解决,那很好。
您通过减少对子例程的调用次数来解决的那种“瓶颈”呢?这就是gprof
应该通过向呼叫者“收回”自我时间来帮助您找到的东西。例程中的“包含时间”包括它的“自身时间”,加上从它调用的例程中冒出来的时间。这是一个简单的例子gprof
:
A 调用 B 十次,B 调用 C 十次,C 为 10 个采样时间执行一些 CPU 密集型循环。请注意,没有一个样本落在 A 或 B 中,因为程序计数器几乎将所有时间都花在 C 中。
gprof
通过计算调用并跟踪调用者,进行一些数学运算并向上传播时间。
所以你看,加速这个程序的一种方法是让 A 调用 B 的次数更少,或者让 B 调用 C 的次数更少,或者两者兼而有之。
prof
不能给你那种信息——你必须猜测。
如果您正在考虑使用gprof
,请注意它的问题,例如不提供行级信息,对 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似乎又输出了一个代表调用图的文件,它看起来像:
调用图:
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显示调用图以显示函数内部也花费了时间。有了它,您可以找到在函数中花费时间的例程。