"perf" - 统计每个方法的指令数

4
我想要在我的代码中为每个函数调用计算动态指令计数器,以便我可以将该计数器视为以下内容:
name of function | instructions 
     foo()       |     3533 
     bar()       |     1234

因此,以下是子问题:

  1. 使用 perf 是否可行?
  2. 如果是:应该使用什么样的 perf 标志来获取(至少)这些信息?
  3. 如果不行:我可以使用哪个其他程序来实现?
2个回答

7
您是否想获取静态指令计数,即在最终二进制文件中编译为每个函数的指令数量?如果是这种情况,这是二进制文件的静态属性,因此您不需要在运行时使用perf来确定它 - 您可以使用objdump -d a.out反汇编二进制文件并计算指令数。 如果要自动化,请使用所选的脚本语言或awk等(可能查找下一个空白行)。
例如,您可以采用以下内容:
int foo(int a, int b) {
    return a << (10 + b);
}

objdump 的输出结果将会看起来像是 这样(你会看到确切的内容取决于编译器和标志):

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的答案中提到。


1
如果您想要精确计算每个块/函数的动态指令数量,类似于Intel PIN(动态代码插装)的工具可能更适合x86架构。 (但我没有使用过,所以无法告诉您如何操作)或者,如果您使用的是英特尔CPU,也可以使用英特尔PT来跟踪分支,并结合基本块的静态指令计数,可以廉价地得到动态指令计数。另外,您还可以使用gdb单步调试并在每次调试时打印函数名称(或在每次步骤后打印指令指针),这也是一种可能的方法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接