2017-02-19 52 views
2

Я реализовал скалярное ядро ​​с добавлением матрицы.В чем преимущества использования vaddss вместо addss в добавлении скалярной матрицы?

#include <stdio.h> 
#include <time.h> 
//#include <x86intrin.h> 

//loops and iterations: 
#define N 128 
#define M N 
#define NUM_LOOP 1000000 


float __attribute__((aligned(32))) A[N][M], 
     __attribute__((aligned(32))) B[N][M], 
     __attribute__((aligned(32))) C[N][M]; 

int main() 
{ 
int w=0, i, j; 
struct timespec tStart, tEnd;//used to record the processiing time 
double tTotal , tBest=10000;//minimum of toltal time will asign to the best time 
do{ 
    clock_gettime(CLOCK_MONOTONIC,&tStart); 

    for(i=0;i<N;i++){ 
     for(j=0;j<M;j++){ 
      C[i][j]= A[i][j] + B[i][j]; 
     } 
    } 

    clock_gettime(CLOCK_MONOTONIC,&tEnd); 
    tTotal = (tEnd.tv_sec - tStart.tv_sec); 
    tTotal += (tEnd.tv_nsec - tStart.tv_nsec)/1000000000.0; 
    if(tTotal<tBest) 
     tBest=tTotal; 
    } while(w++ < NUM_LOOP); 

printf(" The best time: %lf sec in %d repetition for %dX%d matrix\n",tBest,w, N, M); 
return 0; 
} 

В этом случае, я составил программу с другим флагом компилятора и выходом сборки внутреннего цикла выглядит следующим образом:

: Лучшее время: 0,000024 сек в 406490 повторении для 128x128 матрица

movss xmm1, DWORD PTR A[rcx+rax] 
addss xmm1, DWORD PTR B[rcx+rax] 
movss DWORD PTR C[rcx+rax], xmm1 

gcc -O2 -mavx: лучшее время: 0,000009 сек в 1000001 повторения для 128x128 матрицы

vmovss xmm1, DWORD PTR A[rcx+rax] 
vaddss xmm1, xmm1, DWORD PTR B[rcx+rax] 
vmovss DWORD PTR C[rcx+rax], xmm1 

AVX версия gcc -O2 -mavx:

__m256 vec256; 
for(i=0;i<N;i++){ 
    for(j=0;j<M;j+=8){ 
     vec256 = _mm256_add_ps(_mm256_load_ps(&A[i+1][j]) , _mm256_load_ps(&B[i+1][j])); 
     _mm256_store_ps(&C[i+1][j], vec256); 
      } 
     } 

SSE версия gcc -O2 -sse4.2 ::

__m128 vec128; 
for(i=0;i<N;i++){ 
    for(j=0;j<M;j+=4){ 
    vec128= _mm_add_ps(_mm_load_ps(&A[i][j]) , _mm_load_ps(&B[i][j])); 
    _mm_store_ps(&C[i][j], vec128); 
      } 
     } 

В скалярной программе убыстрение -mavx над msse4.2 является 2.7x. Я знаю, что avx улучшил ISA эффективно, и, возможно, из-за этих улучшений. Но когда я реализовал программу в intrinsics для AVX и SSE, ускорение является фактором 3x. Вопрос в том, что сканер AVX в 2,7 раза быстрее, чем SSE, когда я векторизовал его, скорость выше 3x (размер матрицы составляет 128x128 для этого вопроса). Имеет ли смысл при использовании AVX и SSE в режиме скалярного режима, ускорение 2.7x. но векторный метод должен быть лучше, потому что я обрабатываю восемь элементов в AVX по сравнению с четырьмя элементами в SSE. Все программы имеют менее 4,5% промахов в кэше, как сообщалось perf stat.

использованием gcc -O2, linux mint, skylake

