3 points par GN⁺ 2024-07-29 | 1 commentaires | Partager sur WhatsApp
  • Le SMT est une technique par laquelle un même cœur CPU émet des instructions de plusieurs threads au cours d’un même cycle afin de mieux remplir les ressources d’exécution qui resteraient inutilisées avec le seul parallélisme au niveau des instructions
  • Le Hyper-Threading d’Intel est une implémentation à deux threads par cœur : l’état architectural est dupliqué, ce qui fait qu’un cœur physique apparaît au système d’exploitation comme deux processeurs logiques
  • Dans l’implémentation réelle, toutes les ressources ne sont pas simplement doublées : le pointeur d’instruction, l’ITLB et la RAT sont dupliqués, le trace cache et le TLB sont partagés, tandis que la uop queue, les registres physiques et le reorder buffer sont répartis à parts égales
  • Le gain de performances varie selon la charge : si les deux threads se disputent agressivement le cache, les performances peuvent baisser ; à l’inverse, des threads coopératifs qui s’échangent des données peuvent aller plus vite grâce au cache partagé
  • Les ressources partagées et l’exécution spéculative peuvent aussi mener à des vulnérabilités de sécurité ; dans les environnements sensibles ou pour les charges qui exigent des performances maximales et une latence minimale, la désactivation du SMT devient une option réaliste

Pourquoi le SMT est nécessaire

  • Les processeurs modernes disposent de centaines de registres, de plusieurs unités de chargement/stockage et d’unités arithmétiques, et utilisent pour les exploiter des techniques de parallélisme au niveau des instructions comme le pipeline, l’architecture superscalaire et l’exécution dans le désordre
  • Le pipeline découpe l’exécution des instructions en plusieurs étapes et fait passer les instructions à l’étape suivante à chaque cycle ; avec un pipeline de profondeur 5, jusqu’à 5 instructions peuvent progresser simultanément à partir du 5e cycle
  • Un processeur superscalaire peut émettre plusieurs instructions par cycle, et les récents Intel Core i7 peuvent en émettre 4 par cycle
  • Dans les programmes réels, il est difficile de trouver suffisamment d’instructions indépendantes, ce qui laisse parfois des ressources d’exécution inoccupées
    • Le gaspillage horizontal se produit lorsqu’un thread ne contient pas assez d’instructions indépendantes pour remplir l’issue width
    • Le gaspillage vertical se produit lorsque les instructions suivantes dépendent de celles en cours d’exécution et qu’aucune instruction ne peut être émise pendant un cycle
  • Le multithreading traditionnel n’émet que les instructions d’un seul thread par cycle et bascule vers un autre au cycle suivant, ce qui peut réduire le gaspillage vertical, mais laisse subsister le gaspillage horizontal et le surcoût des changements de contexte
  • Le SMT émet des instructions de plusieurs threads dans un même cycle, sans changement de contexte, pour remplir plus efficacement les ressources d’exécution
  • L’implémentation SMT d’Intel, Hyper-Threading, est limitée à deux threads par cœur

Structure de base du SMT à la manière d’Intel

  • Un processeur classique non-SMT ne peut exécuter à un instant donné que les instructions d’un seul thread
  • Chaque thread possède un état architectural comprenant les valeurs des registres, le compteur ordinal, les registres de contrôle, etc.
  • Pour exécuter simultanément les instructions de deux threads, il faut pouvoir représenter en même temps l’état des deux threads ; une implémentation SMT duplique donc l’état architectural du processeur
  • À cause de cette duplication, un processeur physique apparaît au système d’exploitation comme deux processeurs logiques, et l’OS peut y planifier des threads séparément
  • Les buffers et ressources d’exécution au niveau microarchitectural sont dupliqués, partagés ou partitionnés selon des critères de coût, de consommation électrique et de surface de puce
  • La discussion porte principalement sur l’implémentation SMT d’Intel et s’appuie sur un livre blanc Intel de 2002

Les trois parties de la microarchitecture CPU

  • Le processeur expose au programmeur l’ISA comme interface publique ; l’ISA comprend le jeu d’instructions et les registres utilisables par ces instructions
  • La microarchitecture est l’implémentation interne, qui peut varier entre des modèles de processeurs prenant en charge la même ISA
  • La microarchitecture d’un processeur moderne se divise globalement en trois parties
    • Front-end : comprend l’unité de contrôle des instructions qui va chercher et décode les prochaines instructions du programme
    • Back-end : comprend les ressources d’exécution comme les registres physiques, les unités arithmétiques et les unités de chargement/stockage, puis alloue ces ressources aux instructions décodées et planifie leur exécution
    • retirement unit : applique définitivement à l’état architectural du processeur les résultats des instructions exécutées

