在多处理器系统中,每个核心之外的内存在概念上总是 flat/uniform/synchronous 吗?

Is memory outside each core always conceptually flat/uniform/synchronous in a multiprocessor system?

多处理器系统执行 "real" 内存操作(那些影响最终执行的操作,而不仅仅是推测执行)无序且异步,因为等待全局状态的全局同步将几乎一直不必要地停止所有执行.另一方面,就在每个单独的核心之外,从允许的行为角度(允许的语义)来看,从 L1 高速缓存开始的内存系统似乎是完全同步的、一致的、平坦的;显然时间取决于缓存大小和行为。

所以在 CPU 上,一个极端被命名为 "registers",根据定义是私有的,而在另一个极端上,内存是共享的;令人遗憾的是,除了具有特殊命名或寻址模式的微小 space 寄存器之外,内存始终是全局的、共享的和全局同步的,并且有效地完全受制于所有栅栏,即使它是未命名的内存寄存器,目的是存储比几个寄存器容纳的数据更多的数据,而不可能被其他线程检查(除了使用 ptrace 进行调试,它显然会停止、暂停、序列化和存储执行的完整可观察状态)。

现代计算机(现代 = 可以合理支持 C++ 和 Java 的计算机)是否总是如此?

为什么专用 L1 缓存不为那些仅由特定内核使用的内存单元提供类似寄存器的语义?无论如何,缓存都必须跟踪共享的内存。当需要对内存操作进行严格的全局排序时,不必停止对此类本地数据的内存操作,因为没有其他核心在观察它,并且缓存有能力在需要时停止此类外部访问。缓存只需要知道哪些内存单元是私有的(非全局可读)直到乱序操作停顿,这使得一致(缓存可能需要一种方法来要求核心序列化操作并发布一致的状态在内存中)。

是否所有 CPU 停止并同步栅栏或同步操作上的所有内存访问?

内存是否可以用作几乎无限的寄存器资源而不受防护?

实际上,与单处理器系统的设计方式相比,在没有其他线程访问的内存上运行的单核不会为了维护全局内存语义而减慢太多。

但是在大型 multi-socket 系统上,尤其是 x86,cache-coherency(侦听另一个套接字)导致缓存内存延迟更差的部分原因不过,比 single-socket 系统还差。 (对于私有缓存中未命中的访问)。


是的,您可以 运行 单个 multi-threaded 程序的所有 multi-core 系统在所有内核之间都有一致的共享内存,使用 MESI cache-coherency 的一些变体协议。 (这条规则的任何例外都被认为是奇异的,必须专门编程。)

具有多个需要显式刷新的独立一致性域的大型系统更像是一个 tightly-coupled 用于高效消息传递的集群,而不是 SMP 系统。 (普通 NUMA multi-socket 系统 cache-coherent: 专门针对 x86 进行了详细介绍。)


当一个核心在 MESI 修改或独占状态下有一个缓存行时,它可以修改它 而无需 通知其他核心有关更改。一个高速缓存中的 M 和 E 状态意味着系统中没有其他高速缓存具有该行的任何有效副本。但是加载和存储仍然必须遵守内存模型,例如x86 核心仍然必须按程序顺序将存储提交到 L1d 缓存。


L1d 和 L2 是 现代 CPU 核心的一部分,但你是对的,L1d 实际上并没有被推测性地修改。推测可以阅读

您所询问的大部分内容都是由具有存储转发功能的存储缓冲区处理的,允许 store/reload 执行而无需等待存储变得全局可见。

what is a store buffer? and

存储缓冲区 必不可少 用于解耦推测 out-of-order 执行(将数据+地址写入存储缓冲区)从 in-order 提交到 globally-visible L1d缓存。

即使对于 in-order 内核也非常重要,否则 cache-miss 存储会停止执行。通常,您希望存储缓冲区将连续的窄存储合并为单个更宽的缓存写入,尤其是对于可以积极这样做的 weakly-ordered uarches;许多非 x86 微体系结构只有完全有效的提交才能缓存对齐的 4 字节或更宽的块。

