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.