Quelques idées pour aborder AVX2

Pour discuter de l'assembleur
fweil
Messages : 505
Inscription : dim. 16/mai/2004 17:50
Localisation : Bayonne (64)
Contact :

Quelques idées pour aborder AVX2

Message par fweil »

Bonsoir à toutes et à tous.

AVX2 est un mode d'utilisation des processeurs x64 qui permet de faire du calcul numérique parallélisé. L'idée est de permettre d'injecter des données entrant dans des calculs en utilisant un jeu de registres élargi, à l'instar de ce que permet mmx, mais le mode AVX2 utilise une largeur de registres de 256 bits (registres ymm.). Ceci permet de faire passer autant de mots de différents formats que possibles, soit dans le cas d'une arithmétique 64 bits, 4 données en parallèle.

Travailler avec AVX2 nécessite de bien comprendre l'idée de parallélisme : on fait passer plusieurs données à la fois. Cela implique également de "négocier" de longues heures avec l'environnement interne d'un processeur x64 et de jongler avec tous les éléments utiles.

Pour envoyer des données au processeur, il faut les faire passer de la mémoire aux registres, et indiquer les instructions à effectuer, puis récupérer les résultats dans les registres pour les repasser en mémoire afin de les utiliser.

PureBasic ne dispose pas d'instructions spécifiques pour gérer AVX2, mais j'ai mis une petite méthode didactique en place pour y comprendre quelque chose et parvenir à faire réagir la bête à mon commandement. Je n'ai sans doute pas fait le tour du sujet, loin de là, c'est très poilu. Mais si cela peut susciter de l'intérêt tant mieux.

Il faut préciser qu'aucun langage de programmation ne dispose d'un vrai truc spécifique pour faire du parallélisme, quand on y regarde de près, le parallélisme en C ne vaut pas mieux, c'est imbitable malgré la disponibilité de bibliothèques idoines.

La présentation qui est montrée ici ne propose pas une large variété d'exemples, mais c'est un bout qui peut inspirer celles et ceux que ça intéressera pour aller plus loin. Dans une approche plus aboutie, on pourrait en déduire une bibliothèque assez riche, soit à base de macros, soit sous forme de procédures (ou les deux d'ailleurs).

Une petite mise en garde ... si t'aime pas l'assembleur, faut regarder ailleurs :)

Code : Tout sélectionner

Structure NOTHING
EndStructure

Define.NOTHING

Structure PACKED4D ; structure permettant de précharger / lire des Doubles
  d0.d             ; le format est 4 x 64 = 256 bits.
  d1.d             ; Ce format correspond à un registre ymm
  d2.d
  d3.d
EndStructure

Structure PACKED4Q ; structure permettant de précharger / lire des Quads
  q0.q             ; format 4 x 64 = 256 bits compatible registres ymm.
  q1.q
  q2.q
  q3.q
EndStructure

Structure PACKED4x64 ; Structure fusionnée pour adresser soit en Double soit en Quad (Integer)
  StructureUnion
    P4D.PACKED4D
    P4Q.PACKED4Q
  EndStructureUnion
EndStructure

Vector1.PACKED4x64
Vector2.PACKED4x64
Results.PACKED4x64

res.d

Debug "Somme horizontale d'un vecteur AVX2"

  Vector1\P4D\d0 = Random(10, 1)
  Vector1\P4D\d1 = Random(10, 1)
  Vector1\P4D\d2 = Random(10, 1)
  Vector1\P4D\d3 = Random(10, 1)
  !  lea        r9, qword [v_Vector1]
  !  vmovupd    ymm0, yword [r9]
  !  vhaddpd    ymm2, ymm0, ymm0 ; r0 = ymm0\0 + ymm0\1, r1 = ymm0\0 + ymm0\1, r2 = ymm0\2 + ymm0\3, r3 = ymm0\2 + ymm0\3
  !  lea        r9, qword [v_Results]
  !  vmovupd    yword [r9], ymm2
  !  lea        r9, qword [v_Results] ; r0 + r2 = ymm0\0 + ymm0\1 + ymm0\2 + ymm0\3
  !  fld        qword [r9]
  !  fadd       qword [r9+24]
  !  fstp       qword [v_res]
  Debug StrD(Vector1\P4D\d0, 1) + #TAB$ + StrD(Vector1\P4D\d1, 1) + #TAB$ + StrD(Vector1\P4D\d2, 1) + #TAB$ + StrD(Vector1\P4D\d3, 1) + #TAB$ + StrD(res, 1)
  
