| Rechenwerk | auch ALU (Arithmetic and Logic Unit) um Berechnung durchzuführen |
Üblicherweise besitzt eine Recheneinheit (CPU) Daten- oder Rechenregister (Registermaschine). Berechnungen werden ausschließlich mit den Registern vorgenommen. Die Hauptaufgabe der Recheneinheit besteht darin,
> Structural Hazards ("strukturelle Abhängigkeiten oder Gefährdungen"): Verschiedene Fließbandstufen müssen auf dieselbe Hardware-Komponente zugreifen, weil diese nur sehr aufwändig oder überhaupt nicht zu duplizieren ist.
- resource hazards
- data hazards: Datenabhängigkeiten
- **Antidatenabhängig**: falls Befehl j eine Speicherzelle beschreibt, die von i noch gelesen werden müsste.
- WAR (write after read) Abhängigkeit
- **Ausgabeabhängig**: falls Befehle i und j die selbe Speicherzelle beschreiben
- WAW (write after write) Abhängigkeit
- **Datenabhängigkeit**: Operation hängt von der vorhergehenden Operation ab
- RAW (read after write) Abhängigkeit
- control hazards: Kontrollabhängigkeiten
- Gleichheit der Register wird schon in der instruction decode-Stufe geprüft
- Sprungziel wird in separatem Adressaddierer ebenfalls bereits in der instruction decode-Stufe berechnet
Gegenmaßnahmen
- pipeline stall (Anhalten des Fließbandes, NOOPS(s) einfügen)
- Einfachste Art von Puffer (keine Tags, d.h. keine Überprüfung, ob Adresse tatsächlich im Puffer)
- Entspricht sehr einfachem Cache
- Hat eine bestimmte Kapazität
- Kann nicht für alle Sprünge (aktuelle) Einträge enthalten
- Reduziert branch penalty nur, wenn branch delay länger als Berechnung der Zieladresse mit branch prediction buffer dauert
- Prädiktion kann fehlerhaft sein
- Prädiktion kann von anderem Sprungbefehl stammen (mit gleichen Bits im Indexteil der Adressen)
- Nachteile des einfachen 1-Bit Vorhersageschemas
- Höhere Fehlerrate als überhaupt möglich, wenn Häufigkeit der Sprungentscheidungen betrachtet wird
- D.h. auch wenn Sprung fast immer ausgeführt (taken) wird, entstehen 2 Fehler anstatt 1
2-Bit Branch-Prediction Buffer
- Speicherung der Historie, Befehlsadressen als Zugriffsschlüssel:
Allgemein: n-Bit Prädiktor (Spezialfall: 2-Bit)
- Verwendet n-Bit Zähler
- Sättigungsarithmetik (kein wrap around bei Überlauf)
- Kann Werte zwischen 0 und 2 n - 1 annehmen
- Wenn Zähler größer als Hälfte des Maximums (2 n - 1): Vorhersagen, dass Sprung ausgeführt wird; ansonsten vorhersagen, dass Sprung nicht genommen wird
- Zähler wird bei ausgeführtem Sprung inkrementiert und bei nicht ausgeführtem dekrementiert
- In der Praxis: 2-Bit Prädiktor ähnlich gut wie n-Bit Prädiktor
- In den meisten Prozessoren heute: 2-Bit Prädiktor für (lokale) Vorhersage
- Einschränkung des n-Bit (bzw. 2-Bit) Prädiktors:
- Betrachtet nur (vergangenes) Verhalten eines Sprungs, um dessen (zukünftiges) Verhalten vorherzusagen.
- Arbeitet rein lokal!
- Idee: Verbesserung durch Betrachtung des Verhaltens anderer Sprünge
- Man erhält so genannten korrelierenden Prädiktor (correlating predictor) oder zweistufigen Prädiktor
- Prinzip: Aufgrund globaler Information (anderer Sprünge) wird einer von mehreren lokalen Prädiktoren ausgewählt
### Korrelierende Prädikatoren
- Beziehen zur Vorhersage des Verhaltens eines Sprungs Kontext-Information mit ein, d.h. die Historie anderer Sprungbefehle
- Prädiktor benutzt globale Kontext-Bits, um einen von mehreren lokalen Prädiktoren auszuwählen
- Betrachten wiederholte Ausführung des Codefragments (ignorieren dabei alle anderen Sprünge, inkl. dem für Wiederholung)
- Einschränkung: Statt aller möglicher Sequenzen: d wechselt zwischen 2 und 0
Zweistufiger Prädiktor
- Verwendet 1 Bit Kontextinformation
- Es existieren 2 lokale Prädiktoren, beide je 1-Bit
- Vorhersage des zweistufigen Prädiktors: Anhand des Kontexts wird lokaler Prädiktor für die Vorhersage des aktuell betrachteten Sprungs ausgewählt
- Letzter Sprung ist i.a. nicht gleich aktuellem, vorherzusagendem Sprung (nur in einfachen Schleifen)
- Notation des Prädiktorstatus: <X>/<Y> mit
-<X>: Vorhersage, falls letzter Sprung not taken, d.h. Kontext = NT
-<Y>: Vorhersage, falls letzter Sprung taken, d.h. Kontext = T
-<X> und <Y> Vorhersagen: jeweils entweder T oder NT
(m,n)-Prädiktor
- Betrachtet als Kontext das Verhalten der letzten m Sprünge, um aus $2^m$ vielen lokalen Prädiktoren einen n-Bit Prädiktor auszuwählen
- Vorteil gegenüber (rein lokalem) 2-Bit Prädiktor
- Höhere Vorhersagegenauigkeit
- Erfordert kaum Hardwareaufwand
- Sprunggeschichte (Kontext, „Ausgang“ vorangegangener Sprünge) kann in m-Bit Schieberegister gespeichert werden (1 Bit für jeden der m vielen letzten Sprünge im Kontext, Bit gleich 1 wenn Sprung taken)
- Vorhersagepuffer adressiert via Konkatenation von
- Unteren Adressbits der Sprungbefehlsadresse
- m Bit globaler Sprunggeschichte
### High Performance Befehlsdekodierung
In Hochleistungs-Pipelines ist reine Vorhersage eines Sprungs i.d.R. nicht ausreichend
- Insbesondere: Falls mehrere Befehle pro Takt auszugeben sind
- Befehlsstrom mit großer Bandbreite erforderlich!
- Kontrollflussabhängigkeiten dürfen nicht „wahrnehmbar“ sein
- Maßnahmen hierfür
- Pufferung von Sprungzielen, und nicht nur Vorhersage des Sprungverhaltens (branch target buffer)
- Integrierte Einheit für das Holen der Befehle (d.h. nicht nur [relativ] einfache erste Stufe der Pipeline)
- Vorhersage von Rücksprungadressen (bei Prozeduraufruf)
### Branch Target Buffer
5-stufige Pipeline, Auswertung von Sprungbedingungen in EX:
- Branch delay von 2 Takten
- Mit Sprungvorhersage (branch prediction buffer)
- Zugriff erfolgt in ID (Adresse des Sprungbefehls schon in IF bekannt; aber:
- evtl. angesprungenes Ziel erst nach Befehlsdecodierung [ID])
- Nächste vorhergesagte Instruktion kann erst nach ID geholt werden
- Branch delay = 1, falls Prädiktion korrekt
- Mit Pufferung des Sprungziels (branch target buffer)
- Zugriff auf branch target buffer erfolgt in IF. Verhalten wie „echter“ Cache,
- adressiert mit Sprungbefehlsadresse (überprüft, ob Cache-Hit)
- Liefert vorhergesagte Adresse als Ergebnis, d.h. nächsten PC (d.h. nicht nur Vorhersage über Sprungverhalten)
- Keine Verzögerung, falls Prädiktion korrekt!
Zusätzliche Speicherung auch des Sprungziels, z.B. Kombination mit branch prediction buffer
Bei geschickter Organisation kann das Fließband immer gefüllt bleiben; die Sprünge kosten dann effektiv keine Zeit; CPI <1möglich.
Eigenschaften
- Verzögerung durch Sprung kann vollständig vermieden werden (sofern Vorhersage korrekt), da bereits in IF Entscheidung über nächsten Befehlszähler (PC) getroffen wird.
- Da Entscheidung allein auf Basis des PC getroffen wird, muss überprüft werden, ob Adresse im Puffer (impliziert, dass Sprungbefehl vorliegt)
- Speicherung im Prinzip nur für Sprünge notwendig, die als ausgeführt vorhergesagt werden (not taken = normale sequentielle Dekodierung geht weiter)
- Achtung – bei falscher Vorhersage
- Entsteht ursprüngliche Sprung-Verzögerung, plus
- Aufwand zur Aktualisierung des Vorhersagepuffers
### Integrierte Befehls-Hol-Einheit (IF Unit)
Insbesondere mit Blick auf multiple-issue Prozessoren eigene (autonome) funktionale Einheit für Befehlsholphase
- Führt Befehlscodes in Pipeline ein
- Integrierte Funktionalitäten
- Sprungvorhersage: Wird Teil der Befehlsholphase
- Instruction Pre-fetch: Insbes. um mehrere Befehle pro Takt liefern (und später ausgeben) zu können, läuft Befehlsholen weiterer Dekodierung voraus (= pre-fetch)
- Zugriff auf Befehlsspeicher: Bei mehreren Befehlen pro Takt mehrere Zugriffe erforderlich (bei Cache auf ggfs. mehrere cache lines). Werden hier koordiniert/geplant
- Befehlspuffer: Befehle können hier (lokal im Prozessor!) von Issue-Stufe nach Bedarf abgerufen werden