【问题标题】:C++ - the fastest integer type?C++ - 最快的整数类型?
【发布时间】:2012-04-04 16:49:26
【问题描述】:

我正在对算法进行基准测试,没有必要知道细节。主要组件是缓冲区(整数的原始数组)和索引器(整数 - 用于访问缓冲区中的元素)。

缓冲区最快的类型似乎是 unsigned char,以及 short、int、long 的有符号和无符号版本。但是 char/signed char 比较慢。差异:1.07 倍。

对于索引器,有符号和无符号类型之间没有区别。但是 int 和 long 比 char 和 short 快 1.21 倍。

在考虑性能而不是内存消耗时,是否应该默认使用一种类型?

注意:对缓冲区元素和索引器使用的操作是赋值、递增、递减和比较。

【问题讨论】:

  • 你如何衡量这个?它是在一个几乎没有其他处理运行的系统上吗?您是使用计时器来计算它,还是使用 JTAG 连接到开发板并计算 CPU 周期?
  • 是的,了解细节很重要,因为您可能实际上在某个时候测量内存带宽和类型转换。
  • 看看stdint.h。您可能对int_fast32_t 类型感兴趣。 (或您喜欢的任何尺寸)
  • 我正在使用 std::clock() 来测量运行算法所用的时钟。该算法运行的时间足够长,以使使用 std::clock() 获得的结果有效。
  • 你的算法是多线程的吗?

标签: c++ performance


【解决方案1】:

通常最大的优势来自缓存。

如果您的数据值足够小以至于它们适合 8 位,那么您可以在 CPU 缓存中容纳更多的数据,而不是使用整数并浪费 3 个字节/值。如果您正在处理一个数据块,您会在缓存命中方面获得巨大的速度优势。

索引的类型不太重要,只要它适合 CPU 寄存器(即不要尝试在 8 位 CPU 上使用 long long)它就会具有相同的速度

编辑:还值得一提的是,测量速度很棘手。您需要多次运行该算法以允许缓存,您需要查看 CPU 上正在运行的其他内容,甚至还有其他硬件可能正在中断的内容。除非您非常小心,否则 10% 的速度差异可能会被视为噪音。

【讨论】:

  • 对于索引器,unsigned int 是否比 unsigned short 快,因为在 x86 上,数组 [] 运算符需要一个 unsigned int?
  • OP 注意到较大的数据类型更快。这不符合您的论点,即差异是由缓存引起的吗?
  • @Mysticial “缓冲区最快的类型似乎是无符号字符”。 OP 也在谈论 7% 的差异,除非你真的很小心,否则这很难在通用 OS+PC 上测量
  • @NFRCR - 任何体面的编译器都可以很好地处理索引数组,任何重要的事情都在编译时完成。
  • 哦,对了,我忽略了问题的第一部分。我收回我的发言。 :)
【解决方案2】:

这在很大程度上取决于底层架构。通常最快的数据类型是字宽的。根据我使用 IA32 (x86-32) 的经验,比字数据类型更小/更大的数据类型会受到惩罚,有时甚至会为一个数据读取超过一个内存。

一旦在 CPU 寄存器上,通常数据类型长度无关紧要(如果整个数据适合一个寄存器,那就是),但你用它们完成什么操作。当然浮点运算是最昂贵的;最快的是加法、减法(这也是比较)、按位(移位等)和逻辑运算(与、或...)。

【讨论】:

  • 一般使用int作为局部临时变量(除非你需要它们在64位更宽,然后使用size_t或其他)。加载/存储到 char 或 short 几乎是免费的。 (movzx / movsx 加载根本不采用 ALU uop,而是在加载端口中处理。)所以数组应该使用窄类型来最小化缓存消耗。
【解决方案3】:

没有关于哪种类型更快或更慢的承诺。 int 应该代表机器的自然字长,不管这可能意味着什么,所以它可能会更快。或者更慢,取决于其他因素。

【讨论】:

  • 能否请您评论一些可能使 word-wide 类型变慢的因素?
  • @m0skit0:总线速度、缓存,或者如果 CPU 不能天真地处理该类型,可能还有其他因素。
  • 总线速度和缓存应该针对设计良好的架构中的字大小类型进行优化。 CPU 必须擅长该数据类型,因为我说的是“字长”类型。
  • @m0skit0:总线速度和缓存通常针对字长类型的倍数而不是实际字长类型进行优化,即使是 1:1,也使用一半的数据类型字长使它们通过缓存/总线加载速度提高一倍。在我的电脑上,我可以以与单个 int 大致相同的速度加载 ~8 个chars
【解决方案4】:

以下是基本整数类型或扩展整数类型的 typedef。

检查快速模式。 你也可以找到其他类型(char)的快速模组。

库是 :: cstdint

uint_fast8_t :: 我的建议

http://www.cplusplus.com/reference/cstdint/

??你可能需要了解你正在使用的机器的架构!!

【讨论】:

    【解决方案5】:

    正如所说的int 在大多数情况下代表机器字。因此int 将具有与处理器寄存器相同的长度,因此无需执行任何其他操作即可将int 放入寄存器然后放回RAM。

    如果您使用char,它比int 小4 倍(在x86 系统上),也比处理器寄存器小4 倍。因此,在将其放入 RAM 之前,它应该被截断。结果使用了更多的时间。

    此外,具有 32 位寄存器的处理器无法执行 8 位数字的操作。如果将 char 添加到 char 中,则它们都将被注册。所以每个寄存器将有 8 位 char 值和 24 位垃圾。将添加两个 32 位值,然后将结果截断为 8 位。 charshort 同时工作的原因是使用了相同数量的附加操作。而对于int,其他操作未完成。

    我想补充一点,处理器intunsigned int 完全一样,因为它以相同的方式对待它们。对于某些编译器intlong int 也可能相同。

    所以最快的整数类型是长度与机器字相同的类型。如果您使用大小小于机器字的类型,则程序运行速度会变慢。

    【讨论】:

    • 这在大多数现代机器上都不是真的。机器字是 64 位,但int 是 32。英特尔架构有加载和存储字节以及对字节进行操作的指令,因此截断成本为 0。 Intel 架构还支持对字节的直接操作。而“最快的整数类型”将取决于你在做什么;在现代机器上,内存访问和局部性通常起主要作用。
    • movzx / movsx 对整数寄存器的零或符号扩展负载几乎是免费的。在 Intel CPU 上,它们甚至不采用 ALU uop。这一切都在负载单元中完成。而且即使您的寄存器中有高垃圾,that doesn't stop you from doing an add/sub or whatever and then storing the low 8 of the result,也不会受到高垃圾的影响。
    猜你喜欢
    • 2011-04-11
    • 2010-11-27
    • 2020-04-22
    • 2011-07-23
    • 1970-01-01
    • 2011-07-08
    • 2014-08-18
    • 1970-01-01
    • 2013-08-19
    相关资源
    最近更新 更多