2

为了分析执行时间的某些属性,我打算在程序的单独执行中同时使用PerfPIN来获取我的所有信息。PIN 会给我指令混音,Perf 会给我这些混音的硬件性能。作为健全性检查,我分析了以下命令行参数:

g++ hello_world.cpp -o hello

所以我完整的命令行输入如下:

perf stat -e cycles -e instructions g++ hello_world.cpp -o hello
pin -t icount.so -- g++ hello_world.cpp -o hello

在 PIN 命令中,为了这篇文章,我忽略了文件的所有路径内容。icount.so此外,除了默认的动态指令计数之外,我还更改了基本指令以记录指令混合。结果惊人地不同

PIN Results:
Count 1180608
14->COND_BR: 295371
49->UNCOND_BR: 21869
//skipping all of the other instruction types for now

Perf Results:
       20,538,346 branches                                                    
       105,662,160 instructions              #    0.00  insns per cycle        

       0.072352035 seconds time elapsed

这应该通过具有大致相同的指令数和大致相同的分支分布来作为完整性检查。 为什么动态指令计数会减少x100倍?! 我期待一些噪音,但这有点多。

此外,Perf 的分支数量为 20%,但 PIN 报告约为 25%(这似乎也有一点差异,但这可能只是大量指令计数失真的副作用)。

4

1 回答 1

1

icountpintool计算的内容与性能事件之间存在显着差异,instructions性能事件映射到Instructions Retired现代英特尔处理器上的架构硬件性能事件。我假设您使用的是英特尔处理器。

  • pin仅在-follow_execv指定命令行选项时注入子进程,并且如果 pintool 注册了回调函数来拦截进程创建,则回调返回true. 另一方面,perf默认情况下配置所有子进程。您可以告诉perf使用该-i选项仅分析指定的进程。
  • perf,默认情况下,分析在用户模式和内核模式下发生的所有事件(如果/proc/sys/kernel/perf_event_paranoid小于 2)。pin仅支持用户模式下的分析。
  • pintoolicount以基本块粒度进行计数,这本质上是一个短的、单入口、单出口的指令序列。如果块中的一条指令导致异常,则块中的其余指令将不会被执行,但它们已经被计算在内。可以在不终止程序的情况下处理异常。instructions只计算退休时的指示。
  • 默认情况下icountreppintool 将 - 前缀指令的每次迭代计为一条指令。无论迭代次数如何,该instructions事件都将带有rep-prefixed 的指令计为单个指令。
  • 在某些处理器上,instructions事件可能会过度计数或计数不足。

由于instructions前两个原因,事件计数可能会更大。icount由于接下来的两个原因,pintool 指令计数可能会更大。最后一个原因可能会导致不可预知的差异。由于perf计数大约是计数的 100 倍icount,因此很明显前两个因素在这种情况下占主导地位。

-i您可以通过传递给perf不配置子项,将:u修饰符添加到instructions事件名称以仅在用户模式下计数,并传递-reps 1给每个指令而不是每次迭代的pin以 count 为前缀的指令,从而使这两个工具获得更接近的计数。rep

perf stat -i -e cycles,instructions:u g++ hello_world.cpp -o hello
pin -t icount.so -reps 1 -- g++ hello_world.cpp -o hello

您可以按如下方式传递-i给,而不是传递给:perf-follow_execvpin

pin -follow_execv -t icount.so -reps 1 -- g++ hello_world.cpp -o hello

通过这种方式,两个工具都将分析植根于指定进程(即正在运行的g++)的整个进程层次结构。

我希望这些措施的计数非常接近,但它们仍然不会相同。

于 2021-04-05T22:31:15.057 回答