Lässt es sich mit cremefarbenem Papier, einer Tönung, mehr Kontrast oder größerer Schrift besser lesen? Wählen Sie Ihre Farben und Ihre Schrift, einmalig für alle Seiten.

Kostenlose Lektion

Befehle überlappen, um schneller zu rechnen (Pipeline)

Nach dieser Lektion: Ich kann sagen, wie eine Pipeline einen Prozessor schneller macht und was sie bremst.

Lektion, 55 Min.10 BefehleLab für Compilerbau und Rechnerarchitektur: gcc, flex, bison und RISC-V in einer VM

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

BegriffWas er bedeutetBeispiel
Pipelinedie Schritte mehrerer Befehle gleichzeitig ausführen, jeden in einer anderen Stufe
Stufeein Schritt der Pipeline, der einen Takt dauertEX
Konfliktetwas, das den nächsten Befehl nicht rechtzeitig starten lässt
Stallein Takt, in dem eine Stufe wartet und nichts Nützliches tut
Weiterleitungein Ergebnis direkt an den nächsten Befehl geben, bevor es zurückgeschrieben ist
Sprungvorhersageraten, 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

BefehlTakt 1Takt 2Takt 3Takt 4Takt 5Takt 6Takt 7
addi t0, zero, 4IFIDEXMEMWB
addi t1, zero, 5IFIDEXMEMWB
addi t2, zero, 6IFIDEXMEMWB

Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.

In den Architektur-Ordner wechseln

Befehl
cd ~/arch

Hier 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 BefehlWie weit vor dem NutzerStalls ohne WeiterleitungStalls mit Weiterleitung
add oder addi1 Befehl20
add oder addi2 Befehle10
lw1 Befehl21
lw2 Befehle10
Beliebig3 oder mehr00

Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.

Ein Programm mit Load-Use-Konflikt schreiben

Befehl
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.s

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Assemblieren

Befehl
riscv64-linux-gnu-as wartet.s -o wartet.o

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Linken

Befehl
riscv64-linux-gnu-ld wartet.o -o wartet

Hier 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

Befehl
qemu-riscv64 ./wartet

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 Exit-Status lesen

Befehl
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

Befehl
riscv64-linux-gnu-objdump -d wartet

Hier 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

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

Hier 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

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

Hier 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

Befehl
grep -A 4 'L9:' loop.s

Hier 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.

Über dieses Lab und seinen Quellcode: Lab für Compilerbau und Rechnerarchitektur: gcc, flex, bison und RISC-V in einer VM

Sie unterrichten eine Gruppe? Weisen Sie dieses Modul Ihren Studierenden zu, mit Handbuch für Lehrende, automatisch geprüften Aufgaben und einem Lab für jede Person.