Processeurs parallèles et multicœurs

Découvre pourquoi les processeurs sont devenus parallèles et comment les ordinateurs actuels répartissent le travail simultanément entre de nombreuses unités. Compare le parallélisme au niveau des instructions, des données, des threads et des requêtes, classe les machines selon la classification de Flynn et calcule les limites de l’accélération avec les lois d’Amdahl et de Gustafson et le modèle Roofline. Découvre comment les instructions SIMD et vectorielles, les GPU, les puces multicœurs à caches cohérents, les grappes de calcul et les ordinateurs à l’échelle d’un entrepôt utilisent chacun le matériel parallèle pour calculer plus vite ou à moindre coût, à l’aide d’exemples que tu peux vérifier à la main.

IntermédiaireUnité 6 sur 6 de la formation Formation : Architecture informatique : processeur, mémoire et RISC-V

Ce que tu vas apprendre

  1. Explique pourquoi les processeurs sont devenus parallèles, distingue le parallélisme au niveau des instructions, des données, des threads et des requêtes, classe les machines selon la classification de Flynn et décris comment le multithreading matériel maintient un cœur occupé.
    • Explique pourquoi les ordinateurs sont devenus parallèles et nomme les formes de parallélisme
      Relie le mur de puissance au passage aux puces multicœurs et repère le parallélisme au niveau des instructions, des données, des threads et des requêtes dans des programmes réels.
    • Classe les architectures matérielles parallèles selon la classification de Flynn
      Utilise le nombre de flux d’instructions et de flux de données pour classer une machine dans SISD, SIMD, MISD ou MIMD, et explique le style de programmation SPMD.
    • Maintiens un cœur occupé grâce au multithreading matériel
      Explique comment le multithreading à grain fin, à gros grain et simultané masque les blocages, et en quoi les threads matériels diffèrent de cœurs supplémentaires.
  2. Calcule l’accélération et l’efficacité, applique les lois d’Amdahl et de Gustafson, tiens compte du déséquilibre de charge et du surcoût, et utilise le modèle Roofline pour déterminer si un programme est limité par le calcul ou par la bande passante mémoire.
    • Calcule l’accélération et l’efficacité avec la loi d’Amdahl
      Définis l’accélération et l’efficacité, applique la loi d’Amdahl dans les deux sens et explique pourquoi la fraction séquentielle limite l’accélération d’un problème de taille fixe.
    • Distingue le passage à l’échelle fort du passage à l’échelle faible et tiens compte des surcoûts
      Compare l’accélération pour une taille fixe et pour une taille croissante, applique la loi de Gustafson et estime l’effet du déséquilibre de charge, de la communication et de la synchronisation.
    • Détermine une borne de performance avec le modèle Roofline
      Calcule l’intensité arithmétique, lis un modèle Roofline pour déterminer si un noyau de calcul est limité par la bande passante mémoire ou par le débit de calcul de crête, et choisis les optimisations en conséquence.
  3. Utilise les instructions SIMD et les architectures vectorielles pour traiter des tableaux, explique comment un GPU est organisé pour favoriser le débit, et écris et analyse un noyau de calcul simple pour GPU.
    • Traite plusieurs éléments de données à la fois avec les instructions SIMD
      Détermine le nombre de voies d’un registre SIMD, vectorise des boucles simples et repère les organisations des données, les branchements et les dépendances qui limitent l’accélération SIMD.
    • Explique comment les architectures vectorielles exécutent les boucles
      Décris les registres vectoriels, la longueur vectorielle, le découpage en bandes, les voies et les accès à pas constant, en prenant pour exemple l’extension vectorielle RISC-V.
    • Décris comment un GPU est organisé pour favoriser le débit
      Explique les multiprocesseurs de flux, les warps et l’exécution SIMT, le masquage de la latence mémoire par les GPU, la divergence de branchement, la coalescence des accès mémoire et le coût des transferts de données, puis compare les GPU aux processeurs et aux accélérateurs spécialisés.
    • Écris et analyse un noyau de calcul simple pour GPU
      Utilise la hiérarchie des grilles, des blocs et des threads pour affecter les données aux threads, organise le travail de l’hôte et du périphérique et synchronise les threads au sein d’un bloc.
  4. Décris les multiprocesseurs à mémoire partagée et la répartition du travail entre les threads, explique les garanties de la cohérence des caches, suis les protocoles d’espionnage de bus et à répertoire, et évite le faux partage.
    • Décris les multiprocesseurs à mémoire partagée et répartis le travail entre les cœurs
      Explique l’espace d’adressage partagé unique, les accès mémoire uniformes et non uniformes, l’organisation des caches d’une puce multicœur et la façon dont les threads répartissent et combinent le travail.
    • Explique le problème de la cohérence des caches et les garanties qu’elle apporte
      Montre comment des caches privés peuvent renvoyer des données périmées, énonce les conditions de cohérence d’un système mémoire et distingue cohérence, consistance et code sans concurrence critique.
    • Suis le fonctionnement d’un protocole d’espionnage de bus avec les états MSI et MESI
      Suis les états des blocs de cache et les transactions sur le bus au cours d’une séquence de lectures et d’écritures, et explique ce que permet d’économiser l’état exclusif.
    • Explique les protocoles à répertoire et évite le faux partage
      Décris comment un répertoire suit les détenteurs des copies, estime son coût de stockage et repère, mesure et corrige le faux partage.
  5. Décris les grappes de calcul à passage de messages et compare les réseaux d’interconnexion selon leur bande passante et leur coût, puis explique comment les ordinateurs à l’échelle d’un entrepôt fournissent des services internet en tenant compte des coûts, de l’énergie et des pannes.
    • Décris les grappes de calcul à passage de messages et compare les réseaux d’interconnexion
      Explique comment des nœuds dotés de mémoires privées coopèrent par messages et compare les topologies de réseau selon leur bande passante totale, leur bande passante de bissection et leur coût.
    • Explique comment les ordinateurs à l’échelle d’un entrepôt fournissent des services à grande échelle
      Décris l’organisation d’un ordinateur à l’échelle d’un entrepôt et analyse son réseau, sa consommation d’énergie et ses pannes à l’aide de calculs simples.

Processeurs parallèles et multicœurs : cours

5 chapitres

1

Repérer et classer le travail parallèle

Le matériel parallèle peut traiter des instructions, des éléments de tableau, des threads ou des requêtes indépendantes. Le choix utile dépend des parties d’un programme qui peuvent s’exécuter ensemble. Relie ce travail aux limites de puissance qui ont conduit les puces à adopter plusieurs cœurs, puis classe le matériel selon ses flux d’instructions. Le multithreading matériel offre un autre moyen de maintenir un cœur occupé en trouvant des instructions utiles pendant les blocages.

1.1 Pourquoi les puces partagent désormais le travail

Les ordinateurs parallèles effectuent des opérations en même temps. Ils peuvent réduire la latence, le temps nécessaire à une tâche, ou augmenter le débit, le nombre de tâches achevées par seconde. Ces objectifs conduisent à différentes façons de répartir le travail.

Le mur de puissance

Augmenter la fréquence d’horloge rendait autrefois chaque génération de processeurs plus rapide. La puissance dynamique suit approximativement P≈CV2f : capacité multipliée par la tension au carré et par la fréquence de commutation. La tension intervient deux fois dans ce produit. Réduire la tension et la fréquence de 15 % donne 0,852×0,85=0,614125 de la puissance dynamique initiale, soit environ 61 %.

La tension ne pouvait pas continuer à baisser suffisamment pour compenser l’augmentation des fréquences d’horloge. Les fuites et la chaleur rendaient trop coûteuse la poursuite de leur augmentation. Ce mur de puissance a conduit l’industrie vers les puces multicœurs au milieu des années 2000. Une puce multicœur place plusieurs cœurs de processeur sur une même puce ; un système multiprocesseur possède au moins deux processeurs. Des cœurs plus modestes peuvent accomplir davantage de travail total par joule, à condition qu’il y ait assez de travail à partager.

Quatre formes de travail parallèle
FormeQu’est-ce qui s’exécute ensemble ?Exemple
Parallélisme au niveau des instructions (ILP)Instructions d’un même flux d’instructionsUn pipeline fait se chevaucher les étapes d’instructions successives.
Parallélisme de données (DLP)Même opération sur de nombreux élémentsAdditionner les éléments correspondants de deux tableaux.
Parallélisme au niveau des threads (TLP)Plusieurs séquences d’instructionsPlusieurs threads traitent différentes régions d’une image.
Parallélisme au niveau des requêtesTâches indépendantesDes serveurs répondent simultanément aux requêtes de nombreux utilisateurs.

Le matériel et les compilateurs détectent principalement le parallélisme au niveau des instructions. L’exécution en pipeline, l’émission multiple et l’exécution dans le désordre font se chevaucher les instructions tout en préservant les résultats exigés par le programme. Les dépendances et les branchements limitent ce chevauchement.

Le parallélisme de données apparaît lorsque de nombreux éléments nécessitent le même calcul. Les instructions SIMD, les processeurs vectoriels et les GPU exploitent cette régularité. Le parallélisme au niveau des threads exige que le code, une bibliothèque ou un compilateur répartisse le travail entre les threads. Un thread possède son propre compteur ordinal, ses registres et sa pile ; les threads d’un même processus partagent son espace d’adressage. Des processus distincts ont des espaces d’adressage distincts.

Les tâches au niveau des requêtes nécessitent peu de coopération entre elles. Ajouter des serveurs peut donc augmenter la capacité presque proportionnellement aux ressources ajoutées. Exécuter plusieurs programmes indépendants sur un ordinateur portable utilise aussi des cœurs qui seraient autrement inactifs et augmente le débit global, même si aucun de ces programmes n’est parallélisé en interne.

Tâches concurrentes et exécution simultanée

La concurrence signifie que des tâches progressent pendant des périodes qui se chevauchent. Un cœur peut le faire en passant de l’une à l’autre. Le parallélisme signifie que des opérations s’exécutent au même instant sur des unités matérielles distinctes. Un système monocœur peut faire progresser plusieurs programmes sans exécuter leurs instructions simultanément.

Un programme comportant un seul thread séquentiel ne se répartit pas sur huit cœurs simplement parce qu’ils existent. Les cœurs supplémentaires peuvent exécuter d’autres tâches, mais réduire la durée de ce programme nécessite du travail parallèle en son sein. Même après la répartition du travail, toute partie séquentielle restante limite encore le gain.

Points clés

  • Le matériel parallèle peut réduire la latence d’une tâche ou augmenter le débit total.
  • La puissance dynamique dépend de la tension au carré et de la fréquence.
  • Le parallélisme au niveau des instructions, des données, des threads et des requêtes révèle différents types de travail.
  • La concurrence peut utiliser le partage du temps ; le parallélisme utilise l’exécution simultanée.

1.2 Compter les flux d’instructions et de données

Un processeur peut contenir de nombreuses unités arithmétiques sans suivre de nombreux flux d’instructions indépendants. La classification de Flynn classe le matériel selon ses flux d’instructions et ses flux de données : la première étape consiste donc à choisir le niveau de la machine décrit.

Les quatre classes matérielles
ClasseFlux d’instructionsFlux de donnéesSignification
SISDUn seulUn seulUn processeur suit un flux d’instructions ordinaire.
SIMDUn seulPlusieursUne instruction applique une opération à plusieurs éléments de données.
MISDPlusieursUn seulDifférents flux d’instructions agissent sur un seul flux de données.
MIMDPlusieursPlusieursLes processeurs chargent indépendamment leurs instructions et traitent des données.

Un processeur monocœur classique est SISD, même lorsque son pipeline fait se chevaucher plusieurs instructions. L’émission superscalaire ne crée pas à elle seule des compteurs ordinaux indépendants et ne transforme pas le cœur en matériel MIMD.

Une instruction SIMD peut additionner huit paires de nombres à virgule flottante de 32 bits dans un registre de 256 bits. Elle possède huit voies arithmétiques, mais celles-ci suivent une seule instruction. Les extensions SIMD de largeur fixe comprennent x86 SSE et AVX et Arm Neon ; les architectures vectorielles appartiennent aussi à la classe SIMD. Les calculs réguliers sur tableaux conviennent bien, car de nombreux éléments nécessitent la même opération.

Les processeurs MIMD choisissent leurs instructions indépendamment. Les puces multicœurs, les multiprocesseurs à mémoire partagée et les grappes de calcul appartiennent à cette classe. Les cœurs peuvent exécuter des programmes différents ou des copies d’un même programme qui atteignent des branches différentes à des moments différents.

MISD complète la classification à deux par deux. Elle comporte peu d’exemples pratiques incontestés. Certains systèmes tolérants aux pannes et pipelines de traitement sont décrits ainsi, mais leur classification dépend de la façon dont leurs flux sont définis.

Un seul programme peut avoir plusieurs flux d’instructions

SPMD, un programme et plusieurs ensembles de données, est un style de programmation. Chaque unité de travail exécute une copie du même programme et utilise son identifiant pour sélectionner sa part des données. Les unités de travail ont des états d’exécution indépendants : SPMD s’exécute donc couramment sur du matériel MIMD.

Pour quatre cœurs additionnant 4 000 valeurs, le cœur d’identifiant i traite les indices 1000i à 1000i+999. Le cœur 0 traite les indices de 0 à 999 ; le cœur 3 traite ceux de 3000 à 3999. Chacun produit une somme partielle, puis ces quatre sommes sont combinées. Le texte du programme partagé n’exige pas que les quatre cœurs émettent la même instruction au même cycle.

Classer chaque niveau séparément

Considère un processeur à huit cœurs dont les threads utilisent des instructions AVX. Au niveau des cœurs, il est MIMD : les cœurs avancent indépendamment. À l’intérieur d’une opération AVX, il est SIMD : une instruction commande plusieurs voies. Compter ensemble toutes les unités arithmétiques masquerait cette structure.

Une grappe de calcul exécutant des copies d’un programme scientifique est de même un matériel MIMD utilisant un logiciel SPMD. Ses nœuds communiquent par messages. Un GPU combine de nombreux groupes de threads ordonnancés indépendamment avec une exécution de type SIMD à l’intérieur de chaque groupe ; NVIDIA appelle SIMT son mode d’exécution fondé sur les threads.

Pour classer une description, demande-toi qui choisit l’instruction suivante. Demande-toi ensuite si cette instruction traite un ou plusieurs éléments de données. Le nombre de fichiers sources, de programmes installés ou d’unités arithmétiques ne suffit pas à répondre à ces deux questions.

Points clés

  • La classification de Flynn compte les flux d’instructions et les flux de données.
  • L’exécution en pipeline à l’intérieur d’un seul flux d’instructions reste SISD.
  • SIMD partage la commande des instructions entre les voies ; MIMD possède des flux d’instructions indépendants.
  • SPMD est un style de programmation qui s’exécute couramment sur du matériel MIMD.
  • Une machine peut être MIMD entre ses cœurs et SIMD à l’intérieur de chaque cœur.

1.3 Occuper les cycles inutilisés avec un autre thread

Un défaut de cache peut laisser un cœur en attente pendant des centaines de cycles. Le multithreading matériel conserve les états d’exécution de plusieurs threads dans un même cœur afin que des instructions utiles d’un autre thread puissent s’exécuter pendant cette attente.

Ce qui est dupliqué et ce qui est partagé

Chaque thread matériel possède son propre compteur ordinal et son propre état des registres. Les threads partagent les unités d’exécution, les caches et l’accès à la bande passante mémoire du cœur. Conserver l’état dans le matériel rend le changement bien plus rapide que la sauvegarde et la restauration d’un processus par le système d’exploitation, qui peuvent coûter des milliers de cycles. Le matériel peut changer de thread en un cycle ou moins.

Le système d’exploitation voit chaque thread matériel comme un processeur logique. Huit cœurs physiques avec deux threads matériels par cœur présentent 16 processeurs logiques. Ce nombre décrit les contextes de threads disponibles, et non 16 cœurs physiques complets.

Trois approches d’ordonnancement
ApprocheQuand le cœur choisit-il un autre thread ?Principal compromis
À grain finÀ chaque cycle, en sautant les threads bloquésMasque les blocages courts et longs, mais chaque thread attend entre ses tours.
À gros grainLors d’un blocage long, comme un défaut dans le cache de dernier niveauPermet à un thread de s’exécuter longtemps, mais le changement et le remplissage du pipeline prennent du temps.
Multithreading simultané (SMT)Plusieurs threads peuvent émettre pendant le même cycleRemplit les créneaux d’émission inutilisés en partageant les ressources du cœur.

L’ordonnancement à grain fin peut passer d’un thread prêt à l’autre même lorsque le thread précédent pourrait continuer. L’ordonnancement à gros grain continue d’exécuter ce thread jusqu’à ce qu’un blocage coûteux justifie un changement. Le SMT utilise un cœur à émission multiple et à ordonnancement dynamique : les instructions de différents threads peuvent occuper différents créneaux d’émission libres pendant un même cycle. Le renommage des registres sépare leurs états. Hyper-Threading d’Intel est une implémentation du SMT ; certains processeurs IBM POWER prennent en charge huit threads matériels par cœur.

Étudier le masquage de la latence

Supposons qu’un thread calcule pendant 20 cycles puis attende la mémoire pendant 200 cycles. Son cycle dure 220 cycles. Seul, son travail utile occupe 20/220≈0,091, soit 9,1 % du temps.

Avec quatre threads, un travail décalé librement, sans coût de changement ni concurrence supplémentaire, le travail utile peut occuper 4×20/220≈0,364, soit 36,4 %. Le cœur connaît encore des périodes d’inactivité, car quatre séquences de 20 cycles ne peuvent pas couvrir les périodes d’attente.

Onze threads fournissent au total 220 cycles de séquences de calcul. Pendant que l’un attend 200 cycles, les dix autres peuvent calculer chacun pendant 20 cycles. Cet ordonnancement idéal maintient le cœur occupé. La performance réelle dépend aussi de la concurrence éventuelle entre ces threads pour les ressources mémoire et d’exécution.

