<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
	<id>https://wiki-de.moshellshocker.dns64.de/index.php?action=history&amp;feed=atom&amp;title=Explicitly_Parallel_Instruction_Computing</id>
	<title>Explicitly Parallel Instruction Computing - Versionsgeschichte</title>
	<link rel="self" type="application/atom+xml" href="https://wiki-de.moshellshocker.dns64.de/index.php?action=history&amp;feed=atom&amp;title=Explicitly_Parallel_Instruction_Computing"/>
	<link rel="alternate" type="text/html" href="https://wiki-de.moshellshocker.dns64.de/index.php?title=Explicitly_Parallel_Instruction_Computing&amp;action=history"/>
	<updated>2026-05-16T16:45:46Z</updated>
	<subtitle>Versionsgeschichte dieser Seite in Wikipedia (Deutsch) – Lokale Kopie</subtitle>
	<generator>MediaWiki 1.43.8</generator>
	<entry>
		<id>https://wiki-de.moshellshocker.dns64.de/index.php?title=Explicitly_Parallel_Instruction_Computing&amp;diff=188385&amp;oldid=prev</id>
		<title>imported&gt;Pemu am 13. Juni 2019 um 21:36 Uhr</title>
		<link rel="alternate" type="text/html" href="https://wiki-de.moshellshocker.dns64.de/index.php?title=Explicitly_Parallel_Instruction_Computing&amp;diff=188385&amp;oldid=prev"/>
		<updated>2019-06-13T21:36:51Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Neue Seite&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{Belege fehlen|2=Der gesamte Artikel}}&lt;br /&gt;
