为什么增加longlong比增加int慢得多?

我最近很想知道 C++ 可以在一秒钟内大致处理多少整数增量。为了测试这一点,我编写了一个简短的驱动程序,如下所示:

#include <iostream>

using namespace std;

int main()
{
    int num = 0;
    while(++num) {
        if(num%100000000 == 0) { // prints num every 100 million iterations
            cout << num << endl;
        }
    }

    return 0;
}

当我在 g++ 7.5.0 下用优化 -O3 编译这段代码时,程序设法每秒增加大约 800,000,000 次。

但是当我将 a 的类型切换int到 a 时long long,我发现性能严重下降,每秒大约 100,000,000 次。

有人可以解释为什么会出现这种差异吗?

回答

带符号的除法是通过IDIV指令完成的。根据Agner Fog 的指令表,在 Haswell 架构上,IDIV32 位寄存器的倒数吞吐量为 8-11,而 64 位寄存器的倒数吞吐量为 24-81。也就是说,使用 64 位寄存器进行 64 位整数除法所需的时间大约比使用 32 位寄存器所需的时间长 2 到 10 倍。这些数字因架构而异,甚至对于 Haswell 来说也有很​​大的范围,但 8 倍的性能损失似乎是合理的。这不是增量(INC具有固定且非常快的速度;显然每个时钟周期可以分派四次),这是您的测试,以限制您正在执行的% 100000000与更大操作数大小一起使用的输出量。

也许尝试将其替换为基于 2 的大幂而不是 10 的幂的掩码打印(AND非常便宜且与寄存器大小无关),例如:

if((num & ((1 << 27) - 1)) == 0)

如果您真的喜欢使用 10 的幂,您可以随时升级到 IceLake;看起来差异只是 6 和 10 的倒数吞吐量,因此性能损失将小于 2 倍。


以上是为什么增加longlong比增加int慢得多?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>