ES40-Server mit EV6-CPU
Übersicht ES40
Der ES40 gehört zur AlphaServer-Serie von Compaq. Mit ihm gibt es noch
den ES10 und ES20, die sich nur minimal im Aufbau, dafür aber gewaltig
in der Leistung vom ES40 unterscheiden. Angedachte Einsatzgebiete sind im Internet
bzw. Intranet zu finden, dazu gehören z.B. Datenbanken, eCommerce, ISP
und dergleichen. Hieraus wird schon klar, dass es sich hierbei um ein System
handeln muss, bei dem der Datendurchsatz eine erhebliche Rolle spielt. Wobei
auch die Rechenleistung nicht zu verachten ist und u.a. durch Verwendung einer
RISC-Architektur beachtliche Werte erreicht.
Anhand der Nummerierung der ES-Serie lässt sich schon erahnen, dass die
erste Ziffer auf die Anzahl der Prozessoren deutet. Um ganz genau zu sein, handelt
es sich um den maximal möglichen Einsatz von CPU’s in einem solchen
System. Somit kann z.B. der ES40, als größtes Mitglied der Familie
mit einem, zwei oder eben vier Prozessoren betrieben werden. Dass es nicht von
vornherein nur den ES40 mit unterschiedlicher CPU-Ausstattung gibt, wird im
weiteren Verlauf erklärt werden. Soweit kann aber schon verraten werden,
dass es sich wie fast immer um eine reine Kostenfrage handelt.
Ausgeliefert wird der Server in drei grundsätzlich verschiedenen Varianten.
In einem kleinen Tower-Gehäuse für den „normalen“ Gebrauch,
in einem sogenannten Pedestal Model, welches erheblich mehr Platz für zusätzliche
Speichermedien beherbergt und natürlich eine Rack-Variante. Wobei diese
schon dafür ausgelegt ist, bis zu drei ES40 Einheiten aufzunehmen.
Ein einzelner ES40-Server kann, abhängig vom gewählten Gehäuse,
zusätzlich zum standardmäßig eingebauten CD-Rom Laufwerk und,
man glaubt es kaum, Diskettenlaufwerk, bis zu 21 Festplatten aufnehmen und verwalten.
Zum Zeitpunkt der Erstellung des Werbeprospektes können dies bis zu 910
GB in einem System werden.
Mit dem Hauptspeicher wird auch recht großzügig umgegangen, was in
einem Server wohl eine grundlegende Voraussetzung ist. 16 bzw. 32 DIMM Sockel
sind in der Lage, maximal 32 GB an RAM aufzunehmen.
Für die Kommunikation mit der Außenwelt sind in einem ES40 zwei unabhängige
64bit PCI-Busse mit insgesamt 10 PCI-Slots vorhanden.
Ein spezielles Betriebssystem, das Compaqs True64 Unix, oder die Schnittstelle
OpenVMS bilden eine hervorragende Grundlage für den Aufbau eines Clusters.
So soll man laut Hersteller eine Zuverlässigkeit von 99,9999% erreichen.
Information EV6-CPU
Hinter dieser Bezeichnung verbirgt sich der in der Esx0-Serie eingesetzte RISC-Prozessor.
Seine korrekte Bezeichnung lautet Alpha 21264 und wurde ursprünglich von
der Firma DEC entwickelt. Vorgestellt im Jahre 1998 ist er der direkte Nachfolger
des 21164 bzw. 21064, dessen Ursprünge in den Jahren um 1992 zu finden
sind. Dass das eingesetzte Konzept gut ist, zeigen die ständigen Neuentwicklungen
basierend auf dem alten Kern des 21064. Erst vor einem Jahr (2001) wurde schon
die vierte Generation, der 21364 (EV8), für das Jahr 2003/2004 angekündigt.
Anhand der Informationen, die mir zur Verfügung stehen, gibt es den EV6
in mehreren Varianten, die sich meines Wissens nur hinsichtlich der Taktfrequenzen
unterscheiden. Verfügbar sind Prozessoren, die mit 500, 667 und 833MHz
getaktet werden können. Da schon noch höhere Frequenzen angekündigt
wurden, bleibt abzuwarten, ab wann diese verfügbar sein werden.
Um nur ein paar seiner besonderen Eigenschaften zu nennen, sei erwähnt,
dass es sich bei dem 21264 um einen vierfach superskalaren Load-Store RISC Prozessor
mit 64 Bit handelt. Out-of-order und speculative Execution spielen bei der Ausführung
von Befehlen eine leistungssteigernde Rolle.
Bei einem physikalischen Adressraum von 44 Bit sind immerhin 16 TeraByte adressierbar.
Ein 4 MB großer externer L2 Cache läuft mit 200 MHz und ist unabhängig
vom Systembus. In jeder CPU sitzt ein, jeweils 64 KB großer, L1 Cache,
der nach Funktionalität in Daten- und Codecache unterteilt ist.
Zur Erhöhung der Performance wird Register Renaming mit doppeltem Integer-Registersatz
eingesetzt, zur Sicherstellung von Datenkonsistenz wird jedes Register gespiegelt.
Des weiteren gibt es eine sogenannte Privileged Architecture Logic (PAL), die
u.a. eine Ausführung komplexer Operationen ohne Microcode ermöglicht.
In den folgenden Kapiteln soll noch tiefgreifender auf diese eben erwähnten
Besonderheiten dieser Architektur eingegangen werden.
CPU
In den folgenden Kapiteln soll speziell auf die in einem ES40-Server eingesetzte Architektur und die Techniken zur Leistungssteigerung eingegangen werden. Konkret sind dies die RISC-Eigenschaften, Techniken wie Register Renaming, Out of Order Execution und Einrichtungen wie der Cache oder das Bussystem.
RISC
DEC’s EV6 bzw. 21264 ist ein echter 64Bit Prozessor mit einer sehr ausgeprägten
RISC-Struktur, also nicht wie bei Intels Kreuzungen zwischen CISC und RISC in
der neueren Pentium-Familie.
Wie üblich bei einer RISC-CPU hat jeder einzelne Befehl eine feste Wortlänge
von 32 Bits, was der gesamten Behandlung von Befehlen zugute kommt. Im ersten
Moment mag dies vielleicht übertrieben erscheinen, da die Anzahl der Operanden
pro Instruktion stark unterschiedlich ist. Eine Invertierung kommt mit einem
Operanden aus, der sogenannte NOP sogar ohne einen. Wozu also diese Verschwendung
?
Die Erklärungen lassen sich am einfachsten finden, wenn man hierzu den
Vergleich mit der CISC-Welt macht. Dort gibt es 8, 16 und 32Bit lange Befehle,
entsprechend seines Aufgabengebietes und des Umfangs an Operanden bzw. Speicherangaben.
Nun liegt innerhalb eines Programmblocks im Hauptspeicher Befehl an Befehl,
jeder mit einer unterschiedlichen Länge. Der Verarbeitungseinheit ist der
Anfang des Programms bekannt, doch wie soll sie wissen, wo schon der zweite
oder der dritte Befehl beginnt. Es muss so das erste Byte dekodiert werden.
Dann ist erkennbar, wie lang der Befehl ist, wie viele Folgebytes noch dazugehören
und wo der nächste beginnt. Dies erschwert die parallele Abarbeitung von
Instruktionen enorm.
RISC kennt diese Probleme nicht. Jedes noch so spät folgende Befehlswort
lässt sich aufgrund der fixen Länge eindeutig lokalisieren. Beim Ablegen
von Code im Hauptspeicher muss auch kein Platz verschenkt werden, um einen effizienten
Zugriff auf den Code durch die Verarbeitungseinheiten zu ermöglichen, wie
es in der Intel’schen CISC-Welt leider der Fall ist.
Interessant ist auch die generelle Trennung der RISC-üblichen Datenzugriffe
von Datenoperationen. Dieses Verhalten, dass Operationen zur Manipulation von
Daten nur zwischen CPU-Registern durchgeführt und auch die Ergebnisse immer
in Registern abgelegt werden können, wird auch als Load-Store-Architektur
bezeichnet. Insgesamt stehen trotz des reduzierten Opcodes vier verschiedene
Befehlsformat-Klassen zur Verfügung (siehe untere Abbildung)

