CPU-Grundlagen: VLIW-Architekturen & Intels Itanium

24.06.2004 von PROF. DR. CHRISTIAN SIEMERS 
VLIW-Prozessoren laden und verarbeiten mehrere Instruktionen gleichzeitig. Prominentester Vertreter ist Intels Itanium, dessen Architektur etliche Neuerungen bei der Hardware wie auch bei den Compilern erfordert.

Very-Long-Instruction-Word- (VLIW-)Architekturen besitzen ein breites Befehlswort, das in Felder eingeteilt ist. Diese Felder steuern mehrere Funktionseinheiten im Prozessor unabhängig voneinander. Ein zentrales Leitwerk holt in jedem Takt einen breiten Befehl aus dem Befehlsspeicher und stößt die darin kodierten Operationen in parallelen Funktionseinheiten zur Ausführung an.

Die einzelnen Funktionseinheiten sind über eine zentrale Registerdatei miteinander verbunden. Jede Funktionseinheit hat zwei Leseeingänge und einen Schreibausgang. Ein Datenspeicher versorgt die Registerdatei mit Inhalten, was bei einer großen Anzahl von Registern eine hohe Speicherbandbreite erfordert.

Die Architekturbeschreibung zeigt die wesentlichen Mechanismen der VLIW-Architekturen: Die Teilbefehle sind ähnlich zu denen der RISC-Architektur aufgebaut, die Drei-Adressen-Registerstruktur der Befehle ist direkt nachzuvollziehen. Das Befehlsfeld kann auch Direktdaten (Programmkonstanten) enthalten. Die einzigen Operationen, die auf den Speicher zugreifen können, sind Load- und Store-Operationen.

Diesen Artikel und eine ganze Reihe weiterer Grundlagenthemen zu Prozessoren finden Sie auch in unserem tecCHANNEL-Compact "Prozessor-Technologie". Diese Ausgabe können Sie für 9,90 Euro in unserm Online-Shop versandkostenfrei bestellen. Ausführliche Infos zum Inhalt des tecCHANNEL-Compact "Prozessor-Technologie" finden Sie hier.

Allgemeines zu VLIW-Architekturen

Die Kontrollflussstrategie entspricht ebenfalls der der RISC-Prozessoren: Änderungen des sequenziellen Programmflusses erfolgen durch Sprünge, Verzweigungen und Unterprogrammaufrufe. Hierdurch entsteht die gleiche Systematik wie bei superskalaren Prozessoren: Flags (1-Bit-Register) beeinflussen die Programmflusskontrolle in ihrer expliziten Ausführung. Diese Flags erhalten erst zur Laufzeit des Programms ihren Wahrheitswert durch Vergleichs- und eventuell andere Operationen.

Im Unterschied zu superskalaren Prozessoren erfolgt aber die Steuerung des (sequenziellen) Programmflusses, also das Instruction Scheduling, im Wesentlichen schon zur Compile-Zeit. In jedem (Lang-)Befehl sind die Operationen kodiert, die der Prozessor dann in einem Taktzyklus auf den voneinander unabhängigen Funktionseinheiten ausführt.

Der Compiler für die VLIW-Architektur hat also die Aufgabe, aus einem zunächst sequenziellen Strom von Operationen mit Hilfe einer Analyse des Steuer- und des Datenflusses die voneinander unabhängigen Operationen herauszufinden. Die als gleichzeitig innerhalb eines Takts ausführbaren Einzelbefehle packt er anschließend in die breiten Befehlswörter.

Zusätzlich zur Kenntnis der Abhängigkeiten ist es hierfür auch erforderlich, dass der Compiler die Ausführungszeit eines jeden Befehls exakt kennt. Dass das Instruction Scheduling nicht schon komplett zur Compile-Zeit erfolgt, sondern zu einem geringeren Anteil auch noch zur Laufzeit möglich ist, bedeutet keine wirkliche Einschränkung.

Die Steuerung zur Laufzeit nimmt unter Umständen zusätzliche Optimierungen vor. So stehen ihr Informationen zur Verfügung, die der Compiler noch nicht haben kann, wie beispielsweise spekulative Schlussfolgerungen aus dem bisherigen Programmverlauf.

Eine Erhöhung der Instruktionsparallelität erreicht man durch die bedingte Ausführung von Instruktionen: Der Compiler stattet wie im Fall der superskalaren CPU möglichst viele Befehle mit einem zuordnungsfähigen Bedingungs-Flag aus. Nur bei Erfüllung der Bedingung liefert diese Instruktion dann ein Ergebnis.

Eine Operation, die bedingt kodiert ist und deren Bedingung nicht zutrifft, verhält sich wie ein NOP-Befehl (No Operation). Die Zeit zur Auswertung des Flags trägt zur Gesamtausführungszeit des Befehls bei. Allerdings streben die Entwickler einer CPU an, auch bedingte Befehle innerhalb eines Takts ablaufen zu lassen.

Die Herkunft der Bedingungs-Flags kann dem normalen CPU-Modell entsprechen (also Zero, Carry und so weiter), oder der Prozessor stellt dafür neue, zusätzliche Flags zur Verfügung.

Compilerstrategien

Die praktisch erreichbare Performance einer VLIW-Architektur hängt wesentlich von der Parallelisierungsstrategie des Compilers ab. Schon für eine superskalare CPU muss der Compiler viel Arbeit investieren, um die Parallelisierbarkeit des Programms zu erhöhen. Ein VLIW-Compiler muss die Befehle zudem noch sortieren und zusammenfassen.

Dafür kommt häufig der Percolation Scheduling Algorithmus nach A. Nicolau (1985) zum Einsatz. Nach einer sorgfältigen Analyse optimiert der Compiler den Programmcode mit den von superskalaren Prozessoren bekannten Methoden wie dem Ersatz der Branch-Befehle durch die bedingte Ausführung von Befehlen und dem Loop Unrolling.

Anschließend parallelisiert er den Code und setzt die langen Befehlswörter zusammen. Hierzu wählt er einen parallelen Flussgraphen, dessen Knoten die gleichzeitig in einem Taktzyklus ausführbaren Operationen enthält und dessen (gerichtete) Kanten den Steuerfluss im Programm anzeigen.

Dafür existieren im Wesentlichen drei Kerntransformationen:

Der Compiler muss die Kerntransformationen entsprechend wählen, um ein Optimum an Performance zu erreichen. Die passende Strategie kann sich dabei sogar von Applikation zu Applikation unterscheiden.

VLIW-Zusammenfassung

Die VLIW-Architekturen zeichnen sich im Wesentlichen dadurch aus, dass der Compiler die Parallelität der Befehlsausführung bereits zur Übersetzungszeit festlegt. Eine superskalare CPU hingegen führt die Parallelisierung zur Laufzeit aus.

Performance-Gewinne um Größenordnungen sind hierdurch kaum vorstellbar. Die Analyse des Objektcodes kann zwar wesentlich detaillierter und vor allem in einem größeren Kontext erfolgen. Prinzipiell gibt es jedoch keine Unterschiede zwischen superskalarer CPU mit dynamischem Scheduling und VLIW-Architektur mit der Möglichkeit zum statischen Scheduling durch den Compiler.

Der wesentliche Vorteil einer VLIW- gegenüber einer superskalaren Architektur besteht darin, dass ein komplexer Teil der Hardware wegfallen kann. Das Data Forwarding innerhalb der VLIW-CPU muss aber in jedem Fall erhalten bleiben: Ein Fortfall ergäbe zwar drastische Einsparungen in der Hardware, da das Data Forwarding bis zum vierfachen Platz einer ALU einnehmen kann. Die Einschränkungen für den Compiler wären allerdings sehr drastisch, da er alle Datenabhängigkeiten über viele Takte beachten müsste.

Die tatsächlich einzusparende Hardware betrifft vor allem das Register Renaming, das Instruction Dispatching und das Instruction Issueing. Diese Einheiten können ganz oder in weiten Teilen entfallen, da der VLIW-Compiler deren Arbeit übernimmt.

Der wesentliche Nachteil von VLIW-Programmen liegt in ihrer Codegröße: Der zentrale Ansatz der VLIW-Architekturen besteht ja darin, einen großen Block mit mehreren Instruktionen als eine atomare Einheit im Code anzusehen. Kann der Compiler nicht alle Felder darin mit unabhängigen Instruktionen füllen, besetzt er die freien Stellen mit NOP-Befehlen. Diese blähen VLIW-Programme stark auf.

Abhilfe hierfür schafft eine Kodierung, die keine feste Befehlslänge und keine festgelegten Plätze für bestimmte Instruktionsgruppen nutzt. Diese so genannte Configurable-Long-Instruction-Word-Architektur (CLIW) markiert das jeweilige Ende des Codes durch ein ansonsten nicht genutztes Bitmuster.

Intel Itanium-Architektur

Eine herausragende Architektur, die das VLIW-Prinzip implementiert, ist die Itanium-Architektur (IA) von Intel und HP (früher Intel Architecture 64 oder auch IA-64). Die grundlegenden Arbeiten starteten 1994 [16]. Dabei haben die Entwickler für diese Architektur eigens ein neues Prinzip kreiert und EPIC (Explicitly Parallel Instruction Computing) getauft [16, 17, 22, 23]. Mittlerweile existiert bereits die dritte Architekturstufe mit dem Namen Itanium 2 [24].

Die folgenden Seiten erläutert zunächst die EPIC-Philosophie. Im Anschluss daran behandeln sie die Mikroarchitektur, den Aufbau des Prozessorkerns in seiner ersten Implementierung (Itanium) und Fragen zur Software und zum Programmablauf.

Explicitly Parallel Instruction Computing

Intel bezeichnet EPIC als neue Philosophie vergleichbar mit RISC und sieht darin eine Antwort auf den langjährigen Zwist zwischen RISC (Reduced Instruction Set Computing) und CISC (Complex Instruction Set Computing). In der Tat besteht die Hauptaufgabe moderner xx-skalarer Prozessoren (superskalar oder multiskalar) aus dem Verteilen der anstehenden Aufgaben auf viele parallel arbeitende Einheiten. Bei den dynamischen Varianten versucht eine komplexe Hardware jedes Mal aufs Neue, die aufeinander folgenden Befehle zu analysieren und mit allen Tricks eine möglichst parallele Ausführung herbeizuführen. Diese Aufgabe wird in EPIC auf den Compiler abgebildet und ist damit programmstatisch. Das entspricht im Grundsatz der klassischen VLIW-Ideologie. Worin unterscheiden sich EPIC und einfaches VLIW? Intel gibt drei Haupteigenschaften zu EPIC an. Die EPIC-Architektur bietet

Mit anderen Worten: In EPIC sind Compiler und Hardware stark aufeinander abgestimmt, sonst bietet sie keine bahnbrechenden Neuerungen. Im Detail gibt es aber Neuheiten und nützliche Features, die im Folgenden erläutert werden.

Itanium Befehlsformat

Die Itanium-Architektur speichert die (einfachen) Instruktionen in 41 Bits. Zur Kodierung teilt sie alle Befehle in Klassen ein, für deren Ausführung verschiedene Hardware-Einheiten bereitstehen. Dabei gelten folgende Zusammenhänge:

IA Instruktions- und Ausführungstypen

Instruction Type

Description

Execution Unit Type

A

Integer ALU

I- or M-Unit

I

Non-ALU Integer

I-Unit

M

Memory

M-Unit

F

Floating Point

F-Unit

B

Branch

B-Unit

L + X

Extended

I-Unit

Die Kodierung erfolgt für die einzelnen Instruktionstypen unterschiedlich, da Intel zum Teil sich widersprechende Eigenschaften realisieren musste. Allerdings hat man versucht, die Kodierung möglichst einheitlich zu gestalten, was dem RISC-Prinzip entspricht: Jede Instruktion passt komplett mit allen Daten in einen Instruktions-Slot mit 41 Bit Länge.