Débit et durée d’exécution d’un thread

Le multithreading augmente principalement le débit. Un thread donné peut prendre plus de temps, car les autres utilisent des cycles et de l’espace de cache qu’il aurait reçus autrement. Deux threads matériels partageant une unité arithmétique ne peuvent pas tous deux bénéficier de la capacité d’un second cœur complet.

Si les deux threads sollicitent déjà les mêmes unités d’exécution entièrement occupées, le SMT dispose de peu de capacité libre à utiliser. Si l’un est bloqué pendant que l’autre peut s’exécuter, le partage est utile. Les GPU appliquent le masquage de la latence à plus grande échelle en maintenant de nombreux groupes de threads prêts pour leurs ordonnanceurs.

Points clés

  • Les threads matériels dupliquent l’état d’exécution tout en partageant les ressources d’un cœur.
  • Le changement à grain fin a lieu à chaque cycle ; le changement à gros grain répond aux blocages longs.
  • Le SMT peut émettre des instructions de différents threads pendant un même cycle.
  • Le nombre de processeurs logiques inclut les contextes de threads matériels.
  • Le masquage de la latence nécessite du travail prêt à être exécuté et peut être limité par la concurrence pour les ressources.
  • Un débit supérieur ne réduit pas nécessairement la durée d’exécution d’un thread individuel.
2

Estimer l’accélération parallèle utile

Les processeurs supplémentaires ne divisent que le travail qui peut s’exécuter en parallèle et introduisent leurs propres coûts. Pars du temps écoulé et de la fraction séquentielle, puis distingue le fait de terminer plus vite une tâche fixe de celui de résoudre un problème plus grand dans le même temps. L’équilibrage de charge et la coordination expliquent d’autres pertes. Le modèle Roofline ajoute une autre limite : la mémoire peut-elle alimenter assez vite les unités arithmétiques disponibles ?

2.1 Calculer le gain et son plafond

Une machine parallèle est utile lorsqu’elle modifie le temps écoulé. L’accélération compare la meilleure exécution séquentielle à l’exécution parallèle ; l’efficacité compare ce gain au nombre de processeurs utilisés.

Partir du temps mesuré

Pour p processeurs, S(p)=T1/Tp et E(p)=S(p)/p. Une tâche séquentielle de 100 s qui se termine en 16 s sur huit cœurs a une accélération de 100/16=6,25. Son efficacité est de 6,25/8=0,78125, soit environ 78 %. Mesure le temps écoulé pour les deux exécutions, avec la même tâche de taille fixe.

Diviser le temps entre parties améliorée et inchangée

Dans la loi d’Amdahl, f est la fraction du temps d’exécution initial qu’une amélioration accélère. C’est une fraction du temps, pas une fraction des lignes de code source. Si cette partie devient s fois plus rapide, alors

Tnew=Told((1−f)+f/s),S=1(1−f)+f/s.

La partie inchangée prend toujours la totalité de son temps initial. Pour une répartition parallèle idéale entre p processeurs, pose s=p. Ce modèle exclut les surcoûts de communication, de déséquilibre et de synchronisation ; ces coûts peuvent allonger le temps mesuré.

Avec 90 % de temps parallèle et dix processeurs, le temps normalisé est de 0,1+0,9/10=0,19. L’accélération est de 1/0,19≈5,26 et l’efficacité d’environ 53 %. Avec 100 processeurs, le temps est de 0,1+0,009=0,109 et l’accélération d’environ 9,17. Multiplier le nombre de processeurs par dix n’a pas doublé l’accélération.

Trouver la limite avant d’acheter plus de processeurs

Lorsque le nombre de processeurs augmente, le temps parallèle tend vers zéro. La fraction séquentielle subsiste et donne le plafond Smax=1/(1−f). Une fraction séquentielle de 10 % limite l’accélération idéale à 10 ; une fraction de 5 % la limite à 20. Avec un nombre fini de processeurs, l’accélération approche ces plafonds par valeurs inférieures.

La loi d’Amdahl permet aussi d’évaluer une classe d’instructions accélérée. Si la multiplication prend 30 % d’une exécution et devient quatre fois plus rapide, le temps normalisé devient 0,7+0,3/4=0,775. Le programme entier n’est que 1/0,775≈1,29 fois plus rapide.

Remonter à partir d’un objectif

Pour obtenir une accélération de 90 sur 100 processeurs, écris 1/90=(1−f)+f/100=1−0,99f. On obtient donc f=(1−1/90)/0,99≈0,99888. Seuls environ 0,11 % du temps initial peuvent rester séquentiels. Un objectif proche du nombre de processeurs exige une très petite fraction inchangée.

Une accélération mesurée peut parfois dépasser le nombre de processeurs. La division d’un grand ensemble de travail peut permettre à chaque partie de tenir dans le cache, réduisant le coût par opération. Cette accélération superlinéaire modifie une hypothèse du modèle simple : le travail parallèle n’est plus simplement le travail initial divisé en parts égales. Vérifie l’algorithme, la taille des données et le comportement du cache avant d’interpréter une telle mesure.

Points clés

  • L’accélération est le temps séquentiel divisé par le temps parallèle ; l’efficacité est l’accélération divisée par le nombre de processeurs.
  • La fraction de la loi d’Amdahl se rapporte au temps d’exécution initial.
  • Seule la fraction améliorée est divisée par le facteur d’amélioration.
  • La fraction séquentielle fixe le plafond d’accélération pour une charge de travail fixe.
  • Les effets du cache peuvent modifier le coût du travail et produire une accélération mesurée superlinéaire.

2.2 Faire croître le problème et inclure les coûts

Ajouter des processeurs peut soit raccourcir la même tâche, soit permettre à une machine de traiter une tâche plus grande. Le passage à l’échelle fort et le passage à l’échelle faible mesurent ces utilisations différentes, et tous deux dépendent de la quantité de travail utile qui subsiste après les coûts de coordination.

Travail fixe et travail croissant

Le passage à l’échelle fort maintient la taille du problème fixe. Le passage à l’échelle faible augmente le travail proportionnellement au nombre de processeurs, en maintenant constant le travail par processeur. Un passage à l’échelle faible parfait maintient le temps écoulé constant tandis que le travail total augmente.

Considère dix additions séquentielles suivies d’une somme élément par élément de deux matrices. Une matrice de 10 par 10 nécessite 100 additions parallèles. Le temps total est de 110 unités sur un processeur, 20 sur dix et 12 sur cinquante : les accélérations sont de 5,5 et d’environ 9,2. Une matrice de 40 par 40 nécessite 1 600 additions parallèles. Les temps deviennent 1610, 170 et 42 unités : les accélérations sont d’environ 9,5 et 38,3. Le problème plus grand donne plus de poids au travail parallèle utile par rapport aux mêmes dix additions séquentielles.

La référence différente de Gustafson

La loi de Gustafson utilise la fraction du temps séquentiel mesurée lors de l’exécution parallèle. En appelant cette fraction s, l’accélération pour un problème de taille croissante est SG=s+(1−s)p. Pour s=0,05 et 100 processeurs, SG=0,05+0,95(100)=95,05.

La loi d’Amdahl avec 5 % de temps séquentiel lors de l’exécution initiale sur un processeur ne donne qu’environ 16,8 sur 100 processeurs. Ces fractions utilisent des dénominateurs différents et répondent à des questions différentes. Une accélération de 95,05 pour un problème de taille croissante ne signifie pas que la tâche initiale de taille fixe s’est terminée 95,05 fois plus vite.

L’unité de travail la plus lente détermine la fin

Si 400 unités de travail égales sont réparties entre huit cœurs, la part équilibrée est de 50 chacun. Supposons que l’un en reçoive 120 tandis que les sept autres en reçoivent 40 chacun. L’étape dure 120 unités de temps, donc l’accélération est de 400/120≈3,33. Diviser par la charge moyenne ne tiendrait pas compte de l’attente du cœur le plus chargé.

La création et l’ordonnancement des threads, les messages, les barrières et la concurrence pour la bande passante partagée consomment aussi du temps. La granularité est la quantité de calcul entre deux événements de communication ou de synchronisation. De plus gros morceaux réduisent le coût de coordination par opération utile, mais un nombre insuffisant de morceaux peut laisser certaines unités de travail inactives.

Davantage de processeurs peuvent augmenter le temps

Pour une tâche entièrement parallèle de 100 s avec un surcoût de 0,5p secondes, Tp=100/p+0,5p. Dix processeurs prennent 15 s. Quatorze prennent environ 14,14 s, près du minimum situé autour de 200 processeurs. Quarante prennent 22,5 s, car leur surcoût de 20 s dépasse le gain obtenu par un calcul utile plus court.

Lorsque tu présentes un résultat, précise si le travail est resté fixe ou a augmenté, et compare avec le temps du meilleur programme séquentiel. Utiliser comme référence une implémentation parallèle lente exécutée sur un seul processeur peut gonfler l’accélération annoncée.

Points clés

  • Le passage à l’échelle fort fixe le travail total ; le passage à l’échelle faible fixe le travail par processeur.
  • La fraction séquentielle de Gustafson est mesurée lors de l’exécution parallèle.
  • L’unité de travail la plus lente détermine la fin d’une étape parallèle.
  • La communication, la synchronisation et la concurrence pour les ressources peuvent augmenter avec le nombre de processeurs.
  • La granularité implique un compromis entre coût de coordination et équilibrage de charge.
  • Utilise le temps écoulé et le meilleur programme séquentiel comme référence pour présenter une accélération.

2.3 Trouver le toit de calcul ou de mémoire

Le débit arithmétique annoncé pour un processeur n’est qu’une limite parmi d’autres. Le modèle Roofline permet aussi de déterminer si la mémoire peut fournir les données assez vite pour soutenir ce débit. Il donne une borne supérieure qui aide à choisir une piste d’optimisation utile.

Compter les opérations par octet transféré depuis ou vers la DRAM

L’intensité arithmétique est le nombre d’opérations à virgule flottante divisé par le nombre d’octets transférés entre la DRAM et le processeur. Les travaux d’origine sur le modèle Roofline appellent cette mesure fondée sur la DRAM intensité opérationnelle. Compte les transferts à cette frontière, en incluant les lectures et les écritures.

DAXPY calcule yi=axi+yi avec des nombres en double précision. Chaque élément nécessite une multiplication et une addition : deux opérations à virgule flottante. Lire une valeur de 8 octets dans chaque tableau et écrire 8 octets en retour transfère 24 octets. L’intensité est de I=2/24≈0,0833 opération à virgule flottante par octet. Le coefficient scalaire est réutilisé ; dans ce modèle de trafic, il n’est pas chargé à nouveau depuis la DRAM pour chaque élément.

Appliquer les deux limites

Si le débit de calcul de crête est P et la bande passante mémoire de crête B, le toit est min⁡(P,BI). La bande passante multipliée par le nombre d’opérations à virgule flottante par octet s’exprime en opérations à virgule flottante par seconde. Sur un graphique à échelles logarithmiques, la borne de bande passante monte et la borne de calcul est horizontale.

Pour 1 000 GFLOP/s et 100 Go/s, le point de transition est de P/B=1000/100=10 opérations à virgule flottante par octet. En dessous de cette intensité, le toit de bande passante est plus bas ; au-dessus, le toit de calcul est plus bas. DAXPY est limité à 100(2/24)≈8,33 GFLOP/s, soit moins de 1 % du débit de calcul de crête de la machine. Un noyau de calcul d’intensité 2 est limité à 200 GFLOP/s.

Un noyau limité par la mémoire peut encore bénéficier de cœurs supplémentaires ou d’unités SIMD plus larges tant qu’il a trop peu de requêtes en cours pour utiliser la bande passante disponible. Une fois cette bande passante saturée, une capacité arithmétique supplémentaire ne relève pas son toit. Augmenter la bande passante ou effectuer plus de calcul utile par octet transféré le relève.

La réutilisation modifie l’intensité

Multiplier deux matrices de 1000 par 1000 en double précision effectue environ 2(1000)3=2×109 opérations à virgule flottante. Si chaque élément des deux entrées et de la sortie traverse une fois la frontière de la DRAM, le trafic total est de 24 Mo, soit environ 83 opérations à virgule flottante par octet. C’est au-dessus du point de transition de la machine de l’exemple.

Une implémentation naïve peut relire plusieurs fois les valeurs des matrices depuis la DRAM. Le traitement par blocs organise les boucles autour de sous-matrices qui tiennent dans le cache, de sorte que les valeurs servent à de nombreuses opérations avant d’être remplacées. L’algorithme reste une multiplication matricielle, mais l’implémentation transfère moins d’octets depuis ou vers la DRAM par opération.

Un toit n’est pas un résultat mesuré

Un noyau peut s’exécuter sous la borne à cause de dépendances, du surcoût des instructions, de mauvaises séquences d’accès ou d’un manque de travail parallèle. Des plafonds plus bas montrent ces restrictions : l’absence de SIMD peut abaisser le plafond de calcul, tandis que de mauvaises séquences d’accès réduisent la bande passante utilisable. Un point sous un toit mérite d’être étudié ; le toit seul ne prédit pas son débit d’exécution exact.

Points clés

  • L’intensité compte les opérations à virgule flottante par octet transféré à la frontière de la DRAM.
  • Le toit est la plus petite valeur entre le débit de calcul de crête et la bande passante multipliée par l’intensité.
  • Le point de transition est le débit de calcul de crête divisé par la bande passante de crête.
  • La réutilisation peut augmenter l’intensité sans modifier l’algorithme mathématique.
  • Le modèle Roofline donne une borne supérieure ; des plafonds plus bas expliquent des restrictions supplémentaires.
3

Traiter des tableaux avec des voies et des threads de GPU

Les tableaux permettent de répéter des opérations sur des éléments indépendants, qui peuvent être réparties entre des voies et des threads. Suis cette idée depuis les registres SIMD de largeur fixe jusqu’aux boucles vectorielles de longueur variable, puis aux warps des GPU. Chaque architecture nécessite une organisation efficace des données et suffisamment de travail pour occuper son matériel. Un petit noyau de calcul montre comment les indices de tableau deviennent des indices de thread, tandis que les coûts de transfert déterminent si la délégation au GPU aide l’ensemble de la tâche.

3.1 Exécuter des opérations sur tableaux dans les voies SIMD

Une extension SIMD divise un registre large en voies. Une instruction effectue la même opération dans chaque voie, ce qui convient bien aux boucles régulières sur des éléments indépendants.

Compter les voies et les itérations

Le nombre de voies est la largeur du registre divisée par celle d’un élément. Un registre de 256 bits contient huit nombres à virgule flottante de 32 bits, quatre nombres en double précision de 64 bits ou 32 éléments d’un octet. SSE utilise des registres XMM de 128 bits ; AVX et AVX2 utilisent des registres YMM de 256 bits. En mode 64 bits, il y a 16 registres YMM. AVX-512 fournit 32 512 bits de registres ZMM, contenant chacun 16 nombres à virgule flottante. Arm Neon utilise des registres de 128 bits.

Pour c[i] = a[i] + b[i] sur 1 000 nombres à virgule flottante, des instructions à huit voies traitent le tableau en 125 itérations vectorielles. Chaque itération charge deux vecteurs, additionne leurs voies et range un vecteur. Avec 1 003 éléments, 125 itérations complètes laissent trois éléments. Une boucle scalaire pour le reste ou une opération masquée traite cette courte fin sans accéder au-delà des tableaux.

Huit voies représentent une capacité arithmétique, pas une garantie que le programme sera huit fois plus rapide. La préparation, le traitement du reste, le travail séquentiel et les accès soumis à la bande passante mémoire prennent toujours du temps.

Choisir une organisation qui remplit un registre

Les chargements vectoriels simples fonctionnent bien sur des éléments contigus, avec un pas de 1. Un tableau de points {x, y, z} dont chaque champ occupe 4 octets place les champs x consécutifs à 12 octets d’intervalle. Une structure de tableaux place ensemble les valeurs x, puis les valeurs y, puis les valeurs z. Traiter uniquement x peut alors remplir un vecteur avec un seul chargement contigu. Les instructions de rassemblement et de dispersion prennent en charge les adresses dispersées, mais généralement avec un coût d’accès supérieur.

Traiter les conditions dans les voies

Pour c[i] = (a[i] > 0) ? a[i] : 0, une comparaison crée un masque par voie. Une sélection choisit entre les résultats possibles, ou des instructions masquées ne mettent à jour que les voies sélectionnées. Les voies inactives conservent ou reçoivent des valeurs selon le comportement du masque de l’instruction.

Si différentes voies nécessitent des branches longues et différentes, les instructions de ces chemins doivent tout de même être émises, avec seulement les voies concernées actives. Le groupe ne peut pas donner à chaque voie un flux d’instructions distinct. Un masque préserve la correction, mais ne peut pas faire disparaître toutes les instructions de ces chemins.

Vérifier l’indépendance des itérations

Les compilateurs peuvent vectoriser automatiquement les boucles ; les programmeurs peuvent aussi utiliser des bibliothèques ou des fonctions intrinsèques comme _mm256_add_ps. Le compilateur doit établir que des itérations simultanées préservent le résultat. La récurrence a[i] = a[i-1] + b[i] dépend de la nouvelle valeur produite par l’itération précédente et ne peut pas être directement vectorisée comme des éléments indépendants. Un chevauchement possible des pointeurs, appelé aliasing, peut aussi nécessiter une vérification du chevauchement à l’exécution ou empêcher la vectorisation.

Une réduction conserve plusieurs sommes partielles dans un registre, puis combine les voies. Modifier l’ordre des additions en virgule flottante peut changer les derniers bits, car l’addition n’est pas associative. Les sommes d’entiers concordent lorsque l’arithmétique choisie ne présente pas de dépassement de capacité ou utilise une arithmétique modulaire définie.

SIMD et l’exécution multicœur peuvent être combinés. Huit cœurs émettant chacun une addition sur huit voies par cycle peuvent effectuer jusqu’à 64 additions à virgule flottante par cycle. Ils restent soumis à des limites partagées comme la bande passante mémoire.