UPDATE: Вкратце, Скалярное-AVX является 2.7x быстрее, чем Скалярное-SSE, но AVX-256 только 3 раза быстрее, чем SSE-128, пока она векторизации. Я думаю, это может быть из-за конвейерной обработки. в скалярном я имею 3 vec-ALU, который может не использоваться в векторизованном режиме. Я мог бы сравнивать яблоки с апельсинами вместо яблок с яблоками, и это может означать, что я не могу понять причину.

+0

Чтобы ответить на вопрос заголовка (я не могу полностью проанализировать последнюю часть тела): [GCC делает то, что вы сказали, только при компиляции на -O1] (https://godbolt.org/g/T4xnCU). Когда системы таргетинга с AVX [всегда рекомендуют использовать версии VEX устаревших инструкций SSE] (https://software.intel.com/sites/default/files/m/d/4/1/d/8 /11MC12_Avoiding_2BAVX-SSE_2BTransition_2BPenalties_2Brh_2Bfinal.pdf). –

+0

@MargaretBloom, no 'gcc -O2' Я добавил к вопросу. таргетинг в порядке, но я сравниваю чистые 'AVX' и' SSE', а не AVX-256 с AVX-128. – Martin

+0

@MargaretBloom, векторизация разрешена параметром '-ftree-loop-vectorize', который активируется' -O3', но не '-O2'. Это будет даже векторизовано с помощью '-O1 -ftree-loop-vectorize' –

ответ

3

Проблема, которую вы наблюдаете, объясняется here. В системах Skylake, если верхняя половина регистра AVX загрязнена, тогда существует ложная зависимость для операций с бездействующим кодированием SSE в верхней половине регистра AVX. В вашем случае кажется, что в вашей версии glibc 2.23 есть ошибка. На моей системе Skylake с Ubuntu 16.10 и glibc 2.24 у меня нет проблемы. Вы можете использовать

__asm__ __volatile__ ("vzeroupper" : : :); 

очистить верхнюю половину регистра AVX. Я не думаю, что вы можете использовать встроенную функцию, такую ​​как _mm256_zeroupper, чтобы исправить это, потому что GCC скажет, что это SSE-код и не распознает внутреннюю. Варианты -mvzeroupper не будут работать, потому что GCC снова думает, что это SSE-код и не будет выдавать команду vzeroupper.

BTW, it's Microsoft's fault that the hardware has this problem.


Update:

Other people are apparently encountering this problem on Skylake. Это наблюдалось после printf, memset и clock_gettime.

Если вы хотите сравнить 128-битные операции с 256-битными операциями, можете рассмотреть возможность использования -mprefer-avx128 -mavx (что особенно полезно для AMD). Но тогда вы будете сравнивать AVX256 и AVX128, а не AVX256 против SSE. AVX128 и SSE используют 128-битные операции, но их реализация различна. Если вы ориентируетесь, вы должны указать, какой из них вы использовали.

+0

Согласно ABI, каждая функция, использующая AVX, должна выполнить 'vzeroupper', когда она будет выполнена. Кажется, что ошибка где-то в другом месте. – fuz

+0

@fuz, вы прочитали первую ссылку, на которую я указал? Проблема устраняется при очистке верхней части регистра AVX. Я не могу воспроизвести проблему в своей системе, поэтому я не могу ее протестировать. OP сказал, что проблема не исчезла с '__asm__ __volatile__ (« vzeroupper »:::);« сразу после «main», что я и ожидал, но он уходит после того, когда он используется после 'clock_gettime'. В своем ответе я не упомянул об этом, потому что единственное, о чем я довольно уверен, состоит в том, что проблема заключается в том, что верхняя половина грязная. Можем ли мы договориться об этом? –

+0

Прочитайте последние несколько строк сообщения, которое вы связали, в нем говорится в основном то же самое, что я сказал: кто-то, должно быть, использовал инструкции AVX без выполнения «vzeroupper» впоследствии. – fuz

 Смежные вопросы

  • Нет связанных вопросов^_^