Séance 2 — Cohérence de cache et protocoles

Cohérence de cache et protocoles

Dr. El Hadji Bassirou TOURÉ

Département de Mathématiques et Informatique, Faculté des Sciences et Techniques, Université Cheikh Anta Diop de Dakar

Objectifs de la séance

Ce que la séance construit

Chaque cœur a ses propres caches : une même donnée peut exister en plusieurs copies. La séance montre comment le matériel garde ces copies cohérentes (MSI, MESI), ce que cela coûte, comment un programme en souffre sans partager de données (false sharing), et dans quel ordre les cœurs voient les écritures (cohérence séquentielle, TSO).

Plan

  1. Le problème de cohérence de cache
  2. Rappels : opérations de cache
  3. Le protocole MSI
  4. Le protocole MESI
  5. False sharing
  6. Cohérence séquentielle
  7. Modèles de cohérence relâchée
  8. Métriques et optimisations

Prérequis : Séance 1 (hiérarchie mémoire, lignes de \(64\) octets, succès et défauts de cache).

Lab associé : Lab 3 (la mémoire : caches, copies et partage).

Ensuite : Séance 3, programmation parallèle avancée (synchronisation).

Le problème de cohérence de cache

Plusieurs copies d’une même donnée

Dans un système multicœur, chaque cœur possède ses propres caches (L1, L2) pour aller plus vite. Mais cela crée un problème fondamental :

Le problème de cohérence de cache

Il survient quand plusieurs caches peuvent contenir des copies d’une même donnée, et qu’une modification dans un cache doit être visible par tous les autres de manière cohérente.

Exemple concret : x = 0 en mémoire.

  1. Cœur 1 lit x : copie dans son cache, x = 0.
  2. Cœur 2 lit x : copie dans son cache, x = 0.
  3. Cœur 1 écrit x = 5 dans son cache.
  4. Cœur 2 lit x : \(0\) ou \(5\) ?

Les défis de la cohérence

Quand une donnée change :

  • comment informer tous les caches qui en ont une copie ?
  • faut-il détruire (invalider) les anciennes copies, les mettre à jour, ou les signaler obsolètes ?
  • comment limiter les communications que cela coûte ?

Les protocoles de cohérence sont les règles qui régissent ces décisions ; MSI et MESI invalident les autres copies.

Le problème de cohérence, pas à pas

Lecture. P1 lit \(x\) : défaut, la ligne vient de la mémoire (flèche verte) et une copie \(x=0\) entre dans C1 (cadre rouge).

Lecture. P2 lit \(x\) : une seconde copie \(x=0\) entre dans C2. Deux caches détiennent maintenant la même donnée.

Lecture. P1 écrit \(x=5\) dans sa copie (cache write-back) : la mémoire garde \(0\) et la copie de C2 est périmée. Personne ne prévient C2.

Lecture. P2 relit \(x\) : la ligne est dans C2, c’est un succès, et P2 lit \(0\) alors que la dernière valeur écrite est \(5\). Sans mécanisme de cohérence, P2 lirait toujours \(0\).

Rappels : opérations de cache

Opérations, transactions et latences

Lecture. Le contrôleur du cache, s’il lui faut la ligne ou l’exclusivité, place une transaction sur le bus, que tous les caches observent. Les latences du cours sont arrondies : une vraie lecture en mémoire coûte plutôt \(180\) à \(300\) cycles (Séance 1).

Politiques d’écriture

Write-through et write-back

Write-through : chaque écriture est propagée sans attendre à la mémoire principale. Mémoire toujours à jour, mais beaucoup de trafic sur le bus.

Write-back : les écritures sont faites dans le cache seulement ; la mémoire est mise à jour à l’éviction de la ligne. Moins de trafic, mais un contrôleur plus élaboré (une marque « modifiée » par ligne) et une mémoire pas toujours à jour.

Write-allocate et write-no-allocate

Write-allocate : sur un défaut en écriture, la ligne est d’abord chargée dans le cache, puis modifiée. Exploite la localité temporelle ; coûte un chargement. Va typiquement avec write-back.