Le SMT dans le front-end

  • Le pointeur d’instruction suit l’adresse de la prochaine instruction à aller chercher
    • Un processeur compatible SMT possède deux jeux de pointeurs d’instruction afin de suivre indépendamment les prochaines instructions des deux programmes
  • Le trace cache stocke les traces d’instructions récemment décodées afin de réduire le coût de décodage et la latence d’exécution des instructions répétitives
    • Il est partagé dynamiquement entre les deux processeurs logiques selon les besoins
    • Si un thread exécute davantage d’instructions, il peut occuper plus d’entrées du trace cache
    • Chaque entrée est étiquetée avec des informations de thread afin de distinguer les instructions des deux threads
    • L’accès au trace cache est arbitré à chaque cycle entre les deux processeurs logiques
  • En cas de miss dans le trace cache, le front-end cherche les instructions à cette adresse dans le cache d’instructions L1 ; en cas de miss dans ce cache L1, il faut aller les chercher dans le niveau de cache suivant ou dans la mémoire principale
  • Le cache d’instructions L1 met les données en cache à partir d’adresses virtuelles, mais l’accès à la mémoire principale nécessite des adresses physiques
  • L’ITLB traduit les adresses virtuelles en adresses physiques en conservant les traductions récentes
    • Dans un processeur compatible SMT, chaque processeur logique dispose de son propre cache ITLB
    • La logique de récupération des instructions depuis la mémoire principale fonctionne en mode first come first served, mais réserve au moins un slot de requête à chaque processeur logique pour permettre aux deux de progresser
    • Les instructions arrivant de la mémoire principale sont stockées avant décodage dans un petit streaming buffer, lui aussi dupliqué par processeur logique dans un processeur compatible SMT
  • Une fois récupérées, les instructions sont décodées en uop plus petites et plus simples
    • Les uop entrent dans la uop queue, qui sert de frontière entre le front-end et le back-end du CPU
    • La uop queue est partagée à parts égales entre les deux processeurs logiques, cette partition statique permettant à chacun de progresser indépendamment

Le SMT dans le back-end

  • Le back-end récupère les micro-instructions depuis la uop queue et les exécute, sans se limiter strictement à l’ordre original du programme, grâce à l’exécution dans le désordre
  • Les instructions proches dans le programme dépendent souvent les unes des autres, et une opération à forte latence comme une lecture en mémoire principale peut bloquer les instructions dépendantes
  • Le moteur d’exécution dans le désordre exécute des instructions plus lointaines avant leur ordre initial afin de réduire le gaspillage des ressources
  • L’allocator identifie les ressources nécessaires à chaque micro-instruction et les alloue selon leur disponibilité
    • Sur un cycle, il alloue des ressources aux micro-instructions d’un processeur logique, puis passe à l’autre au cycle suivant
    • Si la uop queue ne contient que des micro-instructions d’un seul processeur logique, ou si un processeur logique a épuisé toute sa part de ressources, l’allocator utilise tous les cycles pour l’autre processeur logique
  • Les ressources principales du back-end mélangent duplication, partage et partitionnement
    • Au niveau ISA, le X86-64 ne possède que 16 registres entiers généraux, mais au niveau microarchitectural on trouve des centaines de registres entiers physiques et un nombre comparable de registres en virgule flottante
    • Dans un processeur compatible SMT, les registres physiques sont répartis à parts égales entre les deux processeurs logiques
    • Les load buffer et store buffer utilisés pour les opérations de lecture et d’écriture mémoire sont eux aussi répartis à parts égales entre les deux processeurs logiques