Allen Befehlen gemeinsam ist ein 6Bit-Opcode. Damit lassen sich gerade einmal
64 verschiedene Operationen verwirklichen. Da dies allerdings ein sehr abgespeckter
Befehlsumfang wäre, gibt es die Unterteilung in Klassen.
Im Operate (normale Fix- und Gleitkommaoperationen) und PALcode (wird später
beschrieben) Format kommen noch zusätzlich Bits (Func und Number) hinzu,
die die Auswahl der Funktionen deutlich erhöht. Sowohl im Branch (Sprünge)
als auch im Memory (Transfer) Format wird zum Opcode ein bzw. bei Speichertransfers
zwei Register (RA, RB) angegeben. Ein Displacement (Disp) gibt zusätzlich
die relative Sprungadresse an, bzw. wird für die indirekte Adressierung
verwendet.
Auch der Grundgedanke von Reduced Instruction Set Computers wurde hier verwirklicht.
Ein Großteil der Chipfläche ist für den 128 kB großen
L1 Cache reserviert, dies macht von fast 16 Millionen integrierter Transistoren
immerhin 10 Millionen. Somit bleibt auch nur eine kleine Menge von 6 Millionen
Transistoren für Schalt-, Steuer und Rechenwerke. Vergleicht man dies mit
einem Pentium-Prozessor, ist klar, dass nicht bei weitem der Befehlsumfang auf
einem 21264 enthalten ist. Es befinden sich so nur die absolut notwendigsten
Instruktionen auf der CPU. Hochspezialisierte Einheiten für besonders effiziente
Abarbeitung von multimedialen Aufgaben wird man vergeblich suchen. Schließlich
besteht für solche eher seltenen Ausnahmefälle die Möglichkeit,
jeden noch so komplexen Befehl in viele sehr leistungsstarke aufzubrechen. Dies
mag zwar in diesem Moment zu kleinen Performanceeinbrüchen führen.
Bei den überwiegenden Anwendungen bewirkt dieses Konzept eines sehr großen
Onboard-Cache und einem reduzierten Befehlssatz stark leistungssteigernd.
Wobei gerade mit dieser Prozessorgeneration tatsächlich ein paar speziell
für MPEG De- und Enkodierung Befehle hinzugefügt wurden. Sie interpretieren
Integerregister als Vektoren mit acht oder vier Komponenten (Bytes bzw. Words).
Es gibt Befehle zum Aus- und Einpacken der Vektoren, zur Berechnung der Summe
der Abstände, sowie Minimum- und Maximumfunktionen, die bis zu neun reguläre
Befehle einsparen sollen. Dennoch wurde nicht gleich eine vollständige
MMX-Technolgie (siehe Intels Pentium-CPU’s) oder dergleichen aufgenommen.
Der Alpha 21264 hält noch ein paar weitere Überraschungen parat. Inhalte
zwischen Integer- und Gleitkommaregistern werden direkt, also ohne den Umweg
über den Speicher ausgetauscht. Dabei werden die Werte nicht interpretiert,
d.h. es findet keine gleichzeitige Konvertierung statt. Eine Umwandlung muss
mit einem weiteren Befehl explizit durchgeführt werden.
Interessant ist auch die direkte Auswertung jedes beliebigen Gleitkommaregisters
bei bedingten Sprüngen. Damit entfällt ein üblicherweise notwendiges
Umkopieren und Konvertieren der Sprungbedingung in ein Integerregister.
Wurde der CPU noch eine 128 Bit Multiplikation spendiert, so fehlt ihr tatsächlich
eine Integerdivision. Wobei sich da auch die Frage nach der Notwendigkeit gar
nicht stellt, schließlich fallen bei den wenigsten Divisionen keine Nachkommastellen
an. Also kann die komplette Rechnung gleich in der Gleitkommaeinheit verarbeitet
werden. Soll dann nur der absolute Anteil ausgewertet werden, stellt es wohl
kein Problem dar, den Wert in einen Integer zu konvertieren.
Pipeline und Superskalarität
Ein wichtiges Konzept der RISC-Prozessoren ist die Befehlsverarbeitung in einer Pipeline. Die Ausführung eines Befehls ist selbst bei RISC-CPU’s immer noch so komplex, dass sie niemals in wirklich nur einem Taktzyklus erfolgen können. Stattdessen kann man bei der Befehlsverarbeitung bestimmte Phasen unterscheiden, die jeder Befehl in einer bestimmten Reihenfolge durchlaufen wird. Die Abbildung zeigt eine grafische Darstellung der siebenstufigen Pipeline des EV6.

