【问题标题】:64-bit executable runs slower than 32-bit version64 位可执行文件的运行速度比 32 位版本慢
【发布时间】:2014-02-26 20:03:39
【问题描述】:

我有一个 64 位 Ubuntu 13.04 系统。我很想知道 32 位应用程序如何在 64 位系统上对 64 位应用程序执行,因此我将以下 C 程序编译为 32 位和 64 位可执行文件,并记录它们执行的时间。我使用 gcc 标志为 3 种不同的架构进行编译:

  • -m32:Intel 80386 架构(int、long、指针全部设置为 32 位(ILP32))
  • -m64:AMD 的 x86-64 架构(int 32 bits;long,pointer 64 bits (LP64))
  • -mx32:AMD 的 x86-64 架构(int、long、指针都设置为 32 位(ILP32),但 CPU 处于 long 模式,有 16 个 64b 寄存器,以及 注册呼叫 ABI)
// this program solves the
// project euler problem 16.

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <assert.h>
#include <sys/time.h>

int sumdigit(int a, int b);

int main(void) {
    int a = 2;
    int b = 10000;
    struct timeval start, finish;
    unsigned int i;
    gettimeofday(&start, NULL);
    for(i = 0; i < 1000; i++)
        (void)sumdigit(a, b);
    gettimeofday(&finish, NULL);
    printf("Did %u calls in %.4g seconds\n", 
            i, 
            finish.tv_sec - start.tv_sec + 1E-6 * (finish.tv_usec - start.tv_usec));
    return 0;
}

int sumdigit(int a, int b) {
    // numlen = number of digit in a^b
    // pcount = power of 'a' after ith iteration
    // dcount = number of digit in a^(pcount)

    int numlen = (int) (b * log10(a)) + 1;
    char *arr = calloc(numlen, sizeof *arr);
    int pcount = 0;
    int dcount = 1;
    arr[numlen - 1] = 1;
    int i, sum, carry;

    while(pcount < b) {
        pcount += 1;

        sum = 0; 
        carry = 0;

        for(i = numlen - 1; i >= numlen - dcount; --i) {
            sum = arr[i] * a + carry;
            carry = sum / 10;
            arr[i] = sum % 10;
        }

        while(carry > 0) {
            dcount += 1;
            sum = arr[numlen - dcount] + carry;
            carry = sum / 10;
            arr[numlen - dcount] = sum % 10;
        } 
    }

    int result = 0;
    for(i = numlen - dcount; i < numlen; ++i)
        result += arr[i];

    free(arr);
    return result;
}

我用来获取不同可执行文件的命令:

gcc -std=c99 -Wall -Wextra -Werror -pedantic -pedantic-errors pe16.c -o pe16_x32 -lm -mx32
gcc -std=c99 -Wall -Wextra -Werror -pedantic -pedantic-errors pe16.c -o pe16_32 -lm -m32
gcc -std=c99 -Wall -Wextra -Werror -pedantic -pedantic-errors pe16.c -o pe16_64 -lm

这是我得到的结果:

ajay@ajay:c$ ./pe16_x32
Did 1000 calls in 89.19 seconds

ajay@ajay:c$ ./pe16_32
Did 1000 calls in 88.82 seconds

ajay@ajay:c$ ./pe16_64
Did 1000 calls in 92.05 seconds

为什么 64 位版本的运行速度比 32 位版本慢?我读到,与 32 位架构相比,64 位架构改进了指令集和两倍的通用寄存器,这允许更多优化。我什么时候可以期望在 64 位系统上获得更好的性能?

编辑 我使用-O3 标志打开了优化,现在结果是:

ajay@ajay:c$ ./pe16_x32
Did 1000 calls in 38.07 seconds

ajay@ajay:c$ ./pe16_32
Did 1000 calls in 38.32 seconds

ajay@ajay:c$ ./pe16_64
Did 1000 calls in 38.27 seconds

【问题讨论】:

  • 一些 64 位数据比 32 位数据大,这样可以减少缓存命中率。
  • 您是否尝试过多次运行同一个程序?或者尝试使用不同的优化标志?
  • 只是注意到您没有使用任何优化。这很愚蠢,因为它没有反映性能重要的程序将/应该如何运行。
  • 没有优化的基准代码是完全没有意义的。你想让代码运行得快吗?
  • 我希望此代码在 32 位和 64 位上具有相同的性能。操作数在所有情况下都是相同的大小,并且没有浮点数。

标签: c x86 32bit-64bit x86-64 linux-x32-abi


【解决方案1】:

比较没有优化的代码性能是毫无意义的。如果您关心性能,您将永远只使用优化的代码。

当您启用优化时,您会发现性能差异可以忽略不计。这是可以预料的。您执行的操作都是基于整数的操作,在所有情况下都使用相同大小的数据。由于 32 位和 64 位代码在相同的整数硬件单元上运行,因此您应该期望相同的性能。

您没有使用任何浮点运算,这是由于浮点硬件单元不同(x64 使用 SSE,x86 可能使用 x87)而导致 32 位和 64 位代码之间有时存在差异的一个领域。

总之,结果完全符合预期。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-18
    • 2022-11-12
    • 2023-03-22
    • 1970-01-01
    • 2017-12-01
    • 1970-01-01
    • 2015-01-18
    • 1970-01-01
    相关资源
    最近更新 更多