【问题标题】:"perf" - count instructions per method“perf” - 每个方法的计数指令
【发布时间】:2018-01-09 15:01:11
【问题描述】:

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

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

所以下面的子问题:

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

【问题讨论】:

    标签: linux perf instructions


    【解决方案1】:

    您是否尝试获取 static 指令计数,即每个函数已编译到最终二进制文件中的指令数?

    如果是这种情况,这是二进制文件的静态属性,因此您不需要 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中也提到了这些。

    【讨论】:

      【解决方案2】:

      如果您想要精确计数每个块/每个函数的动态指令,如果您使用的是 x86,英特尔 PIN(动态代码检测)可能会更好。 (但我没用过,所以不能告诉你怎么用

      或者也许使用 Intel PT 跟踪分支(如果您在 Intel CPU 上),结合基本块的静态指令计数,您可以廉价地获得动态指令计数。

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

      【讨论】:

        猜你喜欢
        • 2014-12-06
        • 2014-06-10
        • 1970-01-01
        • 2018-12-28
        • 2016-07-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多