Das obenstehende Bild zeigt jedoch eine Ausnahme: Die Kodierung von 64-Bit-Immediate-Daten. Hier existiert die gleiche Problematik wie bei RISC-Architekturen, da die Kodierung der Daten nicht in das Befehlsgrundformat passt. Die Lösung bei der IA heißt Extended Format (X) und bedeutet, dass der Compiler die 64-Bit-Konstante auf zwei Instruktionen verteilt. Das Kodierungsformat "0110" am Anfang sowie das Bit 20 (extension bit) auf 1 zeigen dem Prozessor die Aufteilung an.

Allgemeines Instruktionsformat

Das folgende Bild zeigt ein Beispiel für ein allgemeines Instruktionsformat: Je sieben Bits für die beiden Source-Register und das Zielregister (somit je 128 adressierbare Register), 14 Bits für den Operationscode und 6 Bits für die Bedingungen (Predicate-Flags) stehen zur Verfügung.

Die Verknüpfung mit Predicate Flags setzt die Itanium-Architektur nahezu durchgängig um. Nur sehr wenige Instruktionen sind ausschließlich unbedingt ausführbar. Der Compiler kann 64 Predicate Flags (P0 bis P63) einsetzen. Die Nummer des Flags, mit dem ein Befehl verknüpft ist, ist im Befehlsformat im 6 Bit großen Predicate-Feld angegeben. Die Verknüpfung mit P0, das fest auf "1" steht, ergibt eine unbedingte Ausführung.

Drei solcher Instruktionen fasst die Itanium-Architektur zu einem Instruktions-Bundle zusammen (Bild Teil b). Diese Gruppierung unterliegt strikten Regeln, es sind keineswegs alle Kombinationen erlaubt:

Im Assembler ist es möglich, dass der Software-Entwickler die Instruktionsbündel selbst definiert und zusammenfasst. Dies ist mit der Gefahr einer Datenabhängigkeit verbunden [17]. In diesem Fall löst der Prozessor eine Ausnahme aus, da für ihn das Programm nicht mehr korrekt ausführbar ist.

Registersatz

Im vorangegangenen Text wurde schon angedeutet, dass die Itanium-Architektur einen erheblichen Satz von Registern zur Verfügung stellt. Das folgende Bild zeigt den Aufbau und die Anzahl für die Datenregister.

Die Itanium-Architektur bietet mit ihren 128 Allzweckregistern (General Purpose Register r0...r127 ) 16-mal mehr Register als die IA-32 an, die zudem alle 65-bittig sind. Das neben den 64 Datenbits vorhandene 65. Bit trägt den Namen Not a Thing (NaT). Die 128 Datenregister (von denen das erste, r0, dauerhaft Null enthält) teilen sich in zwei Bereiche: Die ersten 32 sind klassische statische Register. Die restlichen "stacked" Register verwaltet die CPU dynamisch.

Dies kann man sich ähnlich wie in einem Hochsprachenprogramm mit globalen und lokalen Variablen vorstellen. Der Compiler gibt beim Anlegen einer Unterroutine an, wie viele Register er für Ein- und Ausgabe und lokale Berechnungen benötigt. Das vermeidet einen Großteil der langwierigen Push- und Pop-Operationen, wie sie bei Unterprogrammaufrufen fast aller Prozessorarchitekturen (insbesondere bei IA-32, der Standard-Intel-Architektur) an der Tagesordnung sind.

Der IA-Prozessor kann dabei immerhin aus seinem Pool von 96 Registern schöpfen. Wenn die Software damit nicht auskommt, lagert eine so genannte Register Stack Engine (RSE) "ältere" Register aus höher liegenden Prozeduren in den Speicher (beziehungsweise Cache) aus. Den eigentlichen Körper einer Subroutine kann man dadurch übersichtlich mit den Registernamen in0, in1 ... loc0, loc1 ... out0, out1 gestalten, die auf die Register r32...r127 gemappt sind. Dieses Register-Mapping hat allerdings den Nachteil einer zusätzlichen Pipeline-Stufe für das Renaming.

Registerrotation

Lokale Register bieten zusätzlich die Möglichkeit einer Parallelverarbeitung durch Registerrotation. Dessen statisches Pendant ist das so genannte Loop Unrolling: Es fasst mehrere Schleifendurchgänge zu einem einzigen zusammen, benennt die Register entsprechend um (Compiletime Register Renaming) und sortiert die Instruktionen neu. Durch das Loop Unrolling vermeidet man Verzweigungen und erhöht die Parallelisierbarkeit. Im günstigen Fall können dadurch auch Instruktionen wie etwa in jedem Schleifendurchlauf vorkommende Load-Befehle ganz entfallen.

Im dynamischen Fall kann die CPU mehrere Schleifendurchläufe gleichzeitig starten, sofern entsprechende Ressourcen frei und die Daten voneinander unabhängig sind. Dieser Ansatz der Itanium-Architektur entspricht in etwa dem so genannten Microthreading. Es versucht, die Ausführung eines einzelnen Programms (oder besser: Threads) dynamisch zu parallelisieren, und zwar nicht nur auf Instruktionsebene. Bei der Itanium-Architektur liegt eine einfache Version von Microthreading vor. Wenn in kleinen Schleifen die zu berechnenden Daten voneinander unabhängig sind, kann die IA schon mit der Berechnung der nächsten Schleifeniterationen beginnen, während die erste noch im Gange ist. Sie mappt dazu bei jedem Durchlauf dynamisch die beteiligten Register auf andere physische Register. Allerdings muss dazu bereits der Compiler entsprechende Anweisungen in den Code einbauen.

Statisches und dynamisches Loop Unrolling haben jeweils Vor- und Nachteile: Bei statischem Loop Unrolling wächst die Codegröße normalerweise stark an, was insbesondere für die Cache-Hits des L1-Cache schädlich ist. Allerdings verspricht die statische Optimierung des Instruction Scheduling mehr Optimierungsmöglichkeiten als im dynamischen Fall. Das dynamische Loop Unrolling mit Registerrotation bietet dafür insbesondere beim Multithreading und bei Microthreads erhebliche Vorteile.

Gleitkommaregister

Bei Gleitkommaanwendungen bietet die Itanium-Architektur mit insgesamt 128 entsprechenden Registern ebenfalls genügend Kapazität. Alle Register sind nach dem Drei-Adressen-Schema ansprechbar - sieht man einmal von den ersten beiden ab, die fest auf den Konstanten 0 beziehungsweise 1 stehen. Genauso wie das Integer-Pendant teilen sich die FP-Register in 32 statische und 96 dynamische auf. Sie bieten damit die gleichen Vorteile und Optimierungsmöglichkeiten wie bei den Integerregistern beschrieben.

Die FP-Register sind mit 82 Bit etwas breiter als bei der IA-32 (80 Bit). Da sich 82 Bit für einen 64-Bit-Prozessor relativ schlecht abspeichern lassen, hat Intel dafür eine 128-Bit-Speicherung definiert, die reichlich Reserven für die Zukunft bietet. Zudem verfügt die IA über das Double-Precision-Format (DP) für Gleitkommazahlen. Dessen 64 Bit passen bestens zur natürlichen Datengröße des Itaniums, so dass die CPU pro Takt gleich zwei DP-Werte laden oder speichern kann.

Die höhere 82-Bit-Genauigkeit hat einen praktischen Hintergrund: Division, Wurzel, Sinus, Tangens, Exponentialfunktion oder Logarithmus sind in der Itanium- Architektur nicht als FP-Befehl vorhanden. All diese Funktionen muss der Compiler via Software-Bibliothek bereitstellen. Diese Algorithmen erfordern intern für ihre Zwischenwerte die beiden zusätzlichen Bits, damit das Endergebnis im Rahmen der von der IEEE geforderten Genauigkeit bleibt.

FP-Befehle in Software

Das Fehlen vor allem der elementaren Funktionen Division und Wurzelziehen sieht zunächst nach einem Nachteil aus. Das ist aber mitnichten der Fall. De facto arbeiten nämlich übliche Gleitkommaeinheiten bei diesen Funktionen auch nur mit einem Software-Algorithmus. Dieser ist jedoch im Unterschied zur Itanium- Architektur fest im Mikrocode verdrahtet. Dadurch führt der Prozessor die Berechnungen aber in der Regel kaum oder gar nicht "pipelined" aus: Die Recheneinheit ist während der gesamten Operation weit gehend belegt und kann keine neuen Befehle entgegennehmen.

