Der Wikipedia-Artikel über EPIC hat bereits die vielen Gefahren umrissen, die VLIW und EPIC gemeinsam haben.
Wenn jemand den Sinn des Fatalismus in diesem Artikel nicht erkennt, möchte ich Folgendes hervorheben:
Ladeantworten von einer Speicherhierarchie, die CPU-Caches und DRAM enthält, weisen keine deterministische Verzögerung auf.
Mit anderen Worten, jedes Hardware-Design, das die (*) nicht deterministische Latenz des Speicherzugriffs nicht bewältigt, wird zu einem spektakulären Fehler.
(*) Durch "Bewältigen" ist es notwendig, eine einigermaßen gute Ausführungsleistung (mit anderen Worten "kostengünstig") zu erzielen, die es erforderlich macht, die CPU nicht so oft für Dutzende bis Hunderte von Zyklen in den Leerlauf fallen zu lassen.
Beachten Sie, dass die von EPIC eingesetzte Bewältigungsstrategie (im oben verlinkten Wikipedia-Artikel erwähnt) das Problem nicht tatsächlich löst. Es heißt lediglich, dass die Last der Anzeige der Datenabhängigkeit jetzt beim Compiler liegt. Das ist gut; Der Compiler verfügt bereits über diese Informationen, sodass es für den Compiler unkompliziert ist, diese einzuhalten. Das Problem ist, dass die CPU über einen Speicherzugriff noch einige zehn bis hundert Zyklen im Leerlauf läuft. Mit anderen Worten, es wird eine Nebenverantwortung ausgelagert, während die Hauptverantwortung immer noch nicht bewältigt wird.
Die Frage kann wie folgt umformuliert werden: "Bei einer Hardwareplattform, die zum Scheitern verurteilt ist, warum (1) nicht (2) konnten die Compiler-Autoren keine heldenhaften Anstrengungen unternehmen, um sie einzulösen?"
Ich hoffe, dass meine Neuformulierung die Antwort auf diese Frage offensichtlich macht.
Es gibt einen zweiten Aspekt des Scheiterns, der ebenfalls schwerwiegend ist.
Bei den Coping-Strategien (die im selben Artikel erwähnt werden) wird davon ausgegangen, dass softwarebasiertes Prefetching verwendet werden kann, um mindestens einen Teil des Leistungsverlusts aufgrund nicht deterministischer Latenz beim Speicherzugriff wiederherzustellen.
In der Realität ist das Prefetching nur dann rentabel, wenn Sie Streaming-Vorgänge ausführen (indem Sie den Speicher sequentiell oder mit hoher Vorhersagbarkeit lesen).
(Das heißt, wenn Ihr Code häufig auf einige lokalisierte Speicherbereiche zugreift, hilft das Zwischenspeichern.)
Die meisten allgemeinen Softwareprogramme müssen jedoch zahlreiche zufällige Speicherzugriffe durchführen. Wenn wir die folgenden Schritte betrachten:
- Berechnen Sie die Adresse und dann
- Lesen Sie den Wert und dann
- Verwenden Sie es in einigen Berechnungen
Bei den meisten Allzweckprogrammen müssen diese drei Programme schnell hintereinander ausgeführt werden. Mit anderen Worten, es ist nicht immer möglich (im Rahmen der Softwarelogik), die Adresse im Voraus zu berechnen oder genügend Arbeit zu finden, um die Stände zwischen diesen drei Schritten zu füllen.
Um zu erklären, warum es nicht immer möglich ist, genügend Arbeit zu finden, um die Stände zu füllen, kann man sich dies folgendermaßen vorstellen.
- Nehmen wir an, wir müssen 100 Befehle auffüllen, die nicht vom Arbeitsspeicher abhängen, um die Stände effektiv zu verbergen (sodass keine zusätzliche Latenz entsteht).
- Laden Sie nun als Programmierer eine Software Ihrer Wahl in einen Disassembler. Wählen Sie eine Zufallsfunktion für die Analyse.
- Können Sie irgendwo eine Folge von 100 Befehlen (*) identifizieren, die ausschließlich frei von Speicherzugriffen sind?
(*) Wenn wir jemals NOP
nützliche Arbeit leisten könnten ...
Moderne CPUs versuchen, mit dynamischen Informationen mit dem gleichen Problem umzugehen, indem sie gleichzeitig den Fortschritt der einzelnen Befehle verfolgen, während sie durch die Pipelines zirkulieren. Wie ich oben erwähnt habe, ist ein Teil dieser dynamischen Informationen auf nicht deterministische Speicherlatenz zurückzuführen, daher können Compiler keinen Grad an Genauigkeit vorhersagen. Im Allgemeinen sind zum Zeitpunkt der Kompilierung einfach nicht genügend Informationen verfügbar, um Entscheidungen zu treffen, die diese Stände möglicherweise füllen könnten.
Als Antwort auf die Antwort von AProgrammer
Es ist nicht so, dass "Compiler ... das Extrahieren von Parallelität schwierig ist".
Die Neuordnung von Speicher- und Rechenanweisungen durch moderne Compiler ist der Beweis, dass es kein Problem gibt, Operationen zu identifizieren, die unabhängig und somit gleichzeitig ausführbar sind.
Das Hauptproblem besteht darin, dass eine nicht deterministische Speicherlatenz bedeutet, dass jede "Befehlspaarung", die für den VLIW / EPIC-Prozessor codiert wurde, durch den Speicherzugriff blockiert wird.
Die Optimierung von Anweisungen, die nicht blockieren (nur Register, arithmetisch), hilft nicht bei Leistungsproblemen, die durch Anweisungen verursacht werden, die sehr wahrscheinlich blockieren (Speicherzugriff).
Dies ist ein Beispiel für die Nichtanwendung der 80-20-Optimierungsregel: Die Optimierung von bereits schnellen Dingen führt zu keiner wesentlichen Verbesserung der Gesamtleistung, es sei denn, die langsameren werden ebenfalls optimiert.
Antwort von Basile Starynkevitch
Es ist nicht "... (was auch immer) schwierig", sondern EPIC ist für jede Plattform ungeeignet, die mit einer hohen Dynamik der Latenz fertig werden muss.
Wenn ein Prozessor beispielsweise über Folgendes verfügt:
- Kein direkter Speicherzugriff;
- Jeder Speicherzugriff (Lesen oder Schreiben) muss durch DMA-Übertragung geplant werden.
- Jeder Befehl hat die gleiche Ausführungsverzögerung.
- Auftragsausführung;
- Breite / vektorisierte Ausführungseinheiten;
Dann passt VLIW / EPIC gut zusammen.
Wo findet man solche Prozessoren? DSP. Und hier hat sich VLIW etabliert.
Im Nachhinein ist das Scheitern von Itanium (und die anhaltende Ausweitung der Forschungs- und Entwicklungsanstrengungen trotz offensichtlicher Beweise) ein Beispiel für ein organisatorisches Scheitern und verdient eine eingehende Untersuchung.
Zugegeben, die anderen Vorhaben des Anbieters wie Hyperthreading, SIMD usw. scheinen sehr erfolgreich zu sein. Möglicherweise hat die Investition in Itanium die Fähigkeiten der Ingenieure bereichert und es ihnen ermöglicht, die nächste Generation erfolgreicher Technologien zu entwickeln.