Performance 数据对齐真的能将执行速度提高5%以上吗? 自从我仔细考虑数据结构的对齐。在处理完成之前让CPU洗牌位是有害的。撇开直觉不谈,我测量了未对齐数据的成本:将64位长数据写入GB内存,然后读取它们的值,检查正确性 // c++ code const long long MB = 1024 * 1024; const long long GB = 1024 * MB; void bench(int offset) // pass 0..7 for different alignments { int n = (1 * GB - 1024) / 8; char* mem = (char*) malloc(1 * GB); // benchmarked block { long long* p = (long long*) (mem + offset); for (long i = 0; i < n; i++) { *p++ = i; } p = (long long*) (mem + offset); for (long i = 0; i < n; i++) { if (*p++ != i) throw "wrong value"; } } free(mem); }

Performance 数据对齐真的能将执行速度提高5%以上吗? 自从我仔细考虑数据结构的对齐。在处理完成之前让CPU洗牌位是有害的。撇开直觉不谈,我测量了未对齐数据的成本:将64位长数据写入GB内存,然后读取它们的值,检查正确性 // c++ code const long long MB = 1024 * 1024; const long long GB = 1024 * MB; void bench(int offset) // pass 0..7 for different alignments { int n = (1 * GB - 1024) / 8; char* mem = (char*) malloc(1 * GB); // benchmarked block { long long* p = (long long*) (mem + offset); for (long i = 0; i < n; i++) { *p++ = i; } p = (long long*) (mem + offset); for (long i = 0; i < n; i++) { if (*p++ != i) throw "wrong value"; } } free(mem); },performance,memory-alignment,Performance,Memory Alignment,成本仅为5%(如果我们将其随机存储在任何内存位置,成本将为3,75%,因为25%的内存会对齐)。但存储未对齐的数据有更紧凑的好处,因此3,75%的好处甚至可以得到补偿 测试在英特尔3770 CPU上运行。这种基准测试的许多变化(例如使用指针而不是长指针;随机读取以更改缓存效果)都会导致类似的结果 问题:数据结构对齐是否仍然像我们认为的那样重要? 我知道当64位值分布在缓存线上时会有原子性方面的问题,但这也不是对齐的有力论据,因为更大的数据结构(比如30200字节左右)通常会分布在缓存线上 例如,

成本仅为5%(如果我们将其随机存储在任何内存位置,成本将为3,75%,因为25%的内存会对齐)。但存储未对齐的数据有更紧凑的好处,因此3,75%的好处甚至可以得到补偿

测试在英特尔3770 CPU上运行。这种基准测试的许多变化(例如使用指针而不是长指针;随机读取以更改缓存效果)都会导致类似的结果

问题:数据结构对齐是否仍然像我们认为的那样重要?

我知道当64位值分布在缓存线上时会有原子性方面的问题,但这也不是对齐的有力论据,因为更大的数据结构(比如30200字节左右)通常会分布在缓存线上

例如,我一直坚信这里很好地阐述的速度论点:违背旧规则感觉不舒服。但是:我们可以衡量正确对齐的性能提升吗?

一个好的答案可以提供一个合理的基准,显示对齐与未对齐数据的系数提升>1.25。或者证明常用的其他现代CPU受不对齐的影响更大

谢谢你的想法

编辑:我关心的是结构保存在内存中的经典数据结构。与科学数字运算等特殊情况不同

更新:来自评论的见解:

  • 在Sandy Bridge上有效处理未对齐的内存操作数

    在Sandy Bridge上,读取或写入未对齐的内存操作数不会导致性能损失,但它使用了更多的缓存组,因此当操作数未对齐时,缓存冲突的风险更高。存储到加载转发在大多数情况下也适用于未对齐的操作数


  • 未对齐由于缓存组织,在Sandy Bridge上的访问速度可能会更快(!)。

    是的,数据对齐是在仅支持SSE的体系结构上进行矢量化的一个重要先决条件,SSE具有或在较新的体系结构上,如。Intel AVX确实支持未对齐的访问,但对齐数据仍然被视为一种良好做法:

    Intel®AVX放宽了一些内存对齐要求,因此现在 默认情况下,“英特尔AVX”允许未对齐的访问;但是,这种访问可能会失败 在性能下降的情况下,设计数据的旧规则 内存对齐仍然是一种好的做法(16字节对齐 128位访问和32字节对齐(用于256位访问)。主要 例外情况是SEE指令的VEX扩展版本 明确要求的内存对齐数据:这些指令仍然 需要对齐的数据


    在这些体系结构上,矢量化有用的代码(例如大量使用浮点的科学计算应用程序)可能会受益于满足各自的对齐先决条件;加速比将与FPU中的矢量车道数成比例(4、8、16X)。您可以通过比较软件(如or或任何其他科学软件)是否使用矢量化来衡量矢量化的好处(-xHost代表
    icc
    ,-march=native代表
    gcc
    ),您应该可以轻松获得2倍的加速。

    谢谢-有趣的输入。据我所知,通常的随机访问数据结构不应该受到矢量化的影响。未对齐的访问不是矢量化的先决条件though@harold:你是说“对齐”还是“未对齐”?对齐,但不管怎样。告诉编译器数据是对齐的会使它生成更短的代码,否则会有更多的错误。但它仍然可以矢量化。@harold谢谢,你说得对-AVX支持未对齐访问,尽管Intel建议的做法是对齐数据。但是,SSE不支持未对齐的操作数。我在回答中阐明了这些要点。“英特尔桑迪桥”体系结构几乎完全消除了对内存操作数未对齐的惩罚,我想这正是您所看到的。但是,一些SSE指令仍然需要对齐。@MatthewWatson非常有启发性,非常感谢!将研究Sandy Bridge体系结构。这可能会引起兴趣:如果在Core2上测量,可能会得到非常不同的结果
    值的结果也会非常有趣,特别是如果测试涉及的计算复杂到无法放入可用寄存器。
    1st run         2nd run       %
    i = 0   221     i = 0   217   100 %
    i = 1   228     i = 1   227   105 %
    i = 2   260     i = 2   228   105 %
    i = 3   241     i = 3   228   105 %
    i = 4   219     i = 4   215    99 %
    i = 5   233     i = 5   228   105 %
    i = 6   227     i = 6   229   106 %
    i = 7   228     i = 7   228   105 %