Debug "Comparaison de deux vecteurs AVX2"
  
  Vector1\P4D\d0 = Random(10, 1)
  Vector1\P4D\d1 = Random(10, 1)
  Vector1\P4D\d2 = Random(10, 1)
  Vector1\P4D\d3 = Random(10, 1)
  Vector2\P4D\d0 = Random(10, 1)
  Vector2\P4D\d1 = Random(10, 1)
  Vector2\P4D\d2 = Random(10, 1)
  Vector2\P4D\d3 = Random(10, 1)
  !  lea        r9, qword [v_Vector1]
  !  vmovupd    ymm0, yword [r9]
  !  lea        r9, qword [v_Vector2]
  !  vmovupd    ymm1, yword [r9]
  !  vcmpeqpd   ymm2, ymm1, ymm0 ; eq. vcmppd ymm2, ymm1, ymm0, $0
  !  vmovupd    yword [v_Results], ymm2
  Debug #TAB$ + StrD(Vector1\P4D\d0, 1) + #TAB$ + StrD(Vector1\P4D\d1, 1) + #TAB$ + StrD(Vector1\P4D\d2, 1) + #TAB$ + StrD(Vector1\P4D\d3, 1) + #CRLF$ +
        #TAB$ + StrD(Vector2\P4D\d0, 1) + #TAB$ + StrD(Vector2\P4D\d1, 1) + #TAB$ + StrD(Vector2\P4D\d2, 1) + #TAB$ + StrD(Vector2\P4D\d3, 1) + #CRLF$ +
        "eq" + #TAB$ + Str(Results\P4Q\q0) + #TAB$ + Str(Results\P4Q\q1) + #TAB$ + Str(Results\P4Q\q2) + #TAB$ + Str(Results\P4Q\q3)
  !  vcmpltpd   ymm2, ymm1, ymm0 ; eq. vcmppd ymm2, ymm1, ymm0, $0
  !  vmovupd    yword [v_Results], ymm2
  Debug "lt" + #TAB$ + Str(Results\P4Q\q0) + #TAB$ + Str(Results\P4Q\q1) + #TAB$ + Str(Results\P4Q\q2) + #TAB$ + Str(Results\P4Q\q3)
  
  Debug "Distance entre deux points placés dans un vecteur AVX2"
  
  Vector1\P4D\d0 = Random(10, 1) ; x1
  Vector1\P4D\d1 = Random(10, 1) ; x2     la distance est sqr((x1 - x2)² + (y1 - y2)²)
  Vector1\P4D\d2 = Random(10, 1) ; y1
  Vector1\P4D\d3 = Random(10, 1) ; y2
  !  lea        r9, qword [v_Vector1]
  !  vmovupd    ymm0, yword [r9]
  !  vhsubpd    ymm1, ymm0, ymm0 ; r0 = ymm0\0 - ymm0\1, r1 = ymm0\0 - ymm0\1, r2 = ymm0\2 - ymm0\3, r3 = ymm0\2 - ymm0\3
  !  vmulpd     ymm2, ymm1, ymm1
  !  lea        r9, qword [v_Results]
  !  vmovupd    yword [r9], ymm2
  !  lea        r9, qword [v_Results] ; r0 + r2 = (ymm0\0 - ymm0\1)² + (ymm0\2 - ymm0\3)²
  !  fld        qword [r9]
  !  fadd       qword [r9+24]
  !  fsqrt
  !  fstp       qword [v_res]
  Debug StrD(Vector1\P4D\d0, 1) + #TAB$ + StrD(Vector1\P4D\d1, 1) + #TAB$ + StrD(Vector1\P4D\d2, 1) + #TAB$ + StrD(Vector1\P4D\d3, 1) + #TAB$ + StrD(res, 1) + #TAB$ + StrD(res * res, 1)
  Debug StrD(Results\P4D\d0, 1) + #TAB$ + StrD(Results\P4D\d1, 1) + #TAB$ + StrD(Results\P4D\d2, 1) + #TAB$ + StrD(Results\P4D\d3, 1)