在 strongly-ordered 内存模型上,推测性 out-of-order 加载并稍后检查以查看是否有任何其他内核在我们 "allowed" 读取之前使该行无效对于高性能,允许 hit-under-miss for out-of-order exec 继续执行,而不是一个缓存未命中负载停止所有其他负载。


此模型有一些限制:

  • 有限 store-buffer 大小意味着我们没有太多私人空间 store/reload space
  • a strongly-ordered 内存模型阻止私有存储乱序提交到 L1d,因此存储到必须等待来自另一个核心的行的共享变量可能导致存储缓冲区填满私人商店。
  • 内存屏障指令,如 x86 mfencelock add,或 ARM dsb ish 必须耗尽存储缓冲区,因此存储到(并从中重新加载)thread-private 内存这实际上不是共享的仍然需要等待您关心的商店变得全球可见。
  • 相反,等待您关心的共享存储变得可见(带有屏障或 release-store)也必须等待私有内存操作,即使它们是独立的。

the memory is always global, shared and globally synchronous, and effectively entirely subject to all fences, even if it's memory used as unnamed registers,

我不确定你在这里的意思。如果一个线程正在访问私有数据(即不与任何其他线程共享),那么几乎不需要内存栅栏指令1。栅栏用于控制其他内核看到来自一个内核的内存访问的顺序。

Why doesn't the dedicated L1 cache provide register-like semantics for those memory units that are only used by a particular execution unit?

我认为(如果我理解正确的话)你所描述的称为暂存器内存 (SPM),它是一种硬件内存结构,映射到体系结构物理地址 space 或具有它的自己的物理地址 space。该软件可以直接访问 SPM 中的任何位置,类似于主存储器。但是,与主内存不同的是,SPM 具有比主内存更高的带宽 and/or 更低的延迟,但通常尺寸要小得多。

SPM 比缓存简单得多,因为它不需要标记、MSHR、替换策略或硬件预取器。另外,SPM的一致性就像主存一样工作,即只有在有多个处理器时才会发挥作用。

SPM 已用于许多商业硬件加速器,例如 GPU、DSP 和众核处理器。我熟悉的一个例子是 Knights Landing (KNL) 多核处理器的 MCDRAM,它可以配置为近内存(即 SPM)、主内存的 last-level 高速缓存或混合内存.配置为作为 SPM 工作的 MCDRAM 部分映射到与 DRAM 相同的物理地址 space,L2 高速缓存(每个块专有)成为该部分的 last-level 高速缓存内存。如果有一部分 MCDRAM 配置为 DRAM 的缓存,那么它将只是 DRAM 的 last-level 缓存,而不是 SPM 部分。 MCDRAM 的带宽比 DRAM 高得多,但延迟大致相同。

一般来说,SPM 可以放在内存层次结构的任何位置。例如,它可以放置在与 L1 缓存相同的级别。当不需要或很少需要在 SPM 和 DRAM 之间移动数据时,SPM 可以提高性能并降低能耗。

SPM 非常适合具有real-time 要求的系统,因为它提供了关于最大延迟 and/or 最低带宽的保证,这对于确定 real-time 约束是否可以是必要的遇见了

SPM 不太适合 general-purpose 桌面或服务器系统,它们可以同时是多个应用程序 运行。这样的系统没有 real-time 要求,目前,平均带宽需求不足以证明包含 MCDRAM 之类的东西的成本。此外,在 L1 或 L2 级别使用 SPM 会对 SPM 和缓存施加大小限制,并使 OS 和应用程序难以利用这种内存层次结构。

Intel Optance DC 内存可以映射到物理地址space,但它与主内存处于同一级别,因此不被视为 SPM。


脚注:

(1) 在single-thread(或单处理器)场景中可能仍然需要内存栅栏。例如,如果您想测量 out-of-order 处理器上特定代码区域的执行时间,可能需要将该区域包裹在两个合适的栅栏指令之间。通过 write-combining memory-mapped I/O 页面与 I/O 设备通信时也需要 fence,以确保所有较早的存储都已到达设备。