Write-no-allocate : sur un défaut en écriture, l’écriture va directement en mémoire, sans charger la ligne. Moins de pollution du cache, pas d’exploitation de la localité. Va typiquement avec write-through.

Exercice : quatre accès à une variable

Énoncé

Un programme effectue la séquence suivante sur une variable non présente en cache :

  1. Write x = 10
  2. Write x = 20
  3. Read x
  4. Write x = 30

Comparer le nombre de transferts mémoire avec :

  1. write-through + write-no-allocate ;
  2. write-back + write-allocate.

Correction

(a) Write-through + write-no-allocate

  1. Write x=10 : défaut, écriture directe en mémoire (\(1\) transfert).
  2. Write x=20 : défaut, écriture directe en mémoire (\(1\)).
  3. Read x : défaut, lecture en mémoire, mise en cache (\(1\)).
  4. Write x=30 : succès, écriture dans le cache et en mémoire (\(1\)). Total : \(4\) transferts.

(b) Write-back + write-allocate

  1. Write x=10 : défaut, lecture de la ligne (\(1\)), puis écriture dans le cache seulement.
  2. Write x=20, Read x, Write x=30 : trois succès, dans le cache seulement.
  3. Total : \(1\) transfert (\(+1\) write-back à l’éviction).

Conclusion : write-back + write-allocate est beaucoup plus efficace pour les accès répétés.

Deux politiques d’écriture, pas à pas

Lecture. Write \(x=10\), ligne absente. À gauche, écriture directe en mémoire (\(1\) transfert), le cache reste vide. À droite, la ligne est chargée (\(1\) transfert), puis écrite dans le cache seulement (\(\cdot\cdot\) : valeur inconnue).

Lecture. Write \(x=20\). À gauche, encore un défaut : nouvelle écriture directe en mémoire. À droite, succès : écriture dans le cache, aucun transfert.

Lecture. Read \(x\). À gauche, défaut : la ligne est lue en mémoire et mise en cache (\(1\) transfert). À droite, succès : lecture dans le cache.

Lecture. Write \(x=30\). À gauche, succès, mais write-through écrit aussi en mémoire (total \(4\)). À droite, succès, écriture dans le cache seulement : la mémoire n’a toujours pas la valeur.

Lecture. Éviction de la ligne. À gauche, ligne propre : rien à écrire, total \(4\). À droite, la ligne modifiée part en mémoire (write-back) : total \(2\) pour quatre accès.

Le protocole MSI

Les trois états MSI

MSI est le protocole d’invalidation de base : MESI et les protocoles suivants l’enrichissent.

Le protocole MSI

Trois états possibles pour chaque ligne de cache :

  • M (Modified) : la ligne est modifiée et présente uniquement dans ce cache ; le cache est responsable de la donnée ;
  • S (Shared) : la ligne est valide et peut être présente dans d’autres caches ; lecture seule ;
  • I (Invalid) : la ligne n’est pas valide ou n’est pas présente dans le cache.

Intuition

Pensez aux états MSI comme à des permissions sur un fichier :

  • Modified : vous avez l’unique copie modifiable (accès exclusif en écriture) ;
  • Shared : vous avez une copie en lecture seule (d’autres peuvent aussi lire) ;
  • Invalid : vous n’avez pas le droit d’accéder au fichier.

Espionnage du bus et règles du protocole

Espionnage du bus {bus snooping}

Chaque cache surveille toutes les transactions sur le bus et réagit selon son état actuel et le type de transaction observée.

Notation des transitions : A / B

A, avant la barre : l’événement observé (PrRd, PrWr, BusRd, BusRdX).

B, après la barre : l’action entreprise (BusRd, BusRdX, BusWB, ou – pour aucune action).

Les trois règles de MSI

  1. Pour lire une donnée, il faut au minimum être en S.
  2. Pour écrire, il faut être en M (exclusivité obligatoire).
  3. Quand un cache veut écrire, il émet un BusRdX qui invalide toutes les autres copies.

Lecture. Une ligne en M est la seule copie à jour : si un autre cache la demande, son détenteur l’écrit en mémoire (BusWB) avant de la céder.

