SIMD vs SIMT : modèle d’exécution, branchements, mémoire

SIMD et SIMT appliquent tous deux la même opération à de nombreuses données avec une seule instruction, mais ils se présentent différemment au programme. Le SIMD correspond aux instructions vectorielles des CPU : le programmeur ou le compilateur range les données dans des registres vectoriels de largeur fixe et utilise explicitement ces instructions. Le SIMT est l’approche des GPU : on écrit simplement le traitement d’un thread, et le matériel regroupe par exemple 32 threads en un warp exécuté avec la même instruction. On peut écrire des branchements par thread, mais lorsque les chemins divergent au sein d’un warp, les deux chemins sont exécutés l’un après l’autre et l’efficacité baisse.

CritèreSIMDSIMT
Modèle d’exécutionUne instruction traite simultanément plusieurs éléments rangés dans un registre vectorielUne instruction est exécutée simultanément par de nombreux threads regroupés en un warp. Chaque thread possède ses propres registres
Vue du programmeOn écrit en tenant compte de la largeur des vecteurs, avec des intrinsèques, de l’assembleur ou la vectorisation automatique du compilateurOn écrit le traitement d’un thread comme du code scalaire. Le regroupement est fait par le matériel
Largeur parallèleFixée par la largeur des registres. Par exemple 16 nombres de 32 bits pour 512 bitsLa largeur du warp (32 threads, par exemple). La puce entière maintient des dizaines de milliers de threads simultanément
BranchementsPas de branchement par élément. On calcule les deux côtés et on choisit avec un masque issu d’une comparaisonPossibles par thread. Si les chemins divergent dans un warp, les deux chemins sont exécutés successivement et les threads non concernés sont mis en pause (divergence)
Gestion des éléments actifsExplicite, par le programmeur ou le compilateur, avec des instructions masquées ou de mélange (blend)Le matériel gère automatiquement les threads actifs
Accès mémoireEfficace pour lire ensemble des adresses contiguës. Les adresses dispersées passent par des instructions gather/scatter, mais c’est lentChaque thread peut désigner librement une adresse. Si des threads voisins lisent des adresses voisines, les accès sont regroupés (coalescence)
Masquage de la latence mémoireGrands caches, exécution dans le désordre, préchargementBasculement entre de nombreux warps : pendant qu’un warp attend, un autre s’exécute
Place dans la taxonomie de FlynnLe SIMD lui-mêmeUne forme de SIMD présentée sous forme de threads
Usages typiquesInstructions vectorielles des CPU. Boucles de traitement d’image et de son, de cryptographie et de calcul matricielWarps des GPU. Calcul massivement parallèle : graphisme, entraînement et inférence d’IA, calcul scientifique

Les valeurs indiquées sont des ordres de grandeur typiques et varient selon la génération de procédé et le produit.

Quand choisir l'un ou l'autre ?

SIMD
Pour accélérer sur CPU une boucle qui applique le même calcul à chaque élément d’un tableau. Le gain est important lorsque les données sont contiguës et qu’il n’y a pas de dépendance entre itérations ; la vectorisation automatique du compilateur permet aussi d’en profiter.
SIMT
Calcul massivement parallèle appliquant le même traitement à des milliers ou des millions d’éléments indépendants. Sur GPU, on écrit et exécute un programme par thread. L’efficacité augmente si les branchements et les adresses mémoire sont alignés au sein de chaque warp.
Ensemble
Dans un GPU, l’exécution SIMT par warp s’effectue sur des unités de calcul SIMD. Dans les systèmes qui associent CPU et GPU, le CPU se charge du prétraitement et du contrôle avec le SIMD, et le GPU des grands calculs parallèles.

Questions fréquentes

Le SIMT est-il un mécanisme totalement différent du SIMD ?

Dans le matériel, les deux mécanismes sont proches. Chaque thread d’un warp correspond à une voie d’une unité de calcul SIMD et s’exécute avec la même instruction. La différence tient à la présentation : en SIMT, le matériel gère les registres, les adresses et les branchements de chaque thread, si bien que le programmeur peut écrire sans se soucier de la largeur des vecteurs.

Comment réduire la divergence des warps ?

En faisant en sorte que les threads d’un même warp empruntent autant que possible le même côté d’un branchement. On peut par exemple réordonner les données pour que les résultats de la condition soient homogènes, attribuer les numéros de thread de façon que la condition change par warp entier, ou remplacer les branchements courts par des opérations de sélection.

Comment écrire en SIMD un traitement contenant un if ?

Une instruction de comparaison transforme la condition de chaque élément en masque ; on calcule les deux résultats, puis on choisit élément par élément selon le masque. Avec un jeu d’instructions disposant d’instructions masquées, on peut ne calculer et ne ranger que les éléments qui satisfont la condition. Comme les deux chemins sont calculés, l’efficacité baisse si le branchement est lourd, ce qui rappelle la divergence en SIMT.

