C 在x64处理器上,字对齐加载是否比未对齐加载快?

C 在x64处理器上,字对齐加载是否比未对齐加载快?,c,alignment,x86-64,C,Alignment,X86 64,在x86/64(Intel/AMD 64位)处理器上对齐的变量加载速度是否比未对齐的加载速度快 我的一位同事认为,未对齐的负载速度很慢,应该避免。他引用了在结构中对单词边界填充项来证明未对齐的加载是缓慢的。例如: struct A { char a; uint64_t b; }; 结构的大小通常为16字节 另一方面,Snappy假设“未对齐的32位和64位加载和存储是便宜的”。根据源代码,这适用于英特尔32位和64位处理器 那么:这里的真相是什么?如果未对齐的负载慢了多少?在哪种情况下

在x86/64(Intel/AMD 64位)处理器上对齐的变量加载速度是否比未对齐的加载速度快

我的一位同事认为,未对齐的负载速度很慢,应该避免。他引用了在结构中对单词边界填充项来证明未对齐的加载是缓慢的。例如:

struct A {
  char a;
  uint64_t b;
};
结构的大小通常为16字节

另一方面,Snappy假设“未对齐的32位和64位加载和存储是便宜的”。根据源代码,这适用于英特尔32位和64位处理器


那么:这里的真相是什么?如果未对齐的负载慢了多少?在哪种情况下?

对齐的加载速度更快,cleanly的两个摘录指出了这一点:

3.6优化内存访问

对齐数据,注意数据布局和堆栈对齐

对齐和转发问题是最常见的问题来源之一 基于英特尔NetBurst微体系结构的处理器上的大延迟

3.6.4对准

数据对齐涉及各种变量:

•动态分配的变量

•数据结构的成员

•全局或局部变量

•在堆栈上传递的参数

未对齐数据 访问可能会导致严重的性能损失。这是 对于缓存线拆分尤其如此

在3.6.4中的这一部分之后,编译器开发人员有一个很好的规则:

汇编/编译器编码规则45。(H影响,H一般性)在 自然操作数大小地址边界。如果数据将通过vector访问 指令加载和存储,在16字节边界上对齐数据

然后是对齐规则列表和3.6.6中的另一个gem

用户/信源编码规则6。(H冲击,M)焊盘数据 在源代码中定义的结构,以便每个数据元素 与自然操作数大小地址边界对齐


这两条规则都被标记为“高影响”,这意味着它们可以极大地改变性能。在第3.6节的其余部分中,除了摘录之外,还包含了自然调整数据的其他原因。任何开发人员都值得花时间阅读这些手册,哪怕只是为了了解他/她正在使用的硬件。

我在互联网上找到的一个随机的家伙说,对于486来说,对齐的32位访问需要一个周期。跨四边形但位于同一缓存线内的未对齐32位访问需要四个周期。跨多个缓存线的未对齐etc可能需要额外的6到12个周期

根据定义,一个未对齐的访问需要访问多个四边形内存,对此我一点也不感到惊讶。我可以想象,在现代处理器上更好的缓存性能会使成本稍微降低一些,但这仍然是需要避免的

(顺便说一句,如果您的代码有任何可移植性的自诩……ia32及其子代几乎是唯一支持未对齐访问的现代体系结构。例如,ARM可能会在引发异常、在软件中模拟访问或只是加载错误的值之间产生很大的差异,具体取决于操作系统!)


最新消息:这里有人真的去了。在他的硬件上,他认为未对齐的访问速度是对齐速度的一半。自己去试试吧……

要修复未对齐的读取,处理器需要进行两次对齐读取并修复结果。这比必须进行一次读取而不进行修复要慢

Snappy代码有利用未对齐访问的特殊原因。它将在x86_64上工作;它在未对齐访问不是选项的体系结构上不起作用,而在修复未对齐访问是一个系统调用或类似的昂贵操作的情况下,它将缓慢地起作用。(在DEC Alpha上,有一种机制大约相当于用于修复未对齐访问的系统调用,您必须为您的程序打开它。)


使用未对齐的访问是Snappy作者做出的明智决定。这并不意味着每个人都应该效仿它。例如,如果编译器编写者在默认情况下使用代码,他们会因为代码性能差而受到谴责。

不应使用未对齐的加载/存储,但原因不是性能。原因是C语言禁止它们(通过对齐规则和别名规则),并且如果没有非常慢的仿真代码,它们在许多系统上都无法工作——这些代码也可能破坏多线程代码正确行为所需的C11内存模型,除非它是在完全逐字节的级别上完成的


对于x86和x86_64,对于大多数操作(某些SSE指令除外),允许未对齐的加载和存储,但这并不意味着它们的访问速度与正确的访问速度一样快。这只是意味着CPU为您进行模拟,并且比您自己能够更有效地进行模拟。例如,执行字大小未对齐读取和写入的
memcpy
类型循环将比执行对齐访问的相同
memcpy
稍慢,但也比编写自己的逐字节复制循环快。

未对齐32位和64位访问并不便宜

我做了测试来验证这一点。我在Core i5 M460(64位)上的结果如下:最快的整数类型是32位宽。64位对齐稍慢,但几乎相同。16位对齐和8位对齐都明显慢于32位和64位对齐。16位比8位对齐慢。到目前为止,最慢的访问形式是非对齐32位访问,比对齐32位访问慢3.5倍(速度最快),而未对齐32位访问甚至比未对齐64位访问慢40%

结果: 源代码:

默认结构packi