Zusammenfassend lässt sich die Funktion der Pipeline folgendermaßen
beschreiben. Die Bearbeitung jeder dieser Phasen ist von den anderen Phasen
weitgehend unabhängig. Wenn also ein Befehl Phase 2 abgeschlossen hat,
tritt er in Phase 3 ein und ein anderer Befehl kann in Phase 2 eintreten. Dies
wird dadurch ermöglicht, dass ein Befehl zwischen den für die Bearbeitung
der einzelnen Phasen zuständigen Einheiten des Prozessors (Pipeline Stages)
weitergereicht wird. Bei genügend vielen Stufen entsteht also der Eindruck
einer Fließbandfertigung, wo zu jedem Zeitpunkt jede Bearbeitungseinheit
mit einem anderen Befehl beschäftigt ist. Die Bearbeitung in jeder Phase
dauert dabei einen Taktzyklus und im Mittel verlässt dann pro Zeiteinheit
ein Befehl die Pipeline.
Bis jetzt wurde nur das Pipelineprinzip erklärt. Dennoch blieb es nicht
aus, dass hin und wieder die Skalarität in den Erklärungen vorhanden
war. Deshalb soll der Begriff und die Umsetzung der Superskalarität noch
einmal genauer erklärt werden.
Während bei der Pipeline-Verarbeitung versucht wird sämtliche Bearbeitungseinheiten,
die für die Ausführung eines Prozesses nötig sind, möglichst
gut auszulasten, geht die Superskalararchitektur noch einen Schritt weiter.
Man kann die Befehle nämlich in bestimmte Klassen einteilen, von denen
jede andere Einheiten zur Ausführung benötigt: FPU-Befehle beanspruchen
die Gleitkommaeinheit, IPU-Befehle die Festkommaeinheit und Adressoperationen
die Adressrechnungs-Einheit. Wenn man nun die Befehle eines Programms in geeigneter
Reihenfolge auf die verschiedenen Einheiten aufteilt und diese Einheiten unabhängig
arbeiten können, erreicht man echte Parallelität. Dabei können
sich durchaus auch mehrere Einheiten auf dieselbe Befehlsklasse spezialisieren.
Der Alpha 21264 wird als vierfach superskalar bezeichnet. Nach der eben getroffenen
Aussage, bedeute dies, dass ganze vier Operationen völlig unabhängig
voneinander, also absolut parallel, abgearbeitet werden können. Dennoch
muss man mit einer solchen Aussage vorsichtig sein, da diese vierfache Superskalarität
abhängig von den Aufgaben ist. Ein Blick in die Abbildung oben verrät
unter Stage 5, dass er sich hierbei um zwei Floating-Point Operationen handeln
kann, einen Multiplikation und eine Addition. Die anderen beiden parallel ausführbaren
Befehlen können dann nur noch zwei Integeroperationen bzw. zwei Load/Store-Befehle
sein.
Vereinfacht gesagt, können im günstigsten Fall pro Prozessortakt ganze
vier Befehle gleichzeitig ausgeführt werden.
Register Renaming und Out of Order Execution
Unter dem Begriff „Out of Order Execution“ (OOO) verbirgt sich
die bekannte spekulative Ausführung. Die Grundidee hinter OOO ist, die
vom Programm her vorgegebene Reihenfolge der Befehle zu umgehen und eine, passend
zur implementierten Hardware, bessere Ausführungsreihenfolge zu finden.
Dies hört sich im ersten Moment ein wenig missverständlich an, ist
aber vom Konzept her recht simpel.
Die meisten erstellten Programme haben den Nachteil, dass sie in einer sequentiellen
Struktur geschrieben wurden. Angenommen innerhalb eines Algorithmus werden nacheinander
eine Festpunktaddition, eine Gleitpunktmultiplikation durchgeführt. Dann
sind in diesem Beispiel die jeweiligen Operanden unabhängig. Es ist wohl
leicht einsehbar, dass die Reihenfolge, in der beide Befehle ausgeführt
werden sollen, völlig unerheblich ist. Durch den Programmierer ist hingegen
logischerweise eine fest vorgegeben.
Verinnerlicht man sich noch mal die Pipeline des EV6, wird klar, dass beide
genannten Operationen problemlos parallel durchführbar sind, da jeweils
eine Einheit für Fix- und Gleitpunktarithmetik zur Verfügung steht.
Damit Out of Order Execution richtig zur Geltung kommt, sollte man sich ein
neues Beispiel überlegen. Wie im vorherigen gibt es Gleit- und Festpunktberechnungen,
aber jeweils vier Stück. Als erstes kommen im Programmcode die Berechnungen
der Floatingpoints und anschließend die Integer.

