Y a-t-il des instructions d'ASM pouvant accélérer le calcul de min / max de vecteur de doubles / entiers sur l'architecture Core I7? P>
Je ne m'attendais pas à de telles réponses riches, merci.
Je vois donc que max / min est possible de faire sans ramification.
J'ai une sous-question: p>
Y a-t-il un moyen efficace d'obtenir l'index du plus grand double de la matrice? P>
6 Réponses :
MAXPS et MINPS de SSE fonctionnent tous les deux sur des nombres de points flottants à la précision à la précision emballés. Pmaxsw, PMINSW, Pmaxub et PMinub fonctionnent tous sur des mots de 8 bits emballés, signés ou non signés. Veuillez noter que celles-ci comparent les deux registres SSE d'entrée ou les emplacements d'adresse Élément-wise et stockent le résultat dans un registre ESS ou un emplacement de mémoire. P>
Les versions SSE2 de MAXPS et MINPS doivent fonctionner sur des flotteurs à double précision. P>
Quel drapeaux compilateur et optimisation utilisez-vous? GCC 4.0 et mieux devrait viller automatiquement les opérations si votre cible les prend en charge, des versions antérieures peuvent nécessiter un drapeau spécifique. p>
sse4 a sse2 a Il y a des équivalents min de ce qui précède. P> Pour le boîtier double, vous n'allez probablement pas mieux faire mieux en assembleur Plus d'un compilateur de C ++ à moitié décent en mode SSE: p> où min_max calcule min et max d'un tableau de 500 doubles 100 000 fois en utilisant une boucle naïve: P> < PRE> XXX PRE> En réponse à la deuxième partie, l'optimisation traditionnelle pour éliminer la ramification d'une opération Max consiste à comparer les valeurs, à obtenir le drapeau comme un seul bit (10 ou 1), soustrayez Un (donnant 0 ou 0xFFFF_FFFF) et 'et' et 'et le' avec le Xor des deux résultats possibles, vous obtenez donc l'équivalent de Pmaxsd code> ou
Pmaxud code> pour les entiers signés 32 bits / non signés, ce qui pourrait être utile.
maxpd code> et
maxd code> qui se comparent entre et entre les paires de doubles, de sorte que vous suivez n / 2-1 maxpds avec un maxSD pour obtenir le maximum d'un vecteur de n, avec l'entrelacement habituel des charges et des opérations. p>
(A> meilleur? (actuel_index ^ best_index): 0) ^ best_index) code> . Je doute qu'il y ait une simple façon de le faire, simplement parce que SSE a tendance à fonctionner sur des valeurs emballées plutôt que des valeurs marquées; Il existe certaines opérations d'index horizontales, de sorte que vous pourriez essayer de trouver le maximum, puis soustrayez-la de tous les éléments du vecteur d'origine, puis collectez le bit de signalisation et le zéro signé correspondrait à l'index du max, mais cela serait probablement ne pas être une amélioration à moins que vous utilisiez des shorts ou des octets. p> p>
Vous avez seulement besoin de log2 (Vector_length) Shuffle + MAXPS / MAXPD Opérations, pas VL / 2, pour obtenir le maximum horizontal d'un seul vecteur SIMD. C'est fondamentalement la même idée que une somme horizontale a >: étroit dans la moitié de chaque fois. (Ou laisser le résultat diffusé à chaque élément, échangez haut / bas).
Douillage avec plusieurs accumulateurs devrait donner une meilleure vitesse supérieure à 2x, si vous n'êtes pas goutaré sur la mémoire. ( maxpd code> a une latence de 3 ou 4 cycle, mais un débit de 1 par cycle, vous avez donc besoin du compilateur pour émettre de l'ASM qui utilise plusieurs vecteurs et les combine à la fin de la matrice.) La collage a tendance à Faites cela en vous vectorisant automatiquement, mais GCC ne le fait toujours pas.
Si vous utilisez Intel's bibliothèque IPP Vous pouvez utiliser le vecteur Fonctions statistiques pour calculer Vecteur min / max (entre autres) P>
En réponse à votre deuxième question: sur la plupart des plates-formes, il existe des bibliothèques qui contenaient déjà des implémentations optimisées de cette opération très opérationnelle (et la plupart des autres opérations de vecteur simples). les utiliser strong>. p>
vdsp_maxvid () code> et
cblas_idamax () code> dans l'accélération.framework li>
cblas_idamax () code> li>
cblas_idamax () code> dans la bibliothèque BLAS, qui peut être bien réglé en fonction de sa provenance; Les utilisateurs qui se soucient de la performance auront généralement une bonne implémentation (ou peuvent être convaincus d'installer un) li>
En réponse à votre deuxième question, il peut être intéressant de penser à la façon dont vous collectez et stockez ces données. P>
Vous pouvez stocker les données dans un arbre B qui maintient les données triées à tout moment, nécessitant uniquement les opérations de comparaison logarithmiques. P>
alors vous savez à tout moment où le maximum est. P>
Puisque vous traitez seulement 300 doubles, un arbre binaire auto-équilibré est probablement préférable. EN.Wikipedia.org/wiki/Self --Balancer_binaire_search_tree
mise à jour: je viens de vous rendre compte que vous avez dit "tableau", pas "Vector" dans la partie 2. Je vais laisser cela ici quand même si cela sera utile.
RE: Trouvez l'index de la Élément max / min dans un vecteur SSE: P>
faire un maximum horizontal. Pour un vecteur de 128b de 2 Pour les autres cas, cela prendra bien plus de mesures. Voir moyen le plus rapide de faire une somme de vecteur de flotteur horizontal sur x86 Pour les idées, remplaçant faire un emballé-comparer entre le vecteur original vecteur et le vecteur où chaque élément est le max. p>
( Ceci devrait compiler uniquement 6 instructions (y compris un double code>, c'est juste un
shufpd code> +
maxpd code> pour laisser le résultat diffusé aux deux éléments. P>
addps code> avec
maxps code> ou
mins code>. (Mais noter que l'entier 16 bits est spécial, car vous pouvez utiliser SSE4
Phminposuw code>. Pour max, soustrayez de 255) P> LI>
PCMPEQQ code> des motifs de bit entier ou le
CMPEQPD code> fonctionnerait tous les deux pour le boîtier
double code>). p> li>
int _mm_movemask_pd (__m128d a) code> (
pour obtenir le résultat du comparateur en tant que bitmap entier . li>
MOVMSKPD code>)
bsf code>) pour la (première) match:
index = _bit_scan_forward (CMPMask) Code >
. CMPMASK = 0 est impossible si vous avez utilisé Integer se compare (car au moins un élément correspondra même si elles sont nan). LI>
ul> MOVAPD code>). Yup, vient de vérifier sur Le godbolt Compiler Explorer et cela, avec SSE. P>
#include <immintrin.h>
#include <x86intrin.h>
int maxpos(__m128d v) {
__m128d swapped = _mm_shuffle_pd(v,v, 1);
__m128d maxbcast = _mm_max_pd(swapped, v);
__m128d cmp = _mm_cmpeq_pd(maxbcast, v);
int cmpmask = _mm_movemask_pd(cmp);
return _bit_scan_forward(cmpmask);
}
Quelle est la langue d'hôte? Si c'est C / C ++, je ne m'en avais pas trop.
Max d'environ 300 doubles est dans la boucle la plus interne du grand programme. 85% du temps est passé dans environ 10 lignes de code de 8'000. La langue de l'hôte n'a pas d'importance juste à cause de cela. Mais oui c'est c ++
Connexe: Quelle est l'instruction qui donne à FP min et max sur X86 et max sur X86? a plus de détails sur les MINSS / MAXSS / MINSD / MAXSD, y compris leur Comportement de Na.