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

时间:2020-03-06 15:02:09  来源:igfitidea点击:

在32位CPU上,整数是4个字节,短整数是2个字节。如果我正在编写使用许多数值的C / C ++应用程序,这些数值将始终在所提供的短整数范围内,那么使用4字节整数或者2字节整数是否更有效?

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

解决方案

是的,我们绝对应该在32位CPU上使用32位整数,否则可能会掩盖未使用的位(即它将始终以32位进行数学运算,然后将答案转换为16位)

它不会一次为我们执行两个16位操作,但是如果我们自己编写代码并且确定不会溢出,则可以自己执行。

编辑:我要补充一点,这还取决于我们对"效率"的定义。尽管它能够更快地执行32位操作,但是我们当然会使用两倍的内存。

如果将这些用于内部循环某处的中间计算,请使用32位。但是,如果我们正在从磁盘读取此数据,或者即使我们只需要为高速缓存未命中付出代价,则使用16位整数仍然可能更好。与所有优化一样,只有一种知道的方法:对其进行概要分析。

如果我们有大量的数字,请选择最小的尺寸。使用16位short数组比使用32位int数组更有效,因为我们可以获得两倍的缓存密度。与高速缓存未命中的成本相比,CPU要使用32位寄存器中的16位值进行符号扩展的成本几乎可以忽略不计。

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

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

我们可以找到正在使用的探查器,该探查器可以测量CPU和L2未命中率,例如Intel的VTune。我们将在相同的负载下运行应用程序2次,并且它将2次运行合并到应用程序中热点的一个视图中,我们可以看到每一行代码在该行上花费了多少个周期。如果在昂贵的代码行中看到0个高速缓存未命中,则说明我们受CPU限制。如果看到大量未命中,则说明记忆力有限。

如果要处理大型数据集,则最大的顾虑是内存占用量。在这种情况下,一个好的模型是假设CPU无限快,并花时间担心必须将多少数据移入/移出内存。实际上,CPU现在是如此之快,以至于有时对数据进行编码(例如压缩)会更加有效。这样,CPU会(可能要多做)更多的工作(解码/编码),但是显着减少了内存带宽。

因此,如果数据集很大,则最好使用16位整数。如果对列表进行了排序,则可以设计一种涉及差分或者游程编码的编码方案,这将进一步减少内存带宽。

如果我们使用"许多"整数值,则处理中的瓶颈很可能是内存带宽。 16位整数会更紧密地打包到数据高速缓存中,因此将是性能上的胜利。

如果我们要处理大量数据,请阅读Ulrich Drepper的《每个程序员应该了解的内存知识》。专注于第6章,有关最大程度地提高数据缓存的效率。

当我们说32位时,我假设意思是x86. 16位算术相当慢:操作数大小的前缀使解码确实很慢。因此,请勿使临时变量简短int或者int16_t。

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

However, if I am adding together two short integers, would the CPU package both values in a single pass in parallel (thus spanning the 4 byte bandwidth of the bus)?

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

如果负载是瓶颈,则在加载后通过移位或者遮罩拆分的一个宽负载可以提供帮助。或者使用SIMD并行处理数据,而无需在并行加载后解压缩。

不要听建议,尝试一下。

这可能在很大程度上取决于我们使用的硬件/编译器。快速测试应该使这个问题的工作简短。与在此处编写问题相比,编写测试的时间可能更少。