Bekannt ist, dass die Pipeline vom 21264 gleich vier Befehle als Ganzes aufnehmen
kann. In unserem Fall wären das die vier Gleitpunktoperationen, die aber
aufgrund fehlender Rechenwerke nicht alle parallel ausgeführt werden können.
Dagegen steht die Integereinheit still, da keine Befehle für sie anstehen.
Jetzt kommt die Out of Order Execution, die natürlich schon lange vor Ausführung
des ersten Befehls die Struktur der nächsten Instruktionen erkannt hat.
Zum einen wird nun jeder der Befehle durchnummeriert und dann neu sortiert.
Im angenommenen Beispiel wird nun jeweils eine Integer und ein Floatingpoint
gleichzeitig ausgeführt, was natürlich eine enorme Zeitersparnis ist,
da nun wesentlich mehr Einheiten der CPU pro Zeiteinheit genutzt werden können.
Nach Abarbeitung aller Berechnungen sind acht Ergebnisse vorhanden, die noch
dringend in die richtige Reihenfolge gebracht werden müssen, wie sie bei
sequentieller Ausführung aussehen würde. Hierbei hilft die anfangs
durchgeführte Durchnummerierung der Operationen.
Die Umsortierung der Befehlsreihenfolge funktioniert allerdings nur, wenn die
Ergebnisse der vorherigen Befehle nicht gleichzeitig Operand der folgenden sind.
Unter dieser Voraussetzung spielen identische Operanden keine Rolle, da ihr
Wert nun mal unverändert bleibt.
Man bezeichnet die CPU zwar als vierfach superskalar, schließlich können
bis zu vier Instruktionen gleichzeitig in die Pipeline aufgenommen werden. Dennoch
stehen diesen Befehlen ganze sechs Einheiten mit teilweise unterschiedlicher
Spezialisierung zur Verfügung. Zwei Integer-, zwei Load/Store-Befehle und
zusätzlich eine Floatingpointmultiplikation sowie eine –addition
können gleichzeitig genutzt werden.
Für die Out of Order Logik bedeutet dies eine echte Herausforderung, da
das oberste Ziel ein Auslastung von 100 Prozent aller Einheiten sein soll. Was
nicht immer möglich sein kann, wenn z.B. die FPU zur Zeit nicht gebraucht
wird. Möglichst weit vorausschauen muss das System und protokollieren,
welche Typen von Befehlen anstehen, um die Umverteilung der Befehle schon sehr
früh zu gestalten. Der 21264 ist in der Lage, ganze 80 Befehle im voraus
zu bewerten.
Register Renaming ist ein Verfahren das zusammen mit der Out of Order Execution
genannt werden muss. Aus den vorherigen Absätzen sollte hervor gegangen
sein, dass das Umsortieren der Befehlsausführung von mehreren Faktoren
abhängig ist. Neben der Beziehung der einzelnen Operationen zueinander,
spielen auch die verwendeten Register eine Rolle.
Für die Berechnungen existieren 64 Allzweckregister mit einer Breite von
32 Bit, allerdings aufgeteilt in Integer und Floatingpoint. Auch hier spiegelt
sich der RISC-Gedanke wieder, der einer Spezialisierung von Registern sehr kritisch
gegenüber steht. Dies erschwert einem Compiler zum Zeitpunkt der Programmerstellung
allerdings die geschickteste Auswahl der Register, schließlich kann für
jeden Typ Operation eigentlich jedes Register verwendet werden. Nun scheint
es leider so zu sein, dass die Schwächen der Compiler durch das Register
Renaming ausgeglichen werden müssen.
Durch die Out of Order Execution kann es schon mal vorkommen, das sich in der
Pipeline Anweisungen befinden, die ihr Ergebnis in das gleiche Register schreiben
sollen. Dies wäre natürlich fatal, da mindestens ein Ergebnis verloren
gehen würde. Der Ausweg sieht nun folgendermaßen aus. Vor der Ausführung
wird der in der Instruktion angegebene Speicherort durch ein sogenanntes temporäres
Register ersetzt, von denen insgesamt 82 vorhanden sind. Ist ein eben ausgetauschtes
temporäres Register in einer der direkt folgenden Operationen Speicherstelle
für einen Operanden wird in diesem auch gleich die Operandenangabe korrigiert.
Allerdings wird nach der Ausführung und entsprechend der vorgegebenen Reihenfolge
der Inhalt der temporären Register in die ursprünglich im Code angegebenen
kopiert. Mit diesem Trick können Operationen parallel ausgeführt werden,
die beide im selben Register einen Wert manipulieren sollen.
Branch Prediction
Sobald der Einsatz von Pipelines in einem System erforderlich ist, spielt die
Sprungvorhersage eine äußerst entscheidende Rolle. Dies liegt daran,
dass bei jedem Prozessortakt ein neuer Befehl in die Pipeline geschoben wird,
verständlicherweise in der Reihenfolge wie die Instruktionen im Speicher
stehen. Der Einsatz von Schleifen, Bedingungen und Sprüngen in Programmen
setzt die Effizienz einer Pipeline deutlich herab. In Phase 5 wird beim 21264
erst der Befehl ausgeführt. Handelt es sich nun zufälligerweise um
einen Sprung, der nicht auf den nächst folgenden in der Pipeline zeigt,
besteht hier ein echtes Problem. Vor der Stufe fünf in der Pipeline liegen
schon weitere fünf Befehle, die mit großer Wahrscheinlichkeit alle
nicht gebraucht werden können, da der Sprung an eine völlig andere
Stelle geht. Nun stellt sich die Frage, wie man dieses eingrenzen oder sogar
vermeiden kann.
Mittels einer sogenannten Sprungvorhersage auch Branch Prediction steht ein
Verfahren zur Verfügung, mit dem eine, je nach betriebenen Aufwand, mehr
oder weniger gute Analyse der Sprungwahrscheinlichkeit durchgeführt werden
kann. Konzept dieser Vorherbestimmung gibt es sehr viele, fast jeder Hersteller
von CPU’s hat seine eigene Strategie. Anhand der vorliegenden Daten soll
das im EV6 eingesetzte System beschrieben werden. Im Vorfeld muss noch erwähnt
werden, dass die Informationen hierzu sehr spärlich sind, da die Hersteller
viel Wert auf Geheimhaltung ihrer Lösungen legen.

