现代 Intel x86 CPU 如何实现商店的总订单

How do modern Intel x86 CPUs implement the total order over stores

x86 由于其 TSO 内存模型,保证所有商店的总订单。我的问题是是否有人知道这是如何实际实施的。

我对这 4 个围栏是如何实现的印象很好,所以我可以解释如何保持本地秩序。但是 4 个栅栏只会给出程序顺序;它不会给你 TSO(我知道 TSO 允许旧商店跳到新负载前面,所以隐式需要 4 个栅栏中的 3 个)。

单个地址上所有内存操作的总顺序是一致性的责任。但我想知道英特尔(尤其是 Skylake)如何在多个地址的商店上实现总订单。

x86 TSO 内存模型基本上等于程序顺序加上带有存储转发的存储缓冲区。 (486 硬件就这么简单;后来 CPUs 没有引入新的重新排序。)

大多数由此产生的保证在理论上对于硬件来说相当容易实现,只需拥有一个存储缓冲区和一致的共享内存即可;存储缓冲区将 OoO exec 与按顺序提交要求(以及缓存未命中存储)和 以及(通过存储-> 负载转发)在这些存储仍处于推测状态时重新加载这些存储隔离开来。

  • 所有核心可以就所有存储发生的总顺序达成一致。或者更准确地说,核心不能不同意它们可以实际观察到的总顺序的任何部分。存储到 2 个不同的行可以真正同时进行,因此任何观察都与假设的总顺序中的任何一个顺序兼容。

    如果使存储对任何其他核心可见的唯一方法是使它同时对所有核心可见,则会自动发生这种情况。即通过致力于连贯的 L1d。这使得 IRIW 重新排序变得不可能。 (MESI 确保商店不能提交给 L1d,除非它由该核心独家拥有:没有其他核心具有有效副本。)(观察自己的商店的核心需要一个完整的屏障,否则它将通过商店转发观察自己的商店,而不是全局总顺序。典型的 IRIW 石蕊测试正在考虑总共 4 个线程,因此没有本地重新加载。)

    事实上,任何硬件都很少没有有这个属性;一些 , making it possible for 2 readers to disagree about the order of stores by 2 writers (IRIW reordering). Even though x86 CPUs also often have SMT (e.g. Intel's HyperThreading), the memory model requires them not to store-forward between logical cores. That's fine; they statically partition the store buffer anyway. . And also 用于实验测试。

唯一发生的重新排序是本地的,在每个 CPU 内核中,在它访问全局一致的共享状态之间。(这就是为什么本地内存屏障只是让这个核心等待事情发生,例如存储缓冲区耗尽,可以恢复 x86 TSO 之上的顺序一致性。这同样适用于较弱的内存模型,顺便说一句:只是在 MESI 一致性之上进行本地重新排序。)

这些保证的其余部分分别适用于每个(逻辑)CPU 核心。 ( 关于这如何在内核之间创建同步。)

  • 存储按程序顺序可见:从存储缓冲区按顺序提交到 L1d 缓存。 (存储缓冲区条目在 issue/rename 期间按程序顺序分配)。这意味着缓存未命中存储必须停止存储缓冲区,而不是让年轻的存储提交。请参阅 了解此的简单心智模型,以及有关 Skylake 实际可能执行的操作的一些详细信息(在等待缓存行到达时将存储未命中的数据提交到 LFB)。

  • 加载不会与以后的存储重新排序:简单:要求加载完全完成(已从 L1d 缓存中获取数据)才能退出。由于退役是有序的,并且商店在 退役(变得非投机)之前不能提交 L1d,我们免费获得 LoadStore 订购1.

  • 加载按程序顺序从相干缓存(内存)中获取数据。这是困难的:在执行时加载访问全局状态(缓存),不像存储,其中存储缓冲区可以吸收 OoO exec 和有序提交之间的不匹配。实际上,使每个加载都依赖于先前的加载将防止未命中并扼杀涉及内存的代码的乱序执行的许多好处。

    在实践中,英特尔 CPUs 积极推测现在存在的高速缓存行将 仍然 在体系结构上允许加载发生时存在(早先之后加载执行)。如果不是这种情况,请破坏管道(内存顺序错误推测)。为此有一个性能计数器事件。

在实践中,一切都可能变得更复杂,以追求更高的性能,或者更多地追求推测性的早期加载。

(在 C++ 术语中,这至少与 acq_rel 一样强大,但也涵盖了在 C++ 中可能是 UB 的事物的行为。例如,加载 partially 将最近的存储重叠到另一个线程也可能正在读取或写入的位置,从而允许该核心加载从未出现或将出现在内存中以供其他线程加载的值。)

相关问答:

  • 导致 machine_clears.memory_ordering
  • - MESI 缓存一致性是所有这一切的关键部分。
  • - 这甚至不是正确的心智模型。

脚注 1:
一些 OoO exec weakly-ordered CPUs 可以执行 LoadStore reordering,大概是通过让负载从 ROB 退出,只要负载检查权限并请求缓存行(对于a miss),即使数据还没有真正到达。需要对未就绪的寄存器进行一些单独的跟踪,而不是通常的指令调度程序。

LoadStore 重新排序在有序管道上实际上更容易理解,我们知道需要对缓存未命中负载进行特殊处理才能获得可接受的性能。