Points clés

  • Le nombre de voies SIMD dépend de la largeur du registre et de celle des éléments.
  • Le reste nécessite une fin de boucle scalaire ou un accès correctement masqué.
  • Des organisations contiguës aident les chargements vectoriels à utiliser efficacement leurs voies.
  • Les masques traitent les conditions propres à chaque élément tout en partageant l’émission des instructions.
  • Les dépendances et l’aliasing peuvent empêcher la vectorisation directe.
  • Les réductions en virgule flottante peuvent modifier l’arrondi lorsque les opérations sont regroupées différemment.

3.2 Laisser la longueur vectorielle contrôler chaque passage de boucle

Une architecture vectorielle exprime une opération sur une suite d’éléments et stocke la longueur vectorielle active dans un registre. Le même programme peut s’exécuter sur des implémentations dont les registres vectoriels ont des capacités différentes.

Distinguer capacité, longueur et voies

L’extension vectorielle RISC-V, RVV, version 1.0, a été ratifiée en 2021. Elle fournit 32 registres vectoriels, de v0 à v31. Chaque implémentation choisit la largeur de ses registres, VLEN, sous forme d’une puissance de deux. La largeur des éléments et le regroupement des registres déterminent combien d’éléments peuvent y tenir.

La longueur active, vl, est le nombre d’éléments traités par les prochaines instructions vectorielles. vsetvli configure l’opération vectorielle à partir du nombre d’éléments restants et du format d’élément souhaité, puis renvoie la valeur vl sélectionnée. Le code avance selon la valeur renvoyée. C’est important, car un code portable doit utiliser la longueur effectivement sélectionnée par l’implémentation.

Les voies sont les pipelines parallèles qui exécutent l’opération vectorielle. Une addition de 32 éléments sur quatre voies prend environ huit cycles après le démarrage du pipeline. Un vecteur de 32 éléments ne nécessite pas 32 unités arithmétiques. Des vecteurs plus longs et davantage de voies sont des choix de conception distincts.

Découper une boucle en bandes

Le découpage en bandes divise une longue boucle en morceaux de taille adaptée aux vecteurs. Pour 100 éléments et un maximum de 32 par opération, une suite de longueurs possible est 32, 32, 32 et 4. Chaque passage charge la partie suivante, la traite, la range et réduit le nombre d’éléments restants de sa valeur vl.

DAXPY sur 1 000 nombres en double précision peut de même utiliser 31 passages de 32 suivis d’un passage de huit, soit 32 passages au total. RVV peut choisir d’autres longueurs autorisées vers la fin : la boucle utilise donc la valeur vl renvoyée au lieu de supposer une répartition finale particulière. Définir la longueur active permet de traiter la courte fin sans boucle scalaire distincte pour le reste.

Le schéma de contrôle de la boucle est le suivant :

  1. Demander une longueur pour les éléments restants.
  2. Charger et traiter ce nombre d’éléments.
  3. Ranger les résultats.
  4. Faire avancer les pointeurs et soustraire la longueur renvoyée.

Une instruction vectorielle décrit de nombreuses opérations sur les éléments, ce qui réduit le travail de chargement et de décodage par rapport à un corps de boucle scalaire répété pour chaque élément.

Alimenter les opérations dépendantes et traiter les données non contiguës

Le chaînage permet à une instruction vectorielle qui utilise un résultat de commencer à traiter les premiers éléments avant que l’instruction qui les produit ait terminé les suivants. Pour une multiplication suivie d’une addition, le premier produit peut entrer dans le pipeline d’addition pendant que les produits suivants sont encore en cours de calcul.

Un masque, souvent dans le registre RVV v0, sélectionne les éléments à mettre à jour. Un chargement à pas constant accède à des éléments séparés par un nombre fixe d’octets. Dans une matrice de 100 par 100 nombres en double précision rangée par lignes, descendre d’une ligne dans une colonne fait avancer de 100 éléments, soit 800 octets. Les chargements et rangements indexés utilisent des adresses explicites pour les données irrégulières.

Les architectures vectorielles et les extensions de largeur fixe sont toutes deux SIMD dans la classification de Flynn. Les extensions de largeur fixe codent des largeurs particulières ; le code RVV exprime des longueurs qui s’adaptent au matériel disponible. Les deux nécessitent toujours un ordre d’exécution qui respecte les dépendances de données de la boucle.

Points clés

  • La longueur vectorielle indique le nombre d’éléments traités par une opération ; les voies indiquent combien peuvent avancer ensemble.
  • Le code RVV avance selon la longueur effective renvoyée par vsetvli.
  • Le découpage en bandes traite un long tableau en morceaux de taille adaptée aux vecteurs.
  • Le chaînage fait se chevaucher des opérations vectorielles dépendantes, élément par élément.
  • Les masques, les pas d’accès et les accès indexés prennent en charge des données moins régulières.

3.3 Maintenir un GPU occupé avec de nombreux warps

Un processeur concentre ses ressources sur une faible latence pour quelques threads. Un GPU concentre ses ressources sur un débit élevé pour de nombreux threads parallèles au niveau des données. Choisir entre les deux exige d’examiner l’ensemble de la tâche, y compris les transferts de données.

Les threads s’exécutent sur des multiprocesseurs de flux

Un GPU NVIDIA contient de nombreux multiprocesseurs de flux, ou SM. Un SM possède des voies arithmétiques, des ordonnanceurs de warps, un grand banc de registres et une mémoire partagée rapide sur la puce. Un « cœur CUDA » désigne une voie arithmétique, et non un cœur complet et indépendant comparable à celui d’un processeur. AMD appelle le groupe de traitement correspondant une unité de calcul.

NVIDIA regroupe les threads en warps de 32. Une instruction émise agit sur les threads actifs du warp, chacun ayant ses propres valeurs de registre et données. C’est le SIMT : une instruction, plusieurs threads. AMD utilise des wavefronts de 32 ou 64 threads selon l’architecture.

Un SM conserve de nombreux warps résidents. Lorsque l’un attend la mémoire, l’ordonnanceur sélectionne un autre warp prêt. Disposer de plus de threads prêts que de voies masque la latence ; cela ne réduit pas la latence d’un accès individuel à la DRAM.

La divergence laisse des voies inactives

Si les threads d’un warp suivent des branches différentes, le warp exécute les chemins nécessaires en masquant les autres threads. Une structure conditionnelle dont les threads se répartissent également entre les deux branches, de coût égal, peut prendre environ deux fois le temps d’un chemin, car les deux doivent s’exécuter. Un branchement peut être sans conséquence lorsque sa condition est uniforme dans chaque warp, même si différents warps choisissent des chemins différents.

Coordonner les accès mémoire

Les registres propres à chaque thread contiennent des valeurs privées. La mémoire partagée propre à chaque bloc est un espace sur la puce géré par le programme. Les caches L1 et L2 permettent la réutilisation automatique, tandis que la mémoire globale est la DRAM du GPU, par exemple GDDR ou HBM.

Lorsque 32 threads lisent des mots consécutifs de 4 octets, leur plage de 128 octets peut être servie par un petit nombre de transactions larges. Cette coalescence des accès mémoire utilise efficacement la bande passante. Des adresses dispersées peuvent nécessiter de nombreuses transactions pour les mêmes données utiles. La réutilisation en mémoire partagée peut encore réduire les transferts répétés avec la mémoire globale.

Inclure le temps de transfert

Pour un GPU dédié, les entrées et les résultats traversent une liaison telle que PCIe ou NVLink. Envoyer 800 Mo et recevoir 400 Mo à un débit effectif de 20 Go/s transfère 1,2 Go en 0,06 s, soit 60 ms. Ajouter un noyau de calcul de 10 ms donne 70 ms au total. Un processeur qui termine en 50 ms l’emporte dans cette comparaison malgré le calcul bien plus rapide du GPU.

Conserver les données sur le GPU pour plusieurs noyaux évite des transferts répétés. De grandes tâches régulières peuvent aussi fournir assez d’opérations arithmétiques utiles pour compenser les coûts de transfert et de lancement. Les petites tâches séquentielles riches en branchements favorisent souvent un processeur.

Se spécialiser davantage lorsque le travail le permet

Un système hétérogène utilise le processeur pour exécuter le programme et le système d’exploitation, et un accélérateur pour les parties adaptées. Les accélérateurs spécialisés tels que les TPU et les NPU consacrent du matériel à une tâche plus restreinte, souvent la multiplication matricielle avec des entiers de 8 bits ou des nombres à virgule flottante de 16 bits. La spécialisation peut améliorer la performance par watt dans ce domaine, tout en réduisant l’éventail des travaux que le matériel traite efficacement.

Points clés

  • Un SM ordonnance des warps ; un cœur CUDA est une voie arithmétique.
  • Les warps NVIDIA contiennent 32 threads aux données distinctes qui partagent l’émission des instructions.
  • Les warps résidents prêts masquent les attentes mémoire.
  • La divergence et les accès dispersés gaspillent du temps de voie et de la bande passante mémoire.
  • La décision de déléguer au GPU tient compte des transferts ainsi que du temps du noyau.
  • Les accélérateurs spécialisés sacrifient de la flexibilité au profit de l’efficacité dans un domaine plus restreint.

3.4 Affecter les éléments d’un tableau aux threads d’un GPU

Un noyau de calcul pour GPU s’exécute une fois par thread lancé. L’hôte lance une grille de blocs de threads et chaque thread calcule la partie des données qui lui est affectée. CUDA appelle le processeur l’hôte et le GPU le périphérique ; OpenCL utilise les notions associées d’élément de travail et de groupe de travail.

Calculer un indice unique

Pour un lancement à une dimension, l’indice de l’élément est blockIdx.x * blockDim.x + threadIdx.x. Avec 256 threads par bloc, le thread 5 du bloc 2 traite l’élément 517 : les deux blocs précédents représentent 512 éléments, et le thread ajoute un déplacement de cinq. Les indices des threads et des blocs commencent à zéro.

Un noyau SAXPY applique une multiplication et une addition à chaque nombre à virgule flottante :

__global__ void saxpy(int n, float a, float *x, float *y) {
    int i = blockIdx.x * blockDim.x + threadIdx.x;
    if (i < n) {
        y[i] = a * x[i] + y[i];
    }
}

La grille remplace la boucle ordinaire sur les éléments. Chaque thread actif met à jour son propre y[i] ; les threads voisins utilisent des adresses voisines, ce qui favorise la coalescence.

Arrondir le nombre de blocs à l’entier supérieur

Pour 1 000 000 d’éléments et 256 threads par bloc, la grille nécessite ⌈1000000/256⌉=3907 blocs. Ceux-ci lancent 1 000 192 threads. Les 192 derniers ont des indices hors du tableau, donc la condition i < n empêche leurs accès mémoire. Arrondir à l’entier inférieur lancerait trop peu de threads et laisserait des éléments valides non traités.

Un bloc de 256 threads forme huit warps. Les blocs peuvent être affectés à n’importe quel SM et s’exécuter dans n’importe quel ordre. La correction du programme ne doit pas dépendre du fait que le bloc 0 se termine avant le bloc 1.

Organiser le travail de l’hôte et du périphérique

Un hôte alloue généralement l’espace de stockage du périphérique, copie les entrées, lance saxpy<<<3907, 256>>>(n, 2.0f, d_x, d_y) et récupère les résultats. Le lancement est asynchrone : le processeur peut continuer pendant l’exécution du noyau. L’hôte doit attendre par une synchronisation ou une copie bloquante adaptée des résultats avant d’utiliser les données calculées.

Coopérer à l’intérieur d’un bloc

Les threads d’un bloc peuvent échanger des valeurs par la mémoire partagée et se retrouver à __syncthreads(). Chaque thread participant à cette barrière du bloc doit l’atteindre. Placer la barrière dans if (i < n) n’est pas sûr lorsque seuls certains threads satisfont la condition.

Pour une réduction de 1 024 valeurs en mémoire partagée, 512 threads additionnent des paires, puis 256 combinent les résultats, puis 128, et ainsi de suite. Dix étapes divisant le nombre de participants par deux laissent une somme. Une barrière entre les étapes empêche un thread d’utiliser un résultat partiel avant que le thread qui le produit l’ait écrit.

Un lancement ordinaire ne comporte pas de barrière à l’échelle de la grille. Des blocs distincts peuvent écrire des sommes partielles qu’un second noyau combine, ou des opérations atomiques adaptées peuvent mettre à jour un résultat global. Une barrière de bloc ne peut pas à elle seule coordonner différents blocs. Une boucle dont le pas est lié à la taille de la grille constitue une autre façon de répartir le travail : chaque thread traite plusieurs éléments en avançant selon la taille totale de la grille.

Points clés

  • Calcule les indices à partir de la taille du bloc, de l’indice du bloc et de l’indice du thread.
  • Arrondis le nombre de blocs à l’entier supérieur et protège les accès hors limites.
  • Les lancements de noyaux sont asynchrones par rapport à l’hôte.
  • La mémoire partagée et __syncthreads() permettent la coopération au sein d’un bloc.
  • Les blocs ordinaires s’exécutent indépendamment ; combiner leurs résultats nécessite un autre mécanisme.
4

Partager la mémoire et suivre la propriété des blocs de cache

Un espace d’adressage commun permet aux threads d’échanger des valeurs par des opérations mémoire ordinaires. Les caches privés accélèrent ces opérations, mais créent plusieurs copies qui doivent être coordonnées. Suis une réduction depuis le travail local jusqu’aux résultats partagés, puis suis les droits qui maintiennent la cohérence des copies en cache. Le stockage du répertoire et le faux partage relient ces mécanismes de correction au coût en performance du placement des données en mémoire.

4.1 Partager un espace d’adressage et combiner des résultats partiels

Un multiprocesseur à mémoire partagée donne à ses processeurs un espace d’adressage physique unique. Les threads communiquent par des chargements et des rangements dans des variables partagées, tout en conservant des valeurs privées telles que des sommes partielles locales.

Les adresses partagées peuvent avoir des coûts différents

En UMA, accès mémoire uniforme, le temps d’accès à la mémoire est à peu près le même depuis chaque processeur. En NUMA, accès mémoire non uniforme, un socket accède plus vite à sa mémoire locale qu’à celle d’un autre socket. L’espace d’adressage est partagé même si la mémoire physique est distribuée.

Avec 70 % d’accès locaux à 80 ns et 30 % d’accès distants à 140 ns, la moyenne pondérée est de 0,7(80)+0,3(140)=98 ns. Déplacer les données près de leur utilisateur principal réduit la part des accès distants. Compter chaque accès comme local sous-estimerait le temps.

Une organisation courante donne à chaque cœur des caches L1 privés pour les instructions et les données, souvent un cache L2 privé, et un cache de dernier niveau partagé. Un anneau ou un maillage relie les cœurs et les caches. La mémoire partagée décrit l’adressage ; elle n’exige pas que chaque cœur utilise un seul cache commun.

Répartir, calculer et réduire

Pour additionner 64 000 valeurs sur 64 cœurs, chaque cœur traite 1 000 valeurs. Les 64 sommes partielles peuvent être combinées dans un arbre de réduction. Le nombre d’additionneurs actifs est divisé par deux à chaque étape : 32, 16, 8, 4, 2 et 1. Six étapes combinent les résultats partiels.

Avec environ 1 000 étapes d’addition locales et six étapes de combinaison, on obtient environ 1 006 étapes sur le chemin le plus long, avant les surcoûts. L’arbre évite que chaque entrée mette à jour un compteur partagé unique. Chaque étape dépend des valeurs achevées de l’étape précédente ; les unités de travail se retrouvent donc à des barrières de synchronisation entre les étapes.

OpenMP peut exprimer cela avec #pragma omp parallel for reduction(+:sum). Cette directive répartit les itérations, donne aux threads des sommes partielles privées et les combine. Les threads POSIX offrent un contrôle plus explicite de la gestion des threads.

Rendre une mise à jour indivisible

Une opération de lecture-modification-écriture atomique rend une mise à jour indivisible du point de vue des autres processeurs. L’échange atomique et la lecture et addition atomiques en sont des exemples. Un chargement suivi d’un rangement ordinaire représente deux opérations distinctes, entre lesquelles un autre thread peut intervenir.

RISC-V fournit lr.w et sc.w. Le chargement avec réservation lit un mot et établit une réservation. Le rangement conditionnel tente l’écriture et indique sa réussite ou son échec. Une écriture entre-temps à l’emplacement réservé fait échouer la tentative ; le logiciel réessaie. La réservation ne bloque pas les autres processeurs, et l’échec peut aussi survenir pour d’autres raisons autorisées. Ces primitives servent aux mécanismes de synchronisation.

Surveiller les goulots d’étranglement partagés

Si chaque cœur peut lire en continu à 15 Go/s mais que le socket fournit 60 Go/s, environ quatre flux de ce type saturent la bande passante. Davantage de cœurs ne peuvent pas augmenter le débit de données du socket. La communication par les caches a aussi un coût : un cœur qui écrit sans permission d’écriture doit obtenir la propriété et invalider les autres copies. Un cœur qui détient déjà un bloc à l’état modifié peut continuer localement ; les lecteurs ultérieurs peuvent devoir charger une nouvelle copie.

Points clés

  • La mémoire partagée signifie un espace d’adressage unique, avec toujours la possibilité d’avoir des données et des caches privés.
  • Avec NUMA, le placement des données influe sur la performance.
  • Les sommes partielles locales et un arbre de réduction limitent la concurrence pour les ressources.
  • Les barrières séparent les phases de travail dépendantes.
  • Les opérations atomiques protègent les mises à jour indivisibles ; LR/SC réessaie après les tentatives échouées.
  • Les cœurs partagent la bande passante mémoire et supportent le coût des transferts de propriété.

4.2 Maintenir la cohérence des copies d’un emplacement

Les caches privés améliorent la latence, mais peuvent détenir plusieurs copies d’un même emplacement mémoire. La cohérence des caches empêche ces copies de donner des historiques contradictoires des écritures à cet emplacement.

