IdentifiantMot de passe
Loading...
Mot de passe oubli� ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les r�ponses en temps r�el, voter pour les messages, poser vos propres questions et recevoir la newsletter

Visual C++ Discussion :

Visual C++ SIMD Performance


Sujet :

Visual C++

  1. #1
    Membre confirm�
    Profil pro
    Inscrit en
    F�vrier 2010
    Messages
    60
    D�tails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : F�vrier 2010
    Messages : 60
    Par d�faut Visual C++ SIMD Performance
    Salut ami(e)s dev...
    J'utilise actuellement les intrinsics SSE msvc pour augmenter les performances de 2 de mes fonctions NURBS...
    La 1�re calcule 4 basis functions en une fois
    La 2�me calcule 4 points d'une surface en une fois.
    (Les nurbs ne sont qu'un pretexte....)
    Le probl�me est que le programme prend le meme temps qu'il soit en mode
    SIMD ou pas...Du coup je me pose des questions sur l'optimisation SIMD de
    msvc...Mais avant peut-etre que je peux mieux �crire mon code...
    Alors pour ceux qui s'y connaissent en optimisation SIMD quelles sont les conventions � adopter pour avoir atteindre la performance voulue....??
    Merci

  2. #2
    screetch
    Invit�(e)
    Par d�faut
    a l'aveugle (pas de code...)
    les instructions SIMD marchent bien surtout quand on les fait a la suite.
    je ne sais pas ce que tu essayes de faire, mais bon... une addition par exemple, ca coute presque rien. en faire 4 d'un coup, ca coute toujours presque rien.

    Ce qui co�te a l'execution C++, personne ne le sait. Il faut utiliser un profiler pour voir ce que c'est (exemple: AMD COde Analyst, VTune, etc etc) voire m�me simuler un processeur et voir comment ca s'execute.

    Par exemple, il se peut que le vrai probl�me soit que ta fonction n'est pas inlin�e, un appel de fonction coutera beaucoup plus cher que tes additions ou multiplications.
    Un autre probl�me pourrait �tre que tes valeurs sont tr�s espac�es en m�moire, le temps de les charger dans un registre serait tr�s long. A cot� de ca, encore une fois, une addition ou une multiplication c'est rien.

    Quand tes donn�es seront correctement pr�par�es, proches les unes des autres, que tu auras beaucoup de traitements a la suite sur ces donn�es, alors le SSE commencera a etre interessant. Sans en savoir plus sur ton probl�me, je pense juste que ton optimisation est trop petite pour �tre visible.

    Les intrinsics SSE de visual studio sont pratiquement des equivalents d'instruction assembleur, c'est difficile d'�tre plus performant que ca.

  3. #3
    Membre confirm�
    Profil pro
    Inscrit en
    F�vrier 2010
    Messages
    60
    D�tails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : F�vrier 2010
    Messages : 60
    Par d�faut
    Merci screetch pour ta r�ponse...Je te donne les deux fonctions
    La 1�re.....
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    void basisDerFuncCustom(GLint degree, GLint n, GLint *index, GLfloat *uv, std::vector<GLfloat> &my_knots, std::vector<sfloat4, Eigen::aligned_allocator<sfloat4> > &res){
     
    	//std::cout<<"Entree der custom "<<std::endl;
    	GLint taille = degree+1;
    	std::vector<sfloat4, Eigen::aligned_allocator<sfloat4> > left(degree+1);
    	std::vector<sfloat4, Eigen::aligned_allocator<sfloat4> > right(degree+1);
    	std::vector<sfloat4, Eigen::aligned_allocator<sfloat4> > ndu(taille*taille);
    	std::vector<sfloat4, Eigen::aligned_allocator<sfloat4> > ar(2*taille);
    	//res.resize((n+1)*taille);
     
    	ndu[0] = _mm_set_ps(1.0f, 1.0f, 1.0f, 1.0f);
    	//std::cout<<"ALLoc complete"<<std::endl;
     
    	for(GLint j=1; j<=degree; j++){
     
    		left[j]= _mm_set_ps( (uv[3] - my_knots[index[3]+1-j]), (uv[2] - my_knots[index[2]+1-j]), (uv[1] - my_knots[index[1]+1-j]), (uv[0] - my_knots[index[0]+1-j]));
    		right[j]= _mm_set_ps( (my_knots[index[3]+j] - uv[3]), (my_knots[index[2]+j] - uv[2]), (my_knots[index[1]+j] - uv[1]), (my_knots[index[0]+j] - uv[0]));
    		sfloat4 saved = _mm_setzero_ps(); 
    		sfloat4 temp = _mm_setzero_ps();
     
    		for(GLint r=0; r<j; r++){
    			ndu[(j*taille) + r] = _mm_add_ps( right[r+1], left[j-r] );
    			temp = _mm_div_ps( ndu[(r*taille)+(j-1)], ndu[(j*taille)+r] );
    			ndu[(r*taille)+j] = _mm_add_ps(saved, _mm_mul_ps(right[r+1],temp));
    			saved = _mm_mul_ps(left[j-r], temp);
    		}
    		ndu[(j*taille)+j] = saved;
    	}
     
    	for(GLint j=0; j<=degree; j++)
    		res[j] = ndu[(j*taille)+degree] ;
     
    	for(GLint r=0; r<=degree; r++){
     
    		GLint s1=0; GLint s2=1;
    		ar[0]= _mm_set_ps1(1.0f);
     
    		for(GLint k=1; k<=n; k++){
     
    			sfloat4 d = _mm_set_ps1(0.0f);
    			GLint rk = r-k;  GLint pk = degree-k; GLint j1; GLint j2;
     
    			if(r>=k){
    				ar[s2*taille] = _mm_div_ps(ar[s1*taille], ndu[((pk+1)*taille)+rk]);
    				d = _mm_mul_ps(ar[(s2*taille)], ndu[(rk*taille)+pk]);
    			}
     
    			if(rk>= -1) j1=1;
    			else       j1= -rk;
     
    			if(r-1<=pk) j2=k-1;
    			else        j2=degree-r;
     
    			for(GLint j=j1; j<=j2; j++){
    				ar[(s2*taille)+j] = _mm_div_ps(_mm_sub_ps(ar[(s1*taille)+j], ar[(s1*taille)+j-1]), ndu[((pk+1)*taille)+rk+j]);
    				d = _mm_add_ps(d, _mm_mul_ps(ar[(s2*taille)+j], ndu[((rk+j)*taille)+pk]));
    			}
     
    			if(r <= pk){
    				ar[(s2*taille)+k] = _mm_div_ps( _mm_sub_ps(_mm_setzero_ps(), ar[(s1*taille)+k-1] ), ndu[((pk+1)*taille)+r] );
    				d = _mm_add_ps(d, _mm_mul_ps(ar[(s2*taille)+k], ndu[(r*taille)+pk]));
    			}
    			res[(k*taille)+r] = d;
    			GLint j=s1; s1=s2; s2=j;
    		}
    	}
    	GLint r=degree;
     
    	for(GLint k=1; k<=n; k++){
    		for(GLint j=0; j<=degree; j++)
    			res[(k*taille)+j] = _mm_mul_ps (res[(k*taille)+j], _mm_set_ps((GLfloat)r,(GLfloat)r,(GLfloat)r,(GLfloat)r) );
     
    		r *= (degree-k);
    	}
    }
    La 2�me....plus longue.....
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    void evalDerSurfacePointCustom(GLint d, GLint *IndicesU, GLint *IndicesV, GLfloat *u, GLfloat *v, sfloat4 *, std::vector<glm::detail::tvec3<T> > &Res){
     
    	assert(d <= 1);
    	GLint tailleu = degreeU+1;
    	GLint taillev = degreeV+1;
    	GLint np = knotVectorU.size()-2-degreeU;
    	GLint nq = knotVectorV.size()-2-degreeV;
    	std::vector<std::vector<T> > Bin(d+1,std::vector<T>(d+1,1.0f));
    	std::vector<std::vector<std::vector<sfloat4,Eigen::aligned_allocator<sfloat4> > > > SKL(d+1,std::vector<std::vector<sfloat4,Eigen::aligned_allocator<sfloat4> > >(d+1,std::vector<sfloat4,Eigen::aligned_allocator<sfloat4> >(3)));
     
    	std::vector<std::vector<std::vector<sfloat4,Eigen::aligned_allocator<sfloat4> > > > Aders(d+1,std::vector<std::vector<sfloat4,Eigen::aligned_allocator<sfloat4> > >(d+1,std::vector<sfloat4,Eigen::aligned_allocator<sfloat4> >(4)));
     
    	{//Compute Aders and Wders
    		std::vector<std::vector<sfloat4,Eigen::aligned_allocator<sfloat4> > > temp(taillev,std::vector<sfloat4,Eigen::aligned_allocator<sfloat4> >(4));
    		std::vector<sfloat4, Eigen::aligned_allocator<sfloat4> > Nu((d+1)*tailleu);
    		std::vector<sfloat4, Eigen::aligned_allocator<sfloat4> > Nv((d+1)*taillev);
    		basisDerFuncCustom(degreeU, d, IndicesU, u, knotVectorU, Nu);
    		basisDerFuncCustom(degreeV, d, IndicesV, v, knotVectorV, Nv);
    		GLint du = std::min(d,degreeU);
    		GLint dv = std::min(d,degreeV);
     
    		for(GLint k=0; k<=du; k++){
    			for(GLint s=0; s<=degreeV; s++){
    				for(GLint r=0; r<=degreeU; r++){
    					sfloat4 simd_x = _mm_set_ps(ctrlPointVector[(IndicesU[3]-degreeU+r)*(nq+1)+(IndicesV[3]-degreeV+s)][0], ctrlPointVector[(IndicesU[2]-degreeU+r)*(nq+1)+(IndicesV[2]-degreeV+s)][0], ctrlPointVector[(IndicesU[1]-degreeU+r)*(nq+1)+(IndicesV[1]-degreeV+s)][0], ctrlPointVector[(IndicesU[0]-degreeU+r)*(nq+1)+(IndicesV[0]-degreeV+s)][0]);
    					sfloat4 simd_y = _mm_set_ps(ctrlPointVector[(IndicesU[3]-degreeU+r)*(nq+1)+(IndicesV[3]-degreeV+s)][1], ctrlPointVector[(IndicesU[2]-degreeU+r)*(nq+1)+(IndicesV[2]-degreeV+s)][1], ctrlPointVector[(IndicesU[1]-degreeU+r)*(nq+1)+(IndicesV[1]-degreeV+s)][1], ctrlPointVector[(IndicesU[0]-degreeU+r)*(nq+1)+(IndicesV[0]-degreeV+s)][1]);
    					sfloat4 simd_z = _mm_set_ps(ctrlPointVector[(IndicesU[3]-degreeU+r)*(nq+1)+(IndicesV[3]-degreeV+s)][2], ctrlPointVector[(IndicesU[2]-degreeU+r)*(nq+1)+(IndicesV[2]-degreeV+s)][2], ctrlPointVector[(IndicesU[1]-degreeU+r)*(nq+1)+(IndicesV[1]-degreeV+s)][2], ctrlPointVector[(IndicesU[0]-degreeU+r)*(nq+1)+(IndicesV[0]-degreeV+s)][2]);
    					sfloat4 simd_w = _mm_set_ps(ctrlPointVector[(IndicesU[3]-degreeU+r)*(nq+1)+(IndicesV[3]-degreeV+s)][3], ctrlPointVector[(IndicesU[2]-degreeU+r)*(nq+1)+(IndicesV[2]-degreeV+s)][3], ctrlPointVector[(IndicesU[1]-degreeU+r)*(nq+1)+(IndicesV[1]-degreeV+s)][3], ctrlPointVector[(IndicesU[0]-degreeU+r)*(nq+1)+(IndicesV[0]-degreeV+s)][3]);
    					temp[s][0] = _mm_add_ps(temp[s][0], _mm_mul_ps(Nu[(k*tailleu)+r], simd_x));
    					temp[s][1] = _mm_add_ps(temp[s][1], _mm_mul_ps(Nu[(k*tailleu)+r], simd_y));
    					temp[s][2] = _mm_add_ps(temp[s][2], _mm_mul_ps(Nu[(k*tailleu)+r], simd_z));
    					temp[s][3] = _mm_add_ps(temp[s][3], _mm_mul_ps(Nu[(k*tailleu)+r], simd_w));
    				}
    			}
    			GLint dd = std::min(d-k,dv);
    			for(GLint l=0; l<=dd; l++){
    				for(GLint s=0; s<=degreeV; s++){
    					Aders[k][l][0] = _mm_add_ps(Aders[k][l][0], _mm_mul_ps(Nv[(l*taillev)+s], temp[s][0]));
    					Aders[k][l][1] = _mm_add_ps(Aders[k][l][1], _mm_mul_ps(Nv[(l*taillev)+s], temp[s][1]));
    					Aders[k][l][2] = _mm_add_ps(Aders[k][l][2], _mm_mul_ps(Nv[(l*taillev)+s], temp[s][2]));
    					Aders[k][l][3] = _mm_add_ps(Aders[k][l][3], _mm_mul_ps(Nv[(l*taillev)+s], temp[s][3]));
    				}
    			}
    		}
    	}
    	//Compute nurbs derivates	
    	for(GLint k=0; k<=d; k++){
    		for(GLint l=0; l<=d-k; l++){
    			std::vector<sfloat4,Eigen::aligned_allocator<sfloat4> > v(3);
    			v[0] = Aders[k][l][0];
    			v[1] = Aders[k][l][1];
    			v[2] = Aders[k][l][2];
    			for(GLint j=1; j<=l; j++){
    				v[0] = _mm_sub_ps(v[0], _mm_mul_ps(_mm_set1_ps(Bin[l][j]), _mm_mul_ps(Aders[0][j][3], SKL[k][l-j][0])));
    				v[1] = _mm_sub_ps(v[1], _mm_mul_ps(_mm_set1_ps(Bin[l][j]), _mm_mul_ps(Aders[0][j][3], SKL[k][l-j][1])));
    				v[2] = _mm_sub_ps(v[2], _mm_mul_ps(_mm_set1_ps(Bin[l][j]), _mm_mul_ps(Aders[0][j][3], SKL[k][l-j][2])));
    			}
    			for(GLint i=1; i<=k; i++){
    				v[0] = _mm_sub_ps(v[0], _mm_mul_ps(_mm_set1_ps(Bin[k][i]), _mm_mul_ps(Aders[i][0][3], SKL[k-i][l][0])));
    				v[1] = _mm_sub_ps(v[1], _mm_mul_ps(_mm_set1_ps(Bin[k][i]), _mm_mul_ps(Aders[i][0][3], SKL[k-i][l][1])));
    				v[2] = _mm_sub_ps(v[2], _mm_mul_ps(_mm_set1_ps(Bin[k][i]), _mm_mul_ps(Aders[i][0][3], SKL[k-i][l][2])));
     
    				std::vector<sfloat4,Eigen::aligned_allocator<sfloat4> > v2(3);
    				for(GLint j=1; j<=l; j++){
    					v2[0] = _mm_add_ps(v2[0], _mm_mul_ps(_mm_set1_ps(Bin[l][j]), _mm_mul_ps(Aders[i][j][3], SKL[k-i][l-j][0])));
    					v2[1] = _mm_add_ps(v2[1], _mm_mul_ps(_mm_set1_ps(Bin[l][j]), _mm_mul_ps(Aders[i][j][3], SKL[k-i][l-j][1])));
    					v2[2] = _mm_add_ps(v2[2], _mm_mul_ps(_mm_set1_ps(Bin[l][j]), _mm_mul_ps(Aders[i][j][3], SKL[k-i][l-j][2])));
    				}
    				v[0] = _mm_sub_ps(v[0], _mm_mul_ps(_mm_set1_ps(Bin[k][i]), v2[0]));
    				v[1] = _mm_sub_ps(v[1], _mm_mul_ps(_mm_set1_ps(Bin[k][i]), v2[1]));
    				v[2] = _mm_sub_ps(v[2], _mm_mul_ps(_mm_set1_ps(Bin[k][i]), v2[2]));
    			}
    			SKL[k][l][0] = _mm_div_ps(v[0], Aders[0][0][3]);
    			SKL[k][l][1] = _mm_div_ps(v[1], Aders[0][0][3]);
    			SKL[k][l][2] = _mm_div_ps(v[2], Aders[0][0][3]);
    		}
    	}
     
    	for(GLint i=0; i<=d; i++){
    		for(GLint j=0; j<=d; j++){
    			Res[(i*(d+1)+j)*4] =   (glm::detail::tvec3<T>(SKL[i][j][0].m128_f32[0], SKL[i][j][1].m128_f32[0], SKL[i][j][2].m128_f32[0]));
    			Res[(i*(d+1)+j)*4+1] = (glm::detail::tvec3<T>(SKL[i][j][0].m128_f32[1], SKL[i][j][1].m128_f32[1], SKL[i][j][2].m128_f32[1]));
    			Res[(i*(d+1)+j)*4+2] = (glm::detail::tvec3<T>(SKL[i][j][0].m128_f32[2], SKL[i][j][1].m128_f32[2], SKL[i][j][2].m128_f32[2]));
    			Res[(i*(d+1)+j)*4+3] = (glm::detail::tvec3<T>(SKL[i][j][0].m128_f32[3], SKL[i][j][1].m128_f32[3], SKL[i][j][2].m128_f32[3]));
    		}
    	}
    }
    Je pr�cise que les mm_set_ps utilis�s �taient obligatoires du fait que les donn�es n'�taient pas encore pr�par�es...voil� merci

  4. #4
    screetch
    Invit�(e)
    Par d�faut
    je n'ai pas �t� jusqu'au bout, je prends juste un exemple:

    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
     
    for(GLint i=1; i<=k; i++){
    v[0] = _mm_sub_ps(v[0], _mm_mul_ps(_mm_set1_ps(Bin[k][i]), _mm_mul_ps(Aders[i][0][3], SKL[k-i][l][0])));
    cette ligne va:
    * lire ce qui se trouve dans Bin[k][i] (probablement rapide)
    * lire ce qu'il y a dans Aders[i][0][3]: c'est un cache miss a coup s�r car Aders[i]... va sauter une ligne enti�re de tableau a chaque coup
    * lire SKL[k-i][l][0], cache miss

    la tu viens de perdre 40 cycles dans les cache miss a chaque tour de boucle. Apres ca, la soustraction et les multiplications sont presque instantan�es

    Une r�gle g�n�rale, c'est de faire varier l'index le plus a gauche le moins souvent possible, car la tu ne fais que des cache miss a chaque tour de boucle.

    Mais si tu veux vraiment savoir, la seule solution est d'utiliser un outil de profiling.

  5. #5
    Membre confirm�
    Profil pro
    Inscrit en
    F�vrier 2010
    Messages
    60
    D�tails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : F�vrier 2010
    Messages : 60
    Par d�faut
    Merci screetch...
    J'ai pu doubler les perf en transformant tous les vectors tri ou bi-dimensionnelle
    en uni-dimensionnelle...
    Une r�gle g�n�rale, c'est de faire varier l'index le plus a gauche le moins souvent possible, car la tu ne fais que des cache miss a chaque tour de boucle.
    Moi je dirai tout simplement �vitez les vectors de vector.......
    std::vector<std::vector<int> > par ex est dif�rent de int tab[][] niveau perf...
    Les �lts du 1er ne sont pas contigus en m�moire sachant que ceux du 2�me le sont bien....
    Voil� s'il y en a qui ont des petites astuces pour acc�l�rer les SIMD je suis partant...

  6. #6
    screetch
    Invit�(e)
    Par d�faut
    ca risque d'etre toujours des probl�mes d'acc�s m�moire (ca depend de la taille de tes donn�es)
    tu as utilis� un profiler?

  7. #7
    Membre confirm�
    Profil pro
    Inscrit en
    F�vrier 2010
    Messages
    60
    D�tails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : F�vrier 2010
    Messages : 60
    Par d�faut
    non pas encore en fait je n'en ai jamais utilis�...Sinon T'en as d�j� utilis� un??
    Moi j'utilise visual studio ultimate...

  8. #8
    screetch
    Invit�(e)
    Par d�faut
    j'utilise en general AMD code analyst sans les fonctionnalit�s avanc�es (qui ne marchent pas sur mon processeur intel)
    j'ai aussi deja essay� leur simulateur de pipeline pour trouver les vrais bottlenecks

    en executant ton code tu pourrais voir que certqines instructions prennent presque tout le temps tandis que d'autres sont "gratuites"; en g�n�ral ca veut dire non pas que l'instruction prend reellement du temps, mais que le processeur est d�pendant d'un �v�nement a cet endroit pr�cis

Discussions similaires

  1. R�ponses: 31
    Dernier message: 22/04/2014, 14h55
  2. Performance d'acc�es � la BD sous visual C++
    Par bouzaidi dans le forum C++
    R�ponses: 1
    Dernier message: 23/04/2008, 15h10
  3. R�ponses: 2
    Dernier message: 01/08/2006, 10h20
  4. les performances du C# et du visual basic
    Par 180degr�s dans le forum DirectX
    R�ponses: 17
    Dernier message: 01/09/2005, 04h51
  5. Visual C++ 6/7 - performance
    Par Manu35 dans le forum MFC
    R�ponses: 9
    Dernier message: 19/01/2004, 17h46

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo