“perf” - 计算每种方法的指令

时间:2018-01-09 15:01:11

标签: linux perf instructions

我想在我的代码中为每个函数调用动态指令计数,以便我可以将该计数器视为:

name of function | instructions 
     foo()       |     3533 
     bar()       |     1234

所以关注子问题:

  1. 这可以使用perf吗?
  2. 如果是:我应该使用哪种perf标志来获取(至少)这些信息?
  3. 如果不是:我可以使用哪些其他程序?

2 个答案:

答案 0 :(得分:5)

您是否尝试获取静态指令计数,即每个函数在最终二进制文件中编译成的指令数量?

如果是这种情况,这是二进制文件的静态属性,因此您不需要perf(在运行时工作)来确定这一点 - 您可以使用objdump -d a.out反汇编二进制文件并计算指令数量。如果要自动化它,请使用您选择的脚本语言或awk或其他任何内容(可能正在寻找下一个空行)。

举个例子,你可以采取以下方式:

int foo(int a, int b) {
    return a << (10 + b);
}

objdump输出看起来像like this(你可以看到确切的内容取决于编译器和标志):

foo(int, int): # @foo(int, int)
  lea ecx, [rsi + 10]
  shl edi, cl
  mov eax, edi
  ret

总共有4条指令,包括ret

但是,您可能正在讨论动态指令计数 - 即,在应用程序的特定运行中,每个方法中的执行指令的数量是多少?在这种情况下,您可以使用perf record -e instructions然后perf report -n --stdio快速获得大致答案,其中应列出函数及其样本计数。您可以通过乘以总样本与报告顶部显示的“事件计数”的比率,将相同的计数扩展到指令计数。

典型报告可能如下所示:

#
# Total Lost Samples: 0
#
# Samples: 51K of event 'instructions:p'
# Event count (approx.): 27502612549
#
# Overhead       Samples  Command      Shared Object        Symbol                                                                                           
# ........  ............  ...........  ...................  .................................................................................................
#
    22.01%          4824  uarch-bench  uarch-bench          [.] add_calibration
     1.92%          2480  uarch-bench  uarch-bench          [.] prefetcht2_bench2048_inner.top
     1.92%          2477  uarch-bench  uarch-bench          [.] prefetcht1_bench2048_inner.top
     1.91%           222  uarch-bench  uarch-bench          [.] prefetcht0_bench16_inner.top
     1.91%          2021  uarch-bench  uarch-bench          [.] load_loop512_inner.top

在合理的假设下,您可以预期这些统计结果与真实结果相当接近。但是,如果您需要精确计数,可以使用解决方案,例如使用英特尔处理器跟踪,它可以重建流程的整个执行历史记录。这些也在Peter's answer中提到。

答案 1 :(得分:0)

如果您需要精确计算动态指令,每个块/每个功能,如果您使用x86,那么英特尔PIN(动态代码检测)等功能可能会更好。 (但我还没有使用它,所以我无法告诉你如何

或者也许使用英特尔PT跟踪分支机构(如果您使用的是英特尔CPU),结合基本模块的静态指令计数,您可以便宜地获得动态指令数。

这可能是一种蛮力的方式,gdb单步执行,每次打印功能名称。 (或者在每一步之后打印指令指针)。