CallDebugger
End
Mon avatar reproduit l'image de 4x1.8m présentée au 'Salon international du meuble de Paris' en janvier 2004, dans l'exposition 'Shades' réunisant 22 créateurs autour de Matt Sindall. L'original est un stratifié en 150 dpi.
Avatar de l’utilisateur
Ar-S
Messages : 9472
Inscription : dim. 09/oct./2005 16:51
Contact :

Re: Quelques idées pour aborder AVX2

Message par Ar-S »

Une petite mise en garde ... si t'aime pas l'assembleur, faut regarder ailleurs :)
On va aller voir ailleurs ensemble alors, dans la sections ASM par exemple :wink:
~~~~Règles du forum ~~~~
⋅.˳˳.⋅ॱ˙˙ॱ⋅.˳Ar-S ˳.⋅ॱ˙˙ॱ⋅.˳˳.⋅
W11x64 PB 6.x
Section HORS SUJET : ICI
LDV MULTIMEDIA : Dépannage informatique & mes Logiciels PB
UPLOAD D'IMAGES : Uploader des images de vos logiciels
Ollivier
Messages : 4190
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Re: Quelques idées pour aborder AVX2

Message par Ollivier »

@fweil

Ne pouvant récupérer ce source à l'instant, j'ai juste testé l'une des instructions au pif.

Code : Tout sélectionner

End
! vmovupd ymm0, [eax] ; oui "eax" :.je suis encore en 32 bits
Conclusion : Eh ben, ça marche ! Il y a quelque chose! Tu pousses au vice !
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Re: Quelques idées pour aborder AVX2

Message par djes »

C'est clair, il va nous pousser à faire des jeux dreamcast s'il continue :twisted:

Je plaisante, c'est passionnant, merci du partage :)
Ollivier
Messages : 4190
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Re: Quelques idées pour aborder AVX2

Message par Ollivier »

Quelqu'un avait évoqué les alignements mémoire pour que ce type d'instruction fonctionne correctement (instruction de transfert). Est-ce natif, ou bien faut-il le préciser en tête de "gondole"?
fweil
Messages : 505
Inscription : dim. 16/mai/2004 17:50
Localisation : Bayonne (64)
Contact :

Re: Quelques idées pour aborder AVX2

Message par fweil »

J'ai pas d'info fiable au sujet de l'alignement, mais les spécifications de codage indiquent (docs Intel) que certaines données doivent être alignées, et de quelle manière (bocs d'adresses alignés sur 8, 16, 32 octets).

Lorsque cela est imposé dans la programmation, on peut utiliser une instruction simple :

! align xx

où xx représente le nombre d'octets.

Les données en movupd, par exemple sont normalement non alignées (le u de movupd indique unaligned data). Si aux tests d'une séquence de code on constate que ça embrouille entre les données qu'on propose et celles qui sont dans les registres ou en mémoire après un mov, il y a potentiellement un problème d'alignement.

Si les déclarations de tableaux sont faites depuis PureBasic, ou les datas, je pense que le compilateur PB effectue les alignements nécessaires pour un bon partitionnement des données. Mais ça reste un point à vérifier.
Mon avatar reproduit l'image de 4x1.8m présentée au 'Salon international du meuble de Paris' en janvier 2004, dans l'exposition 'Shades' réunisant 22 créateurs autour de Matt Sindall. L'original est un stratifié en 150 dpi.
Répondre