Приступая к написанию тестовой программы для этой статьи я внутренне ожидал, что CPU Intel положит на обе лопатки AMD, так же как и одноименный компилятор без боя победит Visual Studio. Но не все так просто, может быть, на это повлиял выбор программного теста?
Для теста я использовал целочисленное умножение двух 128-ми битных чисел с получением 256-ти битного результата. Тест повторялся 1 млрд раз и занял всего от 12 до 85 секунд. Использовались процессоры AMD FX-8150 3.60GHz и Intel Core i5 2500 3.30GHz. Никакой мультипоточности, никакого разгона.
Использовались компиляторы Intel Parallel Studio XE Version 12.0.0.104 Build 20101006 его более новая реинкарнация 12.1.5.344 Build 20120612, Visual Studio 2010 SP1 и самый современный Visual Studio 2012 (с интерфейсом Metro и CAPSLOCK меню), он же С++ 11.0 Release Candidate. Про опцию -O2 не забываем, она включена у Visual Studio. А для Intel это необязательно, он оптимизирует с -O2 по умолчанию, для Intel включена опция -O3.
Приведу сам тест. Согласен, что для 64-х битового кода нужно было бы сделать BN_WORD равным __int64, BN_DWORD тогда разделить на low и high части, а для умножения этого хозяйства задействовать intrinsic под названием _mul128, который поддерживается данными компиляторами. Все это есть в планах и предполагается сделать позднее. Целью данной статьи является сравнение оптимизирующих компиляторов, но не сравнение скорости 32-х и 64-х битового умножения, а также развенчивание одного мифа.
Полученные результаты приведены в таблице:
На 64-битном коде имеем примерно одинаковый результат для всех трех компиляторов.
На 32-х битах существенно выигрывает Intel, за ним плетется VS2010, а новейший VS2012 демонстрирует уверенный рост, хотя до Intel ему далеко.
Интересно также сравнить скорость работы на AMD и Core i5. При схожей цене в 7000 руб процессоры показывают схожую производительность в 32-битных приложениях на компиляторе Intel. Хотя ожидалось, что в однопоточном тесте всегда будет преимущество Core i5. В планах есть написание мультипоточного теста, чтобы задействовать всю мощь 8-ми ядер AMD. И тогда уже он, скорее всего, выиграет, так как у него 8 целочисленных арифметических ядер (но 4 ядра с плавающей точкой) против 4-х ядер у Core i5, поддержки multi-threading у (моего) Core i5 нет.
Еще один важный вывод напрашивается сам собой — производители компиляторов все силы бросили на создание оптимизирующего 64-битного компилятора, при этом добились похожих результатов. Производители процессоров также все силы бросили на 64-битную платформу, при этом Intel существенно выигрывает у AMD.
Еще один интересный факт — развенчан миф, что компилятор Intel якобы создает код, который хорошо работает только на Intel, и показывает плачевную производительность на AMD (медленнее в 2 и более раз). Легко увидеть, что компилятор Intel на 32-битном коде дает примерно такой же результат при переходе с AMD на CPU Intel, а вот компилятор VS дает прирост, почему на Core i5 происходит существенное ускорение, если использовать код от VS, выяснить пока не удалось. (Действительно, почему?)
UPD1. В первую редакцию этой статьи закралась ошибка, связанная с тем, что из-за хитрой оптимизации VS2010 не производил умножения и код получался в 5,5 раз быстрее. Сейчас исходник исправлен (введен указатель mul на ф-ию Mul, причем указатель пишется/читается из файла, чтобы обмануть компилятор), результаты обновлены. И еще _WORD исправлен на BN_WORD для получения полной ясности, судя по первому комментарию.
Для теста я использовал целочисленное умножение двух 128-ми битных чисел с получением 256-ти битного результата. Тест повторялся 1 млрд раз и занял всего от 12 до 85 секунд. Использовались процессоры AMD FX-8150 3.60GHz и Intel Core i5 2500 3.30GHz. Никакой мультипоточности, никакого разгона.
Использовались компиляторы Intel Parallel Studio XE Version 12.0.0.104 Build 20101006 его более новая реинкарнация 12.1.5.344 Build 20120612, Visual Studio 2010 SP1 и самый современный Visual Studio 2012 (с интерфейсом Metro и CAPSLOCK меню), он же С++ 11.0 Release Candidate. Про опцию -O2 не забываем, она включена у Visual Studio. А для Intel это необязательно, он оптимизирует с -O2 по умолчанию, для Intel включена опция -O3.
Приведу сам тест. Согласен, что для 64-х битового кода нужно было бы сделать BN_WORD равным __int64, BN_DWORD тогда разделить на low и high части, а для умножения этого хозяйства задействовать intrinsic под названием _mul128, который поддерживается данными компиляторами. Все это есть в планах и предполагается сделать позднее. Целью данной статьи является сравнение оптимизирующих компиляторов, но не сравнение скорости 32-х и 64-х битового умножения, а также развенчивание одного мифа.
#include <stdio.h>
#include <windows.h>
#define QUANTITY 4
typedef unsigned int BN_WORD;
typedef unsigned __int64 BN_DWORD;
void Mul(BN_WORD *C, BN_WORD *A, BN_WORD *B )
{
BN_WORD Carry = 0;
BN_WORD h = *(B++);
int i, j;
union {
BN_DWORD sd;
BN_WORD sw[2];
} s;
for( i = QUANTITY; i > 0; --i)
{
s.sd = (BN_DWORD) *(A++) * h + Carry;
*C++ = s.sw[0];
Carry = s.sw[1];
}
*C = Carry;
for ( j = QUANTITY-1; j > 0; --j )
{
A -= QUANTITY;
h = *(B++);
C -= QUANTITY-1;
Carry = 0;
for( i = QUANTITY; i > 0; --i )
{
s.sd = (BN_DWORD) *(A++) * h + *C + Carry;
*C++ = s.sw[0];
Carry = s.sw[1];
}
*C = Carry;
}
}
typedef void (*my_proc)(BN_WORD*, BN_WORD*, BN_WORD*);
void put_addr(void)
{
FILE *f=fopen("tmp.$$$", "wb");
my_proc proc = Mul;
fwrite(&proc, 1, sizeof(proc), f);
fclose(f);
}
my_proc get_addr(void)
{
FILE *f=fopen("tmp.$$$", "rb");
my_proc proc = NULL;
fread(&proc, 1, sizeof(proc), f);
fclose(f);
return proc;
}
int main(void)
{
int i,j;
LARGE_INTEGER lFrequency, lStart, lEnd;
double dfTime1;
BN_WORD A[QUANTITY], B[QUANTITY], C[QUANTITY*2];
BN_WORD RES[QUANTITY*2]={0xd7a44a41, 0xf6e4895c, 0x1624c878, 0x35650795,
0xa55cb22f, 0x861c7313, 0x66dc33f7, 0x479bf4db };
//это ухищрение, чтобы избежать inline вставки кода функции Mul в тело main
void (*mul)( BN_WORD *C, BN_WORD *A, BN_WORD *B );
put_addr();
mul = get_addr();
for( i=0; i<QUANTITY; ++i)
{
A[i] = B[i] = 0x87654321;
}
QueryPerformanceFrequency(&lFrequency);
QueryPerformanceCounter(&lStart);
for( i=0; i<1000; ++i)
{
for( j=0; j<1000000; ++j)
{
mul(C, A, B);
}
if (memcmp(RES, C, sizeof(RES))!=0)
{
printf("Something wrong!\n");
}
}
QueryPerformanceCounter(&lEnd);
dfTime1 = (double)(lEnd.QuadPart - lStart.QuadPart) / (double)lFrequency.QuadPart;
printf("Time = %g sec\n", dfTime1);
}
Полученные результаты приведены в таблице:
AMD FX-8150 3.60GHz 64 бит | AMD FX-8150 3.60GHz 32 бит | Core i5-2500 3.30GHz 64 бит | Core i5-2500 3.30GHz 32 бит | |
---|---|---|---|---|
Intel Parallel Studio XE 12.0.0.104 Build 20101006 | 22.6235 sec | 25.913 sec | 13.0921 sec | 23.1986 sec |
Intel Parallel Studio XE 12.1.5.344 Build 20120612 | 22.2398 sec | 26.0347 sec | 12.9242 sec | 23.1603 sec |
Visual Studio 2010 C++ 10.0 SP1 | 22.5853 sec | 84.1714 sec | 12.4991 sec | 53.633 sec |
Visual Studio 2012 C++ 11.0 Release Candidate | 22.2952 sec | 72.8279 sec | 12.6212 sec | 47.1136 sec |
На 64-битном коде имеем примерно одинаковый результат для всех трех компиляторов.
На 32-х битах существенно выигрывает Intel, за ним плетется VS2010, а новейший VS2012 демонстрирует уверенный рост, хотя до Intel ему далеко.
Интересно также сравнить скорость работы на AMD и Core i5. При схожей цене в 7000 руб процессоры показывают схожую производительность в 32-битных приложениях на компиляторе Intel. Хотя ожидалось, что в однопоточном тесте всегда будет преимущество Core i5. В планах есть написание мультипоточного теста, чтобы задействовать всю мощь 8-ми ядер AMD. И тогда уже он, скорее всего, выиграет, так как у него 8 целочисленных арифметических ядер (но 4 ядра с плавающей точкой) против 4-х ядер у Core i5, поддержки multi-threading у (моего) Core i5 нет.
Еще один важный вывод напрашивается сам собой — производители компиляторов все силы бросили на создание оптимизирующего 64-битного компилятора, при этом добились похожих результатов. Производители процессоров также все силы бросили на 64-битную платформу, при этом Intel существенно выигрывает у AMD.
Еще один интересный факт — развенчан миф, что компилятор Intel якобы создает код, который хорошо работает только на Intel, и показывает плачевную производительность на AMD (медленнее в 2 и более раз). Легко увидеть, что компилятор Intel на 32-битном коде дает примерно такой же результат при переходе с AMD на CPU Intel, а вот компилятор VS дает прирост, почему на Core i5 происходит существенное ускорение, если использовать код от VS, выяснить пока не удалось. (Действительно, почему?)
UPD1. В первую редакцию этой статьи закралась ошибка, связанная с тем, что из-за хитрой оптимизации VS2010 не производил умножения и код получался в 5,5 раз быстрее. Сейчас исходник исправлен (введен указатель mul на ф-ию Mul, причем указатель пишется/читается из файла, чтобы обмануть компилятор), результаты обновлены. И еще _WORD исправлен на BN_WORD для получения полной ясности, судя по первому комментарию.