我写了一个program可以用来探索英特尔处理器中 RS 的未记录限制,希望我最终能够回答这个问题。基本思想是在循环中分配和执行特定的微指令序列之前确保 RS 完全为空。这RESOURCE_STALLS.RS
可用于确定该序列是否已达到 RS 本身的限制。例如,如果RESOURCE_STALLS.RS
每次迭代为 1,则分配器必须停止一个周期才能为序列中的所有微指令分配 RS 条目。如果RESOURCE_STALLS.RS
每次迭代比 1 小得多,那么它基本上不必停止,所以我们知道我们没有遇到任何 RS 限制。
我已经尝试过一系列依赖ADD
指令、一系列相关 BSWAP 指令、一系列到同一位置的相关加载指令、一系列向后或向前无条件跳转指令以及一系列到同一位置的存储指令。下面两张图显示了序列的结果add
不同目标RS占用的指令(微指令序列同时需要和占用的RS条目的最大数量)。每次迭代都会显示所有值。
下图显示RESOURCE_STALLS.RS
当 RS 占用率为 50 时,每次迭代至少(或接近)每次迭代 1 个周期。虽然不明显可见,RESOURCE_STALLS.RS
当 RS 占用率超过 43 时变得大于零,但只有当 RS 占用率超过 49 时才超过 1。换句话说,我只能同时使用 60 个(在 Haswell 中)RS 条目中最多 49 个,而不会出现 RS 停顿。在那之后,RESOURCE_STALLS.RS
序列中每增加一个微指令,平均增加 1,这与分配器的突发行为以及每个指令的事实是一致的:ADD
uop可以在每个周期完成(每个uop仅占用1个周期的RS条目)。cycles
每增加一个 uop,平均增加 2.3。每个额外的 uop 都大于 1,因为 ROB 上还有额外的停顿,原因与add
uop,但这些都可以,因为它们不会影响RESOURCE_STALLS.RS
.
下图显示了变化cycles
and RESOURCE_STALLS.RS
每次迭代。它说明了执行时间和 RS 停顿之间的强相关性。
当目标RS占用率在44-49之间时,RESOURCE_STALLS.RS
非常小,但仍然不是真正的零。我还注意到,不同微指令呈现给分配器的确切顺序会稍微影响可以达到的 RS 占用率。我认为这是Intel手册中提到的RS阵列写端口分配方案的效果。
那么其他 11 个 RS 条目(Haswell 的 RS 应该有 60 个条目)怎么样了?这RESOURCE_STALLS.ANY
性能事件是回答问题的关键。我已经更新了用于执行这些实验的代码,以测试不同类型的负载:
- 可以使用推测地址分派负载以实现 4 个周期的 L1D 命中延迟。这个案例被称为
loadspec
.
- 无法使用推测地址分派的负载。它们在 Haswell 上的 L1D 命中延迟为 5 个周期。这个案例被称为
loadnonspec
.
- 可以使用推测但不正确的地址分派负载。它们在 Haswell 上的 L1D 命中延迟为 9 个周期。这个案例被称为
loadspecreplay
.
我遵循相同的方法ADD
说明,但这一次我们需要注意RESOURCE_STALLS.ANY
代替RESOURCE_STALLS.RS
(实际上并没有捕获由于负载而导致的 RS 失速)。下图显示了变化cycles
and RESOURCE_STALLS.ANY
每次迭代。第一个尖峰表示目标 RS 占用率已超过该类型 uop 的可用 RS 条目。我们可以清楚地看到,对于loadspec
这种情况下,正好有 11 个用于加载微指令的 RS 条目!当目标 RS 占用率超过 11 时,RS 条目平均需要 3.75 个周期才能空闲到下一个加载 uop。这意味着微指令在完成时从 RS 中释放,而不是在它们被调度时。这也解释了 uop 重放的工作原理。峰值为loadspecreplay
发生在 RS 占用 6 时。loadnonspec
发生在 RS 占用 9 时。正如您稍后将看到的,这 11 个条目并非专用于负载。负载使用的 11 个条目中的一些可能位于负载使用的 49 个条目中ADD
uops.
我还为存储开发了两个测试用例:一个达到存储缓冲区的限制,另一个达到 RS 的限制。上图显示了前一种情况。请注意,存储需要 RS 中的两个条目,因此目标 RS 占用率为奇数的情况与之前的偶数 RS 占用率相同(变化为零)。该图显示 RS 中最多可以同时有 44/2 = 22 个存储。 (我用来制作store graph的代码有一个bug,会导致实现的RS占用率比实际的要大。修复后,结果显示RS中最多可以同时有20个store。)存储地址或存储数据微指令占用的条目可以在一个周期内释放。 Intel 表示 Haswell 的存储缓冲区有 42 个条目,但我无法同时使用所有这些条目。我可能需要设计一个不同的实验来实现这一目标。
跳跃序列没有导致任何停顿。我认为这可以解释如下:跳转微指令释放它在一个周期内占用的RS条目,并且分配器在分配跳转微指令时不会以突发方式运行。也就是说,每个周期一个 RS 条目变得空闲,并且分配器将仅分配一个跳转 uop 而不会停止。因此,无论有多少个跳跃微指令,我们最终都不会停止。这与添加微指令相反,其中突发分配器行为使其停止,直到所需数量的 RS 条目变为空闲(4 个条目),即使添加微指令的延迟也是一个周期。尽快分配跳跃是有意义的,以便尽早检测到任何错误预测。因此,如果分配器看到跳转并且 RS 中有足够的空间供其使用,但其 4 uop 组中没有后续的 uop,那么它仍然会分配它。否则,它可能必须等待潜在的许多周期,这可能会显着延迟错误预测的检测。这可能会非常昂贵
是否有一条指令的uop可以同时占用RS的所有60个条目?是的,一个例子是BSWAP
。它的两个微指令需要两个 RS 条目,我可以清楚地看到使用RESOURCE_STALLS.RS
它的微指令可以同时使用 RS 的所有 60 个条目(假设我的计算对于 RS 占用率如何使用该指令增长是正确的)。这证明RS中确实有60个条目。但我们对它们的使用方式仍然知之甚少。