核心如何决定在 MESI 中使哪个缓存行失效?

How do cores decide which cache line to invalidate in MESI?

我对缓存行有一些误解。我正在使用 HaswellUbuntu。现在假设我们有 2 线程应用程序,其中发生了以下情况。

mov [addr], dword 0xAC763F
;starting Thread 1 and Thread 2

现在假设线程并行执行以下操作:

Thread 1                        Thread 2
mov rax, [addr]              mov rax, [addr]
mov [addr], dword 1     mov [addr], dword 2

现在我对发生的事情的理解是:

  1. 在启动主线程之前写入相应的缓存行(addr)并将其标记为Exclusive
  2. 如果线程 Thread 1Thread 2 在写入开始之前都完成了读取,那么缓存行在所有缓存中的状态都是 Shared

现在我不明白如果Thread 1中的mov [addr], dword 1Thread 2中的mov [addr], dword 2都被标记为Invalid发生了 "at the same time".

首先"at the same time"感觉有点模糊。我认为这是 "during the same CPU clock cycle"。 MESI 协议实现如何解决这个 "the same time writing from different threads problem".

I think of this as "during the same CPU clock cycle"

不同的内核可以使用不同的时钟;例如一个核心可以达到 4GHz,而另一个核心可以达到 800MHz。 (不过,仅适用于 Haswell Xeon;双/quad-core 部分的所有内核都在一个时钟域中。我已经读过,它与您在闲置内核上查看 CPU 频率所看到的相符而一个核心正忙。)

相关:是一个非常相似的问题。 (但是那个问题的 OP 不知道 MESI 是什么)。尽管如此,我还是在那里详细介绍了发送 RFO 请求,所以如果这个答案太简洁的话,可以阅读那个答案。

Before starting the main thread writes to the corresponding cache line (addr) and marks it as Exclusive.

一个核心必须在独占状态下获取高速缓存行,然后它才能修改它。实际上,向 L1D 提交写入会将其从独占翻转为已修改,而不与其他内核进行通信。 (L1D 和 L2 是 write-back 缓存)。

但是,是的,如果两个核心都在写入缓存行之前都读取了缓存行,那么它们都会使该行处于共享状态。他们只能在收到对该线路的 RFO 请求的成功回复后才能将该线路切换为独占。 Wikipedia's MESI article 有状态转换图和 RFO 的定义。


当然有可能同时执行冲突的 RFO 请求。它们需要很多周期才能到达另一个核心,因此不同核心上的商店有足够的时间来处理每个人都在收到 RFO 之前发起 RFO。 (并不是说这会阻止核心发送自己的 RFO;写入任何一个无效的共享行都需要一个 RFO 才能使其进入独占状态,以便存储可以提交。)

我不是 100% 确定哪个请求获胜的决定将在 L3 缓存中决定。但是

Haswell 的 L3 具有包容性,用作一致性流量的后备/过滤器。 L3 不是 实际上 向所有内核广播所有请求,而是 tag-inclusive 带有额外信息来跟踪哪些内核(可能)具有哪一行的副本。 L1 和 L2 是私有的 per-core,所以 L3 是缓存的第一个共享级别。

我猜测 L3 处理哪个核心的 RFO 首先完成的仲裁,因为它已经在跟踪哪些核心(可能)需要查看哪些 RFO。据推测,这是在保存相关物理地址的 L3 切片中完成的。

,MESI 是围绕总线拓扑设计的,而不是更复杂的消息路由网络。英特尔的设计具有相同的状态,但实际上并不像通常的 CPU-architecture 描述所说的那样简单。

因此,我们可以肯定地说:通过某种未知的内部机制,CPU 决定第一个 RFO。当第一个仍在执行 round-trip 时,稍后到达的一个可能会被取消(因此核心必须稍后重试),或者它可能会被缓冲。

我们确实知道英特尔 CPU 有一个硬件仲裁机制来竞争原子 RMW 操作,例如 lock add [mem], eax。据推测,仲裁多个 write-only 访问同一行的机制完全相同,因为唯一的区别是 locked 操作在操作期间保持在行上,不响应无效请求持续时间。


您可以谈论多个 RFO 请求在 L3 使用的 "uncore" 时钟的同一时钟周期内到达 L3 的同一片。

这在 Haswell 上的实践中可能是可能的; cores are connected with a bi-directional ring bus(单向 32 字节宽),因此每个(非核心)时钟周期有两条消息可以到达任何给定的 L3 缓存片。此外,L3 的每个切片都连接到一个核心,因此来自该核心的请求也可以同时到达。

在那种情况下,它可能很简单:如果一个切片甚至可以在同一周期内接收到发往它的多条消息(而不是仅仅通过环),它可能是 hard-wired 所以其中之一该切片的三个来源总是获胜。