&lt;br /&gt;
Das &amp;#039;&amp;#039;&amp;#039;Explicitly Parallel Instruction Computing&amp;#039;&amp;#039;&amp;#039; (&amp;#039;&amp;#039;&amp;#039;EPIC&amp;#039;&amp;#039;&amp;#039;) bezeichnet ein [[Programmierparadigma]] einer [[Befehlssatzarchitektur]] ({{EnS|&amp;#039;&amp;#039;Instruction Set Architecture&amp;#039;&amp;#039;}}, kurz &amp;#039;&amp;#039;ISA&amp;#039;&amp;#039;) und der Verarbeitungsstruktur einer Familie von [[Mikroprozessor]]en, z.&amp;amp;nbsp;B. [[Itanium]]. Bei der [[Programmierung]] von EPIC-CPUs wird die Parallelisierung der Befehle eines Instruktionsstromes explizit vorgenommen. Die ISA hat Eigenschaften, die die explizite [[Parallele Programmierung|Parallelisierung]] unterstützen, während eine herkömmliche ISA von einer sequentiellen Abarbeitung der Befehle ausgeht. Ein Programm, das in einer Nicht-EPIC-[[Maschinensprache]] vorliegt, kann auch parallelisiert werden, aber es ist bei der Ausführung eine komplexe [[Logikgatter|Logik]] notwendig, um parallel ausführbare Instruktionen zu identifizieren, da das Befehlsformat keine Aussagen über parallelisierbare Instruktionen macht. Eine EPIC-[[Hauptprozessor|CPU]] arbeitet nach dem Prinzip der [[in-order execution|in-order Execution]], im Gegensatz zur out-of-order execution der [[Superskalarität|superskalaren]] CPUs.&lt;br /&gt;
&lt;br /&gt;
Die Motivation zur Entwicklung eines EPIC-Prozessors ist die Reduktion der [[Logikgatter]] des Prozessors. Der nun frei gewordene Platz kann dazu benutzt werden, weitere funktionale Einheiten (z.&amp;amp;nbsp;B. Rechenwerke) in die CPU zu integrieren, um&lt;br /&gt;
* die Anzahl der parallel ausführbaren Operationen zu erhöhen,&lt;br /&gt;
* größere [[Cache]]s in den Prozessor zu integrieren,&lt;br /&gt;
* den Einfluss des Flaschenhalses &amp;#039;&amp;#039;Hauptspeicher&amp;#039;&amp;#039; zu verringern oder&lt;br /&gt;
* den Stromverbrauch, die Verlustleistung und damit die Wärmeabgabe zu reduzieren.&lt;br /&gt;
&lt;br /&gt;
Die {{lang|en|out-of-order execution}} ist teilweise auch aus dem Zwang zur Rückwärtskompatibilität zu älteren Prozessoren entstanden. Da das Befehlsformat eines älteren Prozessors weiterhin unterstützt werden musste, konnten Verbesserungen zur parallelen Ausführung nur unter der Haube geschehen. Prinzipiell ist es aber möglich, den [[Compiler]] mit dieser Aufgabe zu betrauen, und in den meisten Fällen ist ein Compiler für diese Aufgabe besser geeignet, da er mehr Zeit auf die Optimierung aufwenden kann und Zugriff auf mehr Informationen über den Programmfluss hat.&lt;br /&gt;
&lt;br /&gt;
== Merkmale ==&lt;br /&gt;
Die wichtigsten Merkmale dieser Befehlssatzarchitektur sind:&lt;br /&gt;
* Statische Befehlsgruppierung: Der Compiler legt fest, welche Befehle parallel abgearbeitet werden können. Dadurch wird der Prozessor wesentlich einfacher (Pentium 4 mit 42 Millionen Transistorfunktionen, Itanium mit 25 Millionen Transistorfunktionen).&lt;br /&gt;
* [[Very Long Instruction Word|VLIW]]-Architektur: Der Prozessor erhält {{lang|en|very long instruction words}}, welche mehrere Befehle und die Aussage enthalten, auf welcher Einheit des Prozessors der Befehl auszuführen ist. Bei der IA-64 werden drei Befehle in ein VLIW gepackt.&lt;br /&gt;
* {{lang|en|predication}}: Unter {{lang|en|Predication}} (Aussage, Behauptung) versteht man die bedingte Ausführung von Befehlen ohne Verwendung von Sprungbefehlen.&lt;br /&gt;
* {{lang|en|speculation}}: Damit im Befehlsablauf nicht auf Daten gewartet werden muss, können Daten zu einem frühen Zeitpunkt spekulativ geladen und bearbeitet werden.&lt;br /&gt;
* {{lang|en|Load/Store}}-Architektur: Speicherzugriffe kommen nur bei Load- und Store-Befehlen vor (und natürlich beim [[Von-Neumann-Zyklus#FETCH|Fetch-Zyklus]]).&lt;br /&gt;
* Große Registersätze: Die Load/Store-Architektur benötigt viele Register, um die Anzahl der Speicherzugriffe möglichst klein zu halten.&lt;br /&gt;
* {{lang|en|register stack}} und {{lang|en|register engine}}: Die Register sind so angeordnet, dass innerhalb einer Prozedur die statischen Register und die von der Prozedur verwendeten Register sichtbar sind. Die Register werden beim Prozeduraufruf dynamisch umbenannt. Die {{lang|en|register engine}} sichert die im Moment nicht sichtbaren Register bei Bedarf im Speicher, so dass für ein Anwenderprogramm die Anzahl Register unbeschränkt ist.&lt;br /&gt;
* Leistungsfähiger Befehlssatz: Der Befehlssatz enthält eine große Anzahl leistungsfähiger, für Parallelverarbeitung geeignete Befehle.&lt;br /&gt;
* {{lang|en|little-endian}} und {{lang|en|big-endian}}: In einem Steuerregister des Prozessors kann man definieren, wie der Prozessor die Daten im Speicher ablegen soll.&lt;br /&gt;
&lt;br /&gt;
== Realisierung ==&lt;br /&gt;
Beim EPIC wird dem Prozessor bei der [[Programmierung]] signalisiert, welche [[Instruktion]]en parallel ausführbar sind. Solche parallelisierbaren Instruktionen werden in Gruppen &amp;#039;&amp;#039;({{lang|en|instruction groups}})&amp;#039;&amp;#039; zusammengefasst. Die Instruktionen einer Gruppe können dann prinzipiell in beliebiger Reihenfolge und mit beliebigem Parallelitätsgrad ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
Um die abhängigen Instruktionen voneinander zu trennen, müssen &amp;#039;&amp;#039;{{lang|en|stops}}&amp;#039;&amp;#039; in den [[Befehlstrom]] eingebaut werden. {{lang|en|Stops}} markieren das Ende einer &amp;#039;&amp;#039;{{lang|en|instruction group}}&amp;#039;&amp;#039; und den Beginn einer Neuen. Die eigentlich &amp;#039;&amp;#039;explizite&amp;#039;&amp;#039; Parallelisierungsinformation sind die &amp;#039;&amp;#039;{{lang|en|stops}},&amp;#039;&amp;#039; denn durch sie werden parallelisierbare Instruktionen identifiziert, ohne dass eine Analyse erfolgen muss.&lt;br /&gt;
&lt;br /&gt;
Das Optimierungsziel eines gegebenen EPIC-Programmes ist, die Anzahl der nötigen &amp;#039;&amp;#039;{{lang|en|instruction groups}}&amp;#039;&amp;#039; zu minimieren, also die durchschnittliche Anzahl der Instruktionen pro &amp;#039;&amp;#039;{{lang|en|instruction group}}&amp;#039;&amp;#039; zu erhöhen.&lt;br /&gt;
&lt;br /&gt;
Dabei gibt es Ausnahmen (beim Beispiel IA-64). Zum Beispiel müssen &amp;#039;&amp;#039;{{lang|en|Exceptions}},&amp;#039;&amp;#039; die durch eine frühe Instruktion einer Gruppe ausgelöst werden immer so ausgeführt werden, als ob die späteren Instruktionen einer Gruppe gar nicht ausgeführt worden sind. Beliebige Instruktionen können aber spekulativ bereits ausgeführt worden sein, deren Ergebnis wird beim Auftauchen einer {{lang|en|Exception}} einer früheren Instruktion verworfen. Der Prozessor muss also den Anschein erwecken, dass die Instruktionen einer Gruppe in Reihenfolge ausgeführt wurden. Andere Ausnahmen betreffen spezielle Instruktionen, die per definition am Anfang oder Ende einer &amp;#039;&amp;#039;{{lang|en|instruction group}}&amp;#039;&amp;#039; vorkommen müssen.&lt;br /&gt;
&lt;br /&gt;
== Eigenschaften ==&lt;br /&gt;
Durch das EPIC spart man [[Ressource]]n, die bei Nicht-EPIC-Prozessoren dazu verwendet werden müssen, die Instruktionen während der Ausführung auf die parallel arbeitenden Einheiten des Prozessors aufzuteilen. Diese Einsparungen sind die Motivation für die Erfindung von EPIC. Es können dadurch die Kosten des Chips gesenkt werden, und die Leistungsaufnahme wird verringert. Die Berechnungen, die zur Parallelisierung des Befehlsstromes notwendig sind, werden bei EPIC einmal beim Kompilieren vorgenommen, bei Nicht-EPIC-Prozessoren jedes Mal bei der Ausführung des Codes und mithilfe einer recht großen Anzahl von Logikgattern.&lt;br /&gt;
&lt;br /&gt;
Moderne Compiler nehmen auch für Nicht-EPIC-ISAs-Optimierungen des Befehlsstromes vor (verschieben z.&amp;amp;nbsp;B. unabhängige Instruktionen innerhalb des Stromes), um den Prozessor bei der Parallelisierung zu unterstützen. Bei EPIC-ISA ist diese Unterstützung des Prozessors zwingend, das heißt man kann einen Abhängigkeitsfehler erzeugen, selbst wenn die Instruktionen in der richtigen sequentiellen Reihenfolge stehen.&lt;br /&gt;
&lt;br /&gt;
EPIC ist mit [[Very Long Instruction Word|VLIW]] verwandt, denn VLIW dient auch dem Gruppieren von Instruktionen. Dabei muss beachtet werden, dass die VLIW-Gruppierung in &amp;#039;&amp;#039;{{lang|en|Bundles}}&amp;#039;&amp;#039; und die EPIC-Gruppierung in &amp;#039;&amp;#039;{{lang|en|instruction groups}}&amp;#039;&amp;#039; bei der [[IA-64]] voneinander unabhängig sind, das heißt zu einer &amp;#039;&amp;#039;{{lang|en|instruction group}}&amp;#039;&amp;#039; gehören eine beliebige Anzahl von &amp;#039;&amp;#039;{{lang|en|Bundles}}&amp;#039;&amp;#039; und ein &amp;#039;&amp;#039;{{lang|en|stop}}&amp;#039;&amp;#039; kann auch zwischen Instruktionen eines einzelnen &amp;#039;&amp;#039;{{lang|en|Bundles}}&amp;#039;&amp;#039; eingebracht werden.&lt;br /&gt;
&lt;br /&gt;
ISAs, die EPIC als Architekturmerkmal haben, sind relativ schwer in [[Assemblersprache]] zu programmieren, und Compiler sind ein beträchtliches Maß komplexer, weil die Parallelisierung nun nicht mehr von der Implementierung der ISA, also dem Prozessor, selbst geleistet wird, sondern explizit erfolgen muss. So gibt es Sachverhalte bei der EPIC-Programmierung, die sich mit Nicht-EPIC-Maschinensprache gar nicht ausdrücken lassen, weil dort das Modell eine strikt sequentielle Ausführung ist.&lt;br /&gt;
&lt;br /&gt;
Da die Berechnungen, die für die Parallelisierung notwendig sind, unabhängig von der Ausführung erfolgen, kann mehr Rechenzeit auf ebendiese Aufgabe verwendet werden.&lt;br /&gt;
&lt;br /&gt;
== Statische Befehlsgruppierung ==&lt;br /&gt;
Statische Befehlsgruppierung bedeutet, dass der Compiler für die Gruppierung parallel ablaufender Befehle zuständig ist. Wichtig ist dabei, dass der Compiler für die Architektur des Prozessors optimiert sein muss, um die Eigenschaften des Prozessors auszunutzen.&lt;br /&gt;
Der Compiler gruppiert die Befehle so, dass möglichst viele parallel abgearbeitet werden können. Zusätzlich legt er fest, was für eine Einheit im Prozessor für die Bearbeitung des Befehls benötigt wird und markiert die Befehle entsprechend. Die Befehle werden dem Prozessor in Gruppen übergeben und aufgrund der vom Compiler festgelegten Zuordnung auf Prozessor-Einheiten verteilt und bearbeitet.&lt;br /&gt;
&lt;br /&gt;
== Predication ==&lt;br /&gt;
{{lang|en|Predication}} ist ein Verfahren, Befehle abhängig von einer Bedingung auszuführen, ohne Sprungbefehle einzusetzen. Das Verfahren wird im Folgenden vereinfacht dargestellt: Die Ausführung eines Befehls kann vom Inhalt eines Predicate-Registers abhängen. Im folgenden Beispiel wird der MOV-Befehl nur ausgeführt, wenn das Predicate-Register &amp;lt;code&amp;gt;p1&amp;lt;/code&amp;gt; true ist; ansonsten wirkt er wie ein NOP.&lt;br /&gt;
&lt;br /&gt;
 p1  mov gr8 = gr5  ; lade gr8 mit dem Wert von gr5 falls p1 = true&lt;br /&gt;
                    ; falls p1 = false, wirkt der Befehl wie ein&lt;br /&gt;
                    ; NOP&lt;br /&gt;
&lt;br /&gt;
Die Predicate-Register können mit Compare-Befehlen gesetzt werden. Der folgende Compare-Befehl testet die Register &amp;lt;code&amp;gt;gr10&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;gr11&amp;lt;/code&amp;gt; auf Gleichheit. Das Predicate-Register &amp;lt;code&amp;gt;p1&amp;lt;/code&amp;gt; wird mit Resultat, das Register &amp;lt;code&amp;gt;p2&amp;lt;/code&amp;gt; mit dessen Negation geladen.&lt;br /&gt;
&lt;br /&gt;
     cmp.eq p1,p2 = gr10,gr11  ; teste gr10 mit gr11 auf equal&lt;br /&gt;
                               ; falls equal: p1 true, p2 false&lt;br /&gt;
                               ; falls not equal: p1 false, p2 true&lt;br /&gt;
&lt;br /&gt;
== Speculation ==&lt;br /&gt;
Je schneller die Prozessoren werden, desto größer ist der Verlust, wenn Daten vom Speicher geladen werden müssen und der Prozessor auf diese Daten warten muss. Darum ist das Ziel, Befehle im Programmablauf früher auszuführen, damit die benötigten Daten vorhanden sind, wenn sie benötigt werden.&lt;br /&gt;
&lt;br /&gt;
Im ersten Beispiel muss nach dem Ladebefehl gewartet werden, bis die Daten in &amp;lt;code&amp;gt;gr4&amp;lt;/code&amp;gt; resp. in &amp;lt;code&amp;gt;gr5&amp;lt;/code&amp;gt; geladen sind. Im zweiten Beispiel wurde die Befehlsreihenfolge vertauscht und damit der Abstand zwischen voneinander abhängigen Befehlen vergrößert.&lt;br /&gt;
&lt;br /&gt;
 ld  gr4, x&lt;br /&gt;
 add gr4 = gr4,gr8&lt;br /&gt;
 st  y, gr4&lt;br /&gt;
 ld  gr5, a&lt;br /&gt;
 add gr5 = gr5,gr9&lt;br /&gt;
 st  b, gr5&lt;br /&gt;
&lt;br /&gt;
 ld  gr4, x&lt;br /&gt;
 ld  gr5, a&lt;br /&gt;
 add gr4 = gr4,gr8&lt;br /&gt;
 add gr5 = gr5,gr9&lt;br /&gt;
 st  y, gr4&lt;br /&gt;
 st  b, gr5&lt;br /&gt;
&lt;br /&gt;
In vielen Fällen genügt es aber nicht, einen Befehl um einen oder zwei Befehle vorzuverlegen, da der Unterschied zwischen der Dynamik des Prozessors und dem Speicher zu groß ist. Die Verarbeitung der Daten muss warten, bis die Daten geladen wurden. Das Laden der Daten soll darum so weit vorverlegt werden, dass kein Warten notwendig ist.&lt;br /&gt;
&lt;br /&gt;
Wird ein Ladebefehl wie im untenstehenden Beispiel über eine Verzweigung vorverlegt, so spricht man von einer &amp;#039;&amp;#039;&amp;#039;{{lang|en|Control Speculation}}.&amp;#039;&amp;#039;&amp;#039; Tritt beim Laden ein Fehler auf, so soll dieser nicht behandelt werden, da man ja noch nicht weiß, ob man die Daten überhaupt benötigt. Das Laden erfolgt spekulativ. Bevor die Daten verarbeitet werden, muss aber geprüft werden, ob beim Laden ein Fehler aufgetreten ist und behoben werden muss. Die zweite Art der Spekulation ist die &amp;#039;&amp;#039;&amp;#039;{{lang|en|Data Speculation}}.&amp;#039;&amp;#039;&amp;#039; Die große Anzahl von Arbeitsregistern erlaubt es viele Datenelemente in Registern zu halten. Um zu verhindern, dass beim Laden auf Daten gewartet werden muss, werden die benötigten Daten frühzeitig in Register geladen. Die folgende Befehlsfolge zeigt ein Beispiel für einen normalen Load. Der Befehl &amp;lt;code&amp;gt;add gr5=gr2,gr7&amp;lt;/code&amp;gt; kann erst durchgeführt werden, wenn die Daten aus dem Speicher in &amp;lt;code&amp;gt;gr2&amp;lt;/code&amp;gt; geladen wurden.&lt;br /&gt;
&lt;br /&gt;
 add gr3 = 4,gr0&lt;br /&gt;
 st  [gr32] = gr3&lt;br /&gt;
 ld  gr2 = [gr33]&lt;br /&gt;
 add gr5 = gr2,gr7&lt;br /&gt;
&lt;br /&gt;
Der Prozessor merkt sich darum alle vorzeitig geladenen Adressen im &amp;#039;&amp;#039;&amp;#039;{{lang|en|Advanced Load Address Table}}&amp;#039;&amp;#039;&amp;#039; (ALAT). Im folgenden Beispiel beinhaltet der Load-Befehl eine {{lang|en|Control Speculation}} da eine Verzweigung zwischen Laden und Verarbeitung liegt und eine Data Speculation, da der Store-Befehl mit dem {{lang|en|Pointer}} &amp;lt;code&amp;gt;[gr32]&amp;lt;/code&amp;gt; den geladenen Wert betreffen könnte. Es handelt sich um einen {{lang|en|Speculative Advanced Load}}. Falls beim &amp;lt;code&amp;gt;ld.sa&amp;lt;/code&amp;gt; ein Fehler auftritt, wird kein ALAT-Eintrag erstellt. Falls der Ladevorgang fehlerfrei abläuft, wird ein Eintrag im ALAT gemacht. Falls der Wert an der Adresse &amp;lt;code&amp;gt;[gr33]&amp;lt;/code&amp;gt; verändert wird, so wird der ALAT-Eintrag gelöscht.&lt;br /&gt;
&lt;br /&gt;
              ld.sa gr2 = [gr33]      ; speculative advanced load&lt;br /&gt;
              ...&lt;br /&gt;
              add gr5 = gr2,gr7       ; use data&lt;br /&gt;
              ...&lt;br /&gt;
              ...&lt;br /&gt;
              add gr3 = 4,gr0&lt;br /&gt;
              st [gr32] = gr3&lt;br /&gt;
              ...&lt;br /&gt;
              cmp.eq p3,p4 = gr7,gr8&lt;br /&gt;
          p3  chk.a gr2,recover       ; prüft ALAT&lt;br /&gt;
 back:    p3  add gr9 = 1, gr6&lt;br /&gt;
              ...&lt;br /&gt;
              ...&lt;br /&gt;
 recover:     ld gr2 = [gr33]&lt;br /&gt;
              add gr5 = gr2,gr7&lt;br /&gt;
              br back&lt;br /&gt;
&lt;br /&gt;
Der Wert wird nicht nur vorzeitig gelesen &amp;lt;code&amp;gt;ld.a gr2 = [gr33]&amp;lt;/code&amp;gt;, sondern auch bearbeitet &amp;lt;code&amp;gt;add gr5 = gr2,gr7&amp;lt;/code&amp;gt;. Falls das verwendete Datenelement durch eine Operation verändert wird (z.&amp;amp;nbsp;B. durch &amp;lt;code&amp;gt;st [gr32] = gr3&amp;lt;/code&amp;gt;), so wird dies durch den Check-Befehl festgestellt (&amp;lt;code&amp;gt;chk.a gr2,recover&amp;lt;/code&amp;gt;), da der Eintrag im ALAT fehlt.&lt;br /&gt;
&lt;br /&gt;
{{Navigationsleiste Prozessorarchitektur}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Prozessorarchitektur nach Befehlssatz]]&lt;/div&gt;</summary>
		<author><name>imported&gt;Pemu</name></author>
	</entry>
</feed>