Zum Inhalt springen

„Out-of-order execution“ – Versionsunterschied

aus Wikipedia, der freien Enzyklopädie
[gesichtete Version][gesichtete Version]
Inhalt gelöscht Inhalt hinzugefügt
Die letzte Textänderung von Benediktneumayr wurde verworfen; keine Verbesserung
K "in-of-order execution" entlinkt und gefettet, da es nach Löschung eine Weiterleitung auf diesen Artikel geworden ist
 
(23 dazwischenliegende Versionen von 15 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
{{lang|en|'''Out-of-order execution'''}} ({{enS}} für etwa ''Ausführung in anderer Reihenfolge [als im Programmcode]'') bezeichnet die Möglichkeit, Maschinenbefehle in den Ausführungseinheiten eines (meist [[Superskalarität|superskalaren]]) [[Prozessor]]s in einer anderen Reihenfolge auszuführen, als sie im [[Programmcode]] stehen. Dadurch können die Stufen der [[Pipeline (Prozessor)|Pipeline]] besser ausgelastet werden. Das Gegenteil von {{lang|en|out-of-order execution}} ist {{lang|en|''[[in-order execution]]''}}, bei der die Befehle strikt nach Programmreihenfolge abgearbeitet werden, wie etwa beim [[Von-Neumann-Zyklus]]. Weil das Ergebnis dieser Operationen das gleiche sein muss wie bei Ausführung in Programmreihenfolge, ist OOE-Ausführung nur bei Befehlsfolgen möglich, die nicht voneinander abhängig sind.
{{lang|en|'''Out-of-order execution'''}} ({{enS}} für etwa ''Ausführung in anderer Reihenfolge [als im Programmcode]'') bezeichnet die Möglichkeit, Maschinenbefehle in den Ausführungseinheiten eines (meist [[Superskalarität|superskalaren]]) [[Prozessor]]s in einer anderen Reihenfolge auszuführen als sie im [[Programmcode]] stehen, ohne allerdings das Ergebnis zu verändern. Dadurch können mehr Befehle parallel ausgeführt werden, da die Recheneinheiten des Prozessors besser ausgelastet werden. Das Gegenteil von {{lang|en|''out-of-order execution''}} ist {{lang|en|'''in-order execution'''}}, bei der die Befehle strikt nach Programmreihenfolge abgearbeitet werden, wie etwa beim [[Von-Neumann-Zyklus]]. Weil das Ergebnis das gleiche sein muss wie bei Ausführung in Programmreihenfolge, erhöht ''out-of-order execution'' die Geschwindigkeit nur bei Befehlsfolgen, bei denen ein nachfolgender Befehl nicht vom Ergebnis des vorherigen Befehls abhängt (sondern nur von Befehlen, die „weit genug entfernt“ zuvor ausgeführt wurden).

Die schwerwiegenden Sicherheitslücken [[Spectre (Sicherheitslücke)|Spectre]] und [[Meltdown (Sicherheitslücke)|Meltdown]] können nur gegen Prozessoren eingesetzt werden, die zu {{lang|en|''out-of-order execution''}} fähig sind.


== Motivation ==
== Motivation ==
Ein superskalarer Prozessor hat mehrere Funktionseinheiten, u. a. [[arithmetisch-logische Einheit|arithmetisch-logischen Einheit]] (ALU), der [[Gleitkommaeinheit]] (FPU), Lade-und-Speicher-Einheit und spezielle Vektoreinheiten, mit dem Ziel, möglichst viel [[Befehlsparallelität]] auszunutzen und damit die Ausführungsgeschwindigkeit zu erhöhen. Wegen [[Datenabhängigkeit]]en zwischen den Befehlen ist die parallele Ausführung aber nicht immer möglich. Hinzu kommt die Einschränkung, dass einige Befehle zwar parallel voneinander ausgeführt werden könnten, diese aber nicht direkt hintereinander im Programmcode stehen, so dass ein Prozessor ohne OOE diese nicht parallel ausführen kann, weil er sich streng an die Ausführungsreihenfolge hält, die im Programm vorgegeben ist.
Ein Prozessor hat mehrere Funktionseinheiten (bei [[x86-Prozessor]]en erstmals seit dem [[Intel Pentium#Die Pentium-1-Familie|Intel Pentium P54]]), u. a. [[arithmetisch-logische Einheit]] (ALU), [[Gleitkommaeinheit]] (FPU), Lade-und-Speicher-Einheit und spezielle (Gleitkomma-)Vektoreinheiten. Bei superskalaren Prozessoren ermöglichen sie, [[Befehlsparallelität]] auszunutzen und damit die Ausführungsgeschwindigkeit zu erhöhen: Während ein vorhergehender Befehl eine Funktionseinheit noch belegt, stehen die freien Funktionseinheiten bereits dem nachfolgenden Befehl zur Verfügung. Wegen [[Datenabhängigkeit]]en zwischen den Befehlen, oder wenn sie dieselbe Funktionseinheit benötigen, ist die parallele Ausführung aber nicht immer möglich. Oft könnten Befehle zwar parallel ausgeführt werden, stehen aber nicht direkt hintereinander im Programmcode; ein Prozessor ohne {{lang|en|''out-of-order execution''}} hält sich streng an die Ausführungsreihenfolge, die im Programm vorgegeben ist, und kann sie dann nicht parallel ausführen.


Eine Umordnung der Befehle im Programm per Hand oder durch den Compiler kann auf einem In-Order-Prozessor zwar zu besseren Ergebnissen führen, ist aber im Allgemeinen nicht optimal, weil die Ausführungszeit von Speicherzugriffen nicht vorhersagbar ist. Diese hängt davon ab, ob der [[Cache]] die geforderten Daten oder der Übersetzungspuffer ([[Translation Lookaside Buffer|TLB]]) die geforderte Seitenübersetzung liefern kann. Das kann man meist nicht oder nur schwer zur [[Kompilierzeit]] voraussagen.
Eine Umordnung der Befehle im Programm per Hand oder durch den Compiler kann auf einem in-order-Prozessor zwar zu besseren Ergebnissen führen, ist aber im Allgemeinen nicht optimal, weil Einflüsse während der Laufzeit nicht oder kaum berücksichtigt werden können. Insbesondere ist die Ausführungszeit von Speicherzugriffen nicht vorhersagbar. Diese hängt davon ab, ob der [[Cache]] die geforderten Daten oder der Übersetzungspuffer ([[Translation Lookaside Buffer|TLB]]) die geforderte Seitenübersetzung liefern kann. Das kann man meist nicht oder nur schwer zur [[Kompilierzeit]] voraussagen.


Ein dynamisches Verfahren wie die OOE-Ausführung kann zur Ausführungszeit entsprechend reagieren und so mehr Befehle parallel ausführen und damit die Bearbeitung beschleunigen.
Ein dynamisches Verfahren zum Umordnen der Befehle, wie die out-of-order-execution-Ausführung, kann zur Ausführungszeit entsprechend reagieren und so mehr Befehle parallel ausführen und damit die Bearbeitung beschleunigen.


== Funktionsprinzip ==
== Funktionsprinzip ==
Zeile 13: Zeile 15:
In früheren Prozessoren wurden die einzelnen Befehle nacheinander abgearbeitet, wobei jeder Befehl nach einer festen Folge aus Teilschritten ({{lang|en|''in-order execution''}}) ausgeführt wurde, vgl. u. a. [[Von-Neumann-Zyklus]]. Diese Teilschritte sind:
In früheren Prozessoren wurden die einzelnen Befehle nacheinander abgearbeitet, wobei jeder Befehl nach einer festen Folge aus Teilschritten ({{lang|en|''in-order execution''}}) ausgeführt wurde, vgl. u. a. [[Von-Neumann-Zyklus]]. Diese Teilschritte sind:
# Befehl laden ({{lang|en|''instruction fetch''}})
# Befehl laden ({{lang|en|''instruction fetch''}})
# Wenn die Operanden verfügbar sind (zum Beispiel in Registern) wird der Befehl an die passende Funktionseinheit zur Ausführung übergeben. Wenn ein oder mehr Operanden im aktuellen Befehlszyklus nicht verfügbar sind (meist weil sie noch aus dem Speicher geladen werden müssen), wartet der Prozessor, bis diese geladen sind.
# Wenn die Operanden verfügbar sind (zum Beispiel in Registern), wird der Befehl an die passende Funktionseinheit zur Ausführung übergeben. Wenn ein oder mehr Operanden im aktuellen Befehlszyklus nicht verfügbar sind (meist weil sie noch aus dem Speicher geladen werden müssen), wartet der Prozessor, bis diese geladen sind.
# Der Befehl wird durch die passende Funktionseinheit ausgeführt.
# Der Befehl wird durch die passende Funktionseinheit ausgeführt.
# Die Funktionseinheit schreibt das Ergebnis in ein Register.
# Die Funktionseinheit schreibt das Ergebnis in ein Register.
Zeile 28: Zeile 30:
Implementiert wird meist [[Scoreboarding]] oder der [[Tomasulo-Algorithmus]].
Implementiert wird meist [[Scoreboarding]] oder der [[Tomasulo-Algorithmus]].
Beim Scoreboarding werden belegte Ressourcen auf einem zentralen [[Scoreboard]] markiert und nach ihrer Verwendung wieder freigegeben.
Beim Scoreboarding werden belegte Ressourcen auf einem zentralen [[Scoreboard]] markiert und nach ihrer Verwendung wieder freigegeben.
Der Tomasulo-Algorithmus implementiert [[dynamisches Scheduling]]. So werden mehrere Befehle gleichzeitig ausgeführt, solange die Operanden unabhängig sind. Verhindert werden Read-After-Write-[[Glitch (Elektronik)|Hazards]], indem der Befehl verzögert wird, und Write-After-Read-Hazards, indem ein neuer Wert zwischengespeichert wird. Zur Reduzierung der Datenabhängigkeiten wird zusätzlich [[Registerumbenennung]] verwendet.
Der Tomasulo-Algorithmus implementiert [[dynamisches Scheduling]]. So werden mehrere Befehle gleichzeitig ausgeführt, solange die Operanden unabhängig sind. Verhindert werden ''read-after-write-[[Pipeline-Hazard|hazards]]'', indem der Befehl verzögert wird, und ''write-after-read-hazards'', indem ein neuer Wert zwischengespeichert wird. Zur Reduzierung der Datenabhängigkeiten wird zusätzlich [[Registerumbenennung]] verwendet.


Fast alle modernen [[X86-Prozessor|x86]]-Prozessoren ab dem [[Intel Pentium Pro]] bzw. [[AMD K5]] können Befehle {{lang|en|out-of-order}} ausführen. Bekannte Ausnahmen sind die [[IDT WinChip]] und [[VIA C3]]/[[VIA C7]] Serien, die von [[Centaur Technology]] entwickelt wurden, und die [[Intel Atom|Intel-Atom]]-Serie bis einschließlich Cedar Trail.
Der erste [[X86-Prozessor|x86]]-Prozessor mit {{lang|en|''out-of-order execution''}} war der [[NexGen#Nx686|Nx686]]. Fast alle modernen [[X86-Prozessor|x86]]-Prozessoren ab dem [[Intel Pentium Pro]] bzw. [[AMD K5]] können Befehle {{lang|en|''out-of-order''}} ausführen. Bekannte Ausnahmen sind die [[IDT WinChip|IDT-WinChip]]-, [[VIA C3|VIA-C3]]- und [[VIA C7|-C7]]-Serien, die von [[Centaur Technology]] entwickelt wurden, und die [[Intel Atom|Intel-Atom]]-Serie bis einschließlich Cedar Trail.


== Siehe auch ==
== Siehe auch ==

Aktuelle Version vom 8. April 2025, 19:04 Uhr

Out-of-order execution (englisch für etwa Ausführung in anderer Reihenfolge [als im Programmcode]) bezeichnet die Möglichkeit, Maschinenbefehle in den Ausführungseinheiten eines (meist superskalaren) Prozessors in einer anderen Reihenfolge auszuführen als sie im Programmcode stehen, ohne allerdings das Ergebnis zu verändern. Dadurch können mehr Befehle parallel ausgeführt werden, da die Recheneinheiten des Prozessors besser ausgelastet werden. Das Gegenteil von out-of-order execution ist in-order execution, bei der die Befehle strikt nach Programmreihenfolge abgearbeitet werden, wie etwa beim Von-Neumann-Zyklus. Weil das Ergebnis das gleiche sein muss wie bei Ausführung in Programmreihenfolge, erhöht out-of-order execution die Geschwindigkeit nur bei Befehlsfolgen, bei denen ein nachfolgender Befehl nicht vom Ergebnis des vorherigen Befehls abhängt (sondern nur von Befehlen, die „weit genug entfernt“ zuvor ausgeführt wurden).

Die schwerwiegenden Sicherheitslücken Spectre und Meltdown können nur gegen Prozessoren eingesetzt werden, die zu out-of-order execution fähig sind.

Ein Prozessor hat mehrere Funktionseinheiten (bei x86-Prozessoren erstmals seit dem Intel Pentium P54), u. a. arithmetisch-logische Einheit (ALU), Gleitkommaeinheit (FPU), Lade-und-Speicher-Einheit und spezielle (Gleitkomma-)Vektoreinheiten. Bei superskalaren Prozessoren ermöglichen sie, Befehlsparallelität auszunutzen und damit die Ausführungsgeschwindigkeit zu erhöhen: Während ein vorhergehender Befehl eine Funktionseinheit noch belegt, stehen die freien Funktionseinheiten bereits dem nachfolgenden Befehl zur Verfügung. Wegen Datenabhängigkeiten zwischen den Befehlen, oder wenn sie dieselbe Funktionseinheit benötigen, ist die parallele Ausführung aber nicht immer möglich. Oft könnten Befehle zwar parallel ausgeführt werden, stehen aber nicht direkt hintereinander im Programmcode; ein Prozessor ohne out-of-order execution hält sich streng an die Ausführungsreihenfolge, die im Programm vorgegeben ist, und kann sie dann nicht parallel ausführen.

Eine Umordnung der Befehle im Programm per Hand oder durch den Compiler kann auf einem in-order-Prozessor zwar zu besseren Ergebnissen führen, ist aber im Allgemeinen nicht optimal, weil Einflüsse während der Laufzeit nicht oder kaum berücksichtigt werden können. Insbesondere ist die Ausführungszeit von Speicherzugriffen nicht vorhersagbar. Diese hängt davon ab, ob der Cache die geforderten Daten oder der Übersetzungspuffer (TLB) die geforderte Seitenübersetzung liefern kann. Das kann man meist nicht oder nur schwer zur Kompilierzeit voraussagen.

Ein dynamisches Verfahren zum Umordnen der Befehle, wie die out-of-order-execution-Ausführung, kann zur Ausführungszeit entsprechend reagieren und so mehr Befehle parallel ausführen und damit die Bearbeitung beschleunigen.

Funktionsprinzip

[Bearbeiten | Quelltext bearbeiten]
Grundprinzip der ungeordneten Befehlsausführung

In früheren Prozessoren wurden die einzelnen Befehle nacheinander abgearbeitet, wobei jeder Befehl nach einer festen Folge aus Teilschritten (in-order execution) ausgeführt wurde, vgl. u. a. Von-Neumann-Zyklus. Diese Teilschritte sind:

  1. Befehl laden (instruction fetch)
  2. Wenn die Operanden verfügbar sind (zum Beispiel in Registern), wird der Befehl an die passende Funktionseinheit zur Ausführung übergeben. Wenn ein oder mehr Operanden im aktuellen Befehlszyklus nicht verfügbar sind (meist weil sie noch aus dem Speicher geladen werden müssen), wartet der Prozessor, bis diese geladen sind.
  3. Der Befehl wird durch die passende Funktionseinheit ausgeführt.
  4. Die Funktionseinheit schreibt das Ergebnis in ein Register.

Das neue Konzept (out-of-order execution) bearbeitet die Befehle in der folgenden Reihenfolge:

  1. Befehl laden (instruction fetch).
  2. Befehl in eine Warteschlange (instruction buffer) eintragen.
  3. Der Befehl wartet im instruction buffer, bis seine Operanden geladen sind. Danach darf der Befehl die Warteschlange verlassen, oft vor früher eingetragenen, älteren Befehlen.
  4. Der Befehl wird an die passende Ausführungseinheit übergeben und dort ausgeführt.
  5. Das Ergebnis wird in eine Warteschlange der Ergebnisse eingetragen. (register retirement file/buffer)
  6. Erst nachdem die Ergebnisse aller früheren, älteren Befehle in die Register geschrieben wurden, wird das Ergebnis des aktuellen Befehls ebenfalls in die Register geschrieben.

Implementierung

[Bearbeiten | Quelltext bearbeiten]

Implementiert wird meist Scoreboarding oder der Tomasulo-Algorithmus. Beim Scoreboarding werden belegte Ressourcen auf einem zentralen Scoreboard markiert und nach ihrer Verwendung wieder freigegeben. Der Tomasulo-Algorithmus implementiert dynamisches Scheduling. So werden mehrere Befehle gleichzeitig ausgeführt, solange die Operanden unabhängig sind. Verhindert werden read-after-write-hazards, indem der Befehl verzögert wird, und write-after-read-hazards, indem ein neuer Wert zwischengespeichert wird. Zur Reduzierung der Datenabhängigkeiten wird zusätzlich Registerumbenennung verwendet.

Der erste x86-Prozessor mit out-of-order execution war der Nx686. Fast alle modernen x86-Prozessoren ab dem Intel Pentium Pro bzw. AMD K5 können Befehle out-of-order ausführen. Bekannte Ausnahmen sind die IDT-WinChip-, VIA-C3- und -C7-Serien, die von Centaur Technology entwickelt wurden, und die Intel-Atom-Serie bis einschließlich Cedar Trail.

  • Oberschelp, Vossen: Rechneraufbau und Rechnerstrukturen. 9. Auflage. Oldenbourg, 2003, ISBN 3-486-27206-3.