我正在学习如何使用gprof配置我的代码。对于我的一个应用程序,我有以下输出:
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls ms/call ms/call name
10.27 1.20 1.20 Location::get_type() const (location.cpp:20 @ 40a4bd)
更远的地方,我看到了这个
1.20 4.98 0.14 34662692 0.00 0.00 Location::get_type() const (location.cpp:19 @ 40a4ac)
这是函数
char Location::get_type() const {
return type;
}
我假设gprof的第一行是指函数需要执行的总时间,而第二行是指return语句所需的时间。我有其他函数是返回int
s的同一个类的getter,但函数time和return语句时间之间的差异只有大约0.1秒,其中我发布的时间差为1.06秒(其他呼叫者的呼叫约减少约200万次,与呼叫总数相比较小)。什么可以解释函数调用的更高时间而不是其中的一行代码?
值得一提的是,我用-g -pg编译,因为我在逐行模式下使用gprof。
编辑: 其中一个答案建议我查看汇编输出。我无法理解,所以我会在这里发布。我发布了两个函数调用的汇编代码。第一个是get_floor(),它相对较快(约.10秒)。第二个是get_type(),这很慢。
_ZNK8Location9get_floorEv:
.LFB5:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movq %rdi, -8(%rbp)
movq -8(%rbp), %rax
movl 8(%rax), %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE5:
.size _ZNK8Location9get_floorEv, .-_ZNK8Location9get_floorEv
.align 2
.globl _ZNK8Location8get_typeEv
.type _ZNK8Location8get_typeEv, @function
_ZNK8Location8get_typeEv:
.LFB6:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movq %rdi, -8(%rbp)
movq -8(%rbp), %rax
movzbl 12(%rax), %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
答案 0 :(得分:1)
基于代码检测的分析器几乎无法用于这种非常快速的功能,你可以从中获取的只是随机数。
原因是现代CPU上的执行时间是一个非常复杂的函数,大量的参数和工具(添加到更新统计信息的函数中添加的代码)会使一切变得混乱。对于像这样的简短函数,单独的检测可能远远超过自己检测的代码。
对于快速分析功能,您应该使用OProfile之类的被动分析器,它只运行程序并以准定期间隔检出。你没有得到精确的计数器,但你可以通过随机抽样获得的近似值更接近实际值,因为程序行为没有被改变太多。
查看程序浪费时间的另一个选择就是试验。如果您怀疑代码的某一部分是瓶颈,那么尝试执行10次(这通常不难)并检查程序总执行时间的变化。如果减速不大,那么你就知道即使能够完成删除代码也不会为你节省太多。
答案 1 :(得分:0)
突然出现的第一个事件是函数调用的成本不为零 - 每次调用时都必须设置并拆除堆栈帧。< / p>
可能是您的差异的根源,您应该检查汇编器输出(例如使用gcc -S
)以查看底层代码是什么。
答案 2 :(得分:0)
如果你想测量一个1立方厘米的盒子内的空气温度,并在里面放一个0.8 cm3的温度计,你就不会测量温度。空气,但温度计之一。
您的功能非常小,以至于探查器实际上正在测量自己的开销。