Pourquoi la mise à jour de la mémoire ne suffit pas

Partons de X = 0 en mémoire. Le cœur A lit et conserve zéro dans son cache ; le cœur B fait de même. A écrit un dans son cache à écriture différée. Sans protocole de cohérence, B peut trouver sa propre copie en cache et continuer à lire zéro. Une écriture simultanée en mémoire ne corrigerait pas la copie déjà présente dans le cache de B.

La cohérence fonctionne à la granularité du bloc de cache, généralement de 64 octets. Un contrôleur suit l’état de chaque bloc et applique les règles du protocole lorsque les processeurs le lisent ou l’écrivent. La migration déplace les données utiles dans le cache de leur utilisateur actuel. La réplication permet à plusieurs lecteurs de détenir des copies non modifiées. La cohérence doit préserver ces deux avantages tout en contrôlant les écritures.

Trois propriétés requises
PropriétéExigence
Ordre du programme pour un emplacementUn processeur lit sa propre écriture précédente si aucune écriture intermédiaire ne l’a remplacée.
Propagation des écrituresUne écriture finit par devenir visible pour les autres processeurs.
Sérialisation des écrituresTous les processeurs s’accordent sur l’ordre des écritures à cet emplacement.

Si un emplacement reçoit une écriture de un suivie d’une écriture de deux, les lecteurs ne peuvent pas être en désaccord sur l’écriture la plus récente. Observer l’écriture ultérieure puis l’écriture antérieure inverserait cet historique. Une nouvelle écriture ultérieure pourrait bien sûr stocker à nouveau la valeur un ; la sérialisation concerne les événements d’écriture, pas la possibilité qu’une valeur numérique réapparaisse.

Contrôler la propriété et les copies

Dans un protocole d’invalidation à l’écriture, un cœur qui écrit obtient une permission d’écriture exclusive et invalide les autres copies en cache. Une lecture ultérieure d’un bloc invalidé produit un défaut et charge les données actuelles. C’est un défaut de cohérence, qui s’ajoute aux défauts à froid, de capacité et de conflit.

Un protocole de mise à jour à l’écriture envoie les nouvelles valeurs aux copies existantes. Des écritures répétées peuvent rendre cette méthode coûteuse. L’espionnage de bus diffuse les requêtes de cohérence afin que les caches puissent réagir. Un répertoire suit les détenteurs des copies et dirige les messages vers les caches concernés.

Cohérence, ordre et atomicité

La cohérence concerne un emplacement. Un modèle de consistance mémoire définit les ordres observables autorisés et les résultats des lectures et écritures, y compris les opérations sur différents emplacements. La consistance séquentielle exige un résultat correspondant à un entrelacement qui préserve l’ordre du programme de chaque processeur. Les modèles plus faibles autorisent davantage de réordonnancements ; les instructions de barrière mémoire imposent l’ordre requis lorsque c’est nécessaire.

Ni des copies cohérentes ni un ordre conforme au modèle de consistance ne rendent atomique une incrémentation composée de plusieurs instructions. Supposons que deux threads incrémentent un compteur partagé initialement égal à cinq. Une séquence possible est : A lit cinq, B lit cinq, A écrit six, B écrit six. Chaque lecture et chaque écriture peuvent être cohérentes, mais le compteur final vaut six au lieu de sept. Le programme a besoin d’une mise à jour atomique ou d’une synchronisation adaptée pour préserver les deux incrémentations.

Points clés

  • La cohérence est nécessaire même lorsque les caches écrivent simultanément en mémoire.
  • Les systèmes cohérents préservent l’ordre du programme pour un même emplacement, propagent les écritures et les sérialisent.
  • L’invalidation à l’écriture supprime les autres copies utilisables avant que le nouveau détenteur écrive.
  • Les données invalidées peuvent provoquer des défauts de cohérence.
  • Les modèles de consistance traitent de l’ordre des opérations entre emplacements.
  • Une lecture cohérente et une écriture cohérente restent deux opérations distinctes.

4.3 Suivre les changements de propriété avec MSI et MESI

Un contrôleur de cache utilisant l’espionnage surveille les requêtes de cohérence sur une interconnexion à diffusion. Pour suivre un protocole, conserve un état pour la copie du bloc de chaque cœur et mets à jour chaque copie concernée après chaque accès.

Lire les états comme des permissions
ÉtatCopie utilisable ?Qui d’autre peut la détenir ?La mémoire est-elle à jour ?
Modifié (M)Oui, lectures et écrituresAucune autre copie valideNon
Partagé (S)Oui, lecturesD’autres lecteurs peuvent détenir des copiesOui
Invalide (I)NonD’autres caches peuvent détenir des copiesCela dépend de leur état
Exclusif (E), MESI seulementOui, lectures et passage à l’écriture sans transactionAucune autre copie valideOui

Dans MSI de base, un défaut de lecture envoie une requête de lecture sur le bus et charge le bloc à l’état S. Écrire dans un bloc à l’état S nécessite une demande de passage en exclusif pour invalider les autres copies. Écrire depuis l’état I nécessite une requête de lecture exclusive pour charger les données et obtenir la propriété. Le cœur qui écrit termine à l’état M. Un succès à l’état M ne nécessite aucune transaction de cohérence.

Suivre cinq accès

Partons de X = 0 en mémoire et de A et B tous deux à l’état invalide.

  1. A lit X. Une lecture sur le bus fournit zéro. États : A = S, B = I.
  2. B lit X. Une autre lecture sur le bus fournit zéro. États : A = S, B = S.
  3. A écrit un. Sa demande de passage en exclusif invalide B. États : A = M, B = I.
  4. B lit X. B subit un défaut ; A fournit un et rétrograde à l’état S. Dans MSI de base, la mémoire est aussi mise à jour. États : A = S, B = S.
  5. B écrit deux. Sa demande de passage en exclusif invalide A. États : A = I, B = M.

Chaque accès de cet exemple nécessite une transaction sur le bus. Le quatrième accès est la vérification importante de la propriété : la mémoire seule contenait encore l’ancienne valeur avant que A fournisse ses données modifiées.

Ce que l’état exclusif économise

MESI ajoute E pour une copie unique en cache non modifiée. Si A lit un bloc absent des caches et qu’aucun autre cache ne le détient, A reçoit l’état E. Une écriture ultérieure fait passer E à M sans transaction, car aucune autre copie ne doit être invalidée. MSI chargerait d’abord le bloc à l’état S, puis enverrait une demande de passage en exclusif pour cette écriture.

Si un autre cœur lit le bloc pendant que A le détient à l’état E, les deux passent à l’état S. M et E ont tous deux un seul détenteur valide, mais seul M contient des données plus récentes que la mémoire.

Écritures répétées et passage à l’échelle

Un cœur qui a obtenu l’état M peut mettre à jour le bloc dix fois sans dix nouvelles invalidations. Une méthode de mise à jour à l’écriture enverrait les valeurs modifiées aux détenteurs des copies.

L’espionnage par diffusion devient coûteux lorsque davantage de cœurs surveillent chaque requête. Les structures à répertoire réduisent cette diffusion. Des protocoles plus élaborés ajoutent des états utiles : l’état propriétaire de MOESI permet une copie modifiée partagée, et MESIF désigne un détenteur chargé de transmettre les données en réponse aux requêtes.

Points clés

  • MSI suit les copies aux états modifié, partagé et invalide.
  • Un cœur qui écrit a besoin de la propriété exclusive ; les succès à l’état modifié restent locaux.
  • Une lecture distante oblige le détenteur à l’état modifié à fournir les données actuelles et à rétrograder dans MSI de base.
  • L’état exclusif de MESI permet à un lecteur seul détenant une copie non modifiée d’écrire sans transaction de passage en exclusif.
  • Les états exclusif et modifié ont tous deux un seul détenteur, mais seul l’état modifié contient une copie modifiée.

4.4 Suivre les détenteurs et séparer les données indépendantes

Diffuser chaque requête de cohérence devient coûteux sur les grandes machines. Un répertoire enregistre les caches susceptibles de détenir chaque bloc afin que les requêtes puissent leur être envoyées. Ce suivi au niveau du bloc explique aussi un problème courant de performance : le faux partage.

Interroger le nœud d’attache d’un bloc

Chaque bloc possède une entrée dans le répertoire de son nœud d’attache, qui indique s’il est absent des caches, partagé ou modifié et quels caches le détiennent. Les nœuds d’attache sont répartis entre les nœuds ou les parties du répertoire, ce qui distribue le stockage et le traitement des requêtes.

Un défaut de lecture est envoyé au nœud d’attache. Si la mémoire contient les données actuelles, elle peut les fournir et le répertoire enregistre le nouveau détenteur. Si un autre cache possède une copie à l’état modifié, le nœud d’attache lui transmet la requête afin qu’il fournisse les données actuelles. Dans un protocole à répertoire de base, cela remet aussi la mémoire à jour.

Pour écrire sans déjà détenir le bloc à l’état modifié, un cœur demande une permission au nœud d’attache. Le répertoire envoie des invalidations aux détenteurs enregistrés, attend les accusés de réception et accorde la propriété exclusive. Les succès d’écriture répétés à l’état M ne nécessitent ensuite aucun autre message de cohérence. Le passage par le répertoire ajoute de la latence, mais le trafic point à point évite d’interroger chaque cache au sujet de chaque bloc. Les filtres d’espionnage sur puce remplissent une fonction apparentée en limitant les requêtes aux détenteurs possibles.

Estimer le stockage du répertoire

Un vecteur de présence complet comporte un bit par cœur et par bloc. Pour 64 cœurs, cela représente 64 bits, soit huit octets. Par rapport à un bloc de données de 64 octets, les seuls bits de présence coûtent 8/64=0,125, soit 12,5 %. Avec 256 cœurs, le vecteur de 32 octets coûte 50 %. Les bits d’état s’y ajoutent. Des listes limitées de détenteurs, des vecteurs moins détaillés et le suivi des seuls blocs en cache réduisent ce besoin de stockage.

Reconnaître le faux partage

Le vrai partage se produit lorsque des cœurs échangent des données par le même mot. Le faux partage se produit lorsqu’ils accèdent à des variables différentes dans un même bloc de cache et qu’au moins l’un d’eux écrit. Les variables sont indépendantes dans le programme, mais l’unité de cohérence est plus grande que chacune d’elles.

Deux threads incrémentent des compteurs distincts de 8 octets aux adresses 0x1000 et 0x1008. Avec des blocs de 64 octets, leurs numéros de bloc sont ⌊4096/64⌋=64 et ⌊4104/64⌋=64. Chaque changement de propriété transfère ensemble les droits sur les deux compteurs. Des écritures alternées fréquentes peuvent faire passer le bloc sans cesse d’un cache à l’autre, même si aucun thread n’a besoin de la valeur de l’autre.

Déplacer le second compteur à 0x1040 le place dans le bloc 65. Le remplissage ou l’alignement peut séparer les données propres à chaque thread ; regrouper les valeurs selon le thread qui les écrit aide aussi. Un accumulateur local réécrit une seule fois réduit le trafic lié à la propriété sans ajouter de remplissage à chaque valeur.

Un cœur qui écrit et un autre qui lit une variable voisine peuvent aussi subir du faux partage : le premier invalide le bloc du lecteur, qui serait autrement utile. Deux lecteurs seuls ne le provoquent pas. Le faux partage ajoute du trafic et de l’attente ; il ne rend pas à lui seul incorrectes les valeurs produites par des mises à jour de variables distinctes. Mesure les accès et le placement des lignes de cache avant de modifier l’organisation des données.

Points clés

  • Les répertoires envoient les messages de cohérence aux détenteurs enregistrés par l’intermédiaire du nœud d’attache du bloc.
  • Le stockage des vecteurs de présence augmente avec le nombre de cœurs et le nombre de blocs.
  • Le faux partage concerne des variables différentes dans un même bloc et au moins un cœur qui écrit.
  • Sépare la propriété par le remplissage, le placement ou la réduction des écritures partagées.
5

Relier les nœuds et exploiter des ordinateurs à l’échelle d’un entrepôt

Au-delà d’une machine unique à mémoire partagée, les nœuds échangent des messages par un réseau. Une grappe de calcul doit placer les données et organiser les communications aussi soigneusement qu’elle répartit les calculs. À l’échelle d’un entrepôt, le réseau doit fonctionner aux côtés des systèmes d’alimentation et de refroidissement, malgré les pannes matérielles courantes. Compare la capacité du réseau à une coupe critique, puis utilise des calculs d’énergie et de latence pour évaluer comment un grand parc fournit un service fiable.

5.1 Comparer les nœuds à mémoire privée et leurs réseaux

Une grappe de calcul relie des ordinateurs complets possédant chacun leur propre mémoire et leur propre système d’exploitation. Les nœuds coopèrent par des messages explicites. Le placement des données et le coût de communication font donc partie du modèle de performance du programme.

Répartir les données et combiner les résultats

MPI, l’interface de passage de messages, donne à chaque processus un rang et des opérations telles que l’envoi, la réception, la diffusion et la réduction. Un programme SPMD peut utiliser les rangs pour sélectionner les données de chaque processus. Un pointeur dans l’espace d’adressage privé d’un nœud n’est pas une référence ordinaire en mémoire partagée vers les données d’un autre nœud.

Si un million de valeurs sont déjà réparties sur 100 nœuds, chaque nœud en additionne 10 000 localement. Une réduction en arbre combine les sommes partielles en sept tours, car ⌈log⁡2100⌉=7. Ces tours impliquent des messages réseau, pas seulement des additions locales. Garder les données près du travail qui les utilise réduit les transferts.

Les grappes de calcul passent à l’échelle avec des composants standards, et le matériel défaillant peut être remplacé. Une application peut toutefois nécessiter une reprise ou un redémarrage après la panne d’un nœud ; des nœuds remplaçables ne préservent pas à eux seuls la progression d’une tâche interrompue.

Mesurer plus que le débit des liaisons

La latence est le temps nécessaire à l’arrivée d’un message. La bande passante d’une liaison est son débit de données. La bande passante totale du réseau additionne la capacité des liaisons et décrit un total idéal où toutes les liaisons sont occupées. La bande passante de bissection additionne la capacité traversant la coupe de plus faible capacité qui divise les nœuds en deux moitiés égales.

Pour des liaisons de même capacité B, comparons des réseaux de 64 nœuds avec une même convention de comptage des liaisons :

TopologieLiaisonsCapacité totaleCapacité de bissection
Anneau6464B2B
Maillage de 8 par 8112112B8B
Tore de 8 par 8128128B16B
Hypercube à 6 dimensions192192B32B
Totalement connecté20162016B1024B

Le maillage comporte huit lignes de sept liaisons horizontales et huit colonnes de sept liaisons verticales, soit 112. Relier les bords opposés dans les deux dimensions produit les 128 liaisons du tore. Chaque nœud de l’hypercube a six voisins, soit 64(6)/2=192 liaisons, car chaque liaison est comptée à ses deux extrémités.

Suivre la coupe, puis considérer le coût

Une coupe qui divise un anneau en deux moitiés ne traverse que deux liaisons. De nombreux messages peuvent donc se disputer cette frontière malgré les 64 liaisons de l’anneau au total. Dans un réseau totalement connecté, 32(32)=1024 liaisons traversent la séparation entre les deux moitiés, mais le réseau nécessite 64(63)/2=2016 liaisons au total.

Davantage de liaisons peuvent améliorer la bande passante et réduire les sauts tout en augmentant le nombre de ports de commutation et de câbles ainsi que la puissance consommée. Les bus partagés disposent d’une seule ressource de communication partagée ; les maillages et les tores répartissent les liaisons dans l’espace. Les grandes grappes de calcul utilisent souvent des réseaux commutés à plusieurs étages, comme les arbres gras. Leur utilité dépend de la nature du trafic autant que de leur capacité totale. Pour la communication entre les moitiés d’une machine, la bissection révèle une limite que le total masque.

Points clés

  • Les nœuds d’une grappe de calcul utilisent des espaces d’adressage privés et une communication explicite.
  • Les rangs MPI identifient les processus ; les opérations collectives combinent le travail distribué.
  • Les tours de messages ajoutent un coût aux calculs locaux.
  • La bande passante totale mesure la capacité globale des liaisons ; la bissection mesure une coupe critique à travers la machine.
  • La capacité du réseau implique un compromis avec les ports, les câbles, la puissance et les sauts.

5.2 Évaluer un centre de données comme un seul ordinateur

Un ordinateur à l’échelle d’un entrepôt associe des dizaines de milliers de serveurs à une alimentation électrique, un système de refroidissement et un réseau pour fournir des services internet. Les requêtes indépendantes fournissent du travail parallèle, tandis que des infrastructures de traitement par lots comme MapReduce répartissent de grandes tâches de traitement de données entre les machines.

Adapter la conception au service

Les systèmes à l’échelle d’un entrepôt privilégient le coût par requête, l’efficacité énergétique et la disponibilité. Les logiciels réessaient les tâches, répliquent les données et contournent les machines en panne. Un supercalculateur privilégie plus souvent un programme scientifique unique fortement couplé et une interconnexion rapide.

Les serveurs sont reliés à des commutateurs en haut de baie, eux-mêmes reliés par des niveaux supérieurs de commutation. Les niveaux supplémentaires ajoutent de la latence aux communications. Les liaisons montantes sont souvent sursouscrites, ce qui signifie que leur capacité est inférieure à la capacité totale des liaisons des serveurs. Certains réseaux non bloquants de type Clos offrent une capacité supérieure suffisante pour éviter cette restriction.

Quarante serveurs reliés à 10 Gbit/s offrent 400 Gbit/s à un commutateur de baie. Quatre liaisons montantes de 25 Gbit/s fournissent 100 Gbit/s, soit un rapport de 4:1. Si tous les serveurs émettent ensemble hors de la baie et se partagent la capacité également, chacun dispose en moyenne de 2,5 Gbit/s. Un serveur peu chargé peut utiliser davantage de bande passante lorsque les autres sont inactifs.