Le diagramme de transitions MSI

Lecture. Notation A / B : événement observé A, action déclenchée B (– pour aucune). Au-dessus, les demandes du processeur : lire depuis I émet un BusRd, écrire depuis I ou S un BusRdX. Au-dessous, les réactions au bus, depuis M toujours après un BusWB.

Les transitions principales

  • I \(\to\) S : PrRd/BusRd (lecture depuis Invalid) ;
  • I \(\to\) M : PrWr/BusRdX (écriture depuis Invalid) ;
  • S \(\to\) M : PrWr/BusRdX (écriture depuis Shared, pour invalider les autres) ;
  • M \(\to\) S : BusRd/BusWB (un autre processeur lit : write-back et partage) ;
  • M \(\to\) I : BusRdX/BusWB (un autre processeur écrit : write-back et invalidation) ;
  • S \(\to\) I : BusRdX/– (un autre processeur écrit : invalidation seule).

S vers M

En S, la copie locale est déjà valide : le BusRdX sert à invalider les autres copies. Certains processeurs utilisent ici une transaction sans données (BusUpgr) ; le cours garde BusRdX, avec la même latence de \(100\) cycles.

La trace MSI, pas à pas

Lecture. P1 lit \(x\) : C1 est en I, P1 émet un BusRd ; aucune autre copie valide, la mémoire fournit. C1 passe de I à S.

Lecture. P2 lit \(x\) : BusRd, la mémoire fournit encore ; C1 a une copie valide, il examine le bus (cadre orange) et reste en S. Deux copies en lecture seule sont permises.

Lecture. P1 écrit \(x=5\) : il faut être en M. P1 émet un BusRdX ; C2 s’invalide (S\(\to\)I), C1 passe de S à M. C1 avait déjà la donnée : le BusRdX sert à invalider. Question (a) de la fiche : l’invalidation a lieu ici.

Lecture. P3 lit \(x\) : BusRd. C1, en M, intercepte la requête, écrit la ligne en mémoire (BusWB, flèche violette) et la fournit ; C1 passe de M à S, C3 de I à S. Question (b) : la donnée vient de C1, pas de la mémoire.

Lecture. P2 écrit \(x=10\) : C2 est en I, P2 émet un BusRdX ; la mémoire, à jour depuis le BusWB, fournit la ligne. C1 et C3 s’invalident, C2 passe en M.

Exercice : trace MSI à trois processeurs

Énoncé

Trois processeurs, protocole MSI, caches initialement invalides. Tracer les états et les transactions pour :

  1. P1 : Read x
  2. P3 : Read x
  3. P3 : Write x = 20
  4. P2 : Read x
  5. P1 : Read x

Correction

Action Bus Fournie par C1 C2 C3
Initial – – I I I
P1 : PrRd x BusRd Mémoire I\(\to\)S I I
P3 : PrRd x BusRd Mémoire S I I\(\to\)S
P3 : PrWr x=20 BusRdX – S\(\to\)I I S\(\to\)M
P2 : PrRd x BusRd C3 (BusWB) I I\(\to\)S M\(\to\)S
P1 : PrRd x BusRd Mémoire I\(\to\)S S S
  • Ligne 3 : P3 invalide toutes les autres copies pour obtenir l’exclusivité.
  • Ligne 4 : P3 doit faire un BusWB car il a la donnée modifiée.
  • Ligne 5 : la donnée vient de la mémoire (à jour après le write-back) ; en MSI, les copies en S ne fournissent pas la donnée.

Le protocole MESI

L’état Exclusive

Pour améliorer les performances de MSI, MESI ajoute un quatrième état.

Le protocole MESI

E (Exclusive) : la ligne est présente uniquement dans ce cache et identique à la mémoire (propre). Le cache peut la modifier sans transaction sur le bus.

Les quatre états : M exclusive et modifiée ({dirty}) ; E exclusive et propre ({clean}) ; S partagée et propre ; I invalide.

Le choix entre E et S se fait à la lecture : les autres caches signalent sur le bus s’ils ont la ligne (signal de partage).

Analogie

