Intel 64 和 IA-32 上的 MESI 有何意义

Kay*_*Kay 3 concurrency x86 caching cpu-architecture mesi

  • MESI 的要点是保留共享内存系统的概念。
  • 然而,对于存储缓冲区,事情就变得复杂了:
  • 一旦数据到达 MESI 实现的缓存,下游内存就会保持一致。
  • 然而,在此之前,每个核心可能对内存位置 X 中的内容存在分歧,具体取决于每个核心的本地存储缓冲区中的内容。
  • 因此,从每个核心的角度来看,内存的状态似乎是不同的——它是不连贯的。
  • 那么,为什么我们要“部分地”强制执行与 MESI 的一致性呢?

编辑:在进一步缩小真正让我困惑的内容之后,进行了实质性编辑。我试图保持问题的一般概念不变,以保留收到的优秀答案的相关性。

Bee*_*ope 5

x86 上的 MESI 的目的与几乎任何多核/CPU 系统上的相同:强制缓存一致性。x86 上等式的缓存一致性部分没有使用“部分一致性”:缓存是完全一致的。那么,可能的重新排序是一致的缓存系统以及与核心本地组件(例如加载/存储子系统(尤其是存储缓冲区)和其他无序机器)交互的结果。

这种交互的结果是 x86 提供的架构强内存模型,仅进行有限的重新排序。如果没有一致的缓存,您根本无法合理地实现该模型,或者几乎无法实现除了完全弱1之外的任何模型。

你的问题似乎嵌入了这样的假设:只有可能的状态“一致”和“其他一切”。此外,缓存一致性的想法(主要专门处理缓存,并且主要是隐藏的细节)和在体系结构上定义并将由每个体系结构2实现的内存一致性模型存在一些混合。维基百科解释说,缓存一致性和内存一致性之间的一个区别是,前者的规则一次仅适用于一个位置,而一致性规则适用于跨位置。在实践中,更重要的区别是内存一致性模型是唯一有架构记录的模型。

简而言之,Intel(以及 AMD 同样)定义了一个特定的内存一致性模型x86-TSO 3 - 就内存模型而言相对较强,但仍然弱于顺序一致性。与顺序一致性相比,被削弱的主要行为是:

  • 较晚的负载可以通过较早的商店。
  • 该存储可以以与总存储顺序不同的顺序看到,但只能由执行其中一个存储的核心看到。

为了实现这个内存模型,各个部分必须遵守规则来实现它。在所有最新的 x86 上,这意味着有序的加载和存储缓冲区,从而避免不允许的重新排序。使用存储缓冲区会导致上述两种重新排序:如果不允许这些重新排序,实现将受到很大限制,并且可能会慢得多。实际上,这也意味着完全一致的数据缓存,因为如果没有它,许多保证(例如,无加载-加载重新排序)将很难实现。

总结一下:

  • 内存一致性与缓存一致性不同:前者是有文档记录的,并且构成编程模型的一部分。
  • 实际上,x86 实现具有完全一致的缓存,这有助于他们实现 x86-TSO 内存模型,该模型相当强大,但弱于顺序一致性。
  • 最后,也许您正在寻找的答案,换句话说:比顺序一致性弱的内存模型仍然非常有用,因为您可以针对它进行编程,并且在您需要某些特定操作的顺序一致性的情况下,您可以插入正确的记忆障碍4
  • 如果您针对语言提供的内存模型(例如JavaC++11)进行编程,则无需担心硬件细节,而不必担心语言内存模型,并且编译器会插入匹配语言内存模型所需的屏障语义与硬件的关系。硬件模型越强大,所需的障碍就越少。

1如果您的内存模型完全弱,即没有真正对跨核心重新排序施加任何限制,我想您可以以廉价的方式直接在非缓存一致性系统上实现正常操作,但随后内存屏障可能会变成非常昂贵,因为他们需要刷新本地私有缓存的很大一部分。

2各种芯片的内部实现方式可能不同,特别是某些芯片可能实现比模型更强的语义(即,永远无法观察到某些允许的重新排序),但如果没有错误,则不会实现较弱的语义。

3这是那篇论文中给它起的名称,我使用它是因为英特尔自己没有给它命名,而且这篇论文是一个比英特尔给出的作为一系列石蕊测试的不太正式模型的定义更正式的定义。

4在 x86 上实践时,您通常使用锁定指令(使用lock前缀)而不是单独的屏障,尽管也存在独立屏障。在这里,我将仅使用术语屏障来指代独立屏障和嵌入到锁定指令中的屏障语义。