Séparer le surcoût de l’installation du calcul utile

L’indicateur d’efficacité énergétique, ou PUE, est l’énergie totale de l’installation divisée par l’énergie des équipements informatiques sur la même période. Une charge informatique constante de dix MW et un surcoût de 1,5 MW pour le refroidissement et la distribution donnent PUE=11,5/10=1,15. La valeur idéale est de 1,0. Google a déclaré un PUE annuel de 1,09 pour l’ensemble de son parc en 2025.

Le PUE mesure le surcoût de l’installation, pas les calculs utiles par joule. Des serveurs inactifs ou inefficaces peuvent gaspiller de l’énergie parmi les équipements informatiques même lorsque le PUE de l’installation est excellent.

Pour 50 000 serveurs consommant en moyenne 300 W, la puissance informatique est de 15 MW. Avec un PUE de 1,2, la puissance de l’installation est de 18 MW. Maintenue pendant 8 760 heures, elle consomme 157 680 MWh ; le surcoût seul consomme 26 280 MWh. Les équipements électriques, le refroidissement, l’électricité, les serveurs et les bâtiments contribuent tous au coût de possession.

Une faible charge peut encore consommer beaucoup de puissance

La proportionnalité énergétique signifie que la puissance devrait augmenter proportionnellement à la charge. Un serveur qui consomme 150 W au repos et 300 W en crête, avec une augmentation linéaire, absorbe 150+0,3(150)=195 W à 30 % de charge. Il utilise 65 % de la puissance de crête pour 30 % du travail maximal. Des mesures antérieures à l’échelle d’entrepôts ont montré que de nombreux serveurs fonctionnaient entre environ 10 % et 50 % d’utilisation, ce qui rend la puissance au repos importante.

Prévoir les pannes et les réponses lentes

Si chacun des 50 000 serveurs connaît en moyenne une panne tous les dix ans, on attend 5 000 pannes par an dans le parc, soit environ 14 par jour. Cette prévision justifie la redondance et les nouvelles tentatives ; elle ne prévoit pas exactement 14 pannes chaque jour.

Une requête qui nécessite les réponses de nombreux serveurs attend la plus lente des réponses requises. Si chacun des 100 serveurs a indépendamment une probabilité de 1 % d’être lent, la probabilité qu’aucun ne le soit est 0,99100. La probabilité qu’au moins l’un soit lent est donc 1−0,99100≈0,634. La latence de queue d’un serveur devient une attente fréquente pour les requêtes lorsque leur diffusion touche de nombreux serveurs.

Points clés

  • La conception à l’échelle d’un entrepôt met en balance le débit du service, l’énergie, le coût et la disponibilité.
  • Les liaisons montantes sursouscrites limitent le trafic simultané sortant des baies.
  • Le PUE mesure le surcoût de l’installation, tandis que l’efficacité des serveurs mesure le travail utile des équipements informatiques.
  • La puissance consommée au repos rend coûteuse une faible utilisation.
  • Les grands parcs connaissent des pannes courantes, et la diffusion des requêtes amplifie la latence de queue.

Processeurs parallèles et multicœurs : exemples

5 Leçons Interactives

1

Choisir une source utile de travail parallèle

15 étapes
Suis une charge de travail depuis les limites de puissance jusqu’aux flux d’instructions, puis utilise des threads prêts pour couvrir les attentes mémoire.
  1. 1
    IntroductionPlus de travail sans une horloge plus chaude

    Un service doit traiter davantage de tâches, mais augmenter la fréquence d’horloge de son processeur dépasserait son budget de puissance. Le matériel parallèle accomplit davantage dans un budget de puissance fixe. Les concepteurs peuvent ajouter des cœurs (MIMD), élargir les opérations sur les données (SIMD) ou garder davantage de threads prêts (multithreading). Chaque choix exige une source de travail adaptée. Commence par déterminer ce qui peut s’exécuter ensemble, puis demande-toi comment ce travail atteint le matériel et si le bénéfice est un temps de réponse plus court ou une capacité de service accrue (débit).

  2. 2
    ExplicationLa tension a un effet au carré

    La puissance dynamique suit approximativement P≈CV2f. À capacité inchangée, réduire la tension et la fréquence à 85 % multiplie la puissance par 0,85×0,85×0,85=0,614125. Cette forte réduction aide à expliquer pourquoi plusieurs cœurs modestes peuvent être intéressants. Le mur de puissance est apparu lorsque les réductions de tension ne pouvaient plus compenser le coût en chaleur et en puissance de l’augmentation des fréquences d’horloge.

  3. 3
    ExempleDistinguer une requête de nombreuses requêtes

    Si quatre téléchargements indépendants s’exécutent sur quatre cœurs, la machine peut achever davantage de téléchargements par seconde même si chacun prend le même temps. C’est un gain de débit provenant du travail au niveau des requêtes. Si une image est divisée en régions indépendantes et que quatre threads les traitent, cette image peut se terminer plus tôt. Le matériel parallèle sert les deux objectifs, mais le programme doit fournir le travail approprié.

  4. 4
    ExplicationTrouver du travail à l’intérieur d’un programme

    Un pipeline fait se chevaucher les instructions d’un même flux : c’est le parallélisme au niveau des instructions. Une opération sur tableau se répète sur les éléments : c’est le parallélisme de données. Des threads distincts fournissent du parallélisme au niveau des threads, avec leur propre état d’exécution et un espace d’adressage de processus partagé. Ces formes peuvent coexister. Un programme à threads sur tableaux peut répartir des régions entre les cœurs, utiliser SIMD dans chaque région et exécuter ces instructions dans le pipeline de chaque cœur.

  5. 5
    DéfiSe relayer compte-t-il ?

    Un cœur alterne entre deux tâches. Toutes deux sont en cours pendant une seconde, mais leurs instructions ne s’exécutent jamais au même instant. Est-ce une exécution parallèle ?

    ---reveal---

    C’est une exécution concurrente par partage du temps. Le parallélisme exige des opérations simultanées sur des ressources matérielles distinctes. Un autre cœur pourrait fournir cette simultanéité, mais il lui faudrait tout de même du travail prêt à être exécuté.

  6. 6
    ExplicationDemander qui choisit l’instruction suivante

    La classification de Flynn part des flux d’instructions et de données. Un cœur unique scalaire classique est SISD. Une opération large qui applique une instruction à plusieurs éléments est SIMD. Des processeurs commandés indépendamment qui traitent leurs données sont MIMD. MISD associe plusieurs flux d’instructions à un seul flux de données et possède peu d’exemples pratiques incontestables. Compte les flux à un niveau matériel choisi.

  7. 7
    ExempleUn programme, des progressions distinctes

    Quatre unités de travail utilisent leurs identifiants pour diviser un tableau de 4 000 éléments en quatre régions de 1 000 éléments. Elles exécutent le même programme, mais l’une peut atteindre son addition finale tandis qu’une autre charge encore des valeurs. C’est un logiciel SPMD sur du matériel MIMD. Partager le texte du programme n’exige pas une émission synchronisée des instructions. Une instruction SIMD à l’intérieur de l’une des unités ajouterait un autre niveau d’exécution parallèle.

  8. 8
    DéfiClasser le niveau choisi

    Un processeur multicœur dont les cœurs sont commandés indépendamment utilise des additions vectorielles dans chaque cœur. Quelles sont les classes entre les cœurs et à l’intérieur d’une addition vectorielle ?

    ---reveal---

    Les cœurs forment un matériel MIMD car ils choisissent leurs instructions indépendamment. Chaque addition vectorielle est SIMD car une instruction agit sur plusieurs éléments de données. Une même machine peut recevoir les deux descriptions lorsqu’elles concernent des niveaux différents.

  9. 9
    ExplicationGarder l’état d’exécution prêt

    Un contexte de thread matériel stocke un compteur ordinal et des registres. Plusieurs contextes peuvent partager les unités arithmétiques et les caches d’un cœur. Lorsqu’une requête mémoire bloque un thread, un autre thread prêt peut remplir la capacité d’exécution inactive. Le système d’exploitation voit chaque contexte comme un processeur logique. Deux contextes dans un cœur partagent toujours les ressources d’exécution physiques de ce cœur.

  10. 10
    ExplicationChoisir quand les threads partagent le cœur

    Le multithreading à grain fin sélectionne un thread prêt à chaque cycle. Le multithreading à gros grain change de thread après un long blocage, en supportant les coûts de changement et de nouveau remplissage du pipeline. Le SMT va plus loin sur un cœur à émission multiple : des instructions de différents threads peuvent être émises pendant le même cycle. Les trois dépendent de la disponibilité de travail utile ; aucun ne fournit une capacité arithmétique supplémentaire illimitée.

  11. 11
    ExempleMesurer d’abord la période inactive

    Un thread calcule pendant 20 cycles puis attend pendant 200 cycles. Sa période est de 220 cycles, donc son temps actif est 20/220≈9,1%. Une longue attente laisse la plupart des cycles inutilisés lorsqu’aucun autre thread n’est disponible. Garde toute la période de calcul et d’attente au dénominateur. Diviser par la seule attente décrirait un autre rapport, pas la fraction des cycles écoulés consacrée au travail utile.

  12. 12
    ExempleCombler l’attente avec des séquences de calcul prêtes

    Avec quatre threads librement décalés, contribuant chacun à 20 cycles de calcul par période de 220 cycles, l’utilisation idéale est 80/220≈36,4%. Onze threads peuvent remplir la période : pendant que l’un attend 200 cycles, les dix autres fournissent 200 cycles de calcul. Ce modèle idéal suppose un changement sans coût et aucune concurrence supplémentaire ; dans la réalité, la concurrence pour la bande passante et le cache peut laisser moins de travail utile prêt.

  13. 13
    DéfiUn autre contexte résoudrait-il le problème ?

    Les unités arithmétiques d’un cœur sont déjà entièrement occupées et ses deux threads ont tous deux besoin de ces mêmes unités. Ajouter un autre thread matériel fournirait-il la capacité d’un autre cœur ? Explique ta réponse à partir de la ressource qu’ils partagent.

    ---reveal---

    Non. Un nouveau contexte fournit un autre flux d’instructions, mais partage toujours les unités d’exécution occupées. Un autre cœur complet ajoute du matériel d’exécution. Le multithreading est surtout utile lorsqu’il remplit la capacité inutilisée à cause des blocages ou d’un nombre limité d’instructions prêtes.

  14. 14
    LienRelier l’amélioration du service à sa cause

    Le service ajoute des contextes matériels et achève désormais davantage de requêtes indépendantes par seconde, tandis que le travail du processeur pour chaque requête prend légèrement plus de temps. Ce résultat correspond à une amélioration du débit : les requêtes prêtes remplissent les créneaux inactifs tout en partageant les ressources. Il serait trompeur d’y voir une amélioration de la latence d’une requête individuelle. Choisis une mesure de performance qui correspond au travail que les utilisateurs veulent voir accompli.

  15. 15
    RécapitulatifPrendre la première décision matérielle

    Pour une nouvelle charge de travail, repère d’abord les instructions, éléments de données, threads ou requêtes indépendants. Détermine ensuite le niveau matériel qui contrôle leurs flux d’instructions. Si le gain proposé provient de contextes supplémentaires, examine quels blocages laissent de la capacité disponible et quelles ressources les contextes partagent. Tu disposes ainsi d’une base concrète pour choisir davantage de cœurs, des opérations plus larges ou davantage de threads prêts avant de mesurer le résultat.

2

Trouver la limite avant d’ajouter des processeurs

16 étapes
Étudie l’accélération à taille fixe, les charges de travail croissantes et un noyau de calcul limité par la bande passante.

Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.

  1. 1
    IntroductionTrois raisons pour lesquelles le matériel supplémentaire peut décevoir
  2. 2
    ExplicationChoisir le temps de référence
  3. 3
    ExempleDiviser uniquement la partie parallèle
  4. 4
    Point cléLa partie fixe détermine toute la limite
  5. 5
    DéfiL’objectif d’accélération est-il possible ?
  6. 6
    ExplicationGarder visible la question de la charge de travail
  7. 7
    ExempleUtiliser la fraction de l’exécution parallèle
  8. 8
    ExempleAttendre l’unité de travail la plus chargée
  9. 9
    DéfiQuand l’ajout de cœurs augmente-t-il le temps ?
  10. 10
    ExplicationCompter les octets qui quittent la mémoire
  11. 11
    ExempleConstruire les deux toits
  12. 12
    ExplicationLa réutilisation déplace le noyau vers la droite
  13. 13
    DéfiQuelle amélioration relève la borne actuelle ?
  14. 14
    DéfiUn noyau rapide dans un programme lent
  15. 15
    ConseilRendre le gain annoncé reproductible
  16. 16
    RécapitulatifChoisir la prochaine mesure
3

Transformer une boucle sur tableau en travail pour GPU

22 étapes
Compte les éléments SIMD, découpe une boucle vectorielle en bandes et construis une affectation aux threads du GPU avec vérification des bornes et coopération correcte.

Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.

  1. 1
    IntroductionPartir d’éléments de tableau indépendants
  2. 2
    ExempleCompter les éléments avant les instructions
  3. 3
    ExplicationPlacer les valeurs côte à côte
  4. 4
    ExplicationSélectionner les éléments avec un masque
  5. 5
    DéfiToutes les itérations peuvent-elles commencer ensemble ?
  6. 6
    ExplicationLaisser la longueur active décrire le passage
  7. 7
    ExempleDiviser un long vecteur en passages
  8. 8
    LienAlimenter une opération vectorielle avec une autre
  9. 9
    DéfiAvancer selon ce qui a réellement été exécuté
  10. 10
    ExplicationOrdonnancer un warp pendant qu’un autre attend
  11. 11
    ExempleDes chemins différents gaspillent des voies actives
  12. 12
    ExplicationFaire servir une transaction à de nombreux threads
  13. 13
    DéfiInclure le trajet vers le périphérique
  14. 14
    LienSe spécialiser pour une charge de travail plus restreinte
  15. 15
    ExempleTrouver l’élément de tableau d’un thread
  16. 16
    ExempleCouvrir le dernier bloc partiel
  17. 17
    ExplicationAttendre avant que l’hôte utilise les résultats
  18. 18
    ExempleEffectuer une réduction dans un bloc
  19. 19
    DéfiUn bloc peut-il attendre tous les autres ?
  20. 20
    Point cléUne réduction modifie l’ordre des opérations arithmétiques
  21. 21
    DéfiCombiner une affectation sûre avec des accès efficaces
  22. 22
    RécapitulatifVérifier le parcours complet du tableau
4

Suivre un bloc partagé du lecteur au cœur qui écrit

19 étapes
Répartis une somme, suis les permissions de cache et diagnostique les interférences entre des compteurs indépendants.

Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.

  1. 1
    IntroductionLes variables partagées nécessitent toujours une coordination
  2. 2
    ExplicationUn espace d’adressage, différents chemins d’accès
  3. 3
    ExempleTerminer le travail local avant de combiner
  4. 4
    DéfiQue faire après une écriture intermédiaire ?
  5. 5
    ExempleRepérer le succès de cache avec une valeur périmée
  6. 6
    ExplicationS’accorder sur l’historique d’un emplacement
  7. 7
    DéfiLa cohérence peut-elle préserver les deux incrémentations ?
  8. 8
    LienDistinguer l’ordre de la propriété
  9. 9
    ExplicationLire les permissions dans MSI
  10. 10
    ExempleDonner d’abord des copies non modifiées aux deux cœurs
  11. 11
    ExempleTransférer la propriété au cœur qui écrit
  12. 12
    Point cléL’état exclusif supprime une requête pour les données privées
  13. 13
    DéfiSuivre une lecture et deux écritures
  14. 14
    ExplicationEnvoyer la requête par le nœud d’attache
  15. 15
    ExempleConvertir les bits avant de mesurer le surcoût
  16. 16
    ExempleTrouver les octets qui partagent la propriété
  17. 17
    DéfiLe lecteur voisin doit-il écrire ?
  18. 18
    DéfiRéduire la concurrence dans une somme correcte
  19. 19
    RécapitulatifExaminer le programme et le bloc
5

Suivre les données, l’énergie et les réponses lentes dans un parc

14 étapes
Compare les coupes de réseau, calcule l’énergie de l’installation et découvre pourquoi les grands services prévoient les événements rares.

Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.

  1. 1
    IntroductionUn nœud est désormais un ordinateur complet
  2. 2
    ExplicationPlacer le travail près de son entrée
  3. 3
    ExempleCombiner les sommes partielles en tours de messages
  4. 4
    ExplicationCompter la coupe étroite
  5. 5
    DéfiPayer le coût d’un réseau plus large
  6. 6
    ExplicationPartager les liaisons montantes
  7. 7
    ExempleInclure le refroidissement et la distribution
  8. 8
    ExempleTransformer une puissance constante en énergie annuelle
  9. 9
    DéfiQuelle efficacité le changement a-t-il améliorée ?
  10. 10
    ExempleUne faible charge consomme toujours de la puissance
  11. 11
    ExplicationLes faibles taux de panne s’additionnent dans le parc
  12. 12
    ExempleUne réponse lente peut retenir la requête
  13. 13
    DéfiDavantage de serveurs raccourciront-ils chaque requête ?
  14. 14
    RécapitulatifChoisir un indicateur du parc selon son objectif

Processeurs parallèles et multicœurs : QCM

50 Questions Pratiques en 5 séries

Série 1 : Reconnaître le travail parallèle et ses coûts10 Questions Pratiques

Question 1 sur 10

Un service web affecte des requêtes indépendantes de téléchargement d’images à différents serveurs. Quelle forme de parallélisme est utilisée ?
  1. Parallélisme au niveau des instructions
  2. Parallélisme au niveau des requêtes
  3. Parallélisme de données
  4. Multithreading à grain fin
