理解CYCLE_ACTIVITY.* Haswell性能监测事件

6
我试图使用顶部向下微架构分析方法(TMAM)来分析在Intel Haswell CPU(Intel® Core™ i7-4900MQ)上的执行,该方法在Intel® 64 and IA-32 Architectures Optimization Reference Manual的B.1和B.4章节中有描述(如果需要,我会根据B.4中描述的Sandy Bridge公式调整到Haswell微架构)。因此,我使用Perf进行性能计数器事件测量。但是有一些结果我不理解:
1. CPU_CLK_UNHALTED.THREAD_P < CYCLE_ACTIVITY.CYCLES_LDM_PENDING。这仅适用于一些测量数据,但仍然很奇怪。PMU是否计算了CYCLE_ACTIVITY.CYCLES_LDM_PENDING的停止周期?
2. CYCLE_ACTIVITY.CYCLES_L2_PENDING > CYCLE_ACTIVITY.CYCLES_L1D_PENDING并且CYCLE_ACTIVITY.STALLS_L2_PENDING > CYCLE_ACTIVITY.STALLS_L1D_PENDING。这适用于所有测量数据。当L1D缓存未命中时,负载将传输到L2缓存,对吧?那么之前未命中L2的负载也未命中L1。这里没有计算L1指令缓存,但是*_L2_PENDING*_L1D_PENDING大100倍甚至1000倍,可能不是那样。难道停顿/周期正在分别测量吗?但是有一个公式:%L2_Bound = (CYCLE_ACTIVITY.STALLS_L1D_PENDING - CYCLE_ACTIVITY.STALLS_L2_PENDING) / CLOCKS。因此假设CYCLE_ACTIVITY.STALLS_L2_PENDING < CYCLE_ACTIVITY.STALLS_L1D_PENDING(公式的结果必须为正)。 (使用该公式的另一件事是它应该是CYCLES而不是STALLS。但是这不能解决上述问题。)那么这怎么解释呢?

你的操作系统和perf版本是什么? - igon
操作系统:Ubuntu 14.04.3 LTS,perf版本:3.13.11-ckt26。 - lary
你检查过你的perf版本是否与你的内核匹配了吗? - igon
我的内核版本是3.13.0-65-generic x86_64。系统上安装了linux-tools-common(3.13.0-65.105, all)和linux-tools-3.13.0-65-generic(3.13.0-65.105, amd64)软件包。我想perf版本应该是适合我的内核版本的,但我如何检查我的perf版本是否正确呢? - lary
尝试禁用超线程和/或预取并观察结果。同时测量TLB缺失。 - Hadi Brais
1个回答

3
我将从问题的第二部分开始回答,即如何使CYCLE_ACTIVITY.CYCLES_L2_PENDINGCYCLE_ACTIVITY.STALLS_L2_PENDING大于CYCLE_ACTIVITY.CYCLES_L1D_PENDINGCYCLE_ACTIVITY.STALLS_L1D_PENDING。首先,请注意%L2_Bound的公式来自英特尔优化手册的B.5节。该部分的第一段说:
“本节涵盖使用性能监测事件的各种性能调整技术。一些技术可以适用于其他微架构,但大多数性能事件是特定于英特尔微架构代号 Sandy Bridge 的。”

我最初的直觉是预取与此有关(请参见我的评论)。这段话让我更进一步地朝着正确的方向前进了;在Sandy Bridge和Haswell中,这些事件可能代表不同的事情。以下是它们在Haswell上的含义:

CYCLE_ACTIVITY.CYCLES_L1D_PENDING:由于L1数据缓存未命中加载而产生的周期数。 CYCLE_ACTIVITY.CYCLES_L2_PENDING:由于L2未命中加载而产生的周期数。 CYCLE_ACTIVITY.STALLS_L1D_PENDING:由于L1数据缓存未命中加载而导致的执行停顿。 CYCLE_ACTIVITY.STALLS_L2_PENDING:L2未命中加载的数量。

手册还说,在关闭超线程时才应使用L2计数器。现在以下是它们在Sandy Bridge上的含义:

