【问题标题】:Semantics of atomic stores in MESI cachelinesMESI 高速缓存行中原子存储的语义
【发布时间】:2019-12-13 11:13:18
【问题描述】:

在并发读取和写入行中(仅读取和存储)。当一行由处于修改或读取模式的核心拥有时会发生什么,并且一些其他核心问题在该行上存储操作(假设这些读取和写入是 std::atomic::load 和 std::atomic::store使用 C++ 编译器)?线路是否被拉入另一个发出写入的核心?或者写入是否根据需要直接到达读取核心?两者的区别在于后者只导致读取线路值的一次往返开销。并且也可能并行化(如果存储和读取发生在交错的时间点)

在考虑 NUMA 在并发应用程序中的后果时出现了这个问题。但问题是当涉及的两个核心位于同一个 NUMA 节点时。


混合中有大量架构。但现在,对英特尔 Skylake 或 Broadwell 上发生的事情感到好奇。

【问题讨论】:

    标签: c++ concurrency x86 intel cpu-cache


    【解决方案1】:

    首先,原子加载/存储与常规存储在编译为 asm 时并没有什么特别之处。 (虽然默认的seq_cst 内存顺序可以编译为xchg,但mov+mfence 也是一个有效的(通常较慢)选项,它在asm 中与普通的发布存储后跟一个完整的屏障没有区别。) xchg 是一个原子 RMW + 一个完整的屏障。编译器使用它来实现全屏障效果;交换的负载部分只是一个不需要的副作用。

    此答案的其余部分完全适用于任何 x86 asm 存储,或内存目标 RMW 指令的存储部分(无论它是否是原子指令)。


    假设它尚未被逐出到 L2 或 L3,最初之前一直在执行写入的内核将在其 L1d 中将行置于 MESI Modified 状态。

    该行更改 MESI 状态(到共享)以响应读取请求,或者对于存储执行写入的核心将发送 RFO(所有权请求)并最终使该行处于修改或独占状态。

    在现代 Intel CPU 上的物理内核之间获取数据始终涉及到共享 L3(不一定是 DRAM)的写回。我认为即使在多插槽系统上也是如此,其中两个内核位于不同的插槽上,因此它们并不真正共享一个公共 L3,使用窥探(和窥探过滤)。

    英特尔使用 MESIF。 AMD 使用 MOESI,它允许直接在内核之间直接共享脏数据,而无需先写回共享的外层缓存。

    更多详情请见Which cache mapping technique is used in intel core i7 processor?


    存储数据无法到达另一个核心,除非通过缓存/内存。

    您对“发生”在另一个内核上的写入的想法并不是任何事情的运作方式。在尊重 x86 内存排序规则的同时,我什至看不到它是如何实现的:来自一个内核的存储在程序顺序中变得全局可见。我不明白如何将存储(到不同的缓存行)发送到不同的内核,并确保一个内核等待另一个内核将这些存储提交到它们各自拥有的缓存行。

    即使对于弱序 ISA,它也不是很合理。通常,当您读取或写入高速缓存行时,您将进行更多的读取+写入。通过内核之间的网状互连分别发送每个读取或写入请求将需要许多微小的消息。高吞吐量比低延迟更容易实现:更宽的总线可以做到这一点。负载的低延迟对于高性能必不可少。如果线程曾经在内核之间迁移,突然之间,它们将在其他内核上读/写 L1d 中的所有热缓存行,这将是可怕的,直到 CPU 以某种方式决定它应该将缓存行迁移到内核访问它。

    L1d 缓存体积小、速度快且相对简单。相对于彼此对核心的读取和写入进行排序以及进行推测加载的逻辑都在单个核心内部。 (存储缓冲区,或者在 Intel 上实际上是一个内存顺序缓冲区,用于跟踪推测加载和存储。)


    这就是为什么你应该避免接触一个共享变量,如果你能证明你没有必要的话。 (或者在适当的情况下使用指数退避)。以及为什么 CAS 循环应该在尝试 CAS 之前以只读方式等待查看它正在寻找的值,而不是在 lock cmpxchg 尝试失败时写入缓存行。

    【讨论】:

    • 英特尔软件开发人员手册第 3 卷(系统编程指南)中的 snooping 和第 11.2 节(缓存术语)中的描述如何?这就是说(除其他外)数据可以在 CPU 之间传递而不被写入系统内存。
    • @1201ProgramAlarm 当处于 M 状态的高速缓存行由于来自另一个处理器/核心的请求而从处理器/核心的私有高速缓存中逐出时,必须将其写入下一个 内存层次结构的级别,以便不会丢失行的全局可观察状态。第 11.2 节的措辞是针对 Pentium Pro 处理器编写的,其中系统总线上可能有多个处理器,并且层次结构的下一个包含级别是主存储器。事实上,该部分在最后一句中确实说过内存控制器必须窥探所有写回。
    • @1201ProgramAlarm:就像我在回答中所说的那样,Intel CPU 只需要回写到共享的 L3 缓存,不需要一直到内存。 AMD 的 MOESI 允许在不受公共共享缓存支持的缓存之间共享脏数据。英特尔 CPU 可以在内核之间获取数据,而无需通过 DRAM,但它确实必须通过共享 L3。 (我认为即使在并非所有内核都共享一个公共 L3 的多插槽系统上也是如此)。
    • @Curious:Which cache mapping technique is used in intel core i7 processor? 在除 Skylake-X 之外的 Intel 上,L3 标签在该套接字中用作窥探过滤器。因此,即使行在私有 L1d 缓存中处于修改状态(因此数据在 L3 中无效),缓存也始终包含标记。否则它将不得不向所有核心广播一个窥探。 (在 Skylake-X 之前的双插槽系统上,插槽只是相互监听所有内容。在四插槽 Xeon 上,有一个小的监听过滤器缓存。我假设 SKX 总是有监听过滤器。)
    • @Curious:是的,这就是为什么这个答案甚至没有尝试进入严肃的细节,只是一个高级图片。
    猜你喜欢
    • 2021-10-01
    • 1970-01-01
    • 2017-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多