Quand la vectorisation automatique du compilateur échoue-t-elle ?

Par exemple lorsqu’il existe des dépendances entre itérations (un résultat est réutilisé à l’itération suivante), lorsque des pointeurs peuvent désigner la même zone, lorsque les données ne sont pas contiguës ou lorsque la boucle contient des branchements complexes ou des appels de fonction. Indiquer au compilateur l’absence de dépendance ou modifier l’agencement des données permet parfois de vectoriser.

Vérifier vos connaissances

Quel mode de traitement applique simultanément une même opération à plusieurs données au moyen d'une seule instruction ?

  1. ASISD
  2. BSIMD
  3. CMISD
Afficher la réponse et l'explication

Réponse : B. SIMD

Le SIMD applique en parallèle une même opération à plusieurs données par une seule instruction ; par exemple, un registre de 512 bits permet de traiter seize nombres de 32 bits à la fois. Il existe notamment SSE et AVX sur x86, NEON et SVE sur ARM, qui apportent des accélérations de plusieurs fois ou plus en traitement d'image, compression vidéo ou calcul matriciel. La taxonomie de Flynn comprend aussi le SISD (traitement séquentiel ordinaire) et le MIMD (multicœur).

Comment appelle-t-on, sur les GPU NVIDIA, l'unité regroupant 32 threads qui exécutent simultanément la même instruction ?

  1. AWarp
  2. BGrille
  3. CPage
Afficher la réponse et l'explication

Réponse : A. Warp

Dans le matériel, les threads d'un bloc sont répartis en warps de 32, et les 32 threads d'un warp exécutent la même instruction simultanément sur des données différentes. Ce mode, qui regroupe un programme écrit sous forme de threads pour l'exécuter avec une même instruction, s'appelle SIMT. Sur les GPU AMD, l'unité équivalente s'appelle wavefront et compte 64 ou 32 threads. La taille de bloc doit en principe être un multiple de 32.

Quelle est la différence entre le mode SIMT (instruction unique, threads multiples) des GPU et les instructions SIMD des CPU ?

  1. ALe SIMT applique simultanément plusieurs instructions à une donnée, le SIMD une instruction à une donnée
  2. BSIMT et SIMD sont strictement identiques, seul le nom diffère
  3. CEn SIMT, chaque thread s'écrit comme un programme indépendant et le matériel gère les branchements, alors qu'en SIMD le programmeur ou le compilateur utilise explicitement des instructions vectorielles de largeur fixe
Afficher la réponse et l'explication

Réponse : C. En SIMT, chaque thread s'écrit comme un programme indépendant et le matériel gère les branchements, alors qu'en SIMD le programmeur ou le compilateur utilise explicitement des instructions vectorielles de largeur fixe

En SIMD sur CPU, une instruction s'applique à un registre vectoriel regroupant 4 ou 8 données ; le programme est donc écrit en tenant compte de la largeur du vecteur. En SIMT sur GPU, le programmeur écrit normalement le traitement d'un seul thread, et le matériel regroupe les threads par 32 pour les exécuter avec la même instruction. Les branchements par thread sont permis : le matériel exécute successivement les chemins divergents, mais l'efficacité baisse alors.

  1. Dans un warp, un branchement conditionnel envoie la moitié des threads dans la branche if et l'autre moitié dans la branche else (divergence de warp). Comment l'exécution se déroule-t-elle généralement ?
  2. Quelle est la définition de l'accès mémoire coalescé (coalescing) sur GPU ?
  3. Quel type d'instructions la vectorisation automatique du compilateur utilise-t-elle ?

Questions d'entraînement sur Programmation GPU

Termes clés expliqués

SIMD
Abréviation de Single Instruction, Multiple Data. Mode où une seule instruction applique la même opération à plusieurs données à la fois. Accélère le traitement d'images et les calculs d'IA.
SIMT
Modèle « une instruction, plusieurs threads ». Le programme est écrit par thread, mais le matériel regroupe les threads en warps (32 chez NVIDIA) exécutant la même instruction.
Divergence de warp
Situation où, dans un même warp, les threads suivent des chemins différents à cause d'un branchement conditionnel. Les chemins étant exécutés l'un après l'autre, l'efficacité diminue.
Coalescence mémoire
Regroupement en un petit nombre d'accès mémoire des accès de threads voisins d'un warp à des adresses voisines. Aussi appelé accès coalescé.
Vectorisation
Optimisation qui transforme un même calcul effectué élément par élément dans une boucle en un traitement de plusieurs éléments à la fois par instructions SIMD. Elle exige l'absence de dépendances de données entre itérations.

Comparatifs associés