L’état Exclusive, c’est emprunter un livre à la bibliothèque :

  • Shared : consulter le livre dans la salle de lecture (d’autres peuvent aussi) ;
  • Exclusive : emprunter le livre chez vous (personne d’autre ne l’a, mais il est intact) ;
  • Modified : emprunter et annoter le livre (vous devez le rendre modifié).

L’avantage : passer d’Exclusive à Modified ne demande aucune communication.

Le diagramme de transitions MESI

Lecture. Lire depuis I donne E si personne n’a la ligne, S sinon ; E\(\to\)M (en vert) se fait sans transaction ; une ligne en E, propre, quitte E sans BusWB.

Les transitions clés de MESI

  • I \(\to\) E : PrRd/BusRd, aucun autre cache n’a la ligne ;
  • I \(\to\) S : PrRd/BusRd, un autre cache signale qu’il a la ligne ;
  • E \(\to\) M : PrWr/– (pas de transaction bus : le gain MESI) ;
  • E \(\to\) S : BusRd/– quand un autre processeur lit ;
  • E \(\to\) I : BusRdX/– quand un autre processeur écrit ;
  • S \(\to\) M : PrWr/BusRdX (invalider les autres copies) ;
  • S \(\to\) I : BusRdX/– (invalidation par un autre processeur) ;
  • M \(\to\) S : BusRd/BusWB (partage après write-back) ;
  • M \(\to\) I : BusRdX/BusWB (invalidation après write-back).

Le gain principal

La transition E\(\to\)M est LE gain de MESI : une écriture sur une donnée exclusive ne génère AUCUNE transaction bus, donc une latence minimale (\(1\) cycle).

Exercice : calcul de latence avec MESI

Énoncé

Système MESI : succès \(1\) cycle ; défaut \(100\) ; BusWB \(100\) ; BusRdX \(100\). Latence totale de :

  1. P0 : Read x (cache vide, personne n’a x)
  2. P0 : Write x = 10
  3. P1 : Read x
  4. P1 : Write x = 20

Correction

Action P0 P1 Transaction Latence
Initial I I – –
P0 : Read x I\(\to\)E I BusRd, sans partage \(100\)
P0 : Write x=10 E\(\to\)M I aucune (locale) \(1\)
P1 : Read x M\(\to\)S I\(\to\)S BusRd + BusWB de P0 \(200\)
P1 : Write x=20 S\(\to\)I S\(\to\)M BusRdX \(100\)
Latence totale \(\mathbf{401}\) cycles

Comparaison avec MSI : l’étape 2 aurait demandé un BusRdX (\(100\) cycles au lieu de \(1\)) ; MSI : \(100+100+200+100=500\) cycles. Gain MESI : \(\mathbf{99}\) cycles dans ce scénario.

La trace MESI et ses latences, pas à pas

Lecture. P0 lit \(x\), personne ne l’a : BusRd, aucun cache ne signale de copie, P0 reçoit la ligne en E (\(100\) cycles). En MSI, elle serait en S.

Lecture. P0 écrit \(x=10\) : E\(\to\)M sans transaction, \(1\) cycle. MSI aurait émis un BusRdX (\(100\) cycles) : c’est le gain de MESI.

Lecture. P1 lit \(x\) : BusRd ; P0, en M, fait un BusWB puis passe en S ; P1 arrive en S. \(100+100=200\) cycles, dans les deux protocoles.

Lecture. P1 écrit \(x=20\) : BusRdX pour invalider la copie de P0 (\(100\) cycles). Total : \(401\) cycles en MESI contre \(500\) en MSI, soit \(99\) cycles de gagnés, tous à l’étape 2.

Impact sur la programmation : false sharing

Deux variables, une ligne de cache

False sharing

Le false sharing (faux partage) se produit quand deux processeurs modifient des variables différentes qui se trouvent dans la même ligne de cache (typiquement \(64\) octets). Cela provoque des invalidations mutuelles constantes.

Lecture. c1, c2 : counter1, counter2 ; une case \(=4\) octets. Relevé avec gcc : counter2 au décalage \(4\), puis \(4+60=64\) : toujours deux lignes.

