在32位CPU上,“整数”类型比“短”类型更有效吗?

时间:2008-10-02 16:14:36

标签: architecture integer cpu 32-bit cpu-architecture

在32位CPU上,整数是4个字节,短整数是2个字节。如果我正在编写一个使用许多数值的C / C ++应用程序,它总是符合短整数的提供范围,那么使用4字节整数或2字节整数会更有效吗?

我听说它建议4字节整数更有效,因为它适合从内存到CPU的总线带宽。但是,如果我将两个短整数相加,那么CPU是否会将这两个值并行打包(从而跨越总线的4字节带宽)?

8 个答案:

答案 0 :(得分:14)

如果您有大量数字,那么请使用最小的数字。由于您获得了两倍的缓存密度,因此使用16位短路阵列而不是32位整数将更有效。与高速缓存未命中的成本相比,CPU在32位寄存器中处理16位值所需的任何符号扩展的成本几乎可以忽略不计。

如果您只是在与其他数据类型混合使用的类中使用成员变量,那么它就不那么明确,因为填充要求可能会消除16位值的任何节省空间的好处。

答案 1 :(得分:13)

是的,你肯定应该在32位CPU上使用32位整数,否则它可能最终屏蔽掉未使用的位(即,它总是以32位进行数学运算,然后将答案转换为16位)

它不会同时为您执行两次16位操作,但如果您自己编写代码并且您确定它不会溢出,则可以自行完成。

编辑:我应该补充一点,它在某种程度上取决于您对“效率”的定义。虽然它能够更快地执行32位操作,但您当然会使用两倍的内存。

如果这些用于某个内部循环的中间计算,则使用32位。但是,如果你是从磁盘读取它,或者即使你只需要为缓存未命中付费,那么使用16位整数仍然可能更好。与所有优化一样,只有一种方法可以知道:对其进行分析

答案 2 :(得分:7)

如果您使用“很多”整数值,则处理中的瓶颈可能是内存带宽。 16位整数更紧密地包含在数据缓存中,因此可以获得性能。

如果您对大量数据进行数字处理,则应阅读Ulrich Drepper撰写的What Every Programmer Should Know About Memory。专注于第6章,关于最大化数据缓存的效率。

答案 3 :(得分:4)

32位CPU是一种CPU,通常在内部以32位值运行,但这并不意味着在8/16位值上执行相同操作时速度会慢一些。例如,x86仍然可以向后兼容到8086,可以在寄存器的一小部分上运行。这意味着即使寄存器为32位宽,它也只能在该寄存器的前16位或前8位运行,并且根本不会减速。这个概念甚至被x86_64采用,其中寄存器是64位,但它们仍然只能在前32,16或8位上运行。

x86 CPU总是从内存中加载整个缓存行,如果还没有在缓存中,并且缓存行总是大于4个字节(对于32位CPU而不是8或16个字节),因此从内存加载2个字节是与从内存加载4个字节一样快。如果从内存处理许多值,则16位值实际上可能比32位值快得多,因为内存传输较少。如果高速缓存行为8字节,则每个高速缓存行有4个16位值,但只有两个32位值,因此当使用16位整数时,每四个值有一个内存访问,使用32位整数,每两个值就有一个,导致处理大型int数组的传输次数增加一倍。

其他CPU,例如PPC,不能只处理寄存器的一小部分,它们总是处理完整的寄存器。然而,这些CPU通常具有允许它们进行的特殊加载操作,例如,从内存加载一个16位值,将其扩展为32位并将其写入寄存器。稍后他们有一个特殊的存储操作,从寄存器中获取值,只将最后16位存储回内存;这两个操作只需要一个CPU周期,就像32位加载/存储需要一样,所以也没有速度差异。并且由于PPC只能对寄存器执行算术运算(与x86不同,它也可以直接在内存上运行),无论是使用32位整数还是16位整数,都会发生此加载/存储过程。

