Question

J'ai essayé de comprendre comment obtenir une certaine amélioration dans mon code à quelques lignes très cruciales:

float x = a*b;
float y = c*d;
float z = e*f;
float w = g*h;

tout a, b, c ... sont des flotteurs.

J'ai décidé de regarder dans SSE, mais ne peut pas sembler trouver une amélioration, en fait, il se révèle être deux fois plus lent. Mon code SSE est:

Vector4 abcd, efgh, result;
abcd = [float a, float b, float c, float d];
efgh = [float e, float f, float g, float h];
_asm {
movups xmm1, abcd
movups xmm2, efgh
mulps xmm1, xmm2
movups result, xmm1
}

J'ai aussi essayé en utilisant l'assembleur en ligne standard, mais il ne semble pas que je peux emballer le registre avec les quatre points flottants comme je peux avec SSE.

Les commentaires, ou de l'aide serait grandement apprécié, je dois surtout de comprendre pourquoi mes calculs en utilisant SSE sont plus lents que le code de série C ++?

Je compile dans Visual Studio 2005, sur un ordinateur Windows XP, en utilisant un Pentium 4 avec HT si cela fournit des informations supplémentaires à Assit.

Merci à l'avance!

Était-ce utile?

La solution

Comme vous l'avez découvert, juste remplacer quelques instructions avec SSE ne va pas au travail parce que vous devez mélanger les données autour de la mémoire afin de charger les registres SSE correctement, et ces données se déplacer dans la mémoire ( le bit qui construit les tableaux) va tuer votre performance en tant que mémoire est très lent (disque dur de côté, la mémoire est toujours le goulot d'étranglement de nos jours).

En outre, il n'y a aucun moyen de transférer des données entre l'ESS et la FPU / ALU sans utiliser une écriture RAM suivie d'une lecture. IA32 modernes puces à faire face bien avec ce modèle particulier (écrire alors lu), mais annule encore une cache qui aura un effet boule de neige.

Pour tirer le meilleur parti de l'ESS, vous devez examiner l'ensemble algorithme et les données les utilisations de l'algorithme. Les valeurs de a, b, c et d et e, f, g et h nécessité de façon permanente dans ces réseaux de sorte qu'il n'y a pas de données de décalage vers la mémoire avant de charger les registres SSE. Il n'est pas simple et peut nécessiter beaucoup de retravaillant de votre code et les données (vous devrez peut-être stocker les données différemment sur le disque).

Il est peut-être aussi pointage vaut le SSE est seulement 32 bits (ou 64 bits si vous utilisez double) alors que la FPU est 80 bits (quel que soit flottant ou double) et vous obtiendrez des résultats légèrement différents lors de l'utilisation SSE par rapport à l'utilisation de la FPU . Seulement, vous savez si ce sera un problème.

Autres conseils

vous utilisez des instructions, qui sont non alignés très lent. Vous pouvez essayer d'aligner correctement vos données, la limite de 16 octets, et en utilisant movaps. Vous êtes meilleure alternative est d'utiliser intrinsics, plutôt que de l'assemblage, parce que le compilateur est libre d'instructions de commande comme il semble nécessaire.

Vous pouvez activer l'utilisation de SSE et SSE2 dans les options du programme dans les nouvelles versions VS et peut-être en 2005. Compile en utilisant une version express?

En outre, votre code SSE est probablement plus lent parce que lorsque vous compilez C série ++, le compilateur est intelligent et fait un très bon travail sur ce qui rend très EXPRESS- par exemple, les mettre automatiquement dans les registres au bon moment. Si les opérations se déroulent en série, le compilateur peut réduire l'impact de la mise en cache et la pagination, par exemple. assembleur inline peuvent optimiser au mieux mal et doit être évitée autant que possible.

En outre, vous devriez être effectuer une énorme quantité de travail pour SSE / 2 pour apporter un avantage notable.

Ceci est un vieux fil, mais je remarque une erreur dans votre exemple. Si vous souhaitez effectuer ceci:

float x = a*b;
float y = c*d;
float z = e*f;
float w = g*h;

Ensuite, le code doit être comme ça:

Vector4 aceg, bdfh, result;  // xyzw
abcd = [float a, float c, float e, float g];
efgh = [float b, float d, float f, float h];
_asm {
movups xmm1, abcd
movups xmm2, efgh
mulps xmm1, xmm2
movups result, xmm1
}

Et pour gagner encore un peu plus la vitesse, je vous suggère que vous n'utilisez pas un registre séparé pour « résultat ».

Pour commencer, tous les algorithmes bénéficieront d'être réécrite en SSE. algorithmes pilotés par les données (comme les algorithmes entraînés par des tables de consultation) ne se traduisent pas bien dans l'ESS, car beaucoup de temps est perdu et l'emballage des données déballer dans des vecteurs pour SSE à utiliser.

Hope this helps encore.

Tout d'abord quand vous avez quelque chose 128bit (16 octets) Disposés vous devez utiliser MOVAPS car il peut être beaucoup plus rapide. Le compilateur devrait vous donner en général un alignement 16 octets, même sur des systèmes 32 bits.

Vos lignes C / C ++ ne pas faire la même chose que votre code sse.

Les quatre flotteurs dans un registre XMM sont multipliés par les quatre flotteurs dans l'autre registre. vous donner:

float x = a*e;
float y = b*f;
float z = c*g;
float w = d*h;

Dans SSE1 vous devez utiliser SHUFPS pour réorganiser les flotteurs dans les deux registres avant de multiplier.

En outre pour le traitement de données qui est plus grande que le cache de cpu vous pouvez utiliser les magasins non-temporels (MOVNTPS) pour réduire la pollution de cache. Notez que les magasins non-temporels sont beaucoup plus lents dans d'autres cas.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top