Le false sharing, pas à pas

Lecture. Le fil 1 (sur P1) incrémente counter1 : c’est une écriture, la ligne doit être en M ; BusRdX, la ligne entière (les deux compteurs) entre dans C1 en M.

Lecture. Le fil 2 (sur P2) incrémente counter2, une autre variable, mais dans la même ligne : BusRdX, C1 fait un BusWB et s’invalide, la ligne passe dans C2 en M. Première invalidation.

Lecture. Le fil 1 incrémente encore : la ligne est repartie, C1 est en I. Nouveau BusRdX, C2 fait un BusWB et s’invalide. Deuxième invalidation.

Lecture. Et ainsi de suite : chaque incrémentation peut faire voyager toute la ligne d’un cache à l’autre (ping-pong), alors que les fils ne partagent aucune donnée.

Lecture. Avec le rembourrage (padding[60]), counter2 est à \(64\) octets de counter1 : chaque compteur a sa ligne, en M dans son cache. Après le premier BusRdX de chaque fil, plus aucune transaction.

Exercice : quatre compteurs

Énoncé

\(4\) fils incrémentent chacun leur compteur un million de fois :

int counters[4];
// le fil i execute :
for (int j = 0; j < 1000000; j++)
    counters[i]++;

Ligne de \(64\) octets, int de \(4\) octets.

  1. Les compteurs sont-ils dans la même ligne ?
  2. Combien d’invalidations cela génère-t-il ?
  3. Proposer deux solutions.

Correction

  1. Oui : \(4\times4=16\) octets \(<64\) : une seule ligne.
  2. Jusqu’à environ \(4\) millions de transferts de la ligne : chaque incrémentation peut trouver la ligne en M ailleurs (BusRdX, BusWB, invalidation). Borne haute : une invalidation par transfert (pas trois), et un fil enchaîne souvent plusieurs incrémentations. Plusieurs fois plus lent : de \(4\) à \(9\) fois selon les essais (deux fils, machine virtuelle à deux cœurs).
  3. Solutions : rembourrage (int value; char pad[60];) ; champ aligné (alignas(64) int value; dans une structure) ; variable locale et une seule écriture finale.

Piège : alignas(64) int counters[4]; n’aligne que le début du tableau. Avec gcc -O2, la boucle devient une seule addition : l’effet se mesure à -O0 ou avec volatile.

Trois dispositions des compteurs

Lecture. Devant le tableau, alignas(64) aligne seulement son début. Sur le champ d’une structure, il fixe taille et alignement de chaque élément à \(64\) : un compteur par ligne. Le rembourrage donne le même écart, sans aligner le tableau.

Cohérence séquentielle

Le modèle de cohérence séquentielle

Cohérence séquentielle

Elle garantit que :

  1. les opérations de chaque processeur apparaissent dans l’ordre du programme ;
  2. il existe un ordre global unique des opérations, vu par tous les processeurs.

Tout se passe comme si une seule mémoire servait les processeurs un accès à la fois, en piochant chaque fois dans l’un des programmes, sans jamais réordonner un même programme.

Lecture. Une exécution est donc un entrelacement des programmes : pour savoir si une sortie est possible, il faut trouver un ordre global qui la produise.

Exercice : deux fils, deux variables

Énoncé

A et B valent \(0\) au départ.

Thread 1 Thread 2
(1) A = 1 (3) B = 1
(2) print(B) (4) print(A)
  1. Donner trois exécutions possibles et leurs résultats.
  2. Quelle sortie est impossible en cohérence séquentielle ?

Correction

Exécutions possibles

  1. (1)\(\to\)(2)\(\to\)(3)\(\to\)(4) : Thread 1 affiche \(0\), Thread 2 affiche \(1\).
  2. (3)\(\to\)(4)\(\to\)(1)\(\to\)(2) : Thread 1 affiche \(1\), Thread 2 affiche \(0\).
  3. (1)\(\to\)(3)\(\to\)(2)\(\to\)(4) : Thread 1 affiche \(1\), Thread 2 affiche \(1\).
  4. (3)\(\to\)(1)\(\to\)(4)\(\to\)(2) : Thread 1 affiche \(1\), Thread 2 affiche \(1\).

