Plus facile à lire avec un fond crème, une teinte, plus de contraste ou un texte plus grand ? Choisissez vos couleurs et votre texte, une fois pour toutes les pages.

Leçon gratuite

Chevaucher les instructions pour aller plus vite (pipeline)

Après cette leçon: Je peux dire comment un pipeline accélère un processeur et ce qui le ralentit.

Leçon de 55 min9 commandesLab de compilation et d’architecture : gcc, flex, bison et RISC-V dans une VM

Cinq postes, un colis par minute

Dans un entrepôt, une seule personne prend l’article, l’emballe, pèse le colis, colle l’étiquette et le charge. Chaque commande demande cinq minutes.

L’entrepôt installe cinq postes, un par geste. Chaque colis demande toujours cinq minutes. Pourtant, un colis prêt sort maintenant chaque minute. Un processeur fait la même chose avec les instructions.

À la fin de cette leçon

Remarque

Je peux dire comment un pipeline accélère un processeur et ce qui le ralentit.

Mots-clés

MotCe que ça veut direExemple
Pipelineles étapes de plusieurs instructions menées en même temps, chacune dans un étage
Étageune étape du pipeline, qui dure un cycle d’horlogeEX
Aléace qui empêche l’instruction suivante de partir à temps
Bulleun cycle où un étage attend sans rien faire d’utile
Transmission anticipéele passage d’un résultat à l’instruction suivante avant son écriture
Prédiction de branchementdeviner le sens d’un branchement avant de le connaître

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

Cinq étages, cinq instructions à la fois

Un pipeline RISC-V classique a cinq étages. IF lit l’instruction, ID la décode et lit les registres, EX calcule. MEM lit ou écrit la mémoire, et WB écrit le résultat dans un registre.

Chaque étage dure un cycle d’horloge. Pendant qu’une instruction est en EX, la suivante est en ID et celle d’après en IF. Jusqu’à cinq instructions sont donc dans le processeur en même temps.

Exemple travaillé : trois instructions, aucun aléa

InstructionCycle 1Cycle 2Cycle 3Cycle 4Cycle 5Cycle 6Cycle 7
addi t0, zero, 4IFIDEXMEMWB
addi t1, zero, 6IFIDEXMEMWB
addi t2, zero, 8IFIDEXMEMWB

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

Aller dans le dossier d’architecture

Commande
cd ~/arch

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Plus rapide sans instruction plus rapide

Une par une, 200 instructions de 5 cycles prennent 1000 cycles. Dans un pipeline, la première finit au bout de 5 cycles, puis une autre finit à chaque cycle. Les 200 instructions prennent donc 5 + 199, soit 204 cycles.

Chaque instruction met toujours 5 cycles du début à la fin. Ce qui augmente, c’est le nombre d’instructions finies par cycle. Cela ne tient que si rien ne fait attendre une instruction.

Un résultat qui n’est pas encore prêt

Un aléa empêche l’instruction suivante de partir à temps. Le plus courant est l’aléa de données : une instruction a besoin d’un registre qu’une instruction plus ancienne n’a pas fini.

Sans aide, le pipeline insère des bulles jusqu’à l’écriture de la valeur. La transmission anticipée supprime presque toute l’attente : le résultat de EX passe directement à l’instruction suivante. Un chargement est différent. Sa valeur n’existe qu’après MEM : l’instruction qui suit attend encore un cycle.

Exemple travaillé : les bulles de notre modèle

Instruction plus ancienneDistance avant l’utilisatriceBulles sans transmissionBulles avec transmission
add, sub ou addi1 instruction20
add, sub ou addi2 instructions10
lw1 instruction21
lw2 instructions10
Toute instruction3 ou plus00

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

Écrire un programme avec un aléa de chargement

Commande
printf '.globl _start\n_start:\n  addi sp, sp, -16\n  li t0, 20\n  sw t0, 8(sp)\n  lw a0, 8(sp)\n  add a0, a0, a0\n  li a7, 93\n  ecall\n' > attente.s

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

L’assembler

Commande
riscv64-linux-gnu-as attente.s -o attente.o

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Faire l’édition de liens

Commande
riscv64-linux-gnu-ld attente.o -o attente

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Le lancer dans l’émulateur

Commande
qemu-riscv64 ./attente

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Lire le code de sortie

Commande
echo $?

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Lire le code machine

Commande
riscv64-linux-gnu-objdump -d attente

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Erreur fréquente

Attention

Beaucoup pensent qu’un pipeline rend chaque instruction plus rapide. C’est faux : chaque instruction passe toujours par les cinq étages. Le pipeline termine plus d’instructions par cycle. Une bulle gaspille une part de ce gain : c’est pourquoi l’ordre des instructions compte.

Le compilateur bouche le trou

Un compilateur connaît les règles des bulles. Quand un chargement est suivi d’une instruction qui en a besoin, il cherche une autre instruction indépendante et la place entre les deux.

Les commandes suivantes compilent le loop.c du labo pour RISC-V. Regardez la boucle ligne par ligne, .L6, et trouvez ce qui sépare le chargement de son addition.

Compiler loop.c en assembleur RISC-V simple

Commande
riscv64-linux-gnu-gcc -O2 -march=rv64gc -S loop.c

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

La boucle ligne par ligne

Commande
grep -A 4 'L6:' loop.s

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Deviner le sens d’un branchement

Un branchement crée un aléa de contrôle : tant que EX n’a pas fait le test, le pipeline ne sait pas quoi lire ensuite. Attendre coûterait des cycles à chaque branchement.

Le processeur pratique donc la prédiction de branchement : il devine et continue. Une bonne prédiction ne coûte rien ; une mauvaise jette le travail lu depuis et repart. Le bne en bas d’une boucle revient en arrière presque à chaque fois : il est facile à deviner.

Pour aller plus loin : supprimer les bulles

Prenez ce programme : lw t0, 0(a0), add t1, t0, t0, lw t2, 4(a0), sub t3, t2, t1. Comptez ses bulles avec transmission, grâce à votre fonction.

Réordonnez ensuite les quatre lignes pour garder le même résultat avec 0 bulle. Dites quelle règle vous a permis de juger qu’un déplacement était sans danger.

À propos de ce labo et de sa source: Lab de compilation et d’architecture : gcc, flex, bison et RISC-V dans une VM

Vous enseignez à une classe ? Proposez ce module à vos étudiants avec un guide de l'enseignant, des devoirs corrigés et un laboratoire pour chaque étudiant.