Afficher la réponseMasquer la réponse
Réponse : B
Chaque serveur traite une requête distincte : le travail parallèle provient donc de tâches indépendantes. Le parallélisme de données appliquerait la même opération à de nombreux éléments d’un calcul ; traiter différentes requêtes n’exige pas qu’elles progressent selon une instruction partagée.

Question 2 sur 10

Tous les processeurs s’accordent sur l’ordre des écritures à un emplacement mémoire. De quelle propriété de cohérence s’agit-il ?
  1. Propagation des écritures
  2. Consistance séquentielle
  3. Lecture-modification-écriture atomique
  4. Sérialisation des écritures
Afficher la réponseMasquer la réponse
Réponse : D
La sérialisation des écritures donne à tous les processeurs le même ordre des écritures à un emplacement. La consistance séquentielle impose en plus des contraintes sur l’entrelacement global des opérations entre emplacements, tout en préservant l’ordre du programme de chaque processeur. L’accord sur le seul historique des écritures à un emplacement est une propriété plus restreinte.

Question 3 sur 10

Une tâche prend 144 s avec la meilleure implémentation séquentielle et 24 s sur huit processeurs. Quelle est son efficacité parallèle ?
  1. 75%
  2. 16,7%
  3. 60%
  4. 80%
Afficher la réponseMasquer la réponse
Réponse : A
L’accélération est le rapport des temps, 144/24 = 6. L’efficacité divise ce gain par les huit processeurs, soit 6/8=0,75, ou 75 %. Le résultat de 16,7 % utilise le temps parallèle divisé par le temps séquentiel : il mesure la fraction de temps restante plutôt que l’efficacité.

Question 4 sur 10

Un noyau de calcul a une intensité de 3 opérations à virgule flottante par octet sur un matériel offrant un débit de calcul de crête de 720 GFLOP/s et une bande passante DRAM de 80 Go/s. Quelle borne du modèle Roofline s’applique ?
  1. 720 GFLOP/s
  2. 960 GFLOP/s
  3. 240 GFLOP/s
  4. 26,7 GFLOP/s
Afficher la réponseMasquer la réponse
Réponse : C
Le toit de bande passante est de 80×3=240 GFLOP/s, sous le toit de calcul de 720 GFLOP/s. Le plafond le plus bas fixe la borne. Choisir le seul débit de calcul de crête suppose que les données arrivent assez vite pour le soutenir, mais ce noyau nécessiterait bien plus d’octets par seconde que la mémoire n’en fournit.

Question 5 sur 10

Combien d’éléments de 64 bits tiennent dans un registre SIMD de 512 bits ?
  1. 4 éléments
  2. 16 éléments
  3. 8 éléments
  4. 64 éléments
Afficher la réponseMasquer la réponse
Réponse : C
Divise la largeur du registre par celle d’un élément : 512/64 = 8. Le nombre de voies dépend de la taille des éléments comme de celle du registre. Seize voies contiendraient des valeurs de 32 bits : utiliser ce nombre pour des valeurs de 64 bits n’allouerait que la moitié de l’espace nécessaire par élément.

Question 6 sur 10

Deux warps de GPU suivent des chemins opposés dans une structure conditionnelle. Dans chaque warp, tous les threads suivent le même chemin. Qu’en est-il de la divergence de branchement ?
  1. Les deux warps exécutent chaque branche.
  2. Aucun des deux warps ne diverge en interne.
  3. La moitié de chaque warp devient inactive.
  4. Chaque warp se divise en deux warps.
Afficher la réponseMasquer la réponse
Réponse : B
La divergence se détermine à l’intérieur d’un warp, où l’émission des instructions est partagée. Chaque warp décrit a une condition uniforme et peut exécuter uniquement son propre chemin. Des warps différents peuvent suivre des chemins différents sans que l’un ou l’autre soit forcé d’exécuter les deux branches avec la moitié de ses voies masquées.

Question 7 sur 10

Une charge de travail NUMA effectue 60 % de ses accès en 75 ns et le reste en 135 ns. Quelle est la latence moyenne d’accès ?
  1. 99 ns
  2. 105 ns
  3. 81 ns
  4. 135 ns
Afficher la réponseMasquer la réponse
Réponse : A
Pondère chaque latence par sa part des accès : 0,6×75+0,4×135=45+54=99 ns. Une moyenne non pondérée donne 105 ns, mais elle supposerait autant d’accès locaux que d’accès distants. Ici, les accès locaux plus rapides sont plus fréquents.

Question 8 sur 10

Deux threads lisent tous deux la valeur 9 dans un compteur cohérent, puis écrivent tous deux 10 après une incrémentation ordinaire. Quelle propriété manque à cette incrémentation ?
  1. Propagation des écritures
  2. Sérialisation des écritures
  3. Réplication du cache
  4. Atomicité
Afficher la réponseMasquer la réponse
Réponse : D
L’incrémentation comprend une lecture et une écriture distincte : les deux threads peuvent donc lire neuf avant que l’un d’eux écrive dix. La cohérence peut sérialiser correctement les deux écritures de dix et perdre tout de même une incrémentation. Une lecture-modification-écriture atomique rend chaque mise à jour entière indivisible pour l’autre thread.

Question 9 sur 10

Dans MSI de base, A et B commencent à l’état invalide pour un bloc contenant 4. A lit, A écrit 7, puis B lit. Quels sont les états finaux A/B et la valeur lue par B ?
  1. M/S, B lit 7
  2. S/S, B lit 7
  3. I/S, B lit 4
  4. S/S, B lit 4
Afficher la réponseMasquer la réponse
Réponse : B
A charge d’abord le bloc à l’état partagé, puis obtient la propriété à l’état modifié pour écrire sept. La lecture ultérieure de B oblige A à fournir la valeur modifiée et à rétrograder à l’état partagé ; B reçoit aussi l’état partagé. Laisser A à l’état modifié contredirait la règle de MSI de base selon laquelle un bloc modifié n’a aucune autre copie valide en cache.

Question 10 sur 10

Un anneau de 20 nœuds possède des liaisons de même bande passante, à 5 Gbit/s. En utilisant une valeur de capacité par liaison, quelle est sa bande passante de bissection ?
  1. 10 Gbit/s
  2. 100 Gbit/s
  3. 50 Gbit/s
  4. 5 Gbit/s
Afficher la réponseMasquer la réponse
Réponse : A
La coupe minimale d’un anneau en deux moitiés égales traverse deux liaisons, donc sa capacité est de 2×5=10 Gbit/s. Le total de 100 Gbit/s compte les vingt liaisons et décrit la capacité globale. Celle-ci ne peut pas entièrement transporter du trafic à travers les deux liaisons qui séparent les moitiés.
Série 2 : Appliquer les règles de passage à l’échelle, d’indexation et de cohérence10 Questions Pratiques

Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.

Question 1 sur 10

Un cœur émet des instructions de deux threads différents pendant le même cycle. Quelle technique matérielle cela décrit-il ?
  1. Multithreading à gros grain
  2. Multithreading à grain fin
  3. Multithreading simultané
  4. Partage du temps par le système d’exploitation
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 2 sur 10

Une tâche de taille fixe consacre 20 % de son temps séquentiel à un travail qui ne peut pas être parallélisé. Avec une répartition idéale du reste sur quatre processeurs, quelle accélération obtient-on ?
  1. 2,5
  2. 3,2
  3. 4,0
  4. 5,0
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 3 sur 10

Une simulation passe de deux millions de cellules sur quatre processeurs à quatre millions de cellules sur huit processeurs, avec un travail fixe par cellule. De quelle expérience de passage à l’échelle s’agit-il ?
  1. Passage à l’échelle fort
  2. Passage à l’échelle superlinéaire
  3. Passage à l’échelle à charge fixe
  4. Passage à l’échelle faible
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 4 sur 10

Une boucle RVV a encore 90 éléments à traiter. Son implémentation choisit les longueurs actives successives 32, 32 et 26. De combien d’éléments le code doit-il avancer après son deuxième passage ?
  1. 26 éléments
  2. 32 éléments
  3. 64 éléments
  4. 90 éléments
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 5 sur 10

Un tableau contient 4 103 éléments. Un noyau de calcul traite un élément par thread et utilise 128 threads par bloc. Combien de blocs faut-il ?
  1. 33 blocs
  2. 32 blocs
  3. 34 blocs
  4. 129 blocs
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 6 sur 10

Six cœurs exécutent chacun une copie d’un même programme. Ils choisissent leurs instructions indépendamment et traitent différentes régions d’un tableau. Quelle est la classe matérielle ?
  1. SIMD
  2. SISD
  3. MISD
  4. MIMD
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 7 sur 10

Dans MESI, A lit un bloc absent des caches, y écrit, y écrit à nouveau, puis B le lit. Les deux copies commencent à l’état invalide. Combien de requêtes de cohérence sur le bus cette séquence produit-elle ?
  1. 1 requête
  2. 3 requêtes
  3. 2 requêtes
  4. 4 requêtes
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 8 sur 10

Un répertoire complet utilise un bit de présence par cœur pour chaque bloc de données de 128 octets. Avec 128 cœurs, quel est le surcoût de stockage du seul vecteur de présence ?
  1. 1,56%
  2. 12,5%
  3. 16%
  4. 100%
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 9 sur 10

Quarante-huit nœuds d’une grappe de calcul détiennent déjà des parts égales de 960 000 valeurs. Un arbre binaire combine une somme locale par nœud. Combien y a-t-il de valeurs par nœud et combien faut-il de tours de combinaison ?
  1. 20 000 valeurs et 48 tours
  2. 46 080 000 valeurs et 6 tours
  3. 20 000 valeurs et 5 tours
  4. 20 000 valeurs et 6 tours
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 10 sur 10

Une baie contient 24 serveurs dotés de liaisons de 25 Gbit/s et six liaisons montantes de 50 Gbit/s. Avec un partage égal lorsque tous les serveurs émettent simultanément hors de la baie, quels sont le rapport de sursouscription et le débit par serveur ?
  1. 2:1 et 25 Gbit/s
  2. 4:1 et 6,25 Gbit/s
  3. 2:1 et 12,5 Gbit/s
  4. 1:2 et 50 Gbit/s
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Série 3 : Diagnostiquer les limites de performance dans tout le système10 Questions Pratiques

Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.

Question 1 sur 10

La capacité reste fixe tandis que la tension tombe à 90 % et la fréquence à 80 % de leurs valeurs initiales. Quelle fraction de la puissance dynamique initiale reste-t-il ?
  1. 0,720
  2. 0,810
  3. 0,5832
  4. 0,648
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 2 sur 10

Un cœur superscalaire unique suit un seul flux d’instructions et fait se chevaucher des instructions scalaires indépendantes. Comment est-il classé dans la classification de Flynn ?
  1. SIMD
  2. SISD
  3. MIMD
  4. MISD
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 3 sur 10

Six cœurs reçoivent initialement des nombres de tâches de même coût : 35, 35, 35, 35, 35 et 65. Un ordonnanceur transfère dix tâches du cœur le plus chargé à chacun des cinq autres. Sans surcoût et à raison d’une tâche par unité de temps et par cœur, comment l’accélération par rapport à l’exécution séquentielle change-t-elle ?
  1. Elle passe d’environ 3,69 à 5,33.
  2. Elle passe d’environ 3,69 à 6,00.
  3. Elle passe d’exactement 6,00 à 5,33.
  4. Elle passe d’exactement 4,00 à 5,33.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 4 sur 10

Une machine atteint au maximum 960 GFLOP/s et 120 Go/s. Un noyau de calcul effectue 12 milliards d’opérations à virgule flottante et transfère 3 Go depuis la DRAM. Le traitement par blocs réduit les transferts de moitié sans modifier le travail. Que devient la borne du modèle Roofline ?
  1. Elle passe de 480 à 1 920 GFLOP/s.
  2. Elle reste fixée à 480 GFLOP/s.
  3. Elle passe de 480 à 960 GFLOP/s.
  4. Elle passe de 240 à 480 GFLOP/s.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 5 sur 10

Une boucle calcule a[i] = a[i-1] + b[i] de gauche à droite. Pourquoi le compilateur ne peut-il pas remplacer directement les itérations consécutives par des voies SIMD indépendantes ?
  1. Chaque itération lit des valeurs dans deux tableaux différents.
  2. Chaque itération nécessite le nouveau résultat de l’itération précédente.
  3. Chaque itération comporte plus d’une entrée arithmétique.
  4. Chaque itération range son résultat dans un tableau contigu.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 6 sur 10

Une boucle RVV a encore 50 nombres en double précision à traiter et une capacité de 32. L’implémentation renvoie vl = 28. Le programmeur avance les deux pointeurs de 32 éléments et soustrait 32 du nombre restant. Quelle est la première plage de données perdue ?
  1. Indices initiaux de 0 à 27
  2. Indices initiaux de 32 à 49
  3. Indices initiaux de 24 à 27
  4. Indices initiaux de 28 à 31
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 7 sur 10

Dans un système NUMA, pourquoi deux accès à la même adresse partagée peuvent-ils avoir des latences différentes depuis deux sockets ?
  1. L’adresse peut être locale à un socket et distante pour l’autre.
  2. Chaque socket doit attribuer une valeur numérique différente à l’adresse.
  3. Chaque socket doit utiliser un espace d’adressage applicatif distinct.
  4. L’adresse doit contourner tous les caches privés de la machine.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 8 sur 10

Avec des blocs de 64 octets, A écrit de façon répétée dans un compteur de 8 octets à l’adresse 0x2040 ; B lit de façon répétée une valeur d’état indépendante de 8 octets à l’adresse 0x2078. Pourquoi B peut-il subir des défauts de cohérence ?
  1. Les variables occupent des blocs voisins, donc chaque lecture charge les deux blocs.
  2. Les deux threads écrivent dans le même compteur, donc une incrémentation est perdue.
  3. Les deux variables occupent le bloc 129 et les écritures de A invalident la copie de B.
  4. Le lecteur a besoin de la propriété à l’état modifié avant de lire la valeur d’état.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 9 sur 10

Une addition vectorielle de 72 éléments s’exécute sur six voies. Sans compter le démarrage, combien de cycles faut-il pour les opérations sur les éléments ?
  1. 6 cycles
  2. 72 cycles
  3. 12 cycles
  4. 432 cycles
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 10 sur 10

Des équipements informatiques absorbent une puissance constante de 8 MW et le surcoût de l’installation ajoute 2 MW. Quel est le PUE ?
  1. 1,25
  2. 0,25
  3. 0,80
  4. 4,00
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Série 4 : Combiner le comportement du matériel et les modèles de performance10 Questions Pratiques

Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.

Question 1 sur 10

Une machine possède 12 cœurs et deux threads matériels par cœur. Combien de processeurs logiques sont visibles et combien de cœurs physiques existent ?
  1. 24 processeurs logiques et 12 cœurs
  2. 24 processeurs logiques et 24 cœurs
  3. 12 processeurs logiques et 24 cœurs
  4. 12 processeurs logiques et 12 cœurs
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 2 sur 10

Un système monocœur alterne entre deux tâches de longue durée, sans jamais exécuter leurs instructions au même instant. Comment décrire leur exécution ?
  1. Parallèle mais non concurrente
  2. À la fois parallèle et concurrente
  3. Concurrente mais non parallèle
  4. Ni parallèle ni concurrente
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 3 sur 10

Un noyau de faible intensité sature déjà la bande passante DRAM et s’exécute à sa borne du modèle Roofline. La largeur SIMD double tandis que la bande passante et l’intensité restent fixes. Comment sa borne évolue-t-elle ?
  1. Elle double.
  2. Elle est divisée par deux.
  3. Elle augmente de l’intensité initiale.
  4. Elle reste identique.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 4 sur 10

Un noyau de réduction utilise if (i < n) { load_into_shared(); __syncthreads(); combine(); }. Dans son dernier bloc, seuls certains threads satisfont la condition. Quelle correction de structure rend la barrière du bloc sûre ?
  1. Supprimer la vérification des bornes pour que tous les threads du bloc chargent un élément du tableau.
  2. Faire atteindre la barrière à tous les threads du bloc, avec des valeurs neutres pour les entrées inactives.
  3. Remplacer la barrière du bloc par une attente de l’hôte après le lancement du noyau.
  4. Placer une seconde barrière identique dans la même branche conditionnelle.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 5 sur 10

Un processeur prend 36 ms par lot. Un GPU dédié nécessite un transfert vers le GPU de 500 Mo, puis trois noyaux de calcul de 4 ms, puis un transfert retour de 100 Mo. Les transferts atteignent 15 Go/s, ne peuvent pas se chevaucher avec le calcul et le coût de lancement est négligeable. Quel parcours est le plus rapide et de combien ?
  1. Le GPU est plus rapide de 24 ms.
  2. Le processeur est plus rapide de 16 ms.
  3. Le processeur est plus rapide de 4 ms.
  4. Le GPU est plus rapide de 16 ms.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 6 sur 10

Trente-deux cœurs se partagent également 32 000 valeurs. Chaque thread part de zéro et additionne les valeurs qui lui sont affectées, puis un arbre binaire combine les sommes partielles. Chaque addition coûte une unité de temps ; chaque étape de l’arbre comporte aussi une barrière de deux unités. Sans autre coût, quelle accélération obtient-on par rapport à une somme séquentielle partant de zéro ?
  1. Environ 31,53
  2. Environ 31,84
  3. Environ 31,69
  4. Exactement 32,00
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 7 sur 10

Un cœur utilise un cache à écriture simultanée. Un autre cœur détient déjà une copie non modifiée en cache pour la même adresse. Pourquoi un mécanisme de cohérence reste-t-il nécessaire après l’écriture du premier cœur ?
  1. L’écriture simultanée empêche le premier cœur de mettre la mémoire à jour.
  2. Une copie non modifiée en cache ne peut jamais devenir invalide.
  3. Le second cœur doit supprimer tous ses blocs de cache à chaque lecture.
  4. La seule mise à jour de la mémoire laisse l’autre copie en cache périmée.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 8 sur 10

