虚假共享和128字节对齐/填充

pol*_*tex 21 c++ locking false-sharing

在做一些关于无锁/无等待算法的研究时,我偶然发现了错误的共享问题.挖掘更多的东西让我得到了Folly的源代码(Facebook的C++库),更具体地说是这个头文件FOLLY_ALIGN_TO_AVOID_FALSE_SHARING宏的定义(目前在第130行).乍一看最令我惊讶的是价值:128(即:而不是64)......

/// An attribute that will cause a variable or field to be aligned so that
/// it doesn't have false sharing with anything at a smaller memory address.
#define FOLLY_ALIGN_TO_AVOID_FALSE_SHARING __attribute__((__aligned__(128)))
Run Code Online (Sandbox Code Playgroud)

AFAIK,现代CPU上的缓存块长度为64字节,实际上,到目前为止,我发现的每一项资源,包括英特尔的这篇文章,都讨论了64字节对齐填充,以帮助解决错误共享问题.

尽管如此,Facebook的人们在需要时将他们的班级成员对齐并填充为128字节.然后我在上面FOLLY_ALIGN_TO_AVOID_FALSE_SHARING的定义中找到了解释的开头:

enum {
    /// Memory locations on the same cache line are subject to false
    /// sharing, which is very bad for performance.  Microbenchmarks
    /// indicate that pairs of cache lines also see interference under
    /// heavy use of atomic operations (observed for atomic increment on
    /// Sandy Bridge).  See FOLLY_ALIGN_TO_AVOID_FALSE_SHARING
    kFalseSharingRange = 128
};
Run Code Online (Sandbox Code Playgroud)

虽然它给了我更多细节,但我仍然觉得我需要一些见解.我很好奇在大量使用原子操作时,连续缓存行的同步或它们上的任何RMW操作如何相互干扰. 有人可以告诉我这甚至可能发生的事情吗?

Eli*_*ias 6

正如 Hans 在评论中指出的,有关这方面的一些信息可以在“Intel\xc2\xae 64 和 IA-32 架构优化参考手册”中找到,在第 3.7.3 节“二级缓存的硬件预取”中,关于英特尔酷睿微架构:

\n\n

“Streamer \xe2\x80\x94 将数据或指令从内存加载到二级缓存。要使用 Streamer,请将数据或指令组织在 128 字节的块中,按 128 字节对齐。第一次访问两者之一该块中的缓存行在内存中时会触发流传输器预取该对行。”

\n


Mat*_*son -1

无论是否使用原子操作,缓存都有一个“缓存行”,它是缓存操作的最小单元。该范围从 32 到 128 字节,具体取决于处理器型号。错误共享是指同一缓存行中的元素在不同线程(在不同处理器上运行[1])之间“共享”。当这种情况发生时,一个处理器更新“其值”,将迫使所有其他处理器“删除其数据副本”。在原子操作的情况下,情况会变得更糟,因为要执行任何原子操作,执行该操作的处理器需要确保所有其他处理器都已删除“它们的副本”,然后才能更新值(以确保没有其他处理器正在使用值更新之前的“旧”值) - 这需要通过系统传播大量缓存维护消息,并且处理器重新加载它们以前在缓存中拥有的值。

因此,从性能角度来看,如果您有一个线程使用的变量,请通过将数据与该变量对齐来将它们分离到自己的缓存行(在原始帖子的示例中,假设为 128 字节)值 - 意味着每个数据块都从均匀的缓存行边界开始,并且没有其他处理器会“共享”相同的数据(除非您真正在线程之间共享数据 - 此时您必须执行相关的缓存维护确保数据在处理器之间正确更新)

[1] 或具有多个核心的现代 CPU 中的处理器核心。为简单起见,我使用术语“处理器”或“多个处理器”来对应真实的处理器插槽或一个插槽内的处理器内核。对于本次讨论来说,这种区别几乎是无关紧要的。

  • 我理解虚假分享的概念。我的问题是关于他们用来进行对齐和填充的值(128 字节)与强制他们选择该值的架构(即:Sandy Bridge,据我所知,它有 64 字节缓存线)。 (4认同)
  • 您已经做出了彻底的回答,我对此表示感谢。但请阅读我的诚然太长且可能不清楚的问题:“微基准表明成对的缓存线也出现干扰......(在桑迪桥上观察到......)。”对于这里的建筑。由于 **Sandy Bridge** 结果不佳,他们已将对齐方式更改为 128 字节。我想了解的是为什么以及如何在特定情况下更大的填充会减少错误共享。@Hans 对这个问题的评论可能会让你感兴趣,就像我一样。 (4认同)