Die IA-Divisionsroutine ist hingegen weit gehend pipelined, und der Compiler hat zudem die Möglichkeit, zwischen verschiedenen Optimierungen zu wählen. Soll eine einzelne Division möglichst schnell fertig werden, so wählt er die "Latency-optimierte Fassung". Muss aber beispielsweise eine Schleife viele voneinander unabhängige Divisionen durchführen, kommt die Throughput-optimierte Version zum Einsatz. Bei dieser dauert es zwar länger, bis die erste Division abgeschlossen ist. Im Schnitt liegt aber die mittlere Rechenzeit pro Division drastisch unter der der Latency-Optimierung. So dauert eine Division mit Datentyp Double im Latency-optimierten Fall 35 Takte (zum Vergleich: PowerPC 31, Pentium III 32 Takte). Throughput-optimiert sinkt die mittlere Divisionszeit jedoch auf nur noch fünf Takte (Power-PC weiterhin 31, Pentium III 29 Takte).

Die IA unterstützt auch SIMD (Single Instruction Multiple Data) für Single-Precision-Gleitkomma, allerdings nicht wie bei SSE vierfach parallel mit 128-bittigen Registern, sondern nur zweifach parallel. Da der Itanium aber zwei Gleitkommabefehle gleichzeitig ausführt, liefert er auch wieder vier Ergebnisse pro Takt.

Wichtig für wissenschaftliche Anwendungen ist der mächtige MAC-Befehl (Multiply-Add). Pro Takt und pro Gleitkommaeinheit kann der Prozessor damit zwei Double-Precision-Operationen, eine Multiplikation und eine Addition, ausführen. Reicht die einfache Genauigkeit, so steigt der Durchsatz durch SIMD wiederum auf vier MAC-Ergebnisse pro Takt.

Spezialregister

Neben den beiden General-Purpose- und Floating-Point-Registersätzen unterstützt die IA noch eine Vielzahl von Spezialregistern: Die 128 Applikationsregister, die für Applikationen sichtbar sind, enthalten beispielsweise Kernel-Register, Statusregister und Loop-Counter (64 Bit). Weitere Register enthalten die CPU-ID und diverse Performance-Monitore.

Die 64 Predicate-Flags dienen wie bereits erwähnt der bedingten Befehlsausführung. Dieses Konzept verhindert durch die so genannte if-conversion Verzweigungsbefehle aus Verzweigungsstrukturen, nicht aber aus Schleifen. Entstanden ist es in den 90er Jahren und bereits in den ARM-Architekturen ab V4 enthalten. Anders als dort definiert die Itanium-Architektur dafür 64 eigenständige Bits und nutzt nicht nur das Carry-Bit. Dadurch hat der Compiler wesentlich mehr Möglichkeiten zum Optimieren des Codes.

Last but not least enthalten die acht speziellen Branch-Register die Informationen für die letzten acht Sprünge (function call linkage and return [22]). Hier speichert die CPU die Rückkehradressen von Unterprogrammaufrufen, ohne dafür den langsameren Stack benutzen zu müssen.

Datenspekulationen

Alle bisher behandelten spekulativen Ausführungen in einem (superskalaren) Prozessor betrafen den Kontrollfluss: Dies erscheint auch besonders lohnenswert, da hier die CPU eine Menge an Ausführungszeit gewinnen kann. Die Speicherzugriffe besitzen einen Sonderstatus innerhalb der Instruktionen. Highperformance-Prozessoren behandeln diese gesondert, um Ausführungszeit zu sparen.

Das Speichersystem zeigt sehr lange Verzögerungszeiten bei echten Hauptspeicherzugriffen. Auch die Speicherhierarchie mit Caches zur statistischen Verkürzung der Speicherzugriffe ist nicht unproblematisch.

Es liefert erst dann einen Geschwindigkeitsvorteil, wenn die Daten und Befehle bereits im Cache liegen. Da die Befehle nach einer Load-Instruktion meist von den geladenen Daten abhängen und somit die gesamte Pipeline auf den Speicherzugriff warten muss, verursacht eine Beschleunigung der Load-Befehle generell einen enormen Leistungsgewinn.