Der sogenannte Branch Predictor (siehe oben), entscheidet aufgrund eigens gesammelter
Informationen, ob die Durchführung eines Sprunges wohl wahrscheinlich sein
könnte.
Angeordnet ist diese Logik an erster Stelle in der Pipeline. Was ja auch Sinn
macht, denn dort wird der Befehl dekodiert. Für die CPU wird somit erkennbar,
ob es sich schon einmal um eine Operation oder einen Sprung handelt. Befindet
sich hier ein Sprungbefehl, muss entschieden werden, welche Instruktionen denn
nun als nächstes in die Pipeline geladen werden sollen. Folgen die falschen,
entstehen „Bubbles“, die ähnlich einem NOP nur einen Leerlauf
verursachen.
Laut Untersuchungen seitens der Firma Compaq erreichen sie mit ihrem Verfahren
bei Standardanwendungen eine Trefferquote von teilweise über 90 Prozent.
Bei einem realen Programm wurden bei 100 durchgeführten Sprüngen über
90 ohne Leistungseinbußen durchgeführt. Lediglich die Differenzen
von unter 10 Sprüngen erzeugen in der Pipeline Blasen.
Der Algorithmus zur Vorhersage des EV6 stützt sich gleich auf drei Tabellen
unterschiedlicher Größen. Dies sind die Tabellen Local Prediction,
Global Prediction und Choice Prediction. Zusätzlich zeichnet eine Local
History die Adressen der sich im Code befindlichen und durchgeführten Sprünge
auf. Zusammen mit der Local Prediction, in der bei Erfolg der Wert inkrementiert
und bei Misserfolg dekrementiert wird, entsteht für die letzten 1024 durchgeführten
Sprünge eine Statistik.
Bei verschachtelten Schleifen und Sprüngen zeichnet die Global Prediction
in Zusammenarbeit mit der Path History, die Sprungrichtung in Abhängigkeit
vom Ergebnis des letzten Ergebnisses auf.
Soweit zur Aufzeichnung der vorherigen Sprünge. Irgendwann wird der 21264
auch auf die gesammelten Daten zurückgreifen wollen, um sich eine Wahrscheinlichkeit
ausgeben zu lassen. Da jeweils die Adressen der Sprünge mit abgelegt wurden,
wird einmal in die Local Prediction und in die Global Prediction geschaut. Zeigen
beide Tabellen das gleiche Ergebnis, also eine identische Sprungvorhersagewahrscheinlichkeit,
dann wird die Richtung beibehalten. Gibt es Differenzen, wird die Choice Predictor
aktualisiert. Welchen Einfluss nun der dort abgelegte Wert auf die Wahrscheinlichkeitsbestimmung
hat, bleibt leider fürs erste ein Betriebsgeheimnis der Firma Compaq.
PAL
Hinter der Abkürzung PAL verbirgt sich der Ausdruck Privileged Architecture
Library. Es handelt sich hierbei um eine Sammlung von Makros aus Assemblerbefehlen,
die entwickelt wurden, um Microcode zu vermeiden.
Microcode ist eine in der CPU fest „eingebrannte“ Software, die
komplexere Aufgaben mit Hilfe atomarer Operationen ausführt. Nachteilig
ist, dass dieser Code nicht verändert werden kann und ein recht großer
Bedarf an Chipfläche vorhanden ist, für Befehle, die selten oder nie
ausgeführt werden.
Eine PALCode-Operation sieht nur von außen wie eine atomare Operation
aus. Vergleichbar sind diese Instruktionen mit einer Art Funktion, die auf der
unterster Ebene ausgeführt werden. Der Vorteil liegt darin, dass sie privilegierte
Rechte besitzen. Während der Ausführung sind z.B. alle Interrupts
abgeschaltet, somit hat man für den Moment der Ausführung die volle
Kontrolle über den Prozessorstatus und kann so auf interne Register zugreifen,
ohne Gefahr zu laufen, dass ein parallel arbeitender Prozess genau in diesem
Moment den Inhalt der Register beeinflusst.
Eine große Rolle spielt die Emulation von Befehlen, die aufgrund der RISC-Architektur
nicht implementiert wurden. Man erinnere sich hier an die fehlende Integerdivision
oder aber auch das HALT-Kommando, mit dem die Ausführung von Code unterbrochen
wird.
PALCode wird weiterhin benutzt, um Betriebsystem-Operationen auszuführen.
Dazu gehören z.B. Taskwechsel, Interrupt/Exception-Handling, Hardwareinitialisierung
beim Systemstart und Eingriff in die Speicherverwaltung.
Bis jetzt erinnert die Umschreibung von PAL sehr stark dem sonst üblichen
Microcode. Dennoch gibt es einen gravierenden Unterschied: PAL befindet sich
nicht auf der CPU, sondern läuft als Bibliothek im Hauptspeicher und lässt
den Chipdesignern mehr Platz für Funktionen, die weitaus häufiger
zum Einsatz kommen.
Cache
Wie bei heutigen Prozessoren allgemein der Fall, steht der Prozessortakt der
Geschwindigkeit des Speichers in einem Verhältnis gegenüber, dass
den Einsatz eines oder mehrerer Zwischenspeicher, Caches, erfordert.
Der EV6 besitzt Onboard einen L1-Cache mit einer Speichertiefe von 128 KB. Allerdings
sind diese in zwei Einheiten mit unterschiedlichen Aufgaben unterteilt. Zum
einen gibt es den reinen Datencache, der die Operanden der Berechnungen für
die Register vorhält. Und zum anderen existiert der Befehlscache mit ebenfalls
64 KB Speicher. In ihm werden die folgenden Instruktionen bereitgestellt, um
so ein lang andauerndes Nachladen zu verhindern.
Ermittelt der schon vorgestellte Branch Predictor eine Sprungadresse, zu dem
es noch keine Instruktionen im Befehlscache gibt, stößt er den Cache
an, damit dieser die fehlenden Befehle nachlädt.
Durch die Ausführung als Dual-Ported ist der Cache in der Lage, gleich
zwei Anforderungen pro Takt zu beantworten. Dies ist möglich, da innerhalb
eines Prozessortaktes sowohl die steigende als auch die fallende Flanke einen
Zugriff auch den Speicher darstellen.
Verständlicherweise greift der L1-Cache nicht direkt auf den Hauptspeicher
zu, dazwischen befindet sich außerhalb der CPU noch der L2-Cache, der
bis zu 4 MB groß ausgelegt ist. Seine Zugriffsgeschwindigkeit ist deutlich
langsamer als die beim L1-Cache. Einen Überblick gibt die von Compaq erstellte
Tabelle (Abbildung unten). In dieser Gegenüberstellung sind die Speicher
entsprechend ihrer Zugriffsverzögerung, auch Latenzzeit genannt, von oben
nach unten aufgelistet. Umgekehrt zu der Latenzzeit steht die Speichergröße.
Je größer der Speicher wird, desto langsamer wird er auch.
Mikroarchitektur
Nachdem nun in den vorherigen Kapiteln die hervorstechenden Eigenschaften der
CPU behandelt wurden, soll noch ein abschließender Überblick über
die Anordnung und das Zusammenspiel der einzelnen Funktionseinheiten erfolgen.
Der EV6 besteht im wesentlichen aus nur vier Segmenten: Cbox, Ibox, Ebox und
Fbox. Des weiteren sind noch der L1-Cache und seine Verwaltungslogik (Mbox)
vorhanden. Um mal eine Vorstellung von der Anordnung und der relativen Größe
der einzelnen Einheiten zu bekommen, sind auf der Fotografie eines realen EV6-Chips
die Segmente eingezeichnet.