Renommage de registres, scheduling et commit

  • Pour permettre l’exécution dans le désordre, le back-end effectue un renommage de registres
    • Au niveau ISA, il y a peu de registres architecturaux, si bien que les instructions du programme réutilisent souvent les mêmes registres dans plusieurs instructions indépendantes
    • Le moteur d’exécution dans le désordre remplace alors un registre logique d’origine par l’un des registres physiques afin de permettre une exécution plus précoce et parallèle
    • Cette correspondance est maintenue dans la register alias table, ou RAT
    • Comme les deux processeurs logiques possèdent chacun leur propre ensemble de registres architecturaux, la RAT existe aussi en une copie distincte pour chacun
  • Les instructions passées par les étapes de register renaming et d’allocation entrent dans des ready queues
    • L’une est destinée aux instructions de lecture/écriture mémoire, l’autre aux instructions générales
    • Dans un cœur compatible SMT, ces files sont réparties à parts égales entre les deux processeurs logiques
  • Le processeur possède plusieurs instruction schedulers en parallèle
    • À chaque cycle CPU, une partie des instructions des ready queues est envoyée vers les schedulers
    • Les files envoient les instructions d’un processeur logique pendant un cycle, puis de l’autre au cycle suivant
    • Le scheduler ne tient pas compte du processeur logique : il envoie immédiatement à l’exécution les micro-instructions dont les opérandes requis et l’unité d’exécution sont disponibles
    • Pour garantir l’équité, il existe une limite au nombre d’entrées actives qu’un processeur logique peut occuper dans la scheduler queue
  • Les résultats des instructions exécutées entrent dans le reorder buffer
    • Même si les instructions s’exécutent dans le désordre, elles doivent être validées dans l’état architectural du processeur selon l’ordre original du programme
    • Dans un cœur compatible SMT, le reorder buffer est réparti à parts égales entre les deux processeurs logiques
  • La retirement unit suit quelles instructions sont prêtes à être validées dans l’état architectural et les retire dans le bon ordre du programme
    • Dans un cœur compatible SMT, elle alterne entre les micro-instructions de chaque processeur logique
    • Si un processeur logique n’a aucune micro-instruction à retirer, toute la bande passante est utilisée par l’autre
    • Après le retrait d’une instruction, il peut être nécessaire d’écrire dans le cache L1 ; la logique de sélection pour ces écritures alterne elle aussi entre les deux processeurs logiques à chaque cycle

Sous-système mémoire et impact du cache

  • Le TLB qui convertit les adresses virtuelles des requêtes de données en adresses physiques est partagé dynamiquement entre les deux processeurs logiques selon les besoins
  • Les entrées du TLB sont étiquetées avec l’identifiant du processeur logique pour distinguer les éléments appartenant à chacun
  • Chaque cœur CPU dispose de son propre cache L1 privé
  • Le cache L2 peut être privé ou partagé entre cœurs selon la microarchitecture
  • S’il existe un cache L3, il est partagé entre les cœurs
  • Les caches n’ont pas conscience de l’existence des processeurs logiques
  • Comme le cache L1, et parfois le cache L2, est privé au cœur, il peut contenir les données des deux processeurs logiques selon les besoins
    • Si deux threads utilisent le cache de manière agressive, des conflits de données et des évictions peuvent se produire et dégrader les performances
    • Si deux threads travaillent sur le même jeu de données, le cache partagé peut au contraire améliorer les performances

Critères de choix entre performances et sécurité

  • Même lorsqu’un seul thread s’exécute sur un cœur compatible SMT, de nombreux buffers et ressources d’exécution restent partagés ou partitionnés entre les deux processeurs logiques, ce qui peut réduire les performances potentielles du thread unique
  • Sur le processeur logique inutilisé, le système d’exploitation exécute une idle loop, qui peut elle aussi consommer des ressources que l’autre processeur logique pourrait employer pour atteindre ses performances maximales
  • Sur les processeurs Intel Core, lorsqu’un seul thread s’exécute sur un cœur, il semble qu’il n’y ait pas de partage ni de partitionnement des ressources ; Intel présente cela comme une amélioration introduite dans cette génération
  • Lorsque deux threads s’exécutent sur les deux processeurs logiques d’un cœur compatible SMT, les motifs d’accès au cache deviennent déterminants pour les performances
    • Si les deux threads se disputent le cache, ils peuvent évincer mutuellement leurs données et faire baisser les performances
    • S’ils coopèrent, par exemple lorsqu’un thread consomme des données produites par l’autre, le partage des données en cache peut améliorer les performances
    • Si les deux threads n’entrent pas en concurrence pour le cache, ils peuvent augmenter le taux d’utilisation des ressources du cœur CPU sans nuire aux performances de l’autre
  • Pour les programmes qui exigent une performance absolue maximale, de nombreux experts estiment qu’il vaut mieux désactiver le SMT afin qu’un seul thread puisse utiliser toutes les ressources
  • Le SMT s’accompagne aussi de problèmes de sécurité
    • En raison des ressources partagées et de l’exécution spéculative, il peut exister un risque de fuite de données sensibles vers un attaquant
    • La documentation d’Oracle Linux et de Red Hat renvoie à des exemples de problèmes de sécurité liés au SMT
    • La recommandation générale est souvent de désactiver le SMT sur le système
    • Il circule aussi des rumeurs selon lesquelles Intel pourrait supprimer Hyper-Threading sur sa prochaine génération de processeurs, Arrow Lake

