Eine Waschstraße mit fünf Stationen
Eine Waschanlage mit nur einem Platz wäscht ein Auto vor, wäscht, spült, wachst und trocknet es. Erst dann fährt das nächste Auto hinein. Jedes braucht fünf Minuten.
Eine Waschstraße hat fünf Stationen hintereinander. Jedes Auto braucht immer noch fünf Minuten. Aber jede Minute fährt ein sauberes Auto heraus. Ein Prozessor macht mit Befehlen dasselbe.
Am Ende dieser Lektion
Notiz
Ich kann sagen, wie eine Pipeline einen Prozessor schneller macht und was sie bremst.
Schlüsselwörter
| Begriff | Was er bedeutet | Beispiel |
|---|---|---|
| Pipeline | die Schritte mehrerer Befehle gleichzeitig ausführen, jeden in einer anderen Stufe | |
| Stufe | ein Schritt der Pipeline, der einen Takt dauert | EX |
| Konflikt | etwas, das den nächsten Befehl nicht rechtzeitig starten lässt | |
| Stall | ein Takt, in dem eine Stufe wartet und nichts Nützliches tut | |
| Weiterleitung | ein Ergebnis direkt an den nächsten Befehl geben, bevor es zurückgeschrieben ist | |
| Sprungvorhersage | raten, wohin eine Verzweigung geht, bevor es feststeht |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Fünf Stufen, fünf Befehle gleichzeitig
Eine klassische RISC-V-Pipeline hat fünf Stufen. IF holt, ID decodiert und liest die Register, EX rechnet, MEM liest oder schreibt den Speicher, und WB schreibt das Ergebnis ins Register zurück.
Jede Stufe dauert einen Takt. Während ein Befehl in EX ist, ist der nächste in ID und der danach in IF. So sind bis zu fünf Befehle gleichzeitig im Prozessor.
Beispiel: drei Befehle ohne Konflikt
| Befehl | Takt 1 | Takt 2 | Takt 3 | Takt 4 | Takt 5 | Takt 6 | Takt 7 |
|---|---|---|---|---|---|---|---|
| addi t0, zero, 4 | IF | ID | EX | MEM | WB | ||
| addi t1, zero, 5 | IF | ID | EX | MEM | WB | ||
| addi t2, zero, 6 | IF | ID | EX | MEM | WB |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
In den Architektur-Ordner wechseln
cd ~/archHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Schneller, ohne einen Befehl zu beschleunigen
Einzeln nacheinander brauchen 200 Befehle zu je 5 Takten 1000 Takte. In einer Pipeline ist der erste nach 5 Takten fertig, danach jeder Takt ein weiterer. 200 Befehle brauchen also 5 + 199, das sind 204 Takte.
Jeder Befehl braucht von Anfang bis Ende immer noch 5 Takte. Es steigt nur die Zahl der Befehle, die je Takt fertig werden. Das gilt nur, solange nichts einen Befehl warten lässt.
Ein Ergebnis, das noch nicht fertig ist
Ein Konflikt ist ein Grund, warum der nächste Befehl nicht rechtzeitig weiterkann. Häufig ist der Datenkonflikt: Ein Befehl braucht ein Register, das ein früherer noch nicht fertig hat.
Ohne Hilfe legt die Pipeline einen Stall ein, bis der Wert zurückgeschrieben ist. Weiterleitung spart das meiste Warten: Das Ergebnis aus EX geht direkt an den nächsten Befehl. Ein Ladebefehl ist anders. Seinen Wert gibt es erst nach MEM, also wartet der direkt folgende Befehl trotzdem einen Takt.
Beispiel: Stall-Takte in unserem Modell
| Der frühere Befehl | Wie weit vor dem Nutzer | Stalls ohne Weiterleitung | Stalls mit Weiterleitung |
|---|---|---|---|
| add oder addi | 1 Befehl | 2 | 0 |
| add oder addi | 2 Befehle | 1 | 0 |
| lw | 1 Befehl | 2 | 1 |
| lw | 2 Befehle | 1 | 0 |
| Beliebig | 3 oder mehr | 0 | 0 |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Ein Programm mit Load-Use-Konflikt schreiben
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 addi a0, a0, 2\n li a7, 93\n ecall\n' > wartet.sHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Assemblieren
riscv64-linux-gnu-as wartet.s -o wartet.oHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Linken
riscv64-linux-gnu-ld wartet.o -o wartetHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Im Emulator ausführen
qemu-riscv64 ./wartetHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Den Exit-Status lesen
echo $?Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Den Maschinencode lesen
riscv64-linux-gnu-objdump -d wartetHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Ein häufiger Fehler
Warnung
Viele glauben, eine Pipeline mache jeden einzelnen Befehl schneller. Das tut sie nicht: Jeder Befehl durchläuft weiter alle fünf Stufen. Eine Pipeline macht je Takt mehr Befehle fertig. Ein Stall verschenkt einen Teil davon. Deshalb zählt die Reihenfolge der Befehle.
Der Compiler füllt die Lücke
Ein Compiler kennt die Stall-Regeln. Folgt auf einen Ladebefehl ein Befehl, der den Wert braucht, sucht er einen anderen Befehl, der ihn nicht braucht. Den setzt er dazwischen.
Die nächsten Runs übersetzen das loop.c des Labs für RISC-V. Sehen Sie sich die zwei Summenschleifen .L6 und .L9 an. Was steht jeweils zwischen Laden und Addieren?
loop.c in einfachen RISC-V-Assembler übersetzen
riscv64-linux-gnu-gcc -O2 -march=rv64gc -S loop.cHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Die Schleife Zeile für Zeile
grep -A 4 'L6:' loop.sHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Die Schleife Spalte für Spalte
grep -A 4 'L9:' loop.sHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Raten, wohin eine Verzweigung geht
Eine Verzweigung erzeugt einen Steuerkonflikt: Bis EX den Test ausgewertet hat, weiß die Pipeline nicht, was sie als Nächstes holen soll. Warten würde bei jeder Verzweigung Takte kosten.
Darum nutzt der Prozessor eine Sprungvorhersage. Er rät und macht weiter. Richtig geraten kostet nichts; falsch geraten verwirft die seitdem geholte Arbeit. Das bne am Ende einer Schleife springt fast immer zurück, ist also leicht zu raten.
Weiterführend: umordnen, bis nichts wartet
Nehmen Sie dieses Programm: lw t0, 0(a1), addi t0, t0, 1, lw t2, 8(a1), addi t2, t2, 1. Zählen Sie mit Ihrer Funktion die Stalls mit Weiterleitung.
Ordnen Sie die vier Zeilen dann so um, dass das Ergebnis gleich bleibt und kein Stall übrig ist. Nennen Sie die Regel, nach der eine Verschiebung sicher war.