Multiprozessorbetrieb
Es sollte inzwischen aufgefallen sein, dass es sich bei dem 21264 um eine recht
hochentwickelte CPU handelt. Informiert man sich ein wenig über die Alpha-Serie,
fällt auf, dass nicht nur Compaq diese Prozessoren verbaut. Auffällig
ist auch, dass es einige System auf dem Markt gibt, die tatsächlich nur
eine CPU vom Typ EV6 verbaut haben. Doch sind diese in der Minderheit und in
der Regel ist dies nur der kleinste Vertreter eine Produktfamilie. Oder es besteht
die Möglichkeit einen solchen Rechner durch den zusätzlichen Einbau
weiterer Prozessoren leistungsfähiger zu machen.
Wie man sich ein System mit mehreren CPU’s vorstellen soll, werden die
nun folgenden Kapitel verdeutlichen. Es soll noch einmal in Erinnerung gerufen
werden, dass der ES40-Server, von dem diese Hausarbeit handeln soll, in der
maximalen Ausbaustufe mit gerade einmal 4 Prozessoren ausgestattet ist. Sowohl
die physikalischen Dimensionen als auch die abgegebene Rechenleistung sind zwar
überragend in seiner Klasse, dennoch handelt es sich keinesfalls um einen
Superrechner mit dem Wetterberechnungen in endlicher Zeit durchführbar
wären.
Chipsatz
Nun stellt sich sicher die Frage, was der verwendete Chipsatz mit dem Aufbau eines Multiprozessorsystems zu tun hat. Im Fall des ES40-Servers spielt er eine ganz entscheidende Rolle. Kennzeichnend für ein Multiprozessorsystem sind neben der eingesetzten CPU’s:
Und alle diese Eigenschaften sind in diesem System im Chipsatz vereint. Doch
was genau soll man nun unter dem Begriff Chipsatz verstehen ? Wie der Name schon
sagt, handelt es sich um einen ganzen Satz von Integrierten Schaltungen. Drei
IC’s mit stark unterschiedlichen Aufgaben bilden diesen Chipsatz, und
sind notwendig, um aus der eigentlichen CPU ein Gesamtsystem zu bilden. Seine
Bezeichnung für die 21264-CPU lautet 21272, wird aber auch als Tsunami
Core Logic Chipset bezeichnet.
Verinnerlicht man sich, welche Möglichkeiten der nackte Prozessor hat,
mit seiner Außenwelt zu kommunizieren, wird schnell klar, wie notwendig
die Chipsätze sind. Eine CPU besitzt zwar die gesamte Logik zur Abarbeitung
der Programme, dafür ist die Funktionalität seiner Ports aber recht
eingeschränkt. Im wesentlichen sind Daten und Adressports unterschiedlicher
Art vorhanden.
Bedingt durch den fehlenden Platz und die damit entstehenden Kosten sind Massenspeicher
(RAM) oder universelle Busse (PCI) in Mikroprozessoren selten bis gar nicht
integriert worden. Allerdings wäre ohne sie kein Programm vorhanden und
auch keine Kommunikation mit dem Nutzer denkbar.
Der Tsunami-Chipsatz übernimmt nun nicht nur die Steuerung der externen
Periphere, er ermöglicht in einem Multiprozessorsystem überhaupt erst
den Einsatz von mehreren Prozessoren.

