"perf" - 计算每个方法的指令数
"perf" - count instructions per method
我想知道我代码中每个函数调用的动态指令计数,这样我就可以像这样查看该计数器:
name of function | instructions
foo() | 3533
bar() | 1234
所以下面的子问题:
- 这可以使用
perf
吗?
- 如果是:我应该使用哪种
perf
标志来获取(至少)这些信息?
- 如果否:我可以使用其他什么程序来做到这一点?
您是否要获取 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
快速获得近似答案,后者应列出函数及其样本数。您可以通过乘以总样本的比率和报告顶部显示的 "Event count" 来将相同的计数扩展到一个指令数。
典型的报告可能如下所示:
#
# 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
在合理的假设下,您可以预期这些统计结果与真实结果相当接近。然而,如果你想要一个精确的计数,解决方案是可用的,比如使用 Intel 的 Processor Trace,它可以重建一个进程的整个执行历史。 .
中也提到了这些
如果您想要精确计算每个块/每个函数的动态指令数,如果您使用的是 x86,Intel PIN(动态代码检测)之类的东西可能会更好。 (但我没用过,所以没法告诉你怎么用)
或者可能使用 Intel PT 来跟踪分支(如果您使用的是 Intel CPU),结合基本块的静态指令计数,您可以获得廉价的动态指令计数。
gdb
可能有一种蛮力方法,每次单步执行并打印函数名称。 (或在每一步后打印指令指针)。
我想知道我代码中每个函数调用的动态指令计数,这样我就可以像这样查看该计数器:
name of function | instructions
foo() | 3533
bar() | 1234
所以下面的子问题:
- 这可以使用
perf
吗? - 如果是:我应该使用哪种
perf
标志来获取(至少)这些信息? - 如果否:我可以使用其他什么程序来做到这一点?
您是否要获取 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
快速获得近似答案,后者应列出函数及其样本数。您可以通过乘以总样本的比率和报告顶部显示的 "Event count" 来将相同的计数扩展到一个指令数。
典型的报告可能如下所示:
#
# 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
在合理的假设下,您可以预期这些统计结果与真实结果相当接近。然而,如果你想要一个精确的计数,解决方案是可用的,比如使用 Intel 的 Processor Trace,它可以重建一个进程的整个执行历史。
如果您想要精确计算每个块/每个函数的动态指令数,如果您使用的是 x86,Intel PIN(动态代码检测)之类的东西可能会更好。 (但我没用过,所以没法告诉你怎么用)
或者可能使用 Intel PT 来跟踪分支(如果您使用的是 Intel CPU),结合基本块的静态指令计数,您可以获得廉价的动态指令计数。
gdb
可能有一种蛮力方法,每次单步执行并打印函数名称。 (或在每一步后打印指令指针)。