Question

I ai un gros morceau de code, dont une partie du corps contient ce morceau de code:

result = (nx * m_Lx + ny * m_Ly + m_Lz) / sqrt(nx * nx + ny * ny + 1);

que je vectorisé comme suit (tout est déjà un float):

__m128 r = _mm_mul_ps(_mm_set_ps(ny, nx, ny, nx),
                      _mm_set_ps(ny, nx, m_Ly, m_Lx));
__declspec(align(16)) int asInt[4] = {
    _mm_extract_ps(r,0), _mm_extract_ps(r,1),
    _mm_extract_ps(r,2), _mm_extract_ps(r,3)
};
float (&res)[4] = reinterpret_cast<float (&)[4]>(asInt);
result = (res[0] + res[1] + m_Lz) / sqrt(res[2] + res[3] + 1);

Le résultat est correct; Cependant, mon analyse comparative montre que la version vectorisée est plus lent :

  • La version non-vectorisé prend 3750 ms
  • La version vectorisée prend 4050 ms
  • Configuration result à 0 directement (et suppression de cette partie du code entièrement) réduit l'ensemble du processus de 2500 ms

Étant donné que la version vectorisée ne contient que un ensemble de multiplications SSE (au lieu de quatre multiplications individuels FPU), pourquoi est-il plus lent? La FPU en effet plus rapide que SSE, ou est-il ici?

une variable confondant

(je suis sur un Core i5 mobile.)

Était-ce utile?

La solution

Vous dépensez beaucoup de temps de déplacement des valeurs scalaires à / de registres SSE avec _mm_set_ps et _mm_extract_ps - cela génère beaucoup d'instructions, le temps d'exécution dont l'emportent loin sur les avantages de l'utilisation _mm_mul_ps. Jetez un oeil à la sortie assembleur généré pour voir combien de code est généré en plus de l'instruction MULPS unique.

Pour vectoriser cela correctement, vous devez utiliser 128 bits charges SSE et les magasins (_mm_load_ps / _mm_store_ps) puis utilisez les instructions SSE pour déplacer les éléments dans les registres en cas de besoin.

Un autre point à noter - les processeurs modernes tels que Core i5, Core i7, deux ont scalaire FPU et peut émettre 2 multiplications à virgule flottante par cycle d'horloge. L'avantage potentiel de SSE pour virgule flottante simple précision est donc seulement 2x au mieux. Il est facile de perdre plus / tout cela 2x avantage si vous avez trop des instructions « d'entretien », comme cela est le cas ici.

Autres conseils

Il y a plusieurs problèmes:

  1. Vous ne verrez pas beaucoup d'avantages avec des instructions SSE dans ces opérations, car les instructions SSE sont censées être mieux sur les opérations parallèles (qui est, en multipliant plusieurs valeurs en même temps). Ce que vous avez fait est un abus de l'ESS
  2. ne contiendraient pas les valeurs, utilisez le pointeur sur la 1ère valeur du tableau, mais vos valeurs ne sont pas dans le tableau
  3. ne pas extraire et copier les valeurs dans le tableau. C'est également un détournement de l'ESS. Le résultat est censé être dans un tableau.

Mon point de vue serait que le processeur a le temps de calculer la première multiplication lors de l'utilisation de la FPU pendant le chargement des valeurs suivantes. L'ESS doit charger toutes les valeurs d'abord.

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