为什么函数调用比根据gprof执行的代码要长得多?

时间:2012-09-28 05:40:42

标签: c++ profiling profiler gprof

我正在学习如何使用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

3 个答案:

答案 0 :(得分:1)

基于代码检测的分析器几乎无法用于这种非常快速的功能,你可以从中获取的只是随机数。

原因是现代CPU上的执行时间是一个非常复杂的函数,大量的参数和工具(添加到更新统计信息的函数中添加的代码)会使一切变得混乱。对于像这样的简短函数,单独的检测可能远远超过自己检测的代码。

对于快速分析功能,您应该使用OProfile之类的被动分析器,它只运行程序并以准定期间隔检出。你没有得到精确的计数器,但你可以通过随机抽样获得的近似值更接近实际值,因为程序行为没有被改变太多。

查看程序浪费时间的另一个选择就是试验。如果您怀疑代码的某一部分是瓶颈,那么尝试执行10次(这通常不难)并检查程序总执行时间的变化。如果减速不大,那么你就知道即使能够完成删除代码也不会为你节省太多。

答案 1 :(得分:0)

突然出现的第一个事件是函数调用的成本不为零 - 每次调用时都必须设置并拆除堆栈帧。< / p>

可能是您的差异的根源,您应该检查汇编器输出(例如使用gcc -S)以查看底层代码是什么。

答案 2 :(得分:0)

如果你想测量一个1立方厘米的盒子内的空气温度,并在里面放一个0.8 cm3的温度计,你就不会测量温度。空气,但温度计之一。

您的功能非常小,以至于探查器实际上正在测量自己的开销。