【问题标题】:What is the point of MESI on Intel 64 and IA-32英特尔 64 和 IA-32 上的 MESI 有何意义
【发布时间】:2018-09-25 09:22:04
【问题描述】:
  • MESI 的重点是保留共享内存系统的概念。
  • 但是,有了存储缓冲区,事情就变得复杂了:
  • 一旦数据到达 MESI 实现缓存,内存就会保持一致。
  • 但是,在此之前,每个内核可能不同意内存位置 X 中的内容,具体取决于每个内核的本地存储缓冲区中的内容。
  • 因此,从每个内核的角度来看,内存状态似乎是不同的 - 它是不连贯的。
  • 那么,我们为什么要“部分”地执行与 MESI 的一致性?

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

【问题讨论】:

  • @PaulA.Clayton。是的,我明白这一点;但这如何回答这个问题?我没有提到一致性——只是一致性:获取一个陈旧的缓存行。
  • @Kay,您给出的示例与“获取陈旧的缓存行”无关,它保留了缓存一致性并符合 TSO 内存排序模型(这确实比顺序一致性弱,但是远非“弱”)。
  • @PaulA.Clayton 我认为我通过链接一个 确实 与一致性有关的示例来混淆问题。对此感到抱歉。
  • @Leeor 我认为我通过链接一个确实与一致性有关的示例来混淆问题。对此感到抱歉。
  • 主流英特尔 CPU 中的缓存完全一致的(对于通常的内存类型和正常的读写),所以你的问题的基础(他们不是)可能是无效的。是的,x86 模型内存本身允许一些有限的重新排序(加载通过较早的存储),但这主要是由于存储缓冲区和其他无序效应导致的内核重新排序的结果,而不是由于不连贯的缓存.没有您描述的类型的“最终一致性”。如果核心没有“立即”响应窥探,则窥探核心必须等待。

标签: caching concurrency x86 cpu-architecture mesi


【解决方案1】:

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

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

您的问题似乎包含了这样一个假设,即只有可能的状态“连贯”和“其他一切”。此外,缓存一致性(主要专门处理缓存,并且大部分是隐藏的细节)和内存一致性模型架构上定义并将由每个架构实现2。 Wikipedia explains 缓存一致性和内存一致性之间的一个区别是前者的规则一次只适用于一个位置,而一致性规则适用于不同的位置。在实践中,更重要的区别是 内存一致性 模型是唯一在架构上记录的模型。

简而言之,英特尔(以及 AMD)定义了一个特定的内存一致性模型x86-TSO3 - 就内存模型而言,它相对强大,但仍然比 sequential consistency 弱。与顺序一致性相比,削弱的主要行为是:

  • 以后的加载可以通过较早的存储。
  • 可以看到商店的顺序与商店总订单不同,但只能通过执行其中一个商店的核心来查看。

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

总结一下:

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

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

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

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

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

【讨论】:

  • 感谢您的好评。我已经重组了这个问题,希望能准确地指出让我感到困惑的地方。正如您所注意到的,这是与存储缓冲区的交互。
  • 我更新了我的答案,但你的问题还是有点糊涂。没有“部分强制执行与 MESI 的一致性”——缓存是完全一致的。然而,不仅仅是缓存的整个系统遵循特定的内存模型,它比完全顺序一致性弱。我认为您的问题更多的是关于硬件支持的内存模型,而不是关于 MESI 或缓存,它们是特定芯片如何实现的内部细节。保证是内存一致性,而不是缓存一致性。
【解决方案2】:

Re:您的编辑,这似乎是一个新问题:对,存储转发“违反”一致性。一个核心可以比任何其他核心更早地看到自己的商店。存储缓冲区不一致。

x86 内存排序规则要求加载按程序顺序全局可见,但允许核心在全局可见之前从其自己的存储加载数据。不必pretend it waited and check for memory-order mis-speculation, like it does in other cases of doing loads earlier than the memory model says it should.

也相关; Can x86 reorder a narrow store with a wider load that fully contains it? 是存储缓冲区 + 存储转发违反通常内存排序规则的特定示例。请参阅 Linus Torvalds 的邮件列表帖子的this collection,其中解释了存储转发对内存排序的影响(以及这意味着所提议的锁定方案如何不起作用)。


如果完全没有一致性,您将如何以原子方式递增共享计数器,或实现其他对于实现锁或直接在无锁代码中使用必不可少的原子读-修改-写操作。 (见Can num++ be atomic for 'int num'?)。

lock add [shared_counter], 1 同时在多个线程中永远不会丢失实际 x86 的任何计数,因为lock 前缀使核心保持对缓存行的独占所有权,直到存储提交到 L1d(因此变为全球可见)。

没有一致缓存的系统会让每个线程增加自己的共享计数器副本,然后内存中的最终值将来自最后刷新该行的线程。

即使在发生其他加载/存储时,允许不同的缓存长期保存同一行的冲突数据,并且跨越内存屏障,会导致各种奇怪。

这也违反了纯存储立即对其他内核可见的假设。如果您根本没有一致性,那么核心可以继续使用共享变量的缓存副本。所以如果你想让读者注意到更新,你必须在每次读取共享变量之前clflush,这使得常见情况变得昂贵(当你上次检查后没有人修改数据时)。

MESI 就像一个推送通知系统,而不是强制每个读取器在每次读取时重新验证其缓存。

MESI(或一般的一致性)允许在共享数据结构未修改的情况下,RCU(读取-复制-更新)等读取器的开销为零(与单线程相比)。请参阅https://lwn.net/Articles/262464/https://en.wikipedia.org/wiki/Read-copy-update。基本思想是,作者不是锁定数据结构,而是复制整个事物,修改副本,然后更新共享指针以指向新版本。所以读者总是完全无需等待;他们只是取消引用一个(原子)指针,并且数据在他们的 L1d 缓存中保持热状态。


硬件支持的一致性非常有价值,几乎每个共享内存 SMP 架构都使用它。即使是内存排序规则比 x86 弱得多的 ISA,如 PowerPC,也使用 MESI。

【讨论】:

  • 多核处理器和 GPGPU 是共享内存架构,通常不实现缓存一致性或提供有限形式的一致性。
  • @HadiBrais:所以在 GPGPU 上增加共享原子需要昂贵的显式屏障来确保连贯性,就像 @ Bee 的回答所暗示的那样?我在写这篇文章时忽略了这种可能性。 (当你说多核时,你是在排除 Xeon Phi,对吗?我认为它实现了 x86 共享内存模型。)
  • 至强融核处理器在自身内部以及与其他处理器之间是一致的。 Xeon Phi 协处理器仅在其自身内部保持一致,而不与其他处理器或协处理器保持一致。这与多插槽多核处理器形成鲜明对比。
  • @PeterCordes - 这些不连贯的架构通常具有明确的通信指令,可用于同步内存的特定区域,因此比内存屏障更丰富。当然,您通常不会以标准 C++ 原子为目标,因此不会真正出现实现 C++ 或类似 CPU 的原子操作和栅栏的“问题”。
  • @PeterCordes 回复:您的编辑:“明确允许核心在全球可见之前查看其自己的商店”。我认为是这样;请参阅英特尔 SDM Vol3:8.2.3.5。 “内存排序模型允许这两个处理器以不同的顺序查看两个处理器的并发存储;具体来说,每个处理器可能会感知到自己的存储发生在另一个处理器之前”。
猜你喜欢
  • 2011-06-16
  • 2011-07-20
  • 1970-01-01
  • 2019-08-02
  • 2014-04-02
  • 1970-01-01
  • 2012-02-25
  • 2012-11-01
相关资源
最近更新 更多