Hier setzt deshalb die spekulative Ausführung der Datenbefehle ein. Sie errät aber keineswegs Datenwerte. Vielmehr führt sie Ladezugriffe vorzeitig, also spekulativ aus. Dies kann üblicherweise auf zwei Arten erfolgen:

Die Itanium-Architektur verfolgt den Weg der spekulativen Ladebefehle (Advanced Load), der allerdings keineswegs trivial ist:

Itanium-Mikroarchitektur

Die erste Inkarnation der Itanium-Architektur heißt schlicht Itanium und besitzt 25 Millionen Transistoren. Vier Integer-, vier Multimedia- und zwei Gleitkommaeinheiten (Single/Double Precision) bilden zusammen mit zwei weiteren Gleitkommaeinheiten mit Single Precision für SIMD, drei Sprung- und zwei Lade-/Speichereinheiten die Bausteine des Prozessors. Zwei Befehlsbündel, also bis zu sechs Befehle, vermag der Itanium pro Takt an diese Einheiten zu delegieren. Damit nutzt Intels Prozessor neben der statischen Parallelität der VLIW-Befehle auch noch superskalare Techniken.

Die Pipeline ist mit ihren zehn Stufen für den - trotz seiner vielen Register und Einheiten - recht einfach strukturierten Prozessor relativ lang. Sie stellt aber einen guten Kompromiss zwischen "sequenzieller Parallelität" (lange Pipeline, kurze Bearbeitungszeit pro Stufe) und Sprunganfälligkeit (kurze Pipeline, geringer Verlust bei Fehlvorhersagen) dar. Dank der Prädikationen hat der Prozessor zudem seltener mit bedingten Sprüngen zu kämpfen.

Blockarchitektur

Neun Issue-Ports (zwei FPU, zwei Memory, zwei Integer und drei Branches) versorgen die insgesamt 17 Funktionseinheiten. Einen aufwendigen Dispatcher wie bei superskalaren Prozessoren gibt es nicht: Die Bündel warten in einem kleinen Puffer (mit einer Kapazität von acht Bündeln), bis sie die Issue Ports als Ganzes an freie Einheiten verteilen.

Die L1-Caches sind mit jeweils 16 KByte für Instruktionen und Daten (4-Wege-assoziativ, 32 Byte je Cache-Line) für ein 64-Bit-System nicht gerade üppig ausgelegt. Hinzu kommt, dass der L1-Daten-Cache nur als Write-through ausgelegt ist. Während der Itanium die Inhalte aus dem L1-Cache mit zwei Takten Latenzzeit ausliefert, hat Intel sie beim Nachfolger Itanium 2 auf einen Takt reduziert.

Die beiden FPUs greifen lediglich auf den L2-Cache zu, so dass der L1-Cache etwas entlastet wird. Die geringfügig größere Latenzzeit des L2-Cache von sechs bis neun Takten fällt bei den möglichen FPU-Doppelzugriffen mit 16 Bytes weniger ins Gewicht. Allerdings ist auch der L2-Cache mit seinen 96 KByte sehr klein ausgefallen. Das Nachfolgemodell Itanium 2 kann im Gegensatz dazu immerhin mit 256 KByte und einer Latenzzeit von nur fünf bis sieben Takten aufwarten.

Cache-Stufen

Der L2-Cache ist als Write-back-Cache mit 64-Bit-ECC (Error Correction Coding) ausgelegt. So wichtig dieses ECC für einen Server-Prozessor ist, für die ebenfalls integrierte 32-Bit-Emulation stellt das einen gehörigen Bremsklotz dar. Bei 8-, 16- oder 32-bittigen Schreibvorgängen muss der Prozessor jedes Mal die zugehörige Cacheline komplett lesen, die gewünschten Bytes verändern, die neue ECC-Prüfsumme bilden und danach alles speichern.

