dme*_*ter 6 c x86-64 alignment
在x86/64(Intel/AMD 64位)处理器上,在字边界上对齐的变量是否比未对齐的加载操作更快?
我的一位同事辩称,未对齐的载荷很慢,应该避免.他引用了项目填充到结构中的单词边界,作为未对齐加载缓慢的证明.例:
struct A {
char a;
uint64_t b;
};
Run Code Online (Sandbox Code Playgroud)
结构A通常大小为16个字节.
另一方面,Snappy压缩器的文档指出Snappy假设"未对齐的32位和64位加载和存储很便宜".根据源代码,英特尔32和64位处理器也是如此.
那么:这里的真相是什么?如果和未对齐的载荷减少多少?在哪种情况下?
互联网上随机的人我发现,486表示对齐的32位访问需要一个周期.跨越四边形但位于同一缓存线内的未对齐32位访问需要四个周期.跨越多个缓存行的未对齐等可能需要额外的六到十二个周期.
鉴于未对齐的访问需要访问多个内存,几乎按照定义,我对此并不感到惊讶.我认为现代处理器上更好的缓存性能会使成本变得不那么糟糕,但仍然需要避免.
(顺便提一下,如果你的代码对可移植性有任何意义 ...... ia32和后代几乎是唯一支持未对齐访问的现代架构.例如,ARM可以在抛出异常,模拟软件访问之间,或者只是加载错误的值,取决于操作系统!)
更新:这是一个真正去过并测量它的人.在他的硬件上,他估计未对齐的访问速度是对齐的一半.去试试吧...
对齐加载是存储更快,英特尔优化手册中的两段摘录清楚地指出了这一点:
3.6 优化内存访问
对齐数据,注意数据布局和堆栈对齐
...
对齐和转发问题是基于 Intel NetBurst 微架构的处理器出现大延迟的最常见原因之一。
和
3.6.4 对齐
数据的对齐涉及各种变量:
• 动态分配的变量
• 数据结构的成员
• 全局或局部变量
• 在堆栈上传递的参数
未对齐的数据访问可能会导致严重的性能损失。对于缓存行拆分尤其如此。
在 3.6.4 中的那部分之后,编译器开发人员有一个很好的规则:
汇编/编译器编码规则 45。(H 影响,H 通用性)在自然操作数大小地址边界上对齐数据。如果将通过向量指令加载和存储访问数据,则在 16 字节边界上对齐数据。
其次是对齐规则列表和 3.6.6 中的另一个 gem
用户/源编码规则 6.(H 影响,M 通用性)填充源代码中定义的数据结构,以便每个数据元素与自然操作数大小地址边界对齐。
这两个规则都被标记为高影响,这意味着它们可以极大地改变性能,连同摘录,第 3.6 节的其余部分充满了自然对齐数据的其他原因。非常值得任何开发人员花时间阅读这些手册,即使只是为了了解他/她正在处理的硬件。
未对齐的 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
| 归档时间: |
|
| 查看次数: |
4822 次 |
| 最近记录: |