4

当乱序处理器遇到类似

LOAD R1, 0x1337
LOAD R2, $R1
LOAD R3, 0x42

假设所有访问都会导致缓存未命中,处理器能否在请求 $R1 甚至 0x1337 的内容之前向内存控制器请求 0x42 的内容?如果是这样,假设访问 $R1 将导致异常(例如,分段错误),我们可以认为 0x42 是推测性加载的,对吗?

顺便说一句,当加载存储单元向内存控制器发送请求时,它是否可以在收到前一个请求的答案之前发送第二个请求?

我的问题并不特别针对任何架构。欢迎与任何主流架构相关的答案。

4

4 回答 4

6

您的问题的答案取决于您的 CPU 的内存排序模型,这与允许乱序执行的 CPU 不同。如果 CPU 实现了总存储排序(例如 x86 或 Sparc),那么您的问题的答案是 0x42 将不会在 0x1337 之前加载

如果 cpu 实现了一个宽松的内存模型(例如 IA-64、PowerPC、alpha),那么在没有内存栅栏指令的情况下,所有关于哪个将首先访问的赌注都是关闭的。除非您正在执行 IO 或处理多线程代码,否则这应该无关紧要。

您应该注意,某些 CPU(例如 Itanium)确实具有宽松的内存模型(因此读取可能是乱序的)但没有任何乱序执行逻辑,因为它们希望编译器以最佳方式对指令和推测指令进行排序而不是在OOE上花费硅空间

于 2012-10-07T22:52:17.203 回答
4

对于具有多个加载存储单元的超标量 CPU,这似乎也是一个合乎逻辑的结论。如今,多通道内存控制器非常普遍。

在乱序指令执行的情况下,大量的逻辑被用于确定指令是否依赖于流中的其他指令——不仅是寄存器依赖,还包括对内存的操作。还有大量用于处理异常的逻辑:CPU 需要完成流中的所有指令,直到出现故障(或者,将其中的某些部分卸载到操作系统上)。

就大多数应用程序看到的编程模型而言,效果永远不会很明显。正如记忆所见,加载并不总是按预期的顺序发生是隐含的——但在使用缓存时无论如何都是这种情况。

显然,在加载和存储的顺序很重要的情况下——例如在访问设备寄存器时,必须禁用 OOE。POWER 体系结构EIEIO为此目的提供了很好的说明。

ARM Cortex-A 系列的一些成员提供 OOE - 我怀疑这些设备的功率限制,以及明显缺乏强制排序的指令,加载存储总是按顺序完成

于 2012-09-20T19:08:45.477 回答
2

与 x86 相关:为什么要为其他逻辑处理器导致的 Memory Order Violation 刷新管道?. 可观察到的结果将遵守 x86 排序规则,但在微架构上是的,它可以提前加载。(当然这是来自缓存;硬件预取是不同的)。

如果地址还没有准备好进行一次加载,OoO exec CPU 确实会重新排序加载执行。或者,如果它在缓存中丢失,则以后的加载可以在数据到达之前运行。但是在 x86 上,要保持正确性。强内存模型(程序顺序 + 带有存储转发的存储缓冲区),核心根据 ISA 的纸上内存模型保证检查最终结果是否合法。(即之前加载的缓存行仍然有效,因此仍然包含我们现在允许加载的数据)。如果没有,请取消依赖于这种可能不安全的推测的飞行指令并回滚到已知的安全状态。

因此,现代 x86 获得了轻松加载排序的性能(大部分时间),同时仍然保持每个加载实际上都是获取加载的内存模型规则。但是,如果你做了一些管道不喜欢的事情,例如虚假共享(这已经够糟糕的了),就会以管道核武器为代价。

其他具有强内存模型 (Sparc TSO) 的 CPU 可能不会这么激进。弱内存模型允许稍后的加载提前完成。

当然这是从缓存中读取的;仅在高速缓存未命中时,内存控制器才会看到需求加载请求。但是硬件预取器可以从 CPU 异步访问内存;这就是他们在 CPU 运行加载它的指令之前将数据放入缓存的方式,理想情况下完全避免缓存未命中。


是的,内存子系统是流水线的,就像 Skylake 中每个核心有 12 到 16 个未完成的请求一样。(L1<->L2 的 12 个 LFB,以及 L2 中的 IIRC 16 个超级队列条目。)

于 2020-12-29T12:19:56.900 回答
1

兼容的 SPARC 处理器必须实现 TSO,但可以实现 RMO 和 PSO。你需要知道你的操作系统在什么模式下运行,除非你碰巧知道你的特定硬件平台没有实现 RMO 和 PSO。

于 2013-02-08T07:23:36.807 回答