Références

1 commentaires

 
GN⁺ 2024-07-29
Réactions sur Hacker News
  • Pour comprendre le SMT de façon très simplifiée, l’idée qui parle le plus est que pendant qu’un thread est bloqué par un cache miss, on peut garder occupée la précieuse ALU
    La LPDDR des anciens laptops était plus lente et il y avait moins de cœurs, donc cela devait avoir plus de valeur, mais aujourd’hui on a souvent plus de cœurs que de tâches réellement parallélisables, donc l’intérêt se ressent moins
    On évite aussi la contention du cache en ne plaçant pas des tâches sur le même cœur qu’un thread important, parce qu’on sait que le goulet d’étranglement est la performance en single-thread
    J’ai autrefois testé les cœurs Efficient/Performance et les cœurs SMT sur le rendu multithread de DirectX 12, et sur un i7-12700K, les temps de rendu de scènes complexes étaient presque identiques entre P-core seuls, P+SMT et P+E+SMT. En revanche, sur Xbox Series X, le même test était légèrement plus rapide quand on plaçait aussi des tâches sur le SMT

    • Le rendu a toujours fait partie des scénarios où le SMT est au mieux équivalent, au pire plus lent. Il y a déjà beaucoup de calculs mathématiques, donc la FPU est en permanence occupée, et en particulier les unités de division comptent parmi les opérations les plus coûteuses du processeur
      Le SMT brille lorsqu’on attend des E/S ou qu’on effectue des opérations entières simples. Si les deux threads peuvent saturer la FPU, alors le SMT est généralement plus lent à cause du surcoût de marquage supplémentaire nécessaire pour associer les données internes du CPU à chaque thread
    • Le Hyper-Threading d’Intel s’apparente en réalité surtout à un hack du pipeline d’écriture
      Le point clé n’est pas tant le cache miss que le fait de permettre au cœur d’exécuter autre chose pendant qu’une écriture se termine
      C’est pour cela que certains codes se parallélisent mal, tandis que d’autres obtiennent des gains de vitesse presque linéaires
    • De nos jours, surtout avec l’alimentation arrière en tête, je me demande dans quelle mesure les arrêts cache d’un processeur réduisent le thermal throttling de ce processeur et des processeurs voisins
      Il vaudrait peut-être mieux laisser ce type de processeurs faire de brèves siestes de temps en temps
    • Concernant l’idée que la LPDDR était plus lente autrefois, curieusement la latence ne s’est pas beaucoup améliorée. La latence CAS des DDR2/3/4/5 se situe généralement autour de 5 à 10 ns
      La largeur de bus, le nombre de transferts par seconde, la mise en file d’attente, ainsi que l’énergie par bit transféré ou stocké se sont améliorés, mais si le programme a besoin de données absentes du cache et que la prédiction échoue, c’est au final la latence de la RAM qui pose problème
    • Je me demande si, au lieu du SMT, on ne pourrait pas aller vers une approche qui coupe brièvement les ALU/FPU inutilisées pendant qu’on attend quelque chose à l’avant du pipeline, afin de réduire la chaleur et la consommation électrique plutôt que de maximiser l’utilisation
  • Le CPU Arrow Lake de nouvelle génération d’Intel devrait supprimer totalement le Hyper-Threading, c’est-à-dire le SMT
    Les gains de performance ont toujours beaucoup dépendu des applications, donc simplifier est peut-être préférable
    Une discussion récente sur les cas où cela a du sens se trouve ici : https://news.ycombinator.com/item?id=39097124

    • La plupart des programmes finissent par rencontrer une limite au nombre de threads qu’ils peuvent utiliser de façon raisonnable. Quand on a bien moins de cœurs que cela, le SMT a du sens pour mieux exploiter les ressources CPU, mais à partir du moment où l’on dispose de suffisamment de cœurs, le SMT peut ne plus avoir beaucoup de sens
      Je ne suis pas encore certain qu’on soit forcément déjà à ce point, mais les P/E cores d’Intel sont une alternative visant un objectif proche, et c’est assez raisonnable sur les desktops où dominent les charges single-thread ou faiblement parallèles. Il semble aussi y avoir un intérêt à ne pas avoir à gérer la distinction entre SMT et E-core dans l’optimisation des applications
      À l’inverse, AMD prévoit pour l’instant de conserver des cœurs largement homogènes et de continuer à utiliser le SMT. La meilleure stratégie dépend probablement tellement des applications qu’il est difficile d’en juger simplement
    • Dans mon usage personnel de développement de jeux et de moteurs, il était plus rapide de prier le dieu de l’affectation des threads CPU pour que chaque thread ait son propre cœur que de compter sur le Hyper-Threading
      J’ai donc décidé de limiter le nombre de threads à std::thread::hardware_concurrency() / 2 - 1, c’est-à-dire nombre de cœurs - 1. Je manipule des std::vector
    • Selon les benchmarks couramment utilisés dans l’industrie, le Hyper-Threading d’Intel a été au moins une génération sur deux plus lent que le fait de le désactiver
      Même quand cela fonctionnait bien, les gains se limitaient à peine à quelques dizaines de pourcents, et il y a eu des générations consécutives où c’était pire, donc je ne comprends pas pourquoi ils continuent d’insister
    • Est-ce aussi le cas pour les composants serveur ?
  • Je suis toujours impressionné en lisant comment fonctionnent ces fonctionnalités CPU de bas niveau
    À l’université, j’ai suivi un cours qui ressemblait à une « introduction au matériel informatique », mais en réalité on aurait plutôt dû l’appeler « introduction à la conception de CPU ». On y fabriquait des additionneurs, des verrous, des bascules, etc. à partir de portes logiques, puis en fin de semestre on pouvait concevoir un processeur très basique au niveau des portes
    Mais imaginer ou inventer des choses comme le renommage de registres ou l’exécution out-of-order dépasse mon imagination. Est-ce qu’on conçoit aussi cela au niveau des portes ? Ou bien existe-t-il un « compilateur » qui part du langage utilisé et place les portes et les transistors ?

    • J’ai suivi le cours d’après, et on y a appris le SMT ainsi que quelques autres sujets
      Tous les exercices se faisaient en Verilog, un langage de description matérielle, ce qui permettait d’écrire en abstrahant plusieurs éléments
  • L’un des grands malentendus fréquents chez les utilisateurs à propos du SMT est le modèle mental qui imagine un « vrai cœur » et un autre cœur inférieur
    Dans tous les aspects observables, les deux threads sont équivalents

    • Cette perception vient sans doute des performances. Les deux threads peuvent exécuter le même type de travail, mais on n’obtient pas une performance multipliée par deux comme avec un vrai second thread, c’est-à-dire un second cœur
      Au final, si l’on regarde uniquement la performance, cela ressemble conceptuellement davantage à 1,25 cœur single-thread, ou à quelque chose de cet ordre selon l’application
    • Quand on lance une tâche très optimisée et très gourmande en calculs comme l’encodage vidéo, que les ventilateurs de l’ordinateur hurlent comme des réacteurs et que le gestionnaire des tâches affiche 50 % d’utilisation CPU, ce genre de perception est assez compréhensible
    • Les nouveaux CPU d’Intel ont effectivement à la fois de vrais cœurs « P-core » et des cœurs inférieurs « E-core »
      À mon avis, la raison principale de l’introduction des E-core n’est pas tant la consommation électrique ou la performance que la chaleur et la surface de die. C’est pourquoi j’achète toujours des puces sans E-core, que je considère meilleures
  • Je me demande comment rechercher ce genre d’articles techniques détaillés.
    J’ai cherché ce sujet précis, mais comme on pouvait s’y attendre, puisqu’il s’agit d’une technique destinée aux utilisateurs finaux, les résultats ne contenaient que des articles pour utilisateurs qui n’expliquaient rien correctement.

    • Il suffit d’utiliser https://hn.algolia.com. En partant du principe que la plupart des articles de ce type sont publiés ou mentionnés sur HN.
    • Les LLM avec accès au web semblent assez bien adaptés à ce type de recherche. Au moins pour trouver une direction.
      En revanche, les URL qu’ils fournissent sont le plus souvent des hallucinations.
    • Je ne sais pas si Google suit le pic d’intérêt pour cet article HN à cause de ce billet, mais en cherchant « how does simultaneous multi threading work », ce billet de blog apparaît pour moi vers le 5e résultat.
      J’ai vérifié dans un nouvel onglet privé Firefox sur un autre appareil ; ça n’élimine sans doute pas complètement le suivi ni le cache, mais ça me paraît une approximation assez raisonnable.
  • L’explication selon laquelle « sur un cœur CPU avec le SMT activé, de nombreux buffers et ressources d’exécution doivent être partagés entre deux processeurs logiques, donc même lorsqu’un seul thread s’exécute sur un cœur SMT, ces ressources ne sont pas disponibles pour ce thread et les performances potentielles diminuent » n’est plus vraie aujourd’hui.
    En mode SMT, on partitionne le ROB, la bande passante de fetch/decode, etc., mais j’ai vu plusieurs cœurs SMT qui permettent d’utiliser l’ensemble de ces ressources lorsqu’on n’est pas en SMT.

    • Les processeurs Phi de la série x200 fonctionnent exactement ainsi. En mode non-SMT, ils disposent de bien plus de ressources par thread qu’en mode SMT à 4 voies.
  • L’objectif central du SMT est de maximiser le taux d’utilisation du moteur d’exécution superscalaire.
    Je me demande si ce discours signifie que les gens pensent que le superscalaire n’est plus aussi important qu’avant.

  • Dans l’ensemble, bon résumé, mais j’ai eu l’impression que certains points étaient un peu mélangés par endroits.
    J’aimerais en savoir davantage sur les astuces métier qu’utilisent les gens du secteur, même hors du périmètre lié à la sécurité.

  • Le pauvre Bulldozer d’AMD s’est tellement fait critiquer pour son absence de SMT, et maintenant tout le monde s’éloigne du SMT.
    Bien sûr, je sais que Bulldozer avait bien plus de problèmes que la seule absence de SMT. En réalité, sa structure était presque l’inverse, avec plusieurs cœurs partageant la même ALU et d’autres éléments du genre. Cela dit, s’ils avaient réussi à en tirer un peu plus de performances, on pourrait presque dire qu’ils avaient vu quelque chose avant les autres.

    • L’architecture PowerXX ne s’éloigne pas du SMT.
      Power10 prend actuellement en charge de manière efficace le SMT8, soit 8 threads par cœur, et vu les années d’efforts consacrés à faire évoluer une conception centrée sur le SMT, il paraît peu probable qu’ils l’abandonnent.
  • Point utile à connaître : les unités de calcul des GPU utilisent elles aussi généralement une forme de SMT, à raison d’environ 7 à 10 threads par CU.
    Cette approche aide à masquer la latence.

    • La plupart des GPU n’utilisent pas le SMT, mais son prédécesseur, le multithreading finement entrelacé.
      À chaque cycle d’horloge, ils choisissent parmi plusieurs threads disponibles une instruction appartenant à un thread qui demande des ressources non occupées, puis la lancent. La plupart des GPU ne lancent pas plusieurs instructions par cycle, même si plusieurs instructions peuvent progresser en parallèle une fois lancées. Même lorsqu’ils lancent plusieurs instructions par cycle, il peut s’agir de classes d’instructions distinctes utilisant des ressources d’exécution différentes, comme les instructions scalaires et vectorielles.
      Le SMT, c’est-à-dire le multithreading simultané, consiste à lancer à chaque cycle d’horloge de nombreuses instructions issues de tous les threads en même temps, ces instructions entrant en concurrence pour les différentes unités d’exécution d’un CPU superscalaire afin de maintenir occupé le plus grand nombre possible d’unités d’exécution. Pour chaque unité d’exécution parallèle, comme chacun des 6 additionneurs entiers d’un CPU moderne, la décision de savoir quelle instruction exécuter est prise séparément à partir d’une file contenant les instructions de tous les threads simultanés.