惩罚通常很小,但在英特尔 CPU 上超过 4k 页面边界后 Skylake 会受到很大惩罚(约 150 个周期)。 How can I accurately benchmark unaligned access speed on x86_64 有一些关于跨越缓存线边界或 4k 边界的实际影响的详细信息。 (这适用于即使加载/存储在一个 2M 或 1G 的大页面内,因为硬件在它开始检查 TLB 两次的过程之后才能知道这一点。)例如在 double 的数组中只有 4 -byte 对齐,在页面边界处会有一个 double 均匀分布在两个 4k 页面上。每个缓存行边界都相同。
不跨越 4k 页面的常规高速缓存行拆分在 Intel 上会花费大约 6 个额外的延迟周期(Skylake 上总共 11c,而普通 L1d 命中需要 4 或 5c),并花费额外的吞吐量(这在通常每个时钟维持接近 2 个负载的代码中可能很重要。)
未跨越 64 字节高速缓存行边界的未对齐对 Intel 的惩罚为零。在 AMD 上,缓存线仍然是 64 字节,但在 32 字节的缓存线内有相关的边界,在某些 CPU 上可能是 16 字节。
我应该对齐每个堆栈变量吗?
不,编译器已经为您完成了这项工作。 x86-64 调用约定维护 16 字节堆栈对齐,因此它们可以免费获得任何对齐,包括 8 字节 int64_t 和 double 数组。
还要记住,大多数局部变量在大部分时间都被保存在寄存器中,它们被大量使用。除非变量是volatile,或者您在没有优化的情况下编译,否则不必在访问之间存储/重新加载该值。
普通的ABIs 还要求所有原始类型自然对齐(与其大小对齐),因此即使在结构等内部,您也会得到对齐,并且单个原始类型永远不会跨越缓存线边界。 (例外:i386 System V 只需要 int64_t 和 double 的 4 字节对齐。在结构之外,编译器会选择给它们更多对齐,但在结构内部它不能更改布局规则。所以声明你的结构以将 8 字节成员放在首位的顺序,或者至少布局以便它们获得 8 字节对齐。如果您关心 32 位代码(如果还没有),可以在此类结构成员上使用 alignas(8)需要这么多对齐的成员。)
x86-64 System V ABI(所有非 Windows 平台)需要将数组对齐 16,如果它们在结构之外具有自动或静态存储。 maxalign_t 在 x86-64 SysV 上为 16,因此 malloc / new 返回 16 字节对齐的内存以进行动态分配。面向 Windows 的 gcc 如果在该函数中对堆栈数组进行自动矢量化,也会对齐堆栈数组。
(如果您通过违反 ABI 的对齐要求而导致未定义的行为,它通常不会导致任何性能差异。它通常不会导致 x86 的正确性问题,但它可能会导致 SIMD 类型的错误,和使用标量类型的自动矢量化。例如Why does unaligned access to mmap'ed memory sometimes segfault on AMD64?。因此,如果您故意不对齐数据,请确保不要使用任何比char* 更宽的指针访问它。
例如使用 memcpy(&tmp, buf, 8) 和 uint64_t tmp 进行未对齐的加载。 gcc 可以通过它自动矢量化,IIRC。)
如果您在启用 AVX 或 AVX512 的情况下编译,您有时可能需要 alignas(32) 或 64 来处理大型数组。对于大型阵列上的 SIMD 循环(不适合 L2 或 L1d 缓存),使用 AVX/AVX2(32 字节向量),确保它在 Intel Haswell/Skylake 上对齐 32 通常几乎为零。来自 L3 或 DRAM 的数据中的内存瓶颈将使核心的加载/存储单元和 L1d 缓存有时间在后台进行多次访问,即使其他加载/存储跨越缓存线边界也是如此。
但是在 Skylake-server 上使用 AVX512,在实践中对阵列的 64 字节对齐有显着影响,即使阵列来自 L3 缓存或可能是 DRAM。我忘记了细节,自从我看一个例子已经有一段时间了,但即使是内存绑定循环也可能有 10% 到 15%? 每个 64 字节向量加载和存储如果未对齐,将跨越 64 字节缓存线边界。
根据循环,您可以通过执行第一个可能未对齐的向量,然后遍历对齐的向量直到最后一个对齐的向量来处理未对齐的输入。到达数组末尾的另一个可能重叠的向量可以处理最后几个字节。这对于复制和处理循环非常有用,在该循环中可以重新复制和重新处理重叠中的相同元素,但还有其他技术可以用于其他情况,例如到对齐边界、较窄向量或掩蔽的标量循环。如果您的编译器是自动矢量化的,则由编译器来选择。如果您使用内在函数手动进行矢量化,您可以/必须选择。如果数组通常是对齐的,那么最好只使用未对齐的加载(如果指针在运行时对齐,则不会有任何损失),并让硬件处理罕见的未对齐输入情况,这样您就没有任何软件开销对齐的输入。