Der L3-Cache sitzt beim ersten Itanium noch extern auf einem Modul, einigermaßen zügig über einen 128-bittigen Backside-Bus mit vollem Prozessortakt (750 MHz) angekoppelt. So erreicht er eine ordentliche Bandbreite von 12 GByte/s. Mit 2 oder 4 MByte hat er auch eine vernünftige Größe. Zum System hin arbeitet Itanium mit einem 64-bittigen Bus, mit 133 MHz Takt und Double Data Rate (2 GByte/s). Das liegt deutlich unter dem des Pentium 4 (3,2 GByte/s). Und auch andere Server-Prozessoren sind hier (dank breiterer Busse) oft schneller. Dafür kann man vier Itanium-Prozessoren ohne Zusatz-Hardware über den Systembus zusammenkoppeln, was vergleichsweise preiswerte Vierfach-Server ermöglicht.

Der Nachfolger Itanium 2 hat beim L3-Cache und dem Bus mehr zu bieten. Derzeit sind 6 MByte mit einer Bandbreite von 32 GByte/s im Prozessor integriert. 2005 soll der Itanium 2 mit bis zu 24 MByte L3-Cache erscheinen. Beim Speicher-Interface hat Intel den Durchsatz mit 6,4 GByte/s auch rund verdreifacht..

Fazit Itanium-Architektur

Die Itanium-Architektur ist mit der EPIC-Philosophie angetreten, um die Architekturlandschaft durch eine neue, von VLIW abgeleitete Variante zu revolutionieren. Die genaue Analyse zeigt jedoch, dass die IA im Kern die VLIW-Architektur annimmt und diese durch einige Erweiterungen für Compiler und für den Betrieb nur besser auslegt.

Als evolutionäre Weiterentwicklungen sind die Kombination von VLIW und superskalarer Architektur zu nennen: Die Analyse auf Datenabhängigkeiten erweist sich im Fall der IA-Instruktionsbündel offenbar als so einfach, dass die Architektur ohne viel Aufwand mehrere Bündel zur Ausführung bringen kann. Diese Instruktionsbündel prüft der Prozessor nur noch auf Fehler (vorhandene Datenabhängigkeiten), ein Verfahren, das vergleichsweise einfach ist.

Eine wirkliche Neuerung ist die Datenspekulation, besser: die Datenzugriffsspekulation. Diese ermöglicht dem Compiler einen vorzeitigen, bei Datenabhängigkeiten aber korrigierbaren Zugriff auf den Speicher. Dadurch kann der Compiler sein Instruction Scheduling erheblich verbessern.

Während die ersten Itanium-Prozessoren ob ihrer schwachen Performance noch in der Kritik standen, hat sich das Bild seit dem Nachfolgemodell Itanium 2 deutlich gewandelt. Bei ihm hat Intel einige Implementationsschwächen wie zu kleine Caches und zu langsamen Speicherzugriff behoben. Dadurch kommen die Architekturvorteile besser zur Geltung, so dass der Prozessor einige wichtige Benchmarks wie SPECfp2000 und TPC-C jetzt anführt.

Diesen Artikel und eine ganze Reihe weiterer Grundlagenthemen zu Prozessoren finden Sie auch in unserem tecCHANNEL-Compact "Prozessor-Technologie". Diese Ausgabe können Sie für 9,90 Euro in unserm Online-Shop versandkostenfrei bestellen. Ausführliche Infos zum Inhalt des tecCHANNEL-Compact "Prozessor-Technologie" finden Sie hier.

Literatur

[16] John Crawford: "Introducing the Itanium Processors", IEEE Micro Vol. 20(5), pp. 9-11, 2000

[17] Andreas Stiller: "Architektur für echte Programmierer: IA-64, EPIC und Itanium", ct 2001, H. 13, S. 148-153

[22] Jerry Huck, Dale Morris, Jonathan Ross, Allan Knies, Hans Mulder, Rumi Zahir: "Introducing the IA-64 Architecture", IEEE Micro Vol. 20(5), pp. 12-23, 2000

[23] Harsh Sharangpani, Ken Arora: "Itanium Processor Microarchitecture", IEEE Micro Vol. 20(5), pp. 24-43, 2000

[24] Cameron McNairy, Don Soltis: "Itanium 2 Processor Microarchitecture", IEEE Micro Vol. 23(2), pp. 44-55, 2003