Die obernstehende Abbildung zeigt den typischen Aufbau eines Systems, in dem
zwei EV6-CPU’s parallel arbeiten. Jede der zwei 21264-Prozessoren besitzt
eine direkte Anbindung an den L2 Cache, welche Daten und Programmcode für
den internen L1 bereit hält.
Ganz rechts in der Grafik liegen die Speicherbänke des Hauptspeichers und
im unteren Teil das PCI-Bussystem. Beides ist direkt verbunden mit dem Chipsatz,
dargestellt in der Mitte als großer Kasten, und dieser wiederum mit dem
Prozessor. Erfordert das ablaufende Programm eine Ausgabe auf dem PCI-Bus, ist
die CPU gar nicht in der Lage, diesen direkt anzusprechen. Sie schickt die Daten
mit einer Anforderung zur Weiterleitung an den Chipsatz. Es ist nun die Aufgabe
des Tsunami, die von einem der CPU’s empfangenen Daten in der richtigen
Reihenfolge an den richtigen Ort zu bringen. Leider verliert die CPU so die
Kontrolle über die Datenübertragung, hat aber den entscheidenden Vorteil,
dass sie sich wieder um den Programmablauf kümmern kann.
In früheren Versionen hat der Chipsatzes auch den L2-Cache gesteuert, ein
Zugriff der CPU ging so immer über den Tsunami. Durch diese entscheidende
Änderung konnte die Zugriffsgeschwindigkeit noch gesteigert werden, indem
die Latenzzeit abgesenkt wurde.

Eine etwas andere Grafik soll die Aufgaben der einzelnen IC’s des Chipsatzes ein wenig näher bringen. Wie zu erkennen ist, gibt es drei grundlegende Einheiten: Dchip, Cchip und den Pchip.
Es wird Zeit ein wenig konkreter auf den Aufbau eines ES40-Servers einzugehen.
Es wird davon ausgegangen, dass die größtmögliche Hardware-Konfiguration
verwendet wird. Schließlich ist nur so ein Maximum an Rechenleistung zu
erwarten.
Für jede CPU steht ein eigener externer L2-Cache zur Verfügung, in
dem nur für sie relevante Daten vorhanden sind. Eine Verbindung zwischen
den einzelnen Caches gibt es nicht.
Jede der vier parallel angeordneten CPU’s ist über einen eigenen
Bus mit dem einen zentralen Cchip des Chipsatzes verbunden. In den Marketingunterlagen
ist die benötigte Anzahl der Cchips fälschlicherweise mit zwei angegeben.
Über diesen Bus werden die Anforderungen an die externe Peripherie gestellt,
die vom Cchip koordiniert werden. Dementsprechend gibt es zu den Pchips und
den Dchips auch jeweils ein Bussystem.

Des weiteren entnimmt man der oberen Abbildung, dass nur maximal zwei CPU’s
zur gleichen Zeit einen Zugriff auf den externen PCI-Bus haben können,
da im Gesamtsystem nur zwei Pchips vorhanden sind, die auch nur exakt einen
Bus bedienen können.
Mit den Zugriffen auf den globalen Hauptspeicher verhält es sich ähnlich.
Es sind zwar vier Speicherbänke vorhanden, dennoch bilden immer zwei ein
Paar, die gemeinsam über einen Datenbus mit den Dchips verbunden sind.
Will man die vorherrschende Architektur nun klassifizieren, sollte klar sein,
dass es sich hier um eine Shared Memory Architecture (SMA) handelt. Mehrere
Prozessoren, hier sind es bis zu vier, greifen über ein Verbindungsnetzwerk
auf den gemeinsamen Globalspeicher zu. Das Verbindungsnetzwerk ist gegeben durch
den Tsunami-Chipsatz, der den Zugriff auf den Speicher überwacht und koordiniert.
Die Abbildung lässt deutlich werden, dass auf die vier Speicherbänke
des RAM’s jede CPU einen gleichberechtigten Zugriff machen kann. Entsprechend
verhält sich die Latenzzeit auf alle Speicherzellen. Dieses Verhalten deutet
auf eine speziellen Form der SMA hin, der Uniform Memory Access-Architecture
oder kurz UMA.

