11
votes

Manière la plus efficace de stocker 4 produits DOT dans un tableau contigu dans C utilisant SSE intrinsics

Je optimise un certain code pour une micro-architecture Intel X86 Nehalem utilisant SSE intrinsique.

Une partie de mon programme calcule 4 produits DOT et ajoute chaque résultat aux valeurs précédentes dans une pièce contiguë d'une matrice. Plus spécifiquement, P>

tmp0 = _mm_add_ps(tmp0, C_0n);
_mm_storeu_ps(C_2, tmp0);


0 commentaires

4 Réponses :


6
votes

Pour le code comme celui-ci, j'aime stocker la "transpose" des A et B, de sorte que {a_0m.x, a_1m.x, a_2m.x, a_3m.x} sont stockés dans un vecteur, etc. Vous pouvez effectuer le produit DOT en utilisant uniquement et ajoute des ajouts, et lorsque vous avez terminé, vous avez tous les 4 produits DOT dans un seul vecteur sans aucun dépassement.

Ceci est utilisé fréquemment dans la rayonnage, pour tester 4 rayons à la fois contre un plan (par exemple, lors de la traversée d'un kd-arbre). Si vous n'avez pas de contrôle sur les données d'entrée, les frais généraux de la transposition ne valent pas la peine. Le code s'exécutera également sur des machines pré-SSE4, bien que cela ne soit pas un problème.


une petite note d'efficacité sur le code existant: au lieu de ce xxx < / PRE>

Il peut être légèrement préférable de faire cela: xxx

comme les deux premiers mm_add_ps S sont complètement indépendants maintenant. En outre, je ne connais pas les horaires relatives d'ajout vs. Shuffling, mais cela pourrait être légèrement plus rapide.


espère que cela aide.


0 commentaires

1
votes

Vous pouvez essayer de quitter le résultat du produit DOT dans le mot bas et utilisez le magasin Scalar Store OP _mm_store_ss pour enregistrer un flotteur de chaque enregistrement M128 dans l'emplacement approprié de la matrice. Le tampon de magasin de Nehalem devrait accumuler des écrivies consécutives sur la même ligne et les rincer à L1 en lots.

Le moyen de le faire est la transposition de Celion. _mm_transpose4_ps macro fera la transposition pour vous .


1 commentaires

Vous devrez encore ajouter l'ancienne valeur (C_0N) à chaque produit DOT avant le magasin. Ils seront tous indépendants, donc ce n'est peut-être pas trop lent, mais ce n'est pas beaucoup plus joli :)



3
votes

Il est également possible d'utiliser le SSE3 Hadd. Il s'est avéré plus rapidement que d'utiliser _Dot_ps, dans certains tests triviaux. Cela renvoie 4 produits DOT qui pourraient être ajoutés.

static inline __m128 dot_p(const __m128 x, const __m128 y[4])
{
   __m128 z[4];

   z[0] = x * y[0];
   z[1] = x * y[1];
   z[2] = x * y[2];
   z[3] = x * y[3];
   z[0] = _mm_hadd_ps(z[0], z[1]);
   z[2] = _mm_hadd_ps(z[2], z[3]);
   z[0] = _mm_hadd_ps(z[0], z[2]);

   return z[0];
}


0 commentaires

1
votes

Je réalise que cette question est ancienne, mais pourquoi utiliser _mm_add_ps code> du tout? Remplacez-le par:

_mm_storeu_ps(C_2, _mm_add_ps(tmp0, C_0));


0 commentaires