【问题标题】:CPU and Data alignmentCPU 和数据对齐
【发布时间】:2011-03-02 19:02:25
【问题描述】:

如果您觉得这个问题已被多次回答,请原谅我,但我需要以下问题的答案!

  1. 为什么必须对齐数据(在 2 字节/4 字节/8 字节边界上)?我的疑问是,当 CPU 有地址线 Ax Ax-1 Ax-2 ... A2 A1 A0 时,很有可能按顺序寻址内存位置。那么为什么需要在特定边界对齐数据呢?

  2. 在编译代码和生成可执行文件时如何找到对齐要求?

  3. 如果例如数据对齐是 4 字节边界,这是否意味着每个连续字节都位于模 4 偏移处?我的疑问是,如果数据是 4 字节对齐的,这是否意味着如果一个字节位于 1004,那么下一个字节位于 1008(或 1005)?

【问题讨论】:

    标签: c alignment cpu-architecture processor


    【解决方案1】:

    对于英特尔架构,Intel 64 and IA-32 Architectures Software Developer’s Manual 的第 4 章数据类型回答了您的问题 1。

    【讨论】:

      【解决方案2】:

      出于性能原因,CPU 需要数据对齐。英特尔网站详细介绍了如何对齐内存中的数据

      Data Alignment when Migrating to 64-Bit Intel® Architecture

      其中之一是数据项的对齐——它们在内存中的位置与四、八或 16 字节的倍数的地址相关。在 16 位 Intel 架构下,数据对齐对性能的影响很小,它的使用完全是可选的。在 IA-32 下,正确对齐数据可能是一项重要的优化,尽管它的使用仍然是可选的,除了极少数例外,正确对齐是强制性的。然而,64 位环境对数据项提出了更严格的要求。未对齐的对象会导致程序异常。要正确对齐项目,它必须满足 64 位 Intel 架构(稍后讨论)以及用于构建应用程序的链接器的要求。

      数据对齐的基本规则是最安全(也是最广泛支持)的方法依赖于英特尔所说的“自然边界”。当您将数据项的大小四舍五入到下一个最大大小(2、4、8 或 16 个字节)时,就会出现这些情况。例如,10 字节浮点数应与 16 字节地址对齐,而 64 位整数应与 8 字节地址对齐。因为这是一个 64 位架构,所以指针大小都是 8 字节宽,因此它们也应该在 8 字节边界上对齐。

      建议所有大于 16 字节的结构在 16 字节边界上对齐。一般来说,为了获得最佳性能,请按如下方式对齐数据:

      • 在任意地址对齐 8 位数据
      • 对齐 16 位数据以包含在对齐的四字节字中
      • 对齐 32 位数据,使其基地址为 4 的倍数
      • 对齐 64 位数据,使其基地址为 8 的倍数
      • 对齐 80 位数据,使其基地址为 16 的倍数
      • 对齐 128 位数据,使其基地址为 16 的倍数

      应对齐 64 字节或更大的数据结构或数组,使其基地址为 64 的倍数。按大小递减的顺序对数据进行排序是帮助自然对齐的一种启发式方法。只要不跨越 16 字节边界(和缓存行),自然对齐就不是绝对必要的,尽管它是强制遵守一般对齐建议的简单方法。

      在结构中正确对齐数据可能会导致数据膨胀(由于正确放置字段所需的填充),因此在必要和可能的情况下,重组结构是有用的,以便需要最广泛对齐的字段在结构中首先出现。有关解决此问题的更多信息,请参阅文章“为 IA-64 架构准备代码(代码清理)”。

      【讨论】:

      • 您的引文中提到了 IA-64。那是安腾,而不是 x86-64。但是,该建议确实适用于当前的 x86-64 CPU。这也是 x86-64 System V ABI 选择用于对齐原始 C 类型的方法。 (使用alignof(short) = 2 因为没有办法放松结构内 4 字节块的中间 2 字节。)
      【解决方案3】:

      这完全取决于你使用的 CPU!

      有些架构只处理 32(或 36!)位字,您需要特殊指令来加载单个字符或半个字。

      一些 CPU(特别是 PowerPC 和其他 IBM RISC 芯片)不关心对齐,会从奇数地址加载整数。

      对于大多数现代架构,您需要将整数与字边界对齐,将长整数与双字边界对齐。这简化了加载寄存器的电路并大大加快了速度。

      【讨论】:

        【解决方案4】:

        1.) 有些架构根本没有这个要求,有些架构鼓励对齐(访问非对齐数据项时会降低速度),有些架构可能会严格执行(未对齐会导致处理器异常)。
        当今许多流行的架构都属于速度惩罚类别。 CPU 设计人员必须在灵活性/性能和成本(硅面积/总线周期所需的控制信号数量)之间进行权衡。

        2.) 什么语言,什么架构?请查阅您的编译器手册和/或 CPU 架构文档。

        3.) 这完全取决于架构(某些架构可能根本不允许访问字节大小的项目,或者总线宽度甚至不是 8 位的倍数)。因此,除非您询问特定架构,否则您不会得到任何有用的答案。

        【讨论】:

          【解决方案5】:

          很少有数据“必须”对齐。更重要的是某些类型的数据可能执行得更好,或者某些 cpu 操作需要一定的数据对齐。

          首先,假设您一次读取 4 个字节的数据。假设您的 CPU 有 32 位数据总线。假设您的数据存储在系统内存中的字节 2 中。

          现在,由于您可以一次加载 4 个字节的数据,因此让您的地址寄存器指向单个字节并没有太大意义。通过使您的地址寄存器指向每 4 个字节,您可以操作 4 次数据。所以换句话说,您的 CPU 可能只能读取从字节 0、4、8、12、16 等开始的数据。

          所以这就是问题所在。如果您想要从字节 2 开始的数据并且您正在读取 4 个字节,那么您的一半数据将位于地址位置 0,另一半位于地址位置 1。

          所以基本上你最终会两次访问内存来读取你的一个 4 字节数据元素。某些 CPU 不支持这种操作(或强制您手动加载和组合这两个结果)。

          点击这里了解更多详情:http://en.wikipedia.org/wiki/Data_structure_alignment

          【讨论】:

          • +1 表示链接,但您应该注意,只有某些处理器可以容忍未对齐的数据。英特尔支持 IA32 和 IA64 架构,但不适用于安腾。您的解释仅适用于能够容忍错位数据的处理器,例如 IA32/IA64。 Alpha AXP 会产生故障,我认为 MIPS 也会。一些操作系统会在故障处理程序中处理未对齐的数据,但这样做的性能损失是巨大的。如果操作系统不处理它,那么未对齐的数据对于这些系统根本不起作用。
          【解决方案6】:

          CPU 是面向字的,而不是面向字节的。在简单的 CPU 中,内存通常配置为每个地址选通返回一个 word(32 位、64 位等),其中底部两个(或更多)地址线通常是无关位。

          Intel CPU 可以对许多指令执行非字边界的访问,但是会降低性能,因为 CPU 在内部执行两次内存访问和一次数学运算来加载一个字。如果您正在执行字节读取,则不适用对齐方式。

          某些 CPU(ARM 或 Intel SSE 指令)需要对齐的内存,并且在执行未对齐的访问(或引发异常)时具有未定义的操作。通过不实施更复杂的加载/存储子系统,它们节省了大量的芯片空间。

          对齐取决于 CPU 字大小(16、32、64 位),或者在 SSE 的情况下,取决于 SSE 寄存器大小(128 位)。

          对于您的最后一个问题,如果您一次加载单个数据字节,则大多数 CPU 没有对齐限制(某些 DSP 没有字节级指令,但您可能不会遇到)。

          【讨论】:

          • 嗨剧院,这又是我的疑问!为什么消除了较低的 2 个地址线?因为有了这个设置,我只能从地址 0、4、8 访问数据......等等。那么在这种情况下如何处理字节操作呢?您提到单个数据字节没有对齐限制,当底部的 2 个地址线不关心时,这是如何实现的?感谢您的回复!
          • 我最关心的是为什么地址行不在乎当我的代码中可能存在字节操作时(并且一直在做同样的事情..)?跨度>
          • 英特尔 CPU 不会因高速缓存行中的未对齐访问而降低性能。对齐数据对于避免缓存行拆分很有用,其中一些字节在一行中,一些在另一行中,但所有字节都在同一 64 字节行中,例如从 [0x4000007] 加载 DWORD 或其他东西,它是一个访问缓存。 (在旧 CPU 上,即使地址对齐,SSE movdqu 也很慢,但在 Nehalem 和更高版本上,只有跨越 64 字节边界,尤其是页面边界会受到惩罚。AMD 的 x86 CPU 在 32 字节边界上会产生一些影响,可能是 16 .)
          • 参见Why is integer assignment on a naturally aligned variable atomic on x86?:自然原子的加载/存储就是这种方式,因为 CPU 将它们作为单个操作执行,对于缓存访问,在复制缓存行时不会发生撕裂。另请参阅 Choice between aligned vs. unaligned x86 SIMD instructions 以了解未对齐的 SSE/AVX。对齐你的数据通常是一件好事,但你的推理并不完全正确,它只对现代 x86 的 AVX512 至关重要(每个向量都是一条完整的线)。
          【解决方案7】:

          一般来说,这三个问题的唯一答案是“这取决于您的系统”。更多细节:

          1. 您的内存系统可能无法进行字节寻址。除此之外,您可能会因让处理器访问未对齐的数据而导致性能损失。一些处理器(例如较旧的 ARM 芯片)根本无法做到这一点。

          2. 阅读您的处理器的手册以及为您生成代码的任何 ABI 规范,

          3. 通常当人们提到数据处于某种对齐方式时,它只指第一个字节。因此,如果 ABI 规范说“数据结构 X 必须是 4 字节对齐”,这意味着 X 应该被放置在内存中可被 4 整除的地址处。该声明并未暗示结构 X 的大小或内部布局.

            就您的特定示例而言,如果数据从地址 1004 开始以 4 字节对齐,则下一个字节将位于 1005。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-08-23
            • 1970-01-01
            • 2022-01-10
            • 1970-01-01
            • 1970-01-01
            • 2019-07-12
            相关资源
            最近更新 更多