唯一的缺点是,如果在一个只能在完全寄存器上运行的32位CPU上进行多个操作,那么在下一次操作之前,最后一次操作的32位结果可能必须“减少”到16位执行,否则结果可能不正确。这样的削减只是一个单独的CPU周期(一个简单的AND操作),并且编译器非常善于确定何时真正需要这样的削减并且当它离开时不会对最终结果产生任何影响因此,每次指令后都不会执行这样的削减,只有在真正不可避免的情况下才会执行。有些CPU提供了各种“增强”指令,这些指令不需要这样做,我已经看到了我生活中的大量代码,我曾期望这样的削减,但是看看生成的汇编代码,编译器找到了一种方法。完全避免它。

因此,如果您期望这里有一般规则,我将不得不让您失望。也不能确定16位操作对32位操作同样快,也不能确定32位操作总是会更快。这还取决于你的代码究竟是用这些数字做的,以及它是如何做到的。我已经看到基准测试中某些32位CPU的32位操作比16位操作的相同代码更快,但我也已经看到相反的情况。即使从一个编译器切换到另一个编译器或升级您的编译器版本,也可能已经再次转向一切。我只能说以下内容:无论是谁声称使用短片都比使用int更慢,请提供该声明的示例源代码并命名他用于测试的CPU和编译器,因为我从未经历过类似的内容大约过去10年。在某些情况下,使用int可能会快1-5%,但是低于10%的任何东西都不是“重要”而且问题是,在某些情况下浪费两倍的内存是否值得因为它可能会让你失望2%的表现?我不这么认为。

答案 4 :(得分:3)

这取决于。如果您受CPU限制,32位CPU上的32位操作将比16位快。如果你受内存限制(特别是如果你有太多L2缓存未命中),那么使用你可以挤进的最小数据。

你可以找出你正在使用的探测器,它将测量像Intel's VTune这样的CPU和L2未命中。您将使用相同的负载运行您的应用程序2次,它会将2次运行合并到您应用程序中热点的一个视图中,您可以看到每行代码在该行上花费了多少个周期。如果在昂贵的代码行中,您会看到0个高速缓存未命中,则表示您受CPU限制。如果你看到大量的失误,你就会受到记忆的约束。

答案 5 :(得分:3)

不要听取建议,试试吧。

这可能在很大程度上取决于您正在使用的硬件/编译器。快速测试应该简化这个问题。编写测试的时间可能比编写问题的时间少。

答案 6 :(得分:1)

如果您在大型数据集上运行,最大的问题是内存占用。在这种情况下,一个好的模型是假设CPU速度非常快,并且花时间担心必须将多少数据移入/移出内存。实际上,CPU现在非常快,以至于编码(例如,压缩)数据有时更有效。这样,CPU(可能更多)工作(解码/编码),但内存带宽大大减少。

因此,如果您的数据集很大,那么最好使用16位整数。如果您的列表已排序,您可能会设计一种涉及差分或行程编码的编码方案,这将进一步降低内存带宽。

答案 7 :(得分:0)

当你说32位时,我会假设你的意思是x86。 16位算术运行速度很慢:操作数大小的前缀使解码真的慢。所以不要让你的临时变量为short int或int16_t。

但是,x86可以有效地将16位和8位整数加载到32位或64位寄存器中。 (movzx / movsx:零和符号扩展名)。因此可以随意对数组和结构字段使用short int,但请确保对临时变量使用int或long。

  

但是,如果我将两个短整数相加,那么CPU是否会将这两个值并行打包(从而跨越总线的4字节带宽)?

这是胡说八道。加载/存储指令与L1缓存交互,限制因素是操作数;宽度无关紧要。例如在core2:1负载和每个周期1个存储,无论宽度。 L1缓存具有到L2缓存的128或256位路径。

如果负载是你的瓶颈,那么在加载后用一个班次或面具拆分的一个宽负载会有所帮助。或者使用SIMD并行处理数据,而不是在并行加载后解压缩。