Es handelt zwar um eine homogene Architektur, da jeder die gleichen Zugriffsrechte
auf die Peripherie hat, dennoch können zur gleichen Zeit nicht alle Prozessoren
auf den PCI-Bus oder den Hauptspeicher zugreifen.
Liegen die relevanten Daten in unterschiedlichen Speicherbänken, können
zwei Zugriffe auf den RAM-Speicher und auch zwei Zugriffe auf PCI durchgeführt
werden. Hier gilt allerdings das gleiche, es darf sich nicht um den selben Bus
handeln, da es ansonsten zu Kollisionen kommen könnte. Allerdings verhindert
der Cchip als steuernde Einheit solche sich überkreuzenden Operationen.
Cache
In einem ES40-Server gibt es drei verschiedene Typen von Caches, einmal den
Befehlscache (ICache), dann den Datencache (DCache) und dann noch den L2-Cache
(BCache). Letzterer ist extern vorhanden, während die beiden ersten direkt
in der CPU integriert sind und auch als L1 bezeichnet werden.
Aufgrund des hohen Platzbedarfes und der damit verbundenen Kosten fällt
ein Cache im Verhältnis zum Hauptspeicher um ein Vielfaches kleiner aus.
Dies bedeutet allerdings, dass es im Cache ständig zu Platzproblemen kommen
wird und geklärt werden muss, wo welcher Hauptspeicherinhalt abgelegt werden
darf.
Eingesetzt im Chipsatz Tsunami des ES40 wird die Set Associative-Strategie,
mit deren Hilfe die Zuordnung vom Ram-Speicher in den Cache erfolgt.
Bei einem Set Associative Cache wird der Speicherplatz in sogenannte Sets fester
Größen aufgeteilt. Ein Set bietet Platz für einen Block aus
dem Hauptspeicher, doch kann dieser noch innerhalb des Sets seine Position wählen.
Die Anzahl der Sets wird durch den vorangestellten Wert festgelegt.
Im internen L1 wurde sowohl beim Daten- als auch beim Befehlscache ein 2 Way
Set Associative Cache umgesetzt. Der eben getroffenen Aussage nach, kann ein
Block aus dem RAM im Cache zwei Positionen einnehmen.
Dagegen steht der L2, der sogar einen 3 Way Set Associative Cache darstellt.
Es versteht sich von selbst, dass bei steigendem Faktor von 2 auf 3 auch die
gesamte Größe des Caches steigen muss. Denn nun kommt pro Block und
Set ein weiterer Platz hinzu.
Beim Befehlscache (ICache) hat man sich sogar etwas besonderes einfallen lassen.
Da er mit dem Branch Predictor in der Pipeline zusammenarbeitet, wird die Zuteilung
und damit die Verdrängung von Daten im Cache nicht zufällig oder nach
dem Prinzip des ältesten Datums vollzogen, sondern in Abhängigkeit
mit der Sprungwahrscheinlichkeit, dass die vorliegenden Daten noch benötigt
werden.
Die Abbildung zeigt eine hierarchische Darstellung der einzelnen Cahces. Was
verwundert, ist, dass der DCache von dem ICache getrennt liegt, obwohl sie beide
innerhalb der CPU den L1 bilden. Doch macht dies auch Sinn, dass der Befehlscache
außerhalb der anderen liegt, schließlich ist er der einzige, der
Daten nur in eine Richtung weiterleitet. Instruktionen haben die Eigenschaft
von dem Prozessor benötigt aber niemals verändert zu werden, somit
wandern die Befehle immer vom RAM zum L2 und dann in den L1-Cache.

Dies zieht eine ganz andere und viel wichtigere Folgerung mit sich. Das Problem
von Dateninkonsistenz kann hier niemals auftreten, da es sich um konstante Daten
handelt, die immer nur gelesen, aber sinnigerweise niemals vom L1-Cache zurückgeschrieben
werden müssen.
Gerade in Multiprozessorsystemen stellt die Konsistenz von Daten ein ernsthaftes
Problem dar, deshalb soll in den folgenden Absätzen auf die eingesetzten
Kohärenzprotokolle eingegangen werden.
Obwohl keine Begründung in den Unterlagen zu finden ist, gibt es für
den ICache tatsächlich ein Möglichkeit die Dateninhalte auf Kohärenz
hin zu überprüfen. Dies wird allerdings nicht von der Hardware unterstützt.
Hierzu gibt es spezielle Routinen, die auf PAL basieren.
Über die Notwendigkeit eines solchen Befehls kann ich leider nur Vermutungen
anstellen. Vielleicht wird dies notwendig, bei Programmupdates laufender Programme
dieses dem Cache mitzuteilen !?
Ein Kohärenzprotokoll bei dem BCache und dem ICache macht allerdings sehr
viel Sinn, da beide von dem Prozessor modifizierbare Daten enthalten können.
Da sich der interne DCache seine Daten nur aus dem L2-Cache holt, wird auch
verständlich, warum in der Hierarchie der eine dem anderen untersteht.
Zur Kontrolle von Datenkohärenz gibt es ein spezielles Protokoll, welches
den Dateninhalt jedes L1-Caches beobachtet. Ein Datum kann insgesamt fünf
verschiedene Zustände einnehmen:
Damit ein Block nicht mehrmals pro Zyklus hintereinander überschrieben werden kann, erlaubt die Logik nur ein einmaliges Rückschreiben der Blöcke pro Takt. Sobald ein Datum mit dem Zustand Dirty im L2-Cache aktualisiert wurde, ändert sich sein Zustand in Invalid, da nun keine Kopie mehr vorhanden ist. Ähnlich verhält es sich mit den anderen Zuständen.