Dans MESI, A lit un bloc absent des caches, B le lit, A écrit 3, A écrit 6, puis B lit à nouveau. Combien de requêtes sur le bus ont lieu et quelle valeur B obtient-il à sa dernière lecture ?
  1. 3 requêtes, B obtient 6
  2. 5 requêtes, B obtient 6
  3. 4 requêtes, B obtient 6
  4. 4 requêtes, B obtient 3
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 9 sur 10

Deux installations ont le même PUE. L’une utilise surtout des serveurs inactifs ; l’autre accomplit beaucoup plus de travail avec son énergie informatique. Qu’établit l’égalité des PUE ?
  1. Leurs calculs utiles par joule sont égaux.
  2. Leurs énergies totales d’installation sont égales.
  3. Leurs taux d’utilisation des serveurs sont égaux.
  4. Leurs rapports entre énergie totale et informatique sont égaux.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 10 sur 10

Huit cœurs de processeur commandés indépendamment exécutent chacun une addition SIMD à huit voies en un cycle. Comment décrire les deux niveaux ?
  1. SIMD entre les cœurs et SISD dans chaque addition
  2. SISD entre les cœurs et MIMD dans chaque addition
  3. MIMD entre les cœurs et SIMD dans chaque addition
  4. MISD entre les cœurs et SIMD dans chaque addition
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Série 5 : Appliquer les modèles à de nouvelles décisions de conception10 Questions Pratiques

Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.

Question 1 sur 10

Une exécution idéale à charge fixe atteint une accélération de 4 sur huit processeurs. Son travail séquentiel devient ensuite deux fois plus rapide, tandis que le travail parallèle reste inchangé. Quelle accélération la nouvelle exécution sur huit processeurs atteint-elle par rapport à la référence séquentielle initiale ?
  1. 4,0
  2. 5,6
  3. 4,67
  4. 8,0
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 2 sur 10

L’architecture A possède quatre cœurs avec deux contextes matériels chacun ; l’architecture B possède deux cœurs avec huit contextes chacun. Chaque thread répète 15 cycles de calcul puis 105 cycles d’attente. Chaque cœur peut effectuer une étape de calcul par cycle. Avec un décalage idéal, un changement sans coût et aucune concurrence pour la mémoire, comment leurs débits de calcul en régime établi se comparent-ils ?
  1. A fournit deux fois le débit de B.
  2. Les deux fournissent le même débit.
  3. B fournit deux fois le débit de A.
  4. B fournit quatre fois le débit de A.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 3 sur 10

Une charge de travail fixe doit atteindre une accélération d’au moins 12 sur seize processeurs selon un passage à l’échelle idéal conforme à la loi d’Amdahl. Quelle est la plus grande fraction séquentielle autorisée de son temps initial ?
  1. 1/45, soit environ 2,22 %
  2. 1/12, soit environ 8,33 %
  3. 1/16, soit environ 6,25 %
  4. 1/15, soit environ 6,67 %
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 4 sur 10

Une tâche entièrement divisible suit le modèle de temps mesuré Tp=288/p+2p secondes. Tu peux utiliser 8, 12, 16 ou 24 processeurs. Quelle allocation termine le plus vite ?
  1. 8 processeurs
  2. 16 processeurs
  3. 24 processeurs
  4. 12 processeurs
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 5 sur 10

Une boucle additionne deux tableaux de 1 237 nombres à virgule flottante avec des instructions SIMD de 256 bits. Les vecteurs complets sont traités d’abord, puis une fin scalaire. Combien d’itérations complètes et d’éléments scalaires faut-il ?
  1. 155 itérations vectorielles et 3 éléments scalaires
  2. 154 itérations vectorielles et 8 éléments scalaires
  3. 153 itérations vectorielles et 5 éléments scalaires
  4. 154 itérations vectorielles et 5 éléments scalaires
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 6 sur 10

Un anneau de 16 nœuds et un réseau totalement connecté de 16 nœuds utilisent tous deux des liaisons de 10 Gbit/s. Avec une valeur de capacité par liaison, quel gain de capacité de bissection la connexion totale apporte-t-elle et combien de liaisons supplémentaires nécessite-t-elle ?
  1. 32 fois la capacité, avec 120 liaisons supplémentaires
  2. 32 fois la capacité, avec 104 liaisons supplémentaires
  3. 8 fois la capacité, avec 104 liaisons supplémentaires
  4. 7,5 fois la capacité, avec 104 liaisons supplémentaires
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 7 sur 10

Quel groupe matériel contient 32 threads qui partagent l’émission des instructions dans le modèle d’exécution SIMT de NVIDIA ?
  1. Un bloc de threads
  2. Un multiprocesseur de flux
  3. Un warp
  4. Un cœur CUDA
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 8 sur 10

Un noyau traitant un élément par thread avec vérification des bornes lance 37 blocs de 64 threads pour un tableau de 2 350 éléments. Combien de threads du dernier bloc accèdent à des éléments valides et quel est leur dernier indice de thread valide dans ce bloc ?
  1. 46 threads ; dernier indice local 45
  2. 46 threads ; dernier indice local 46
  3. 18 threads ; dernier indice local 17
  4. 47 threads ; dernier indice local 46
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 9 sur 10

Un cache détient un bloc à l’état exclusif selon MESI. Son processeur écrit dans le bloc tandis qu’aucun autre cœur n’y accède. Quels sont l’état et la requête de cohérence qui en résultent ?
  1. Modifié, sans requête sur le bus
  2. Partagé, avec une lecture sur le bus
  3. Modifié, avec une demande de passage en exclusif
  4. Exclusif, avec une requête de mise à jour à l’écriture
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 10 sur 10

Deux compteurs indépendants de 8 octets se trouvent à 0x3000 et 0x3038 avec des blocs de cache de 64 octets. Chacun est modifié par un cœur distinct. Quel déplacement les sépare dans des blocs différents ?
  1. Déplacer le second compteur à 0x3020.
  2. Déplacer le second compteur à 0x3040.
  3. Déplacer le premier compteur à 0x3008.
  4. Déplacer le second compteur à 0x3010.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Tu bloques sur ton propre exercice ? Aide aux Devoirs

Mots-Clés

100 Mots-Clés, chacun avec sa définition

A

Accélérateur spécialisé
Un accélérateur spécialisé consacre son matériel à une charge de travail restreinte, en échangeant de la flexibilité contre une performance par watt élevée dans ce domaine.
Un accélérateur spécialisé orienté vers les matrices peut privilégier la multiplication de faible précision pour les réseaux de neurones.
Accélération
L’accélération est le meilleur temps d’exécution séquentiel divisé par le temps d’exécution parallèle pour la charge de travail comparée.
Un programme qui se termine en 12 s au lieu de 60 s a une accélération de cinq par rapport à sa référence séquentielle.
Accélération superlinéaire
Une accélération superlinéaire est une accélération mesurée qui dépasse le nombre de processeurs, possible lorsque la répartition parallèle réduit aussi le coût du travail.
Un meilleur placement dans le cache peut produire une accélération superlinéaire lorsque chaque partie évite les défauts nécessitant un accès à la DRAM de l’exécution séquentielle.
Accès à pas constant
Un accès à pas constant parcourt des éléments successifs séparés par un espacement fixe entre adresses, comme la distance entre les entrées d’une colonne de matrice.
Un accès à pas constant descendant une colonne d’une matrice de nombres en double précision à 100 colonnes avance de 800 octets entre deux entrées voisines.
Accès indexé
Un accès indexé obtient les adresses des éléments à partir d’indices, ce qui permet des rassemblements et dispersions vectoriels irréguliers au-delà des pas fixes.
Un accès indexé peut charger les entrées d’un tableau sélectionnées par une liste irrégulière de positions.
Aliasing
L’aliasing se produit lorsque différentes références peuvent accéder à des zones de stockage qui se chevauchent, ce qui peut rendre dangereuses des opérations simultanées dans une boucle.
Un compilateur vérifie l’aliasing avant de réordonner des chargements et des rangements effectués par des pointeurs susceptibles de se chevaucher.
Arbre de réduction
Un arbre de réduction combine des résultats partiels en étapes parallèles successives, réduisant de nombreuses valeurs à une seule avec un court chemin de dépendance.
Un arbre de réduction combine 32 sommes partielles en cinq étapes par paires au lieu de 31 additions consécutives.

B

Bande passante d’une liaison
La bande passante d’une liaison est le débit de données disponible sur une liaison réseau, mesuré selon une convention cohérente de capacité directionnelle.
Une topologie avec davantage de liaisons peut avoir une capacité totale supérieure même lorsque la bande passante de chaque liaison reste inchangée.
Bande passante de bissection
La bande passante de bissection est la capacité totale minimale des liaisons traversant une coupe qui divise les nœuds d’un réseau en deux groupes de taille égale.
Un anneau ne possède que deux liaisons traversant une coupe minimale ; sa bande passante de bissection peut donc limiter le trafic entre les moitiés.
Barrière de synchronisation
Une barrière de synchronisation est un point que tous les threads participants doivent atteindre avant que l’un d’eux passe à la phase suivante.
Une barrière de synchronisation entre deux étapes de réduction empêche une unité de travail de lire une somme partielle avant son écriture.
Bloc de threads
Un bloc de threads est un groupe de threads de GPU qui peuvent coopérer par la mémoire partagée et se synchroniser avec une barrière commune au bloc.
Un bloc de threads peut combiner ses sommes partielles, tandis qu’un noyau ultérieur combine les résultats de blocs distincts.

C

Chaînage
Le chaînage fait se chevaucher des opérations vectorielles dépendantes en permettant à une instruction d’utiliser les premiers éléments avant que celle qui les produit ait terminé tous les éléments.
Le chaînage permet à une addition d’utiliser les premiers produits pendant que le pipeline de multiplication continue de produire les suivants.
Classification de Flynn
La classification de Flynn classe le matériel selon que les flux d’instructions et les flux de données sont uniques ou multiples à un niveau choisi de la machine.
La classification de Flynn peut décrire les cœurs indépendants d’un processeur différemment des unités SIMD à l’intérieur de ces cœurs.
Coalescence des accès mémoire
La coalescence des accès mémoire combine les accès proches de threads voisins en un petit nombre de transactions larges pour utiliser efficacement la bande passante.
La coalescence des accès mémoire fonctionne bien lorsque des threads consécutifs d’un warp lisent des éléments consécutifs de 4 octets d’un tableau.
Cohérence des caches
La cohérence des caches coordonne les copies d’un emplacement afin que les processeurs observent un historique compatible de ses écritures et des valeurs lues.
La cohérence des caches empêche un lecteur d’utiliser indéfiniment une copie privée périmée après qu’un autre cœur a mis à jour l’emplacement.
Concurrence
La concurrence est la progression de plusieurs tâches pendant des périodes qui se chevauchent, y compris lorsqu’elles se relaient sur une seule ressource d’exécution.
Un système d’exploitation monocœur permet la concurrence en alternant entre un téléchargement et un éditeur.
Consistance séquentielle
La consistance séquentielle exige des résultats correspondant à un entrelacement des opérations de tous les processeurs qui préserve l’ordre du programme de chacun.
La consistance séquentielle contraint l’historique combiné sans exiger que les processeurs s’exécutent à la même vitesse.

D

Découpage en bandes
Le découpage en bandes divise une longue boucle en morceaux adaptés à la configuration vectorielle et met à jour la progression après chaque morceau traité.
Le découpage en bandes peut traiter 100 éléments avec les longueurs actives successives 32, 32, 32 et quatre.
Défaut de cohérence
Un défaut de cohérence se produit lorsqu’un accès doit charger à nouveau un bloc qu’une action de cohérence d’un autre processeur a invalidé.
Le cœur qui écrit dans une variable voisine peut provoquer un défaut de cohérence même lorsque la variable du lecteur ne change jamais.
Dépendance portée par la boucle
Une dépendance portée par la boucle se produit lorsqu’une itération nécessite une valeur produite par une autre itération, ce qui contraint leur ordre d’exécution.
Une récurrence avec accumulation présente une dépendance portée par la boucle car chaque nouvelle valeur utilise le résultat précédent.
Diffusion
La diffusion est la répartition du travail d’une requête entre plusieurs serveurs dont les réponses requises contribuent à son achèvement.
Une diffusion plus large multiplie les occasions qu’un ralentissement rare sur un serveur retarde la requête complète.
Disponibilité
La disponibilité est la capacité d’un service à rester utilisable malgré les pannes, soutenue à grande échelle par la redondance, les nouvelles tentatives et le reroutage.
Un service à l’échelle d’un entrepôt protège sa disponibilité en dirigeant les nouvelles requêtes ailleurs que vers un serveur en panne.
Divergence de branchement
La divergence de branchement se produit lorsque les threads d’un même warp suivent des chemins différents, qui doivent alors s’exécuter avec des masques actifs différents.
La divergence de branchement peut laisser la moitié d’un warp inactive pendant que les threads affectés à l’autre chemin s’exécutent.

E

Efficacité énergétique
L’efficacité énergétique compare le travail utile accompli à l’énergie consommée, en tenant compte notamment de l’utilisation efficace des ressources des serveurs.
Une installation peut améliorer son PUE tout en conservant une mauvaise efficacité énergétique des serveurs si une grande partie de sa charge informatique n’effectue aucun travail utile.
Efficacité parallèle
L’efficacité parallèle est l’accélération divisée par le nombre de processeurs ; elle exprime le gain utile par rapport aux processeurs alloués.
Une accélération de six sur huit processeurs donne une efficacité parallèle de 75 %, même si la réduction du temps est plus grande.
Espionnage de bus
L’espionnage de bus est une méthode de cohérence dans laquelle les contrôleurs de cache surveillent les requêtes diffusées et mettent à jour les permissions ou les données de leurs blocs.
L’espionnage de bus permet à un détenteur à l’état modifié de détecter la requête de lecture d’un autre cœur et de fournir le contenu actuel du bloc.

É

Équilibrage de charge
L’équilibrage de charge est la répartition du travail utile entre les processeurs de sorte qu’aucune unité de travail ne retarde inutilement la phase par une charge excessive.
Un mauvais équilibrage de charge laisse sept unités de travail en attente tandis qu’une autre termine une partie disproportionnée.
État exclusif
L’état exclusif dans MESI désigne un bloc non modifié détenu par un seul cache, permettant un passage à l’état modifié sans transaction lors d’une écriture.
Une lecture suivie d’une écriture privée bénéficie de l’état exclusif, car l’écriture ne nécessite aucune demande de passage en exclusif.
État invalide
L’état invalide désigne un bloc de cache dont le contenu ne peut pas être utilisé pour satisfaire l’accès en lecture ou en écriture du processeur.
Une lecture ultérieure d’un bloc à l’état invalide doit obtenir une copie valide par la hiérarchie mémoire.
État modifié
L’état modifié désigne la seule copie valide d’un bloc en cache, dont les données ont été modifiées et sont plus récentes que la mémoire.
Un cœur peut mettre à jour à plusieurs reprises un bloc à l’état modifié sans obtenir à nouveau la permission d’écriture.
État partagé
L’état partagé désigne une copie en cache non modifiée et en lecture seule d’un bloc qui peut aussi être présent dans d’autres caches.
Un cœur doit demander la propriété avant de modifier un bloc à l’état partagé, car d’autres lecteurs peuvent le détenir.

F

Faux partage
Le faux partage est une interférence de cohérence entre des cœurs qui accèdent à des variables différentes dans un même bloc de cache lorsqu’au moins un cœur écrit.
Le faux partage peut ralentir des compteurs distincts lorsque les cœurs qui les modifient échangent sans cesse la propriété d’un bloc.
Fraction séquentielle
La fraction séquentielle est la partie du temps d’exécution de référence qui ne peut pas être répartie entre les processeurs dans le modèle parallèle.
Une fraction séquentielle de 0,1 laisse un dixième du temps initial même si tout le travail parallèle devenait gratuit.

G

Granularité
La granularité est la quantité de calcul effectuée entre des événements de communication ou de synchronisation dans un calcul parallèle.
Une granularité plus grande peut réduire le coût des messages par opération, mais laisser trop peu de morceaux pour un bon équilibrage de charge.
Grappe de calcul
Une grappe de calcul est un ensemble d’ordinateurs complets reliés par un réseau, chacun possédant sa propre mémoire et son propre système d’exploitation.
Une grappe de calcul répartit un grand tableau entre les nœuds et combine leurs résultats locaux par des messages réseau.
Grille
Une grille est l’ensemble des blocs de threads créés par le lancement d’un noyau de GPU, dont les blocs ordinaires peuvent s’exécuter dans n’importe quel ordre.
Une grille doit contenir assez de blocs pour couvrir toutes les données lorsque le noyau ne traite qu’un élément par thread.

H

Hôte
L’hôte est la partie d’un programme hétérogène exécutée sur le processeur, chargée d’organiser le stockage du périphérique, les transferts, les lancements et l’utilisation des résultats.
L’hôte peut continuer après un lancement, mais doit attendre les résultats achevés du périphérique avant de les utiliser.

I

Intensité arithmétique
L’intensité arithmétique est le nombre d’opérations à virgule flottante par octet transféré ; dans un modèle Roofline fondé sur la DRAM, elle compte les octets à la frontière de la DRAM.
La réutilisation en cache augmente l’intensité arithmétique lorsque le nombre d’opérations utiles reste fixe mais que les transferts avec la DRAM diminuent.

L

