如何记录每个内存访问的带有时间戳的痕迹?

时间:2018-08-30 13:55:53

标签: linux memory cpu-architecture perf

是否有一种方法可以记录给定程序的每个内存访问,包括时间戳。可以使用perf来做到这一点吗?

3 个答案:

答案 0 :(得分:3)

如果您使用的是Intel,我认为其他答案中提到的Intel PT功能与后处理和分析相结合最有可能为您带来高速所需的功能(即某些功能)就像性能上的个位数回归一样。

如果您不关心性能,则可以使用任意数量的二进制检测框架来获取此信息。例如,valgrind框架有一个cachegrind工具,它捕获每个内存访问,并根据理想化的缓存模型使用它们来估计缓存行为。

您几乎可以修改cachegrind工具,以吐出您要访问的访问列表以及时间戳。当然,问题在于cachegrind的运行速度可能比本地应用程序慢10倍左右,因此您的时间戳将同时被“拉长”和扭曲(即,因为程序的各个部分可能具有不同的检测开销)。

对您的应用而言,重要的取决于您。

关于Valgrind的好处是它不依赖任何特定的硬件,并且可以在不同的硬件体系结构上工作。比起基于Intel PT的分析工作,这可能还容易-尽管我不确定自己是否尝试过,但我不确定100%。

如果您不在乎录制时实际过程的总运行时间,但主要需要准确的时序图,则还可以考虑在CPU仿真器(例如Sniper x86 simulator或彼得在评论中提到的gem5

This site描述CMP $ im工具可能对您非常有用。它可以使用英特尔的PIN technology生成访问的痕迹,@ Leeor在下面的注释中也提到了该痕迹。我建议您查看从该站点链接的作者的相关论文。

答案 1 :(得分:2)

我能想到的最接近的硬件功能是Intel PT(处理器跟踪),它可以记录每个(已取?)分支上的时间戳,因此您可以将执行重构到包含负载的块。我没有使用pt,也不确定perf是否可以使用pt,或者您是否需要其他程序。

(不完全是“基本块”,因为在其他地方经过分支目标时没有记录)

那可能仅是在发出加载指令时,而不是在乱序执行实际上是在运行它们或数据从内存/一级缓存到达时。

我不认为任何现有的x86芯片都能为每次加载完成记录准确的时间戳;那将是太多的数据。


如果您要查找内存热点,建议使用perf record -e mem_load_retired.l3_miss,mem_load_retired.l2_miss或类似的计数器进行分析,以查找经常在不同级别的缓存中丢失的负载。有一些存储事件,但主要用于加载,因为CPU必须等待加载数据到达才能使用它。

也许还有dtlb_load_misses.miss_causes_a_walk或其他TLB错过事件。

还有cycle_activity.stalls_l3_miss的事件,该事件在停顿时会计数每个周期,以查找OoO执行人员无法隐藏缓存丢失延迟的情况。

使用perf list查看perf知道的事件。如果您的perf很旧,则可能需要ocperf.py包装器。 https://github.com/andikleen/pmu-tools

答案 2 :(得分:2)

IntelPT将记录时间戳并跟踪正在运行的应用程序的控制流信息,以及将记录到硬件中的各种数据包。然后,来自IntelPT的此信息可以用作decoders的输入,这将有助于获得反汇编的指令痕迹。而且IntelPT也已集成到perf中。

您可以将perf与IntelPT一起用作以下事件-

perf record -e intel_pt//[uk]  /bin/ls

[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.384 MB perf.data ]

但是,我建议使用的是 PEBS (基于精确事件的采样)。 PEBS (基于精确事件的采样)是事件子集可用的功能,它使硬件可以收集非常接近所配置事件溢出确切时间的其他信息。您也可以将 PEBS perf一起使用。

说您要记录与内存负载有关的信息。 PEBS计数器将被初始化为某个最大值(实际上是采样周期)。然后,这些计数器将在每次内存加载时递减1。一旦计数器达到零,PEBS硬件就会准备就绪。然后,下一个内存加载事件将导致PEBS记录被写入PEBS缓冲区。一旦发生这种情况,PEBS计数器将自动重置为其先前值。这样,采样周期2将导致系统在间隔2之后记录内存负载。

无论如何,使用PEBS的一个好处是它非常精确,可以从其工作方式中猜出。与大多数其他记录机制不同,在本质上,您必须等待软件中断来记录事件详细信息,并且记录会在数百个CPU周期后发生。

结合使用perf和PEBS来记录这样的内存负载-

perf record -e r81d0:pp -c 1 -d <application_name> <application_params>

r81d0:pp以数字形式表示事件已退休指令中的内存加载。在某些情况下,某些CPU架构将不支持某些事件,因此必须使用此类数字事件。

但是,就像彼得所说的那样,正如在其他许多questionsanswers中所强调的那样,如果没有外部硬件机制和/或引起运行时的大量开销。

想了解有关 PEBS 的信息? Intel's software developer manual将是您最好的朋友。