2013-08-30 5 views
0

J'utilise vs2012 et je veux tester l'efficacité de SSE et AVX. Le code pour SSE et AVX est presque le même, sauf que le SSE utilise _m128 et AVX utilise _m256. Je m'attendais à ce que le code AVX soit deux fois plus rapide que le code SSE, Mais le résultat du test montre que leur vitesse est presque la même.Pourquoi le SSE et AVX ont-ils la même efficacité?

J'essaie de sélectionner le/arch: AVX ou/arch: SSE ou/NON SET et commentez le code SSE ou commentaire le code AVX, tout ce que je teste, le temps utilisé pour le code SSE est d'environ 2138ms et Le code AVX est d'environ 2106ms. L'extérieur de la boucle est juste utilisé pour augmenter le temps de cycle,

#include "testfun.h" 
#include <iostream> 
#include <time.h> 
#include <malloc.h> 
#include "immintrin.h" 
using namespace std; 
#define dataLen 800000 

void testfun() 
{ 
float *buf1 = reinterpret_cast<float*>(_aligned_malloc(sizeof(float)*dataLen, 32)); 
float *buf2 = reinterpret_cast<float*>(_aligned_malloc(sizeof(float)*dataLen, 32)); 
for(int i=0; i<dataLen; i++) 
{ 
    buf1[i] = 1; 
    buf2[i] = 1; 
} 
double timePassed; 
int t = clock(); 
float sum = 0; 
//=========================SSE CODE===================================== 
__m128 *p1 = (__m128 *)buf1; 
__m128 *p2 = (__m128 *)buf2; 
__m128 _result = _mm_set_ps1(0.0f); 

for(int j=0;j<10000; j++) 
{ 
    p1 = (__m128 *)buf1; 
    p2 = (__m128 *)buf2;   
    _result = _mm_sub_ps(_mm_set_ps(j,0,0,0) ,_result); 

    for(int i=0; i<dataLen/4; i++) 
    { 
     _result = _mm_add_ps(_mm_mul_ps(*p1, *p2), _result); 
     p1++; 
     p2++; 
    } 
} 

sum = _result.m128_f32[0]+_result.m128_f32[1]+_result.m128_f32[2]+_result.m128_f32[3]; 
timePassed = clock() - t; 
std::cout<<std::fixed<<"SSE calculate result : "<<sum<<std::endl; 
std::cout<<"SSE time used: "<<timePassed<<"ms"<<std::endl; 

//=========================AVX CODE===================================== 
t = clock(); 
__m256 *pp1 ; 
__m256 *pp2 ; 
__m256 _rresult = _mm256_setzero_ps(); 
sum = 0; 

for(int j=0;j<10000; j++) 
{ 
    pp1 = (__m256*) buf1; 
    pp2 = (__m256*) buf2; 
    _rresult = _mm256_sub_ps(_mm256_set_ps(j,0,0,0,0,0,0,0), _rresult); 

    for(int i=0; i<dataLen/8; i++) 
    {  
     _rresult = _mm256_add_ps(_mm256_mul_ps(*pp1, *pp2), _rresult); 
     pp1++; 
     pp2++; 
    } 
} 

sum = _rresult.m256_f32[0]+_rresult.m256_f32[1]+_rresult.m256_f32[2]+_rresult.m256_f32[3]+_rresult.m256_f32[4]+_rresult.m256_f32[5]+_rresult.m256_f32[6]+_rresult.m256_f32[7]; 
timePassed = clock() - t; 
std::cout<<std::fixed<<"AVX calculate result : "<<sum<<std::endl; 
std::cout<<"AVX time used: "<<timePassed<<"ms"<<std::endl; 

_aligned_free(buf1); 
_aligned_free(buf2); 

}

Répondre

5

Vous êtes très probablement juste une bande passante limitée, puisque vous avez seulement deux instructions arithmétiques dans votre boucle et vous avez deux charges . Si vous réduisez la taille de votre ensemble de données afin qu'il corresponde au cache, vous devriez voir une différence de performance (puisque vous aurez une bande passante beaucoup plus importante et une latence réduite pour les charges du cache).

(En outre, vos numéros de synchronisation semblent très élevés - assurez-vous que vous utilisez la version release, à savoir que vous avez l'optimisation a permis, sinon vos résultats seront trompeurs.)

+1

+1 CPUs aussi comme un bulldozer ont deux sse unifiable en un avx par module donc il peut ne pas importer sans opérations de mémoire aussi. Je n'ai pas essayé. –

+0

Vous avez raison, si je mets le "dataLen" à 4000, et supprime les opérations _mm_sub_ps et _mm_set_ps au-dessus de la boucle interne pour, alors l'AVX est environ deux fois plus rapide que SSE. (en mode release, et paramétré sur "Extensions vectorielles avancées (/ arch: AVX)) Je ne comprends toujours pas pourquoi les données ont une si grande influence sur le résultat Dans la situation actuelle, le tableau doit être calculé est-ce que vous voulez dire que si l'ensemble de données est adapté au cache, alors il ne chargera qu'une fois au total, si l'ensemble de données est plus grand que la cachette, alors il chargera deux fois dans chaque boucle for? – myej

+0

@myej: de nos jours, les processeurs sont beaucoup plus rapides que la mémoire, ce qui explique pourquoi nous avons des caches de plus en plus volumineux.Pour obtenir les meilleures performances, vous devez minimiser les échecs de cache, ce qui signifie travailler autant que possible sur vos données. Si vous ne faites qu'un petit nombre d'opérations, le coût de l'accès au cache et de l'accès DRAM à bande passante relativement faible l'emporte sur toute optimisation de calcul .. –