2014-02-03 1 views
1

У меня 64-разрядная система Ubuntu 13.04. Мне было любопытно посмотреть, как 32-разрядные приложения работают с 64-разрядными приложениями в 64-разрядной системе, поэтому я скомпилировал следующую программу на C как 32-битный и 64-разрядный исполняемый файл и записал время, которое они потребовали для выполнения. Я использовал GCC флагов компиляции для 3 различных архитектур:64-разрядный исполняемый файл работает медленнее, чем 32-разрядная версия

  • -m32: Intel 80386 архитектуры (INT, длинный, указатель весь набор 32 бит (ILP32))
  • -m64: x86-64 архитектуры AMD, (межд 32 бит, длинный указатель 64 бит (LP64))
  • -mx32 Архитектура AMD x86-64 (int, long, указатель все установлен на 32 бита (ILP32), но CPU в длинном режиме с шестнадцатью 64-битными регистрами и регистром звонок 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 

Вот результаты, которые я получил:

[email protected]:c$ ./pe16_x32 
Did 1000 calls in 89.19 seconds 

[email protected]:c$ ./pe16_32 
Did 1000 calls in 88.82 seconds 

[email protected]:c$ ./pe16_64 
Did 1000 calls in 92.05 seconds 

Почему 64-разрядная версия работает медленнее, чем 32- бит один? Я читал, что 64-битная архитектура имеет улучшенный набор инструкций и еще два регистра общего назначения по сравнению с 32-разрядной архитектурой, что позволяет увеличить оптимизацию. Когда можно ожидать повышения производительности на 64-битной системе?

Редактировать Я включил оптимизации с использованием -O3 флаг и теперь результаты:

[email protected]:c$ ./pe16_x32 
Did 1000 calls in 38.07 seconds 

[email protected]:c$ ./pe16_32 
Did 1000 calls in 38.32 seconds 

[email protected]:c$ ./pe16_64 
Did 1000 calls in 38.27 seconds 
+0

Некоторые 64-разрядные данные больше, чем 32-разрядные данные, и это может уменьшить количество попаданий в кэш. – Barmar

+0

Вы пытались запустить одну и ту же программу несколько раз друг за другом? Или пытались с разными флагами оптимизации? –

+0

x32 <-> 32 различаются только на 0,5% и x32 <-> 63 отличаются только на 3%. Я склонен записывать это под шум. Можете ли вы надежно воспроизвести эти различия? – delnan

ответ

1

Сравнение производительности кода без оптимизаций довольно бессмысленно. Если вы заботитесь о производительности, вы будете использовать только оптимизированный код.

И когда вы включаете оптимизацию, вы обнаружите, что различия в производительности незначительны. Этого следует ожидать. Операции, которые вы выполняете, представляют собой операции с целыми числами, используя данные одинакового размера во всех случаях. Поскольку 32-битный и 64-разрядный код работают на одних и тех же целых аппаратных устройствах, вы должны ожидать такую ​​же производительность.

Вы не используете никаких операций с плавающей запятой, которая является одной областью, где иногда существуют различия между 32 и 64-битным кодом из-за разных аппаратных единиц с плавающей точкой (x64 использует SSE, x86 может использовать x87).

Иными словами, результаты в точности соответствуют ожидаемым.