【问题标题】:What's the actual effect of successful unaligned accesses on x86?在 x86 上成功的非对齐访问的实际效果是什么?
【发布时间】:2012-09-11 13:50:56
【问题描述】:

我总是听说未对齐的访问很糟糕,因为它们要么会导致运行时错误并使程序崩溃,要么会降低内存访问速度。但是我找不到任何关于它们会减慢多少速度的实际数据。

假设我在 x86 上并且有一些(但未知的)未对齐访问份额 - 实际上可能出现的最严重的减速是什么?如何在不消除所有未对齐访问并比较两个版本代码的运行时间的情况下估算它?

【问题讨论】:

  • 经验法则:与对齐读取相比,大多数架构上的未对齐读取会导致约 2 倍的性能损失,因为它需要两个读取周期来获取数据并修复它。写入稍微复杂一些。
  • 相关:How can I accurately benchmark unaligned access speed on x86_64 有一些关于现代 Intel 上高速缓存行拆分和页面拆分的吞吐量和延迟影响的具体细节。

标签: performance memory x86 alignment memory-alignment


【解决方案1】:

这取决于指令,对于大多数 x86 SSE 加载/存储指令(不包括未对齐的变体),它会导致错误,这意味着它可能会导致您的程序崩溃或导致大量往返于您的异常处理程序(这意味着几乎或所有性能都会丢失)。未对齐的加载/存储变体以 IIRC 的两倍周期运行,因为它们执行部分读/写,因此需要 2 来执行操作(除非你很幸运并且它在缓存中,这大大减少了惩罚)。

对于一般 x86 加载/存储指令,代价是速度,因为执行读取或写入需要更多周期。不对齐也可能影响缓存,导致缓存行拆分和缓存边界跨越。它还可以防止读取和写入的原子性(保证所有对齐的 x86 读取/写入,障碍和传播是另一回事,但是在未对齐的数据上使用 LOCK 指令可能会导致异常或大大增加本已巨大的惩罚lock incurs),这是并发编程的禁忌。

Intels x86 & x64 optimizations manual 详细介绍了上述每个问题、它们的副作用以及如何解决它们。

Agner Fog' optimization manuals 应该具有您正在寻找的原始周期吞吐量的确切数字。

【讨论】:

  • 查看了 Agner Fog 论文,但找不到具体数字。你能指出我正确的页面/表格吗?
  • @NitsanWakart:此处列出了未对齐的 SSE 指令:agner.org/optimize/instruction_tables.pdf,对于正常指令的惩罚,您需要查阅开发人员手册中相应的英特尔章节(第 8 章或第 9 章 IIRC,至少,未对齐的读取需要双倍的循环)
  • 我正在专门寻找对使用最近(Core2 后)cpu 的未对齐(不是缓存线跨越)访问的 MOV 的惩罚。在 Agner 的指令表成本中,我找不到惩罚,除了对齐数据的一般建议外,我在英特尔手册中找不到相关参考。
  • @NitsanWakart:英特尔架构和指令集手册中的 4.1.1 指出,任何未对齐的访问都需要 2 次加载/存储,这基本上会产生双倍的周期(但这可能会因其他条件而异): A word or doubleword operand that crosses a 4-byte boundary or a quadword operand that crosses an 8-byte boundary is considered unaligned and requires two separate memory bus cycles for access.
【解决方案2】:

在某些 Intel 微架构上,按缓存线边界分割的加载比平时多花费十几个周期,而按页面边界分割的加载则多花费 200 多个周期。糟糕的是,如果负载在循环中始终未对齐,那么值得进行两次对齐的负载并手动合并结果,即使palignr 不是一个选项。即使是 SSE 的未对齐负载也无法拯救您,除非它们完全从中间分开。

在 AMD 上,这从来都不是问题,在 Nehalem 中问题基本消失了,但仍然有很多 Core2。

【讨论】:

    【解决方案3】:

    一般来说,估计现代处理器的速度非常复杂。这不仅适用于未对齐的访问,而且一般来说都是如此。

    现代处理器具有流水线架构,指令无序并且可能并行执行以及许多其他可能影响执行的因素。

    如果不支持未对齐访问,则会出现异常。但是,如果它受支持,您可能会或可能不会减速,具体取决于许多因素。这些因素包括您在未对齐指令之前和之后执行的其他指令(因为处理器可能能够在执行之前的指令时开始获取您的数据,或者在等待时继续执行后续指令)。

    如果未对齐访问发生在缓存线边界上,则会发生另一个非常重要的区别。通常,对于未对齐的访问,可能会发生对缓存的 2 倍访问,真正的减速是如果访问越过缓存线边界并导致双缓存未命中。在最坏的可能情况下,2 字节未对齐读取可能需要处理器将两个高速缓存行刷新到内存,然后从内存中读取 2 个高速缓存行。这需要大量的数据移动。

    优化的一般规则也适用于此:先编码,然后测量,然后当且仅当存在问题时找出解决方案。

    【讨论】:

      猜你喜欢
      • 2022-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-17
      • 2019-01-25
      • 2010-09-07
      • 2019-08-27
      • 2012-08-03
      相关资源
      最近更新 更多