CYCLE_ACTIVITY.CYCLES_L1D_PENDING: 每个周期该线程有一个未命中的需求加载,增加1。
CYCLE_ACTIVITY.CYCLES_L2_PENDING: 每个周期该线程有一个MLC未命中的需求加载,增加1。
CYCLE_ACTIVITY.STALLS_L1D_PENDING: 每个周期该线程有一个未命中的需求加载且没有uops分派,增加1。
CYCLE_ACTIVITY.STALLS_L2_PENDING: 每个周期该线程有一个MLC未命中的需求加载且没有uops分派,增加1。

这里有三个重要的区别:

  • 当启用超线程时,部分Haswell事件可能无效。而所有SNB事件即使在启用超线程时也是有效的。
  • 在HSW上,CYCLE_ACTIVITY.STALLS_L2_PENDING计算L2中的加载未命中次数,但在SNB上,它计算至少有一个需求加载未命中的周期数。
  • HSW事件包括所有访问,而不仅仅是需求加载。相比之下,SNB事件仅适用于需求加载。
在HSW上,CYCLE_ACTIVITY.CYCLES_L2_PENDING可能比CYCLE_ACTIVITY.CYCLES_L1D_PENDING大,因为L1D预取器(和/或L2预取器(取决于预取器是否增加相同级别的缓存计数器))发出的未命中预取加载。同样,尽管它们计算不同的东西,CYCLE_ACTIVITY.STALLS_L2_PENDING可能比CYCLE_ACTIVITY.STALLS_L1D_PENDING更大,这是由于预取。在HSW上,TLB预取和其他MMU缓存的预取也可能影响这些性能事件。另一方面,在SNB上,可以保证CYCLE_ACTIVITY.STALLS_L2_PENDING<CYCLE_ACTIVITY.STALLS_L1D_PENDING,这就是为什么%L2_Bound公式在SNB上有效的原因。
正如我在评论中所说,禁用HT和/或 prefetching可能会“解决”您的问题。

实际上,移动Haswell处理器的英特尔规格更新文档提到了两个影响的错误:

  • HSM63:Haswell上的预期行为仅计算需求加载,但在SMT模式下可能计算不准确。
  • HSM80:可能由于来自下一页预取器的请求而过度计数。

我认为您可以通过禁用SMT(在BIOS中或将另一个逻辑核心置于睡眠状态)来最小化中的错误。此外,请尝试不触发NPP。这可以通过避免虚拟页面末尾位置来实现,在该位置下一页的转换尚未在TLB层次结构中。

相关链接:当L1缺失与L2访问非常不同...与TLB有关?

关于问题的第一部分,即如何使CPU_CLK_UNHALTED.THREAD_P小于CYCLE_ACTIVITY.CYCLES_LDM_PENDING。我能想到的一个解释是,CYCLE_ACTIVITY.CYCLES_LDM_PENDING发生在从(某些)其他线程(特别是在同一个物理核心上)发出的负载中,而不仅仅是停止的线程。勘误HSM146提到当逻辑核心不处于C0状态时,CYCLES_LDM_PENDING可能会计算不准确,这就解释了为什么CPU_CLK_UNHALTED.THREAD_P可以小于CYCLES_LDM_PENDING。禁用HT可能会消除这种不准确性,尽管规范更新文档没有提供任何解决方法。

在Skylake上,计数器CYCLE_ACTIVITY.CYCLES_L1D_PENDING被重命名为CYCLE_ACTIVITY.CYCLES_L1D_MISS(perf list显示为这样)。同样,在Haswell上,CYCLE_ACTIVITY.CYCLES_LDM_PENDING表示为event=0xA3,umask=0x2,cmask=0x2。在Skylake上,相同的事件、umask和cmask定义了CYCLE_ACTIVITY.CYCLES_L3_MISS,不再有CYCLE_ACTIVITY.CYCLES_LDM_PENDING,但是CYCLE_ACTIVITY.CYCLES_MEM_ANY被添加为event=0xA3,umask=0x10,cmask=0x10 - St.Antario
LDM和LDM_PENDING是什么意思? - BeeOnRope
1
@BeeOnRope,它代表着负载依赖矩阵。 - Hadi Brais

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接