Sortie impossible : les deux threads affichent \(0\).

Explication : si Thread 1 affiche \(0\), (2) précède (3) ; si Thread 2 affiche \(0\), (4) précède (1). Avec l’ordre des programmes, cela crée un cycle : (2)\(\to\)(3)\(\to\)(4)\(\to\)(1)\(\to\)(2), impossible en cohérence séquentielle.

Les six entrelacements

Lecture. Deux fils de deux opérations donnent \(\binom{4}{2}=6\) ordres globaux, et trois sorties : \((0,1)\), \((1,0)\), \((1,1)\). La sortie \((0,0)\) n’apparaît dans aucun : la cohérence séquentielle l’interdit.

Modèles de cohérence relâchée

Modèles relâchés et TSO

La cohérence séquentielle est intuitive mais limite les optimisations. Les modèles relâchés permettent certains réordonnancements pour améliorer les performances.

Modèles de cohérence relâchée

Ils assouplissent les contraintes d’ordonnancement. Le plus répandu sur les PC et les serveurs est TSO ({Total Store Order}), celui des processeurs x86 ; ARM et RISC-V autorisent davantage de réordonnancements.

Le modèle TSO (x86)

Il permet uniquement le réordonnancement W\(\to\)R :

  • les écritures peuvent être mises en tampon et retardées ;
  • les lectures peuvent dépasser les écritures précédentes (vers des adresses différentes) ;
  • l’ordre des lectures est préservé ;
  • l’ordre des écritures est préservé.

TSO et le tampon d’écriture, pas à pas

Lecture. Le fil 1 écrit \(A=1\) : sous TSO, l’écriture entre dans le tampon d’écriture de P1 (cadre rouge) ; la mémoire garde \(A=0\) et le fil continue sans attendre.

Lecture. Le fil 2 écrit \(B=1\) : même chose, dans le tampon de P2. Aucun des deux cœurs ne voit l’écriture de l’autre.

Lecture. Le fil 1 lit \(B\) : la lecture dépasse l’écriture qui attend dans son tampon (réordonnancement W\(\to\)R) ; elle va en mémoire, où \(B\) vaut encore \(0\) : \(r_1=0\).

Lecture. Le fil 2 lit \(A\) : même dépassement, \(r_2=0\). Les deux lectures ont vu \(0\).

Lecture. Les tampons se vident dans l’ordre : \(A=1\) et \(B=1\) en mémoire. Résultat \(r_1=r_2=0\), impossible en cohérence séquentielle, possible sous TSO. Une barrière StoreLoad dans chaque fil l’interdit.

Barrières mémoire

Barrières mémoire

Elles forcent l’ordre des opérations :

  • StoreLoad : empêche W\(\to\)R (la plus coûteuse) ;
  • StoreStore : empêche W\(\to\)W ;
  • LoadLoad : empêche R\(\to\)R ;
  • LoadStore : empêche R\(\to\)W.

Sous TSO, seule la barrière StoreLoad est utile : les trois autres ordres sont déjà garantis.

Thread 1 Thread 2
A = 1; B = 1;
[barrière StoreLoad]{.c-2073ba} [barrière StoreLoad]{.c-2073ba}
r1 = B; r2 = A;

Lecture. Sur x86, l’instruction mfence joue ce rôle : chaque fil vide son tampon d’écriture avant de lire. La sortie \(r_1=r_2=0\) devient impossible ; il reste \((0,1)\), \((1,0)\) et \((1,1)\).

Métriques et optimisations

Métriques et récapitulatif des transitions

Métriques clés pour la cohérence

  • Hit rate : pourcentage d’accès trouvés en cache ;
  • Coherence miss : défauts causés par les invalidations de cohérence ;
  • False sharing rate : invalidations dues au false sharing.
