Grundlagen

Die CPU

Programmzähler, Befehlsregister, Registersatz, ALU, Speicher – und ein Steuerwerk, das in jedem Takt die richtigen Leitungen schaltet. Hier setzen sich die Bausteine aus Block H zur Lehrmaschine zusammen, und man sieht Befehl für Befehl, wie Holen, Dekodieren und Ausführen in Hardware aussehen.

Lesestand

Eine CPU besteht aus zwei Teilen. Der Datenpfad enthält die Bausteine, die Daten halten und verarbeiten: Programmzähler (PC), Befehlsregister (IR), Registersatz und ALU, verbunden mit dem Speicher durch Busse und Multiplexer. Das Steuerwerk ist ein Schaltwerk, das aus dem Opcode des aktuellen Befehls und der aktuellen Phase berechnet, welche Leitungen in diesem Takt aktiv sind: Welches Register wird gelesen, was rechnet die ALU, wohin wird geschrieben.

So wird jeder Befehl in Phasen ausgeführt: Holen (der Befehl an der Adresse im PC kommt ins IR, der PC zählt weiter), Dekodieren (das Steuerwerk liest den Opcode), Ausführen (die ausgewählten Bausteine arbeiten, das Ergebnis wird geschrieben). Moderne Prozessoren überlappen diese Phasen mehrerer Befehle – das Pipelining – und raten bei Sprüngen voraus, wohin es weitergeht.

Der Datenpfad der Lehrmaschine

Alle Teile kennen wir schon: Der PC ist ein 8-Bit-Register mit einem Addierer, der 1 dazuzählt (H4, H5). Der Speicher sind 256 Register mit Decoder (H5). Der Registersatz sind 16 Register, aus denen zwei Multiplexer gleichzeitig zwei Werte lesen und in das ein Decoder einen Wert schreibt. Die ALU rechnet (H4). Das IR hält den aktuellen Befehl, damit seine Bitfelder – Opcode, d, s, t, Adresse – während der Ausführung anliegen. Klick dich durch ein Programm aus H2, Phase für Phase:

Holen, Dekodieren, Ausführen
1 · Holen2 · Dekodieren3 · Ausführen
Steuersignale der eben ausgeführten Phase

Das Steuerwerk selbst ist ein Schaltwerk wie in H5: Ein kleines Register merkt sich die Phase, ein Schaltnetz berechnet aus Phase und Opcode die Steuersignale. Für 16 Opcodes und drei Phasen ist das eine Wahrheitstabelle mit 48 Zeilen und rund zwanzig Ausgängen – in Hardware wenige hundert Gatter. Bei komplizierten Befehlssätzen wie x86 werden manche Befehle intern zusätzlich in Folgen einfacherer Schritte zerlegt (Mikrocode, bei modernen Prozessoren Mikrooperationen).

Damit ist der Kreis von Block H geschlossen: Aus Bits (H1) werden Befehle (H2), aus Gattern (H3) Schaltnetze (H4) und Speicher (H5), und zusammen eine Maschine, die Programme ausführt – eine universelle Maschine im Sinne von G3.

Pipelining: mehrere Befehle gleichzeitig

Die Lehrmaschine erledigt einen Befehl nach dem anderen, jede Phase in einem eigenen Takt. Dabei steht der größte Teil der Schaltung meistens still: Während die ALU rechnet, hat der Speicher nichts zu tun. Echte Prozessoren teilen die Arbeit deshalb in Stufen ein und schieben die Befehle wie am Fließband durch – wenn Befehl 1 ausgeführt wird, wird Befehl 2 schon dekodiert und Befehl 3 geholt. Die klassische Lehrbuch-Pipeline hat fünf Stufen: Holen (IF), Dekodieren (ID), Ausführen (EX), Speicherzugriff (MEM), Zurückschreiben (WB).

Fünf Befehle, fünf Stufen

Zwei Störungen bremsen das Fließband. Braucht ein Befehl das Ergebnis seines Vorgängers, muss er warten, bis es da ist – oder die Hardware leitet es auf einer Abkürzung direkt weiter (Forwarding). Und bei einem bedingten Sprung weiß der Prozessor erst spät, wo es weitergeht. Statt zu warten, rät er: Eine Sprungvorhersage merkt sich, wie sich jeder Sprung bisher verhalten hat, und liegt bei typischem Code weit über 90 % richtig. Lag sie falsch, werden die schon begonnenen Befehle verworfen. Bei modernen Prozessoren mit 15 bis 20 Stufen kostet das jeweils viele Takte.

