Этот пост тесно связан с другим, который я опубликовал несколько дней назад .На этот раз я написал простой код, который просто добавляет пару массивов элементов, умножает результат на значения в другом массиве и сохраняет его в четвертом массиве, все переменные с плавающей точкой с двойной точностью набираются.
Я сделал две версии этого кода: одну с инструкциями SSE, используя вызовы, а другую без них, а затем скомпилировал их с уровнем оптимизации gcc и -O0.Я пишу их ниже:
// SSE VERSION
#define N 10000
#define NTIMES 100000
#include <time.h>
#include <stdio.h>
#include <xmmintrin.h>
#include <pmmintrin.h>
double a[N] __attribute__((aligned(16)));
double b[N] __attribute__((aligned(16)));
double c[N] __attribute__((aligned(16)));
double r[N] __attribute__((aligned(16)));
int main(void){
int i, times;
for( times = 0; times < NTIMES; times++ ){
for( i = 0; i <N; i+= 2){
__m128d mm_a = _mm_load_pd( &a[i] );
_mm_prefetch( &a[i+4], _MM_HINT_T0 );
__m128d mm_b = _mm_load_pd( &b[i] );
_mm_prefetch( &b[i+4] , _MM_HINT_T0 );
__m128d mm_c = _mm_load_pd( &c[i] );
_mm_prefetch( &c[i+4] , _MM_HINT_T0 );
__m128d mm_r;
mm_r = _mm_add_pd( mm_a, mm_b );
mm_a = _mm_mul_pd( mm_r , mm_c );
_mm_store_pd( &r[i], mm_a );
}
}
}
//NO SSE VERSION
//same definitions as before
int main(void){
int i, times;
for( times = 0; times < NTIMES; times++ ){
for( i = 0; i < N; i++ ){
r[i] = (a[i]+b[i])*c[i];
}
}
}
При компиляции с помощью -O0, gcc использует регистры XMM / MMX и инструкции SSE, если специально не указаны параметры -mno-sse (и другие).Я проверил код ассемблера, сгенерированный для второго кода, и заметил, что он использует инструкции movsd , addd и mulsd .Так что он использует инструкции SSE, но только те, которые используют самую низкую часть регистров, если я не ошибаюсь.Код сборки, сгенерированный для первого кода C, использовал, как и ожидалось, инструкции addp и mulpd , хотя был сгенерирован довольно большой код сборки.
В любом случае, первый код должен, насколько мне известно, получать большую прибыль от парадигмы SIMD, поскольку на каждой итерации вычисляются два результирующих значения.Тем не менее, второй код выполняет что-то вроде 25 процентов быстрее, чем первый.Я также сделал тест с одинарной точностью и получил аналогичные результаты.В чем причина?