Lancement asynchrone
Un lancement asynchrone démarre un travail sur le périphérique sans obliger l’hôte à attendre sa fin avant de poursuivre son exécution.
Un lancement asynchrone nécessite une vérification ultérieure de l’achèvement ou une copie bloquante des résultats avant leur utilisation par l’hôte.
Latence de queue
La latence de queue désigne l’extrémité des temps de réponse correspondant aux attentes élevées, qui peuvent dominer une requête nécessitant les réponses de nombreux serveurs.
Une requête diffusée attend sa réponse requise la plus lente, ce qui fait de la latence de queue d’un seul serveur une préoccupation pour l’ensemble du service.
Lecture et addition atomiques
La lecture et addition atomiques constituent une opération atomique qui renvoie la valeur précédente d’un emplacement tout en lui ajoutant une quantité donnée de manière indivisible.
La lecture et addition atomiques peuvent préserver chaque incrémentation lorsque plusieurs threads mettent à jour simultanément un compteur partagé.
Lecture-modification-écriture atomique
Une lecture-modification-écriture atomique met à jour un emplacement mémoire de manière indivisible du point de vue des autres processeurs, en combinant la lecture et l’écriture.
Une lecture-modification-écriture atomique empêche deux incrémentations de compteur d’écraser toutes deux la même ancienne valeur.
Loi d’Amdahl
La loi d’Amdahl borne l’accélération globale d’une amélioration à partir de la fraction du temps initial qu’elle concerne et de l’accélération de cette fraction.
La loi d’Amdahl explique pourquoi rendre une petite partie d’un programme beaucoup plus rapide peut à peine modifier son temps total.
Loi de Gustafson
La loi de Gustafson estime l’accélération pour un problème de taille croissante à partir du nombre de processeurs et de la fraction du temps séquentiel mesurée lors de l’exécution parallèle.
La loi de Gustafson décrit comment un problème parallèle plus grand peut utiliser une machine plus grande dans un temps comparable.
Longueur vectorielle
La longueur vectorielle est le nombre d’éléments actifs traités par les instructions vectorielles dans la configuration vectorielle courante.
Une longueur vectorielle courte permet au dernier passage d’une boucle de mettre à jour ses huit éléments restants sans exécuter de fin scalaire distincte.

M

Masquage de la latence
Le masquage de la latence exécute un autre travail prêt pendant une attente, ce qui améliore l’utilisation des ressources sans raccourcir l’opération en attente elle-même.
Un GPU utilise le masquage de la latence lorsque son ordonnanceur sélectionne un autre warp pendant un accès mémoire en cours.
Masque
Un masque sélectionne les éléments actifs d’une opération SIMD ou vectorielle, ce qui permet un travail conditionnel sans flux d’instructions distinct par voie.
Un masque peut empêcher la mise à jour des éléments d’un tableau qui ne satisfont pas une comparaison ou qui dépassent la fin valide.
Mémoire globale
La mémoire globale est la DRAM du périphérique GPU accessible dans toute la grille, dont les accès passent par la hiérarchie de caches du périphérique.
Un noyau de calcul peut réutiliser des blocs de données en mémoire partagée pour réduire le nombre de relectures depuis la mémoire globale.
Mémoire partagée
La mémoire partagée est un espace de stockage sur puce du GPU, géré par le programme et accessible aux threads d’un bloc pour coopérer et réutiliser des données.
Un bloc charge un bloc de données dans la mémoire partagée avant de le réutiliser pour plusieurs opérations arithmétiques.
MIMD
MIMD est une classe matérielle avec plusieurs flux d’instructions commandés indépendamment qui agissent sur plusieurs flux de données.
Une grappe de calcul est MIMD lorsque ses nœuds progressent indépendamment dans leurs calculs et échangent des messages.
MISD
MISD est la classe matérielle où plusieurs flux d’instructions agissent sur un seul flux de données ; peu de machines réelles y correspondent clairement.
La désignation MISD complète les quatre combinaisons de flux uniques et multiples, tandis que les exemples réels proposés dépendent souvent de l’interprétation.
Modèle de consistance mémoire
Un modèle de consistance mémoire définit les ordres observables et les résultats autorisés des lectures et écritures, y compris sur des emplacements différents.
Un modèle de consistance mémoire détermine comment un autre processeur peut observer les accès à un indicateur et à ses données.
Modèle Roofline
Le modèle Roofline borne la performance arithmétique atteignable par la plus petite valeur entre le débit de calcul de crête et la bande passante multipliée par l’intensité.
Le modèle Roofline aide à déterminer si un calcul plus rapide ou une réduction des transferts de données peut relever la borne d’un noyau de calcul.
MPI
MPI est une interface standard de passage de messages permettant aux processus d’échanger des données et d’effectuer des opérations collectives dans un programme parallèle.
Une réduction MPI combine des sommes partielles distribuées sans traiter les données des nœuds distants comme des pointeurs locaux ordinaires.
Multiprocesseur à mémoire partagée
Un multiprocesseur à mémoire partagée permet aux processeurs de communiquer par des chargements et des rangements dans un espace d’adressage physique unique.
Un multiprocesseur à mémoire partagée peut tout de même posséder des caches privés distincts et une mémoire répartie entre les sockets.
Multiprocesseur de flux
Un multiprocesseur de flux est une unité de traitement des GPU NVIDIA qui ordonnance les warps résidents sur des voies arithmétiques et utilise du stockage sur puce.
Un multiprocesseur de flux peut émettre les instructions d’un autre warp prêt lorsqu’un warp résident attend la mémoire globale.
Multithreading à grain fin
Le multithreading à grain fin sélectionne un thread à chaque cycle d’horloge, généralement en passant d’un contexte prêt à l’autre et en sautant ceux qui sont bloqués.
Le multithreading à grain fin peut alterner de courtes séquences de plusieurs threads pour couvrir les blocages du pipeline.
Multithreading à gros grain
Le multithreading à gros grain change de thread lors de blocages longs, permettant une exécution prolongée d’un seul thread entre les changements coûteux.
Le multithreading à gros grain peut changer de thread après un défaut dans le cache de dernier niveau qui nécessite un long accès mémoire.
Multithreading matériel
Le multithreading matériel conserve plusieurs contextes de threads dans un cœur pour qu’il puisse exécuter du travail prêt lorsqu’un autre thread est bloqué.
Le multithreading matériel peut remplir les cycles d’attente mémoire sans dupliquer un cœur physique complet.
Multithreading simultané
Le multithreading simultané permet à un cœur à émission multiple d’émettre des instructions de différents threads matériels au cours d’un même cycle.
Le multithreading simultané remplit les créneaux d’émission libres lorsqu’un thread ne peut pas fournir assez d’instructions prêtes.
Mur de puissance
Le mur de puissance est la contrainte de puissance et de chaleur qui limite les gains de performance obtenus en continuant à augmenter les fréquences d’horloge des processeurs.
Le mur de puissance a incité les concepteurs de puces à consacrer les transistors supplémentaires à davantage de cœurs de processeur.

N

Nœud d’attache
Un nœud d’attache gère l’entrée de répertoire d’un bloc mémoire donné et coordonne les requêtes concernant les copies en cache de ce bloc.
Différents blocs peuvent avoir différents nœuds d’attache, ce qui répartit le stockage du répertoire et le traitement des requêtes.
Noyau de calcul (kernel)
Un noyau de calcul est une fonction du périphérique lancée sur de nombreux threads de GPU, chacun exécutant la fonction avec ses propres indices et données.
Un noyau de calcul SAXPY affecte un élément de tableau à chaque thread valide et vérifie la borne supérieure de l’indice.
Noyau limité par la mémoire
Un noyau limité par la mémoire possède un toit de bande passante mémoire inférieur à son toit de calcul : son débit maximal dépend donc de l’alimentation en données.
Une fois qu’un noyau limité par la mémoire sature la bande passante DRAM, des unités arithmétiques plus larges ne peuvent pas à elles seules relever sa borne du modèle Roofline.
Noyau limité par le calcul
Un noyau limité par le calcul possède une intensité suffisante pour que la capacité arithmétique de crête soit la limite la plus basse dans le modèle Roofline.
Le traitement par blocs peut rapprocher un calcul d’un noyau limité par le calcul en réutilisant les données pour de nombreuses opérations arithmétiques.
NUMA
NUMA est une organisation de mémoire partagée dans laquelle le coût d’accès à la mémoire dépend de l’emplacement du processeur par rapport aux données.
Une charge de travail NUMA peut réduire la latence moyenne en plaçant les pages fréquemment utilisées près des threads qui y accèdent.

O

Ordinateur à l’échelle d’un entrepôt
Un ordinateur à l’échelle d’un entrepôt exploite un grand bâtiment de serveurs en réseau, avec son alimentation et son refroidissement, comme une plateforme unique pour les services et le travail par lots.
Un ordinateur à l’échelle d’un entrepôt doit tenir compte de l’énergie et des pannes courantes ainsi que du débit de requêtes.

P

Parallélisme
Le parallélisme est l’exécution simultanée d’opérations sur des ressources matérielles distinctes pour réduire la latence ou augmenter le débit.
Une simulation utilise le parallélisme lorsque plusieurs cœurs mettent à jour des régions indépendantes au même instant.
Parallélisme au niveau des instructions
Le parallélisme au niveau des instructions fait se chevaucher les instructions d’un même flux grâce à des techniques comme l’exécution en pipeline et l’émission multiple.
Un cœur exploite le parallélisme au niveau des instructions en émettant ensemble deux additions scalaires indépendantes.
Parallélisme au niveau des requêtes
Le parallélisme au niveau des requêtes exécute simultanément des tâches ou des requêtes de service indépendantes, avec peu de coordination entre leurs calculs.
Un service de recherche obtient du parallélisme au niveau des requêtes grâce aux questions indépendantes de milliers d’utilisateurs.
Parallélisme au niveau des threads
Le parallélisme au niveau des threads exécute plusieurs threads en même temps, chacun avec son propre compteur ordinal et son propre état des registres.
Un moteur de rendu d’image utilise le parallélisme au niveau des threads en affectant différentes régions de l’image à différentes unités de travail.
Parallélisme de données
Le parallélisme de données applique la même opération à plusieurs éléments de données indépendants, souvent à l’aide de voies SIMD ou de threads de GPU.
Additionner les éléments correspondants de tableaux offre du parallélisme de données, car chaque paire peut être traitée indépendamment.
Passage à l’échelle faible
Le passage à l’échelle faible augmente le travail total proportionnellement au nombre de processeurs, en gardant constant le travail par processeur au cours de l’expérience.
Une expérience de passage à l’échelle faible double les données lorsqu’elle double les processeurs, puis compare les temps écoulés.
Passage à l’échelle fort
Le passage à l’échelle fort mesure comment le temps écoulé change lorsque davantage de processeurs exécutent le même problème de calcul de taille fixe.
Une expérience de passage à l’échelle fort garde fixe le nombre de cellules d’une simulation tout en augmentant le nombre de processeurs alloués.
Plafond
Un plafond est une limite plus basse dans une analyse Roofline, qui représente une restriction comme l’absence de SIMD ou de mauvaises séquences d’accès.
Un plafond de bande passante sous le toit principal peut montrer la perte de performance due à des accès mémoire inefficaces.
Point de transition
Le point de transition est l’intensité où le toit de bande passante rejoint le toit de calcul ; elle est égale au débit de calcul de crête divisé par la bande passante.
Un point de transition à dix opérations à virgule flottante par octet place un noyau à deux opérations par octet en dehors de la région limitée par le calcul.
Processeur logique
Un processeur logique est un contexte de thread matériel visible par le système d’exploitation comme un emplacement où un thread logiciel peut s’exécuter.
Une puce à six cœurs avec deux contextes par cœur présente douze processeurs logiques qui partagent six cœurs.
Propagation des écritures
La propagation des écritures est l’exigence de cohérence selon laquelle l’écriture d’un processeur finit par devenir visible lors des lectures des autres processeurs.
La propagation des écritures garantit qu’une nouvelle valeur ne reste pas cachée en permanence dans le cache privé du cœur qui l’a écrite.
Proportionnalité énergétique
La proportionnalité énergétique est l’objectif de conception selon lequel la puissance consommée devrait augmenter proportionnellement à la charge utile traitée par un système.
Une puissance élevée au repos affaiblit la proportionnalité énergétique, car un serveur peu chargé consomme toujours beaucoup d’énergie.
Protocole d’invalidation à l’écriture
Un protocole d’invalidation à l’écriture accorde une permission d’écriture exclusive à un cœur en rendant inutilisables les autres copies en cache de son bloc.
Un protocole d’invalidation à l’écriture permet à un détenteur d’effectuer des écritures répétées à l’état modifié sans diffuser chaque nouvelle valeur.
PUE
Le PUE est le rapport entre l’énergie totale de l’installation et celle des équipements informatiques sur la même période ; il mesure le surcoût énergétique extérieur à la charge informatique.
Un PUE de 1,2 signifie que l’énergie totale de l’installation dépasse l’énergie informatique de 20 %, sans mesurer le travail utile effectué dans les serveurs.

R

Rang
Un rang est l’identifiant d’un processus MPI dans un communicateur, utilisé pour sélectionner les participants et attribuer des données ou des rôles de communication.
Un processus utilise son rang pour déterminer quelle partie du tableau additionner et où envoyer son résultat partiel.
Répertoire
Un répertoire enregistre l’état de cohérence des blocs mémoire et les caches qui les détiennent afin que les requêtes puissent être envoyées aux caches concernés.
Un répertoire transmet une requête de lecture au cache qui détient la copie modifiée la plus récente au lieu de la diffuser.

S

Sérialisation des écritures
La sérialisation des écritures exige que chaque processeur s’accorde sur l’ordre des écritures au même emplacement dans un système mémoire cohérent.
La sérialisation des écritures empêche les processeurs d’observer des ordres opposés pour deux écritures au même emplacement X.
SIMD
SIMD est une classe matérielle dans laquelle une instruction commande la même opération sur plusieurs éléments de données ou voies arithmétiques.
Une addition de tableaux à huit voies est SIMD même si elle effectue huit additions d’éléments avec une seule instruction émise.
SIMT
SIMT est un mode d’exécution des GPU qui présente des threads indépendants tout en émettant une instruction pour les threads actifs d’un groupe.
Un code SIMT calcule un indice par thread même si l’émission des instructions est partagée dans chaque warp.
SISD
SISD est une classe matérielle avec un seul flux d’instructions et un seul flux de données, qui comprend les cœurs scalaires classiques en pipeline.
Un cœur scalaire en pipeline reste SISD car les instructions qui se chevauchent suivent toujours un seul flux d’instructions.
SPMD
SPMD est un style de programmation dans lequel des unités de travail exécutent des copies du même programme et utilisent leurs identifiants pour sélectionner des données différentes.
Une somme de tableau SPMD utilise l’identifiant de chaque unité de travail pour choisir une région avant de combiner les résultats partiels.
Structure de tableaux
Une structure de tableaux stocke les valeurs de chaque champ dans un tableau distinct, rendant contiguës les valeurs d’un même champ pour l’accès vectoriel.
Une structure de tableaux garde toutes les coordonnées x ensemble lorsqu’une boucle de géométrie ne traite que ce champ.
Surcoût du parallélisme
Le surcoût du parallélisme est le coût d’exécution ajouté par l’organisation parallèle, comme l’ordonnancement, la communication, la synchronisation ou le travail supplémentaire.
Le surcoût du parallélisme peut augmenter au point qu’une tâche prenne plus de temps après l’ajout de processeurs.
Sursouscription
La sursouscription se produit lorsque les liaisons réseau supérieures offrent moins de capacité que la capacité totale des liaisons inférieures qui les alimentent.
Une baie avec 400 Gbit/s de liaisons de serveurs et 100 Gbit/s de liaisons montantes présente une sursouscription de 4:1.

T

Tore
Un tore est un réseau maillé doté de liaisons reliant les bords opposés, qui ajoutent des chemins et augmentent la capacité de traversée.
Un tore de 8 par 8 possède 128 liaisons, dont les connexions entre bords opposés absentes d’un maillage ordinaire.

U

UMA
UMA est une organisation de mémoire partagée dans laquelle le temps d’accès aux emplacements mémoire est approximativement uniforme depuis les processeurs.
Une petite machine UMA présente des chemins d’accès mémoire similaires sans distinction entre socket local et distant.

V

Vecteur de présence
Un vecteur de présence utilise un bit par cœur pour enregistrer les caches qui détiennent un bloc donné dans un répertoire à vecteur complet.
Un vecteur de présence pour 64 cœurs nécessite huit octets par bloc suivi avant les bits d’état de cohérence.
Vectorisation automatique
La vectorisation automatique est une transformation du compilateur qui convertit le travail scalaire adapté d’une boucle en opérations SIMD tout en préservant les résultats requis.
Un chevauchement possible des pointeurs peut empêcher la vectorisation automatique, sauf si une vérification établit que les tableaux ne se chevauchent pas.
Vérification des bornes
Une vérification des bornes teste si un indice calculé se trouve dans la plage de données valide avant qu’un thread effectue l’accès mémoire associé.
Lorsqu’une grille est arrondie à un nombre entier de blocs, une vérification des bornes désactive les threads supplémentaires du dernier bloc sans ignorer d’éléments valides.
VLEN
VLEN est la largeur en bits des registres vectoriels d’une implémentation RVV, distincte du nombre d’éléments actifs et du nombre de voies d’exécution parallèles.
Une VLEN plus grande peut contenir davantage d’éléments, tandis que le programme avance toujours selon la longueur active qu’il reçoit.
Voie SIMD
Une voie SIMD est un emplacement d’élément et le travail arithmétique qui lui est associé dans une opération large commandée par une instruction partagée.
Une addition de 256 bits possède huit voies SIMD pour des nombres à virgule flottante de 32 bits, mais quatre voies pour des nombres en double précision de 64 bits.
Vrai partage
Le vrai partage se produit lorsque des processeurs communiquent par le même mot mémoire, de sorte que leur interaction de cohérence concerne les mêmes données.
Un thread écrit une valeur qu’un autre lit, créant un vrai partage de cette variable de communication.

W

Warp
Un warp est un groupe de 32 threads dans le modèle d’exécution de NVIDIA ; les threads actifs partagent l’émission des instructions et conservent des données distinctes.
Les threads d’un warp peuvent utiliser des indices consécutifs afin que leurs chargements se combinent en transactions mémoire efficaces.

À propos de cette unité

Par StudeliSignaler une erreur

Crée ton propre Matériel d'Étude

Transforme tes notes, diapos et documents en Guides d'Étude, Questions Pratiques, Flashcards et 6 autres outils.

Commencer