【问题标题】:how to put two class members in the same cache line?如何将两个类成员放在同一个缓存行中?
【发布时间】:2021-11-11 12:05:43
【问题描述】:

这个问题的灵感来自一个较早的问题https://stackoverflow.com/a/8469621/14064670。在此链接中,@Phil Miller 提到开头的填充将保证前两个成员最终位于同一缓存行中,但我无法理解。有人能解释一下吗?

开头的填充意味着 buffer_ 和 buffer_mask_ 最终位于同一缓存行上,而不是分成两行,因此需要双倍的内存流量才能访问。

在我看来,当两个成员在开始时,__attribute__ 或 memalign() 都可以提供帮助,但是如果这两个成员在结构的中间呢?

【问题讨论】:

  • 阅读 cmets 的答案。填充仅防止错误共享。开头的填充防止与相邻变量的错误共享。它实际上并没有使buffer_buffer_mask_ 共享一个缓存行。

标签: c++ caching padding memory-alignment


【解决方案1】:

您所询问的报价通常不是真的。帖子中的一条非常受欢迎的评论也指出了这一点:

实际上,没有假设“cacheline_pad_t 本身会对齐到 64 字节;”实际上不需要对齐。填充只是保证唯一的目标,即前后的变量在不同的缓存行中。

换句话说,优化的重点纯粹是关于在填充之间声明的变量的缓存行分离。编译器/链接器/运行时中的任何内容都不能保证 buffer_buffer_mask_ 在一行中给出地址。

也就是说,实际上,他们可能会这样做。至少在所示的 sn-p 中,声明的前三个变量是:pad0_(64 字节)、buffer_(指针大小,可能是 8 字节,取决于架构)和buffer_mask_(可能是 8 字节,取决于架构) )。这三个都将放在.bss 部分。

当这个模块在几乎任何常见的运行时系统上加载到内存中时,.bss 部分将被放置在页面边界上,因为这是 MMU 管理系统中的标准内存单元。页面大小通常最小为 4k,缓存线通常(但不是必须)为 64 字节,因此与页面对齐意味着您也与缓存线对齐。那么pad0_将是页面对齐的,它将占用一个完整的缓存行,这意味着buffer_开始了一个新的缓存行,并且只占用了它的8个字节,这使得buffer_mask_紧跟在它之后的同一行中。

我将在这里再次强调:这一切都保证会发生,它很可能基于最常见的工具链 + 运行时行为。

关于你的第二个问题:

在我看来,当两个成员在开始时,attribute 或 memalign() 都可以提供帮助,但是如果这两个成员在结构的中间呢?

我最好的建议是利用 C/C++ 对结构标准布局的保证,这意味着您在结构中声明的字段保证按照您声明它们的顺序放置。因此,如果您希望结构中间的字段以特定方式对齐,则需要手动填充它们以强制对齐。请注意,不同的体系结构确实具有不同的缓存线大小,因此通常这不会是可移植的。例如:

// not cache optimized:
struct CacheNonOpt {
    uint32_t someArray1[12]; // 48 bytes
    uint32_t someArray2[12]; // 48 bytes
} myNonOptStruct;

// probably cache optimized, assuming you align it:
struct CacheNonOpt {
    uint32_t someArray1[12]; // 48 bytes
    uint32_t pad[4]; // 16 bytes
    uint32_t someArray2[12]; // 48 bytes
} myOptStruct;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-07-08
    • 1970-01-01
    • 1970-01-01
    • 2022-07-08
    • 2011-05-24
    • 1970-01-01
    • 2016-11-21
    相关资源
    最近更新 更多