缓存操作是原子的吗?

Are cache operations atomic?

我正在学习 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 2L1D 中的缓存行标记为已修改并将更改写入其中。
  2. core 1L1D 缓存中的缓存行仍处于 Shared 状态,因此读取恰好读取了陈旧值。
  3. 读取过时值后,core 1L1D 缓存中的行已标记为无效。

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

在第1步,before核心2可以将行标记为已修改,它必须通知核心1。所以在第2步,该行不再在核心1 L1D .所以在第2步,在访问线路之前,核心1必须从核心2获取更新后的值。

The cache line in core 1's L1D cache is still in Shared state

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

不过,在您的示例中,它并不是真正的 "intermediate" 步骤。如果没有同步,就无法将不可能的情况与简单地让核心 1 加载发生在线路失效之前区分开来。即核心 1 的加载可以在全局顺序中出现在核心 2 的存储之前。

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


在 MESI(以及 MESIF 或 MOESI 等所有变体)中,如果一个缓存中有一行处于 E 或 M 状态,则其他缓存都不能拥有该行的副本the MESI wikipedia article 中的状态 table 非常清楚:如果一个缓存有 E 或 M 状态,其他缓存都无效。

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

如果一个核心想要修改缓存行,它会获得该行的独占所有权,这样其他核心就无法观察到过时的值。这必须发生在 之前 商店可以提交到 L1D。存储队列的存在是为了隐藏 Read-For-Ownership 的延迟(除其他外),但存储队列中的数据尚未提交给 L1D。 (相关: 有更多关于商店队列的信息)。


顺便说一句,让我们假设 [mem] 是 naturally-aligned,所以对它的加载/存储是原子的(由 x86 架构保证)。 .


Multi-level 缓存和修改行

使用 multi-level 缓存,脏缓存行可以向上传播层次结构。所以一条线路可以在同一核心的L1D和L2中处于Modified状态。这很好,因为来自 L1D 的 write-back 通过 L2。

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

在 multi-socket 系统上进行这项工作很棘手;我不确定是否已设置好,以便套接字中的 L3 只能缓存与连接到该套接字的 DRAM 相对应的物理地址。在任何情况下,侦听请求都会在 L3 缓存未命中时在套接字之间发送,并且您可以配置许多复杂的设置来在 Xeon 系统上调整它。 (例如,参见 an Anandtech article about Haswell Xeon。)