У меня 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
Некоторые 64-разрядные данные больше, чем 32-разрядные данные, и это может уменьшить количество попаданий в кэш. – Barmar
Вы пытались запустить одну и ту же программу несколько раз друг за другом? Или пытались с разными флагами оптимизации? –
x32 <-> 32 различаются только на 0,5% и x32 <-> 63 отличаются только на 3%. Я склонен записывать это под шум. Можете ли вы надежно воспроизвести эти различия? – delnan