Was moderne Prozessoren noch tun

TechnikIdee
Superskalarmehrere ALUs: mehrere Befehle pro Takt in jeder Stufe
Out-of-OrderBefehle in anderer Reihenfolge ausführen, wenn ihre Daten schon bereitstehen – das Ergebnis sieht aus, als wäre alles der Reihe nach passiert
Spekulationhinter einer vorhergesagten Verzweigung weiterrechnen und bei Irrtum verwerfen
Cacheskleine SRAM-Speicher, damit nicht jeder Zugriff hunderte Takte auf den DRAM wartet (Speicherhierarchie)
SIMDeine Operation auf 4, 8 oder 16 Werte zugleich – breite ALUs
Mehrere Kernemehrere vollständige Datenpfade auf einem Chip – für mehrere Threads

Dass Spekulation Nebenwirkungen in den Caches hinterlässt, die man messen kann, wurde 2018 als Sicherheitsproblem bekannt (Spectre, Meltdown). Seitdem sind Betriebssysteme, Browser und JVMs mit Gegenmaßnahmen ausgestattet – ein Beispiel dafür, dass Hardwaredetails bis in die Softwareschichten durchschlagen.

Für Entwickler übersetzt

Die meisten Details der CPU bleiben unter der JVM verborgen – aber nicht alle. Das berühmteste Beispiel ist die Sprungvorhersage:

int[] daten = zufallszahlen(1_000_000, 0, 256);
// Arrays.sort(daten);   // mit dieser Zeile kann die Schleife um ein Vielfaches schneller sein

long summe = 0;
for (int x : daten)
    if (x >= 128)            // zufällige Daten: die Vorhersage liegt oft falsch
        summe += x;           // sortierte Daten: erst immer nein, dann immer ja – fast perfekt vorhersagbar

Ob der Effekt auftritt, hängt allerdings vom JIT ab: Erkennt er das Muster, ersetzt er den Sprung durch einen bedingten Move oder vektorisiert die Schleife, und der Unterschied verschwindet. Genau deshalb misst man solche Dinge nicht mit System.nanoTime() um eine Schleife, sondern mit JMH, das Aufwärmen, JIT-Effekte und Optimierungen berücksichtigt.

CPU-EigenschaftWas es in Java bedeutet
Sprungvorhersagevorhersagbare Verzweigungen sind billig, zufällige teuer
Cachesein int[] durchlaufen ist viel schneller als eine LinkedList – die Daten liegen hintereinander
SIMDder JIT vektorisiert einfache Schleifen selbst; die Vector API (Inkubator-Modul jdk.incubator.vector) macht es ausdrücklich
Out-of-Order und mehrere Kerneohne Synchronisation sieht ein anderer Thread Schreibzugriffe womöglich in anderer Reihenfolge – deshalb gibt es das Java Memory Model, volatile und Locks
Befehlssatz-XX:+PrintAssembly (mit hsdis) zeigt, was der JIT tatsächlich erzeugt

Häufige Irrtümer

„Die CPU führt Befehle streng nacheinander aus.“ – Sie tut nur so. Intern laufen Dutzende Befehle überlappend, außer der Reihe und spekulativ; nach außen sieht es aus, als wäre einer nach dem anderen fertig geworden.
„Das Steuerwerk ist ein Programm.“ – Bei einfachen Prozessoren ist es reine Schaltungslogik. Mikrocode gibt es bei manchen komplexen Befehlen, aber auch er wird von Hardware abgearbeitet.
„Mehr Kerne machen jedes Programm schneller.“ – Nur Programme, die ihre Arbeit auf mehrere Threads verteilen. Ein einzelner Thread läuft immer auf einem Kern.
„Der Prozessor wartet meist auf das Rechnen.“ – Meist wartet er auf Daten aus dem Speicher. Der Engpass zwischen Prozessor und Speicher heißt seit den 1970ern Von-Neumann-Flaschenhals.

Verwandte Begriffe