在字边界上对齐的变量是否比x86 / 64(Intel / AMD 64位)处理器上的未对齐加载操作更快?
我的一位同事辩称,未对齐的载荷很慢,应该避免。他引用了项目填充到结构中的单词边界,作为未对齐加载缓慢的证明。例如:
struct A {
char a;
uint64_t b;
};
结构A通常大小为16个字节。
另一方面,documentation of the Snappy compressor表示Snappy认为“未对齐的32位和64位加载和存储很便宜”。根据源代码,这适用于Intel 32和64位处理器。
那么:这里的真相是什么?如果和未对齐的载荷减少多少?在哪种情况下?
答案 0 :(得分:5)
互联网上随机的人我发现,486表示对齐的32位访问需要一个周期。跨越四边形但位于同一缓存线内的未对齐32位访问需要四个周期。跨越多个缓存行的未对齐等可以使额外六到十二个周期。
鉴于未对齐的访问需要访问多个内存,几乎按照定义,我对此并不感到惊讶。我认为现代处理器上更好的缓存性能会使成本变得不那么糟糕,但它还有待避免。
(顺便说一下,如果您的代码具有任何可扩展性的自命令... ia32和后代几乎是唯一支持未对齐访问的现代架构。例如,ARM可以在抛出之间例外,在软件中模拟访问,或只是加载错误的值,具体取决于操作系统!)
更新:这是实际去过measured it的人。在他的硬件上,他估计未对齐的访问速度是对齐的一半。去试试吧......
答案 1 :(得分:3)
对齐加载商店更快,Intel Optimization Manual的两个摘录清楚地指出了这一点:
3.6优化内存访问
对齐数据,注意数据布局和堆栈对齐
...
对齐和转发问题是最常见的来源 基于英特尔NetBurst微体系结构的处理器出现大量延迟。
和
3.6.4对齐
数据的对齐涉及各种变量:
•动态分配变量
•数据结构的成员
•全局或局部变量
•在堆栈上传递的参数
数据未对齐 访问可能会导致严重的性能损失。这是 特别适用于缓存行拆分。
在3.6.4中的那一部分之后,编译器开发人员有一个很好的规则:
汇编/编译器编码规则45.(H影响,H一般性)对齐数据 自然操作数大小地址边界。如果数据将使用向量访问 指令加载和存储,将数据对齐16字节边界。
后面是对齐规则列表和3.6.6
中的另一个gem用户/源编码规则6.(H影响,M一般性)填充数据 源代码中定义的结构,以便每个数据元素都是 与自然操作数大小地址边界对齐。
这两个规则都标记为高影响,意味着它们可以大大改变性能,连同摘录,第3.6节的其余部分充满了自然对齐数据的其他原因。如果只是了解他/她正在使用的硬件,那么开发人员有时间阅读这些手册是非常值得的。
答案 2 :(得分:2)
要修复未对齐的读取,处理器需要执行两次对齐读取并修复结果。这比必须进行一次读取和没有修复要慢。
Snappy代码具有利用未对齐访问的特殊原因。它适用于x86_64;它不适用于不能选择未对齐访问的体系结构,并且在修复未对齐访问是系统调用或类似的昂贵操作时,它将工作缓慢。 (在DEC Alpha上,有一种机制大致相当于修复未对齐访问的系统调用,你必须为你的程序打开它。)
使用未对齐访问是Snappy的作者做出的明智决定。对每个人来说,模仿它并不合理。例如,如果编译器编写者默认使用它们,那么他们的代码性能会很差。
答案 3 :(得分:1)
永远不应使用未对齐的加载/存储,但原因不是性能。原因是C语言禁止它们(通过对齐规则和别名规则),并且它们不能在没有极慢的仿真代码的情况下在许多系统上工作 - 代码也可能破坏正确行为所需的C11内存模型多线程代码,除非它是在纯字节级别上完成的。
对于x86和x86_64,对于大多数操作(某些SSE指令除外),允许使用未对齐的加载和存储,但这并不意味着它们与正确访问一样快。它只是意味着CPU为您进行仿真,并且比您自己做的更有效率。例如,一个memcpy
- 类型的循环正在进行未对齐的字大小读取和写入将比执行对齐访问的相同memcpy
慢一些,但它也会比编写自己的字节更快 - 逐字节复制循环。
答案 4 :(得分:0)
未对齐的32位和64位访问并不便宜。
我做了测试来验证这一点。我在Core i5 M460(64位)上的结果如下:最快的整数类型是32位宽。 64位对齐稍慢但几乎相同。 16位对齐和8位对齐都明显慢于32位和64位对齐。 16位比8位对齐慢。迄今为止最慢的访问形式是非对齐32位访问,比对齐32位访问慢3.5倍(最快),未对齐32位访问比未对齐64位访问慢40%。
结果:https://github.com/mkschreder/align-test/blob/master/results-i5-64bit.jpg?raw=true 源代码:https://github.com/mkschreder/align-test