Transition Transaction Cycles MSI MESI
Read miss (excl.) BusRd \(100\) I\(\to\)S I\(\to\)E
Write après read excl. BusRdX / aucune \(100\) / \(1\) S\(\to\)M E\(\to\)M
Write miss BusRdX \(100\) I\(\to\)M I\(\to\)M
Invalidation autre BusRdX – S/M\(\to\)I S/M\(\to\)I
Write-back BusWB \(100\) M\(\to\)S/I M\(\to\)S/I

Lecture. Une seule ligne sépare les deux protocoles : écrire une donnée qu’on est seul à avoir lue coûte \(100\) cycles en MSI, \(1\) en MESI.

Optimisations et comparaison des protocoles

Techniques d’optimisation

  1. Minimiser le partage : variables locales, réduction finale.
  2. Aligner les données : rembourrage, structure dont le champ porte alignas(64).
  3. Grouper les modifications.
  4. Prefetching : anticiper les besoins futurs.
Caractéristique MSI MESI Gain MESI
Nombre d’états \(3\) \(4\) –
État Exclusive non oui E\(\to\)M local
Write sur donnée excl. BusRdX aucun bus \(99\) cycles (\(100\to1\))
Signal de partage non oui choix de E ou S
Trafic bus plus élevé réduit selon le programme

Lecture. Le gain de trafic de MESI porte sur les données lues puis écrites par un seul cœur ; il disparaît quand les données sont réellement partagées.

Ce qu’il faut retenir

À retenir (1/2)

  1. La cohérence est essentielle dans les systèmes multicœurs.
  2. L’espionnage du bus (snooping) permet la cohérence par surveillance du bus.
  3. MSI : \(3\) états (Modified, Shared, Invalid).
  4. MESI : ajoute Exclusive pour permettre E\(\to\)M sans bus (gain majeur).
  5. BusWB : write-back des données modifiées vers la mémoire.

À retenir (2/2)

  1. False sharing : des variables indépendantes dans une même ligne ; la ligne fait des allers-retours.
  2. Cohérence séquentielle : modèle mental intuitif mais restrictif.
  3. TSO (x86) : permet W\(\to\)R ; barrière StoreLoad pour l’interdire.
  4. Optimisations : rembourrage, alignement, variables locales.
  5. Latences types : succès \(1\), défaut \(100\), BusWB \(100\), BusRdX \(100\) cycles.

Questions de révision

Vrai ou faux ?

  1. L’état Modified peut être dans plusieurs caches simultanément.
  2. MESI élimine tous les défauts de cache.
  3. E\(\to\)M ne génère pas de transaction bus.
  4. Write-allocate charge la ligne avant modification.
  5. BusWB transfère les données modifiées vers la mémoire.
  6. Le false sharing affecte des variables logiquement indépendantes.
  7. TSO permet le réordonnancement W\(\to\)R.
  8. L’état Exclusive garantit qu’aucun autre cache n’a la ligne.

Correction

  1. Faux : Modified est exclusif à un seul cache.
  2. Faux : MESI ne supprime aucun défaut de lecture ni d’écriture sur une ligne absente ; il supprime l’« upgrade » (BusRdX) d’une écriture sur une ligne en E.
  3. Vrai.
  4. Vrai.
  5. Vrai.
  6. Vrai.
  7. Vrai.
  8. Vrai.

Lab 3 et prochaine séance

Lab 3 : la mémoire

  • lire dans l’ordre ou au hasard, lire un nombre sur \(k\) : la ligne de cache de \(64\) octets vue depuis NumPy ;
  • chaque processus reçoit une copie de ses données, et la copie coûte ;
  • deux processus qui incrémentent le même compteur perdent des mises à jour ; un verrou les répare, mais la ligne voyage d’un cœur à l’autre ;
  • calcul local et fusion à la fin ; tableau partagé sans copie.

Prochaine séance

Séance 3 : programmation parallèle avancée. Synchronisation des fils : sections critiques, verrous, sémaphores, barrières. Lab 4 : synchroniser.

Références : Hennessy et Patterson, Computer Architecture: A Quantitative Approach, chap. 5 ; Papamarcos et Patel, ISCA 1984 (MESI, protocole Illinois) ; Lamport, IEEE Trans. Computers, 1979 (cohérence séquentielle).