(:requiretuid:)
Mehrere Implementierungen für eine Architektur sind möglich:
Wir beginnen zunächst mit einer Untermenge des MIPS Befehlssatzes:
and
, or
, add
, sub
, slt
lw
, sw
beq
Die auf Ebene der Architektur sichtbaren, also für die Programmiererin zugänglichen, Daten bestimmen den vollständigen Zustand der Architektur. Diese sind:
PC
(program counter)
Im Folgende erarbeiten wir gemeinsam Datenpfad und Steuerwerk eines Ein-Takt MIPS Prozessors.
lw
BefehlsEin load word Befehl (lw
) soll ausgeführt werden.
1. Schritt: Hole Instruktion
2. Schritt: Lese Quelloperand aus Registerfeld
3. Schritt: Vorzeichenerweitere den 16b Direktwert auf 32b Signal SignImm
4. Schritt: Berechne die effektive Speicheradresse
5. Schritt: Lese Daten aus Speicher und schreibe sie ins passende Register
6. Schritt: Bestimme Adresse des nächsten Befehls (Erhöhe PC
nach lw
)
sw
Schreibe Daten aus rt
in den Speicher
rs
und rt
rd
(statt nach rt
wie bei sw
)
beq
rs
und rt
gleich sind
or
addi
Dazu ist keine Änderung am Datenpfad nötig. Wir erweitern lediglich das Steuerwerk.
j
Wir müssen den Datenpfad nur geringfügig erweitern, sowie das Steuerwerk an den neuen Befehl anpassen.
Die Ausführungzeit eines Programms berechnet sich nach folgender Formel.
Ausführungszeit = (# Instruktionen)(Takte/Instruktion)(Sekunden/Takt) = #Instruktionen CPI Tc
Tc wird durch den längsten Pfad bestimmt (lw
).
Tc = tpcq_PC + 2tmem + tRFread + tmux + tALU + tRFsetup
Nehmen wir nun an, dass wir ein Programm mit 100 Milliarden Instruktionen auf unserem Ein-Takt MIPS Prozessor ausführen.
Ausführungszeit = #Instruktionen CPI Tc
lw
)
Wir ersetzen die getrennten Instruktions- und Datenspeicher (Hardvard-Architektur) durch einen gemeinsamen Speicher (Von Neumann-Architektur). Letztere ist heute weiter verbreitet.
Als Beispiel betrachten wir die Ausführung von lw
.
lw
lw
Direktwert ausführenlw
lw
lw
sw
Die Daten aus rt
werden in den Speicher geschrieben.
rs
und rt
rd
(statt nach rt
)
beq
-Instruktionrs
und rt
gleich sind
Im Folgenden erarbeiten wir schrittweise die Arbeitsweise des Hauptsteuerwerks.
lw
sw
beq
addi
-Instruktionj
j
In einem Mehrtaktprozessor benötigen die Instruktionen unterschiedlich viele Takte:
beq
, j
sw
, addi
lw
CPI wird daher als gewichteter Durchschnitt bestimmt. Der SPECint 2000 Benchmark legt dabei zum Beispiel folgende Gewichtung fest:
Es ergibt sich also:
Durchschnittliche CPI = (0,11 + 0,02)(3) + (0,52 + 0,10)(4) + (0,25)(5) = 4,12
Tc = tpcq + tmux + max(tALU + tmux, tmem) + tsetup
Tc = tpcq_PC + tmux + max(tALU + tmux, tmem) + tsetup
Wir nehmen an, dass ein Programm mit 100 Milliarden Instruktionen auf dem Mehrtaktprozessor ausgeführt wird:
Ausführungszeit = (#Instruktionen) x CPI x Tc
Es fällt auf, dass der Mehrtaktprozessor langsamer ist als der
Ein-Takt-Prozessor (brauchte nur 92,5 Sekunden).
Zwar hat der Mehrtaktprozessor eine unterschiedlich lange Anzahl von Ausführungstakten (bis zu 5 für lw
),
aber keine 5-mal schnellere Taktfrequenz. Außerdem gibt es eine zusätzliche Verzögerung für sequentielle Logik
mehrfach je Befehl ( tpcq + tsetup = 50 ps). Dafür ist der Mehrtakt-MIPS-Prozessor
im Hinblick auf die Größe der Hardware potenziell etwas kleiner.
Um den MIPS Prozessor zu optimieren wenden wir das Prinzip der zeitlichen Parallelität an. Dazu teilen wir den Ablauf im Ein-Takt-Prozessor in fünf Stufen:
Um dies umzusetzen fügen wir Pipeline-Register zwischen den Stufen ein.
WriteReg muss zur gleichen Zeit am Registerfeld ankommen wie Result.
Das Steuerwerk ist identisch zum Ein-Takt-Steuerwerk, aber die Signale werden über die Pipeline-Stufen verzögert.
Hazards treten auf, wenn eine Instruktion vom Ergebnis einer vorhergehenden abhängt, diese aber noch nicht kein Ergebnis geliefert hat.
Wir unterscheiden zwei Arten von Hazards:
Hier: Read-after-Write Hazard (RAW) - $s0 muss vor dem Lesen geschrieben werden
Einplanen von Wartezeiten von Anfang an:
nop
s zu Compile-Zeit
Umstellen des Maschinencode zur Compile-Zeit
Schnelleres Weiterleiten der Daten über Abkürzungen zur Laufzeit
Anhalten des Prozessors zur Laufzeit bis zur Ankunft der Daten
Wir fügen entweder ausreichend viele nop
s ein bis das Ergebnis bereitsteht oder schieben unabhängige Instruktionen nach vorne (statt nop
s)
"Abkürzung" zur Execute-Stufe von
Forwarding-Logik für Signal ForwardAE(Weiterleiten von Operand A):
Die Forwarding-Logik für das Signal ForwardBE(Weiterleiten von Operand B) funktioniert analog. Wir ersetzen lediglich rsE durch rtE
Um stalling zu ermöglichen, müssen wir die Hazard Unit erweitern.
Die Hazard Unit verwendet dabei folgende Logik.
Control Hazards können bei Verzweigungen auftreten, z.B. bei beq
:
Die Kosten eines falsch vorhergesagten Sprunges sind daher die Anzahl von zu entfernenden Instruktionen, falls der Sprung genommen wird. Diese könnten reduziert werden, wenn der Sprung in einer früheren Pipeline-Stufe entschieden würde.
Bei dem orthogonalen Ansatz der Sprungvorhersage versucht man vorherzusagen, ob ein Sprung genommen wird. Danach können die Instruktionen von der richtigen Stelle geholt werden.
Man kann davon ausgehen, dass Rückwärtssprünge genommen werden, da diese hauptsächlich in Schleifen verwendet werde. Dafür wird eine Historie geführt. In dieser wird gespeichert, ob der Sprung die letzten Male genommen wurde. Denn war dies der Fall, dann ist die Wahrscheinlichkeit groß, dass er wieder genommen wird.
Eine gute Vorhersage reduziert die Zahl der Srpünge, die einen Flush der Pipeline erforderlich machen.
Idealerweise wäre natürlich CPI = 1.
Manchmal treten aber Stalls auf. Diese treten durch Lage- und Verzweigungsfehler auf.
SPECint 2000 benchmark:
Wir machen folgende Annahmen:
Wie hoch ist der durchschnittliche CPI-Wert?
Durchschnittlieche CPI = (0,25)(1,4)+(0,1)(0,1)+(0,11)(1,25)+(0,02)(2,0)+(0,52)(1,0) = 1,15
Wir führen nun 100 Milliarden Instruktionen auf einem Pipelined-MIPS-Porzessor aus.
Dabei haben wir:
Exceptions entstehen durch einen außerplanmäßigen Aufruf der Ausnahmebehandlungsroutine. Dies wird verursacht durch:
Wenn eine dieser Ausnahmen auftritt, dann wird:
Die Register für die Ausnahmebehandlung sind nicht Teil des regulären MIPS Registerfelds.
Cause
EPC (Exception PC)
Befehl: "Move from Coprozessor 0"
mfc0 $t0, Cause
Dies überträgt den aktuellen Wert von Cause nach $t0.
Weitere Themen in der Mikroarchitektur sind:
Üblicherweise beträgt die Tiefe einer Pipeline 10-20 Stufen. Es gibt aber auch Ausnahmen, wie Fehlkonstruktionen (z.B. Intel P4, mit mehr als 30 Stufen). Für anwendungsspezifische Spezialprozessoren gilt diese Konvention nicht. Diese können gegebenenfalls auch hunderte von Stufen haben.
Grenzen für die Pipeline-Tiefe sind gegeben durch:
Ein idealer Pipelined-Prozessor hat eine CPI von 1. Durch Fehler bei der Sprungvorhersage, erhöht% sich die CPI.
Die statische Sprungvorhersage prüft, ob die Sprungrichtung vorwärts oder rückwärts ist. Falls rückwärts gesprungen wird, sagt dies "Springen" vorher, ansonsten "Nicht springen".
Die dynamische Sprungvorhersage führt eine Historie der letzten (einigen hundert) Verzweigungen im Branch Target Buffer und speichert dabei:
add $s1, $0, $0 # sum = 0
add $s0, $0, $0 # i = 0
addi $t0, $0, 10 # $t0 = 10
for:
beq $s0, $t0, done # falls i == 10, springe
add $s1, $s1, $s0 # sum = sum + i
addi $s0, $s0, 1 # inkrementiere i
j for
done:
Die 1-Bit Sprungvorhersage speichert, ob die Verzweigung das letzte Mal %blue&genommen wurde und sagt genau dieses Verhalten für das aktuelle Mal vorher.
Fehlervorhersagen
Sie wird einmal beim Austritt aus der Schleife beim Schleifenende das Falsche vorhersagen und demnach auch wieder, beim erneuten Eintritt in die Schleife.
add $s1, $0, $0 # sum = 0
add $s0, $0, $0 # i = 0
addi $t0, $0, 10 # $t0 = 10
for:
beq $s0, $t0, done # falls i == 10, springe
add $s1, $s1, $s0 # sum = sum + i
addi $s0, $s0, 1 # inkrementiere i
j for
done:
Die 2-Bit Sprungvorhersage macht nur beim letzten Sprung aus der Schleife heraus eine falsche Vorhersage.
add $s1, $0, $0 # sum = 0
add $s0, $0, $0 # i = 0
addi $t0, $0, 10 # $t0 = 10
for:
beq $s0, $t0, done # falls i == 10, springe
add $s1, $s1, $s0 # sum = sum + i
addi $s0, $s0, 1 # inkrementiere i
j for
done:
Superskalare Mikroarchitektur bedeutet, dass mehrere Instanzen des Datenpfades mehrere Instruktionen gleichzeitig ausführen. Abhängigkeiten zwischen den Instruktionen erschweren die parallele Ausführung.
lw $t0, 40($s0) add $t1, $t0, $s1 sub $t0, $s2, $s3 and $t2, $s4, $t0 or $t3, $s5, $s6 sw $s7, 80($t3)
lw $t0, 40($s0) add $t1, $t0, $s1 sub $t0, $s2, $s3 and $t2, $s4, $t0 or $t3, $s5, $s6 sw $s7, 80($t3)
Die Out of Order-Mikroarchitektur kann die Ausführungsreihenfolge von Instruktionen umsortieren. Dabei sucht sie im Voraus nach parallel startbaren Instruktionen und startet diese in beliebiger% Reihenfolge, solange dadurch keine Abhängigkeiten verletzt werden.
Es gibt folgende Abhängigkeiten:
Parallelismus auf Instruktionsebene (instruction level parallelism, ILP)
Scoreboard
lw $t0, 40($s0) add $t1, $t0, $s1 sub $t0, $s2, $s3 and $t2, $s4, $t0 or $t3, $s5, $s6 sw $s7, 80($t3)
lw $t0, 40($s0) add $t1, $t0, $s1 sub $t0, $s2, $s3 and $t2, $s4, $t0 or $t3, $s5, $s6 sw $s7, 80($t3
SIMD steht für Single Instruction Multiple Data.
Das bedeutet, dass eine Instruktion auf mehrere Datenelemente gleichzeitig angewendet wird. Dies wird oft im Graphik- und Multimediabereich verwendet. Dabei werden oft schmale arithmetische Operationen ausgeführt. Dies nennt man auch gepackte Arithmetik. Ein Beispiel ist das gleichzeitige Addieren von vier Bytes.
Dafür muss die ALU verändert werden. Es gibt keinen Übertrag mehr zwischen einzelnen Bytes.
Multithreading
Multiprozessoren
Prozesse sind auf dem Computer gleichzeitig laufende Programme wie z.B. der Web-Browser, Musik im Hintergrund, Textverarbeitung.
Ein Thread ist die parallele Ausführung als Teil eines Programmes. Ein Prozess kann mehreren Threads enthalten.
In konventionellem Prozessor:
Beim Multithreading auf Mikroarchitekturebene haben wir mehrere Instanzen des Architekturzustandes im Prozessor. Damit sind mehrere Threads nun gleichzeitig% aktiv.
Das erhöht nicht den Grad an ILP (instruction-level parallelism) innerhalb eines Threads! Es erhöht aber den Durchsatz des Gesamtsystems mit mehreren Threads.
Als Multiprozessoren bezeichnet man mehrere unabhängige Prozessorkerne mit einem dazwischenliegenden Kommunikationsnetz. Dabei gibt es verschieden Arten von Multiprocessing: