4

我正在学习 CPU 缓存,现在我仍然对缓存一致性协议 (MESI) 有误解。想象一下,我们有 2 个内核有一个处于共享状态的缓存线。其中一个执行读取,另一个执行写入:

 ;mem is cached in Shared state
 Thread 1 (core 1)          Thread 2 (core 2)
  mov rax, [mem]            mov [mem], dword 1

核心 1 可以观察到一些中间状态吗?我的意思是这样的:

  1. Core 2将缓存行标记L1D为已修改并将更改写入其中。
  2. core 1的缓存中的缓存行L1D仍然处于Shared状态,因此读取恰好读取了陈旧的值。
  3. 在读取过时值之后,缓存中的行已core 1L1D标记为无效。

在英特尔的 MESI/MESIF 实施中是否可能出现这种情况?

4

2 回答 2

6

核心 1 的 L1D 缓存中的缓存线仍处于共享状态

这是违反 MESI 的场景的一部分。在核心 2 发送的 RFO 完成之前,存储无法提交,因此核心 1 的行处于无效状态。

不过,在您的示例中,它实际上并不是一个“中间”步骤。如果没有同步,则无法将您的不可能场景与仅在线路无效之前发生核心 1 的负载区分开来。即核心 1 的加载可以在全局顺序中出现在核心 2 的存储之前。

存储在本地执行之后才变得全局可见(它们必须退出,然后存储队列可以将它们提交到 L1D),并且 x86 的内存模型允许 StoreLoad 重新排序,因此可以延迟存储(隐藏在私有存储中) queue) 直到稍后由核心 2 加载后变为全局可见。(有关内存重新排序的更多背景信息以及 StoreLoad 重新排序的含义,请参阅 Jeff Preshing 的Memory Barriers Are Like Source Control Operations )。


在 MESI(以及 MESIF 或 MOESI 等所有变体)中,如果一个高速缓存有一条处于 E 或 M 状态的行,则没有其他高速缓存可以拥有该行的副本MESI 维基百科文章中的状态表非常清楚地说明了这一点:如果一个缓存具有 E 或 M 状态,则其他缓存都具有无效。

两个缓存永远不可能同时拥有具有不同数据的行的有效副本。这就是缓存一致的含义,阻止这种情况发生是 MESI 协议的重点。

如果一个核心想要修改一个高速缓存行,它会获得该行的独占所有权,因此没有其他核心可以观察到陈旧的值。这必须在商店可以提交到 L1D之前发生。存储队列的存在是为了隐藏 Read-For-Ownership 的延迟(除其他外),但存储队列中的数据尚未提交到 L1D。(相关:当不同的 CPU 内核在没有同步的情况下写入同一个 RAM 地址时会发生什么?关于存储队列的更多信息)。


顺便说一句,让我们假设它[mem]是自然对齐的,因此对其的加载/存储是原子的(由 x86 架构保证)。 为什么在 x86 上对自然对齐的变量进行整数赋值是原子的?.


多级缓存和修改行

使用多级缓存,脏缓存行可以向上传播。所以一条线可以在同一个核心的L1D和L2处于Modified状态。这很好,因为来自 L1D 的回写通过 L2。

据我了解,英特尔 CPU 中的共享包容性 L3 高速缓存不必回写到 DRAM,就可以将高速缓存线的副本共享给多个内核。因此,就普通/简单的 MESI 而言,将 L3 视为后备存储,而不是 DRAM。

在多插槽系统上进行这项工作很棘手;我不确定是否设置好了,因此套接字中的 L3 只能缓存与连接到该套接字的 DRAM 相对应的物理地址。在任何情况下,监听请求都会在 L3 缓存未命中时在套接字之间发送,并且您可以配置许多复杂的设置来在 Xeon 系统上进行调整。(例如,请参阅有关 Haswell Xeon 的 Anandtech 文章。)

于 2018-02-25T19:30:47.113 回答
2

在步骤 1 中,核心 2 将线路标记为已修改之前,它必须通知核心 1。因此在步骤 2 中,线路不再位于核心 1 L1D 中。所以在第 2 步,在访问线路之前,核心 1 必须从核心 2 获取更新后的值。

于 2018-02-25T19:24:11.560 回答