主要性能和 PIN 分析差异

Posted

技术标签:

【中文标题】主要性能和 PIN 分析差异【英文标题】:Major Perf and PIN profiling discrepancies 【发布时间】:2013-11-24 02:58:00 【问题描述】:

为了分析执行时间的某些属性,我打算在一个程序的单独执行中同时使用Perf 和PIN 来获取我的所有信息。 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%(这似乎也有一点差异,但这可能只是大量指令计数失真的副作用)。

【问题讨论】:

g++ 内部启动了很多程序:cc1 编译器本身,作为汇编器,ld 链接器。将-v 选项添加到 g++ 以查看所有子程序并尝试修改您的 g++ 命令以仅启动单个工具,例如-c(编译器+汇编器)或-S(编译器)。 【参考方案1】:

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

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

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

您可以通过将-i 传递给perf 以不配置子级,将:u 修饰符添加到instructions 事件名称以仅在用户模式下计数,并且将-reps 1 传递给pin 以计算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

您可以将-follow_execv 传递给pin,而不是将-i 传递给perf,如下所示:

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

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

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

【讨论】:

指令事件将带有代表前缀的指令计为单个指令,而与迭代次数无关。 - 有没有人测试过大事件期间是否出现页面错误或计时器中断rep movsb 可以多次计算吗?部分完成确实必须“退休”。很小的差异,如果每次部分或全部完成时计数,仍然至少比 PIN 少 4096 倍,但是因为您正在枚举极端情况...... @PeterCordes AFAIK,只有Weaver 测试了硬件中断和页面错误对指令计数的影响。根据他的结果,在 SnB/IvB 和一些较旧的处理器上,每个硬件中断和页面错误都会导致额外的指令被计数(即使在以 rep 为前缀的指令的中间)。但我不知道是否有人在更新的处理器上进行过测试。重要的一点,因为这个问题是在 2013 年发布的,所以它非常相关。

以上是关于主要性能和 PIN 分析差异的主要内容,如果未能解决你的问题,请参考以下文章

Lepton 无损压缩原理及性能分析

RTSP/Onvif协议EasyNVR视频平台水印性能差异分析测试

cursor:pin S wait on X故障诊分析

cursor:pin S wait on X故障诊分析

WebGPU性能测试分析

RT-Thread学习——rt_pin_mode()函数分析