4

我用 C++ 编写了这个小程序来检查 CPU 负载情况。

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <time.h>
int main()
{

    double x = 1;
    int t1 = GetTickCount();
    srand(10000);

    for (unsigned long i = 0; i < 10000000; i++)
    {
        int r = rand();
        double l = sqrt((double)r);
        x *= log(l/3) * pow(x, r);
    }

    int t2 = GetTickCount();
    printf("Time: %d\r\n", t2-t1);
    getchar();
}

我在 win7 x64 上为 x86 和 x64 编译了它。
出于某种原因,当我运行 x64 版本时,它在大约 3 秒内完成运行,
但是当我尝试使用 x86 版本时,它花了 48 (!!!) 秒。
我尝试了很多次,总是得到类似的结果。
什么可能导致这种差异?

4

4 回答 4

14

查看带有/Ox(最大优化)的汇编器输出,x86 和 x64 构建之间的速度差异是显而易见的:

; cl /Ox /Fa tick.cpp
; x86 Line 17: x *= log(l/3) * pow(x, r)
fld     QWORD PTR _x$[esp+32]
mov     eax, esi
test    esi, esi
; ...

我们看到 x87 指令正在用于此计算。将此与 x64 构建进行比较:

; cl /Ox /Fa tick.cpp
; x64 Line 17: x *= log(l/3) * pow(x, r)
movapd  xmm1, xmm8
mov     ecx, ebx
movapd  xmm5, xmm0
test    ebx, ebx
; ...

现在我们看到使用了 SSE 指令。

您可以通过/arch:SSE2尝试和按摩Visual Studio 2010 来生成类似的指令,但看起来 64 位编译器只是为您手头的任务生成更好更快的汇编。

最后,如果您放宽浮点模型,x86 和 x64 的性能几乎相同。

计时,不科学的 3 最佳:

  • x86, /Ox: 22704 滴答声
  • x64, /Ox: 822 滴答声
  • x86, /Ox /arch:SSE2: 3432 滴答声
  • x64, /Ox /favor:INTEL64: 1014 滴答声
  • x86, /Ox /arch:SSE2 /fp:fast: 834 滴答
于 2012-04-25T14:52:04.133 回答
5

原因确实与SSE有关。/arch:SSE2VS 中的 64 位发行版默认生成 SSE2 指令,但您必须使用switch显式启用它以进行 32 位构建。当您这样做时,您将获得 32 位和 64 位构建的可比运行时间。

于 2012-04-25T14:57:35.823 回答
3

这里的许多可能性与 x86 与 x64 几乎没有关系。一种明显的可能性是大多数(全部?)编译器使用 SSE 进行浮点运算,其中大多数通常在 x86 模式下使用 8087 样式的指令。由于您的代码在浮点上很重,这可能会产生重大影响。

另一种可能性是,在为 x64 编写或重写的过程中,他们注意到/修复了代码生成器中的一些问题,这些问题至少在某些情况下可以生成更好的代码。

虽然它看起来在这里并不适用,但一些代码也从增加的大小和/或 64 位模式下可用的寄存器数量中受益匪浅。

于 2012-04-25T14:43:12.950 回答
1

Part of it is definitely the SSE, but there's a huge reason why x64 uses SSE mode: all AMD64 CPUs are required to have SSE2. Another part could also be the increased register count

于 2012-06-09T16:57:47.103 回答