0

我正在学习如何使用 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 的第一行是指函数需要执行的总时间,而第二行是指返回语句所需的时间。我有其他函数是返回 s 的同一类的 getter int,但函数时间和 return 语句时间之间的差异只有大约 0.1 秒,而与我发布的时间一样,时间差是 1.06 秒(其他 getter 是调用次数减少了大约 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
4

3 回答 3

1

基于代码检测的分析器对于这种非常快速的函数几乎毫无用处,你能从中得到的只是随机数。

原因是现代 CPU 上的执行时间是一个非常复杂的函数,包含大量参数和工具(添加到函数中以更新统计信息的代码)会搞砸一切。对于像这样的短函数,单独的检测可能比被检测的代码本身要多得多。

对于分析快速功能,您应该使用像OProfile这样的被动分析器,它只运行程序并以准定期的时间间隔检查它所在的位置。你没有得到精确的计数器,但是你可以从随机采样中得到的近似值更接近真实的东西,因为程序行为没有发生太大的改变。

查看程序在哪里浪费时间的另一种选择是通过实验。如果您怀疑代码的某个部分是瓶颈,请尝试执行 10 次(这通常不难做到)并检查程序的总执行时间更改了多少。如果减速不大,那么您知道即使能够完全删除该代码也不会为您节省太多。

于 2012-09-28T05:57:28.097 回答
0

我想到的第一件事是函数调用的成本不是零——每次调用它时都必须设置和拆除堆栈帧。

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

于 2012-09-28T05:44:51.260 回答
0

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

您的函数是如此之小,以至于分析器实际上正在测量它自己的开销。

于 2012-09-28T06:16:51.553 回答