Cache-Speicher


Der Flaschenhals

Die großen Fortschritte in der Halbleiter-Prozesstechnologie ermöglichen es seit geraumer Zeit, Microprozessoren herzustellen, deren Verarbeitungsgeschwindigkeit die, der üblicherweise als Arbeitsspeicher eingesetzten dynamischen Speicher (DRAM) oder der für embedded Systeme verwendeten nichtflüchtigen "Flash"-Speicher, bei weitem übertrifft. Der Flaschenhals eines Microprozessor-Systems ist damit nicht mehr der Prozessor sondern der Speicher. Die Daten und Instruktionen können nicht mehr schnell genug vom Speicher bereitgestellt werden und das System muß zwangsläufig mit Wartezyklen (Wait States) gebremst werden. In den Prozessor-Architekturen sind bereits viele Möglichkeiten ausgereizt um die Verarbeitungsleistung zu optimieren (Pipelines etc...), was aber den Engpaß zwischen Speicher und Prozessor nicht beseitigt. Der erste Weg den Datendurchsatz zu erhöhen war die Erweiterung der Datenbus-Breite. 32 Bit bzw. 64 Bit Busse sind heute der Stand der Technik. So können pro Speicherzyklus mehr Bytes gleichzeitig gelesen werden und die Busbandbreite und der Speicherdurchsatz erhöht sich entsprechend.

Grundsätzlich wäre es möglich Prozessorsysteme mit externen SRAM (statische RAM Bausteine) zu entwickeln. SRAM´s haben sehr kurze Zugriffszeiten (< 5 ns) die auch bei Prozessoren mit Taktraten von einigen 100 MHz noch keine Verringerung der  Verarbeitungsleistung verursachen würden. Das Problem bei SRAM´s liegt mehr im kommerziellen Bereich. SRAM-Bausteine sind bei gleicher Kapazität (Speichergröße) wesentlich teurer als dynamische RAM´s. Dies liegt vor allem daran, daß für eine SRAM-Zelle typisch 4-6 Transistoren benötigt werden, für eine DRAM-Zelle nur ein einzigerTransistor, daraus ergibt sich eine wesentlich größere Fläche des SRAM Speicher-Chips (Silizium-Fläche), welche natürlich zu einem wesentlich höheren Preis führt. Da in heute üblichen Computersystemen sehr große Arbeitsspeicher benötigt werden, würde dies den Preis eines solchen Systems stark in die Höhe treiben. SRAM´s (static RAM´s) sind außerdem nicht mit den hohen Speicherkapazitäten wie DRAM´s verfügbar, so dass ein entsprechend großer Hauptspeicher sehr viel Platz benötigt.

Der Ausweg aus diesem Dilemma ist ein Cache-Speicher, der zwischen die schnelle Verarbeitungseinheit (z.B. die CPU) und den "langsamen" Speicher (hier den Arbeitsspeicher) geschaltet wird. Dieser Cache-Speicher benötigt allerdings auch eine  Kontrolleinheit, den Cache-Controller, der die Zugriffe entsprechend steuert.

Als Speicher werden für einen externen Cache durchwegs schnelle statische RAM-Bausteine verwendet. Auch interne, also auf dem Prozessor bereits integrierte Caches werden ebenfalls auf der Basis von statischen RAM´s aufgebaut.

Der Cache-Speicher kann schaltungstechnisch entweder zwischen die CPU und den Hauptspeicher als "Look-Through-Cache"  (nicht zu verwechseln mit "Write-Through", siehe weiter unten) implementiert werden oder als "Look-Aside-Cache" an einem gemeinsamen Bus mit CPU und Hauptspeicher.


Jedes System hat seine eigenen Vor- und Nachteile. Im Großen und Ganzen hat sich aber die "Look-Through-Cache" Konfiguration als Vorteilhaft erwiesen, da der eigentliche Speicherbus dadurch weniger belastet wird und daher andere Bus-Master oder externe DMA-Kanäle effizienteren Zugriff bekommen. Das "Look-Aside-System" ist dagegen weniger aufwändig bezüglich des Cache-Controllers und kann als eigenständiges Subsystem implementiert werden.  

Das Cache Grundprinzip

Das Prinzip eines Cache arbeitete dabei wie folgt. Ein Zugriff auf eine Speicherstelle des "langsamen" Arbeitsspeichers wird vom Cache-Controller überwacht und falls die Daten im Cache-Speicher "vorrätig" sind werden diese verwendet. Dadurch kann ein "langsamer" Speicherzyklus zum Hauptspeicher eingespart werden und die Daten stehen in viel kürzerer Zeit der CPU zur Verfügung. Es gibt dabei zwei mögliche Situationen:

Cache "Miss"

Der Cache-Controller kann die Adresse nicht in seinem Cache-Speicher finden:

In diesem Fall wird ein ganz normaler Speicher-Bus-Zyklus zum Arbeitsspeicher ausgeführt und die Daten werden gelesen oder geschrieben. Soweit hat dies keinen Einfluss auf den Cache-Speicher aber der Cache-Controller schreibt die Daten (sowohl Schreib- als auch Lese-Daten) in eine Speicherstelle des Cache-Speichers.

Da der Cache-Controller dies simultan zum eigentlichen Schreib/Lesezyklus bewirkt tritt auch keine wesentliche Verzögerung auf.

Cache "Hit "

Der Cache-Controller kann die Adresse einer Speicherzelle im Cache-Speicher zuordnen:

In diesem Fall liest der Cache-Controller die Daten aus dem Cache-Speicher und legt diese auf den Datenbus für den Prozessor. Der Bus-Zyklus zum Arbeitsspeicher wird vollkommen unterdrückt und andere Systeme oder Busmaster am Speicherbus haben freien Zugriff auf den Arbeitsspeicher. Anders verhält sich die Sache bei einem Schreib-Zugriff zum Arbeitsspeicher. Hier gibt es zwei unterschiedliche Cache-Strategien.

Ein "Write-Through"-Cache schreibt die Daten grundsätzlich sowohl in den Arbeitsspeicher (langsamer Zugriff) als auch in den Cache-Speicher (schneller Zugriff). Leider wird die Zykluszeit in diesem Fall vom langsameren Zugriff  bestimmt, es ergibt sich also gegenüber einem System ohne Cache-Speicher kein Vorteil bei einem Schreibvorgang.

Die Lösung für eine teilweise Beschleunigung der schreibenden Zugriffe heißt "Write-Back"-Cache. Bei einer Write-Back-Cache Strategie wird im Falle eines Cache-Hits das zu schreibende Datenwort nur in den Cache-Speicher geschrieben. Dadurch wird die Zykluszeit auch beim Schreiben auf die kurze Zugriffszeit des Cache-Speichers reduziert. Es tritt aber jetzt das Problem der Daten-Integrität auf, d.h. in der Speicherstelle im Arbeitsspeicher steht ein falsches (weil "altes" Datenwort) und das aktuelle Datenwort steht nur im Cache-Speicher. Soweit noch kein Problem, aber der Cache-Speicher ist im Verhältnis zum Arbeitsspeicher sehr klein und deshalb wird über kurz oder lang diese Speicherstelle für ein anderes Datenwort gebraucht. Jetzt wird eine Strategie benötigt die sicherstellt, daß das aktuelle Datenwort rechtzeitig in den Arbeitsspeicher "zurückgeschrieben" (write-back) wird. Dies erfordert nun zwar wieder einen "langsamen" Speicherzyklus zum Arbeitsspeicher aber da das Datenwort zwischenzeitlich mehrmals gelesen oder geschrieben werden konnte, ergibt sich daraus doch eine nennenswerte Zeitersparnis.

Ein System mit "Write-Back"-Cache auf dem eine Software läuft die niemals wieder dieselben Daten verwendet und auch von der Ausführung her ohne Schleifen, eine lange Kette von Anweisungen durchläuft, wird sogar langsamer sein als ein System ohne Cache-Speicher. Aber Software ist von Natur aus auf Schleifen oder rekursive Funktionen und lokale Variablen oder Puffer aufgebaut und daher wird mit einem Write-Back-Cache ein guter Geschwindigkeitsvorteil erzielt.

Die Cache Architektur

Wie bereits erwähnt ist ein Cache-Speicher aus Kostengründen gegenüber dem eigentlichen Haupt- oder Arbeitsspeicher eher klein in Bezug auf dessen Speicherkapazität. Es würde ja auch keinen Sinn haben, den Cache genau so groß wie den Arbeitsspeicher zu planen, da der Arbeitsspeicher ja dann wegfallen könnte (entspricht einem System mit schnellem SRAM als Arbeitsspeicher). Da also immer nur ein kleiner Teil der Daten aus dem Hauptspeicher im Cache vorrätig sein kann, ist es die Hauptaufgabe des Cache-Controllers die Übersicht zu behalten, welche Speicherstellen (Adressen) des Hauptspeichers - gespiegelt im Cache-Speicher verfügbar sind.

Der Cache-Controller benötigt also neben dem eigentlichen Datenspeicher noch einen weiteren Speicher für eine "Look-up" Tabelle die die Zuordnung von externer Hauptspeicher-Adresse zu Cachespeicher-Adresse beinhaltet. Diese Tabelle muß darüber hinaus sehr schnell les-/schreibbar sein um Verzögerungen bei einen Datenzugriff zu vermeiden. Diesen Zusatzspeicher bezeichnet man auch als "Tag"-Speicher, warum werden wir später noch sehen.

Ein Cache besteht also nicht nur aus einem zusätzlichen schnellen Speicher sondern auch aus einem "Tag"-Speicher (für die Adress-Umsetzung und den eigentlichen Tags) und der Cache-Controller Logik.

Der Cache-Daten-Speicher

Ein Cache-Speicher, so würde man erwarten, hat die Datenbreite des Hauptspeichers und eine gewisse Tiefe (einige zehn- bzw. hundert Kilobyte) ist also der Busbreite des Prozessors angepaßt. Prinzipiell wäre ein solcher Cache möglich aber in der Praxis hat sich eine andere Speicherkonzeption angeboten und zwar aus folgendem Grund.

Cache-Speicher werden hauptsächlich im Zusammenhang mit DRAM´s (dynamische RAM Speicher) benützt um deren relativ langsame Zugriffszeiten zu umgehen. DRAM´s haben aber einen gemultiplexten Adress-Bus, der für jeden Zugriff auf eine Speicherstelle die Adresse dieser Speicherstelle in zwei aufeinander folgenden Schritten (Zeitmultiplex der niedriger-wertigen und der höher-wertigen Adressbits) im DRAM-Baustein "latched" (in einem Register abspeichert). Die DRAM-Architekturen wurden deshalb hinsichtlich ihres Zugriffs optimiert.

Im sogenannten Burst-Mode können diese Bausteine aufeinanderfolgende Adressen innerhalb einer Page (eine Page ist dadurch gekennzeichnet, daß sich nur die Adressbits ändern die wärend des CAS-Signales "gelatched" werden) wesentlich schneller ausgeben, weil ein Teil der Adresse nicht erneut geschrieben werden muß. In den meisten Fällen kann ein solcher Burst 4 nacheinanderfolgende Speicherstellen in etwa der halben Zeit die für  Einzelzugriffe benötigt wird, ausgeben.

Da die Speicherbreite heutiger Systeme mit Cache typisch 32 Bit beträgt (oder 64 Bit) und 4 aufeinanderfolgende Zugriffe also 4 Wörter a´ 32 Bit liefern, bietet sich eine Cache-Speicherbreite von 4 x 32 Bit = 128 Bit oder 16 Byte an. Man spricht dabei von einer "Cache-Line", weil ja mehr als ein Datenwort (als Beispiel, 32 Bit) an einer Cache Adresse gespeichert wird. Ein 2 kByte großer Cache-Speicher hätte dabei insgesamt 128 Cache-Lines mit jeweils 4 Worten (oder 16 Byte).

Die einzelnen Bytes einer Cache-Line sind dabei immer noch direkt der ursprünglichen Adresse (also den "4 least significant bits" der Adresse) zugeordnet, wobei die beiden "least significant bits" (niedrigwertigsten Bits = "Bit0" und "Bit1") weiterhin für die Auswahl eines Bytes innerhalb eines Datenwortes (32 Bit in diesem Fall) zuständig sind, während die beiden nächsthöheren Adress-bits ("Bit2" und "Bit3") ein Datenwort innerhalb einer Cache-Line ansprechen. Die Zuordnung jeder Cache-Line zur ursprünglichen Speicheradresse geschieht dabei durch das "Tagfield" das aber im Absatz "Der Tag Speicher" noch genauer beschrieben wird. Theoretisch ist auch jede andere Cache-Line Breite möglich und die Cache-Architektur ist nur von der Implementierung abhängig.

Ein weiterer Vorteil von Cache-Lines mit einer Breite von z.B. 16 Bytes ist die Reduzierung des Tag-Speichers, da nur eine Tag-Adresse und entsprechende Tags pro Cache-Line und nicht pro Datenwort benötigt wird. Das Optimum liegt also irgendwo im Bereich von 16 Byte, da größere Cache-Lines den Cache unflexibler machen würden und ein zusätzlicher Overhead durch das Nachladen vieler Bytes entstehen würde.

Da mehr Cache-Speicher die Leistungsfähigkeit eines Systems erhöht ging man den Weg, mehrere der oben beschriebenen Cache-Blöcke (128 lines à 16 Byte) parallel zu schalten, d.h. es entsteht ein Speichersystem mit mehreren Speicher-Bänken (Banks) oder "Ways" (Wege).

Nimmt man 4 Cache-Blöcke mit jeweils 2 kByte Speichergröße, entsteht ein 8 kByte großer "4-Bank Cache". Jeder dieser 4 Blöcke verhält sich identisch, jedoch werden die beiden Adressbits "Bit11" und "Bit12" dazu verwendet eine der vier möglichen Bänke zu selektieren. Wir können innerhalb eines solchen Systems also durch die 13 „least significant Bits" der ursprünglichen Adresse den gesamten Cache-Speicher „byte-weise“ adressieren.

Die zweite Möglichkeit besteht darin, die vier Bänke "gleich" zu behandeln also jede Cache-Line Adresse spricht alle vier Cache-Lines mit der gleichen Adresse in jeder Cache-Bank an, man spricht dann von einem "4-Way Cache".

Die Unterscheidung der 4 Lines erfolgt durch die 4 „Least Significant Bits“ der Adresse die im Tag-RAM im Adressfeld gespeichert wird. Es können also maximal 4 Cache-Lines mit identischen 11 LSB der Hauptspeicher-Adresse „gecached“ werden.

Nun eine solche "feste" Zuordnung wäre wenig Hilfreich, da wir damit nur 8 kByte eines Hauptspeichers von z.b. 64 Mbyte "beschleunigen" könnten. Es muß also eine Möglichkeit geschaffen werden eine "sinnvolle, variable" Zuordnung zwischen einer Cache-Line und einer Anzahl Bytes im Haupt- oder Arbeitsspeicher, herzustellen.

Der Tag-Speicher

Wie schon einmal kurz angesprochen, benötigt ein Cache-System einen zusätzlichen Speicher zur Zuordnung einer Cache-Line zu einer Hauptspeicher-Adresse. Diesen zusätzlichen Speicher bezeichnet man als "Tag-RAM".

Jeder Cache-Line wird ein zusätzlicher Speicher zugeordnet der die möglichen Adress-Bits des Systems (z.B. 32 Adress-Bits = 4 GByte) abzüglich der durch die Cache-Architektur festgelegten Adressbits (wie oben beschrieben "Bit0" bis "Bit12" bei 4 Cache-Bänken) plus weitere Bit-Felder (Tags) beinhalten kann.

Eine solche freie Zuordnung  zwischen der Systemadresse und der Tag-Adresse einer Cache-Line nennt man "fully associative" und ein solches Cache-System einen "Fully Associative Cache". Jede Cache-Line kann also beliebige 4 aufeinander folgende 32-Bit Worte aus dem Hauptspeicher aufnehmen. Der Nachteil eines „fully associative Cache“ ist der hohe Aufwand für den Adress-Vergleich während eines Schreib-/ Lese-Vorgangs, da alle Tag-Adressen gleichzeitig und ohne Zeitverlust überprüft werden müssen um einen Cache-Hit festzustellen.

Es gibt aber auch die Möglichkeit die Cache-Line-Adressen im Cache direkt einem Teil der Systemadresse zuzuordnen. D.h. in unserem Beispiel (128 Lines à 128 Bits) würden die Adressbits "Bit0" bis "Bit12" den Bits der Systemadresse entsprechen. Die Adressbits "Bit13" bis "Bit31" werden im Tag-RAM gespeichert. Bei dieser Zuordnung ergibt sich die Einschränkung, daß zur gleichen Zeit immer nur eine Systemadresse mit identischen Adressbits "Bit0" bis "Bit12" gespeichert werden kann. Soll eine neue Adresse mit den identischen Bits "gecached" werden so muß die vorhergehende Cache-Line überschrieben werden. Einen solchen Cache nennt man „Direct mapped Cache“ oder „1-Way Associative Cache". Der Vorteil liegt im geringeren Speicherbedarf des Tag-Speichers, da weniger Adressbits pro Cache-Line abgelegt werden müssen.

Um diese Einschränkung zu umgehen greift man auf das oben beschriebene "Banking" des Cache zurück. Man nimmt 4 Cache-Bänke mit identischen Cache-Line Adressen (4-Way Cache) die den System-Adressen direkt zugeordnet werden (wie bei einem 1-Way Assoviative Cache - "Bit0" bis "Bit10"). Damit werden mit den Adress-Bits "Bit0" bis "Bit10" vier mögliche Speicherstellen im Cache angesprochen. Die eindeutige Zuordnung erfolgt durch das Abspeichern eines Tags mit den fehlenden Adressbits ("Bit11" bis "Bit31") im Tag-Speicher einer der vier möglichen Cache-Lines. Eine solche Organsiation des Cache bezeichnet man als "4-Way-Associative Cache".

Der Tag-Speicher beinhaltet aber nicht nur Zuordnungs-Adressen sondern auch weitere wichtige Informationen bezüglich der Aktualität der in jeder Cache-Line gespeicherten Daten.

Erfolgt in einer Cache-Line ein aktueller Eintrag so muss sichergestellt sein, dass dieser Eintrag bei erneutem Schreiben/Lesen der gleichen Adresse berücksichtigt wird (Cache-Hit). Ein Bit per Cache-Line im Tag-RAM wird bei einigen Cache-Architekturen als "Valid-Bit" bezeichnet. Ist das Valid-Bit gesetzt wird die dazu gehörende "Tag-Adresse" vom Cache-Controller mit einer neuen Systemadresse verglichen falls ein neuer Schreib- oder Lesevorgang ansteht. Ist das Valid-Bit nicht gesetzt, ist die Cache-Line frei verfügbar und kann mit Daten gefüllt werden.

Speziell bei Caches die im "Write back" Mode arbeiten ist es unumgänglich die Daten vor dem Überschreiben mit einer neuen Cache-Line in den Haupt- oder Arbeitsspeicher zurückzuschreiben um die Daten Integrität zu gewährleisten. Dazu wird pro Cache-Line ein Bit im Tag-RAM breitgestellt, das "Dirty-Tag". Dieses Bit wird vom Cache-Controller gesetzt wenn der Prozessor nur in den Cache schreibt (in diesem Fall steht im Hauptspeicher noch die ursprüngliche Information). Soll nun eine Cache-Line überschrieben werden, prüft der Cache-Controller das "Dirty-Tag" und kopiert die Cache-Line erst in den Hauptspeicher zurück ehe er diese Speicherstelle mit einem neuen Inhalt überschreibt. Beim Zurückschreiben in den Hauptspeicher wird das "Dirty-Tag" automatisch zurückgesetzt, da ja die danach geschriebene neue Information zu diesem Zeitpunkt identisch ist mit der Information im Hauptspeicher.

Einige weitere Bits per Cache-Line werden vom Cache-Controller verwendet um die Auswahl, welche Cache-Line sinnvollerweise als nächstes überschrieben wird , zu optimieren.

Üblicherweise verwendet man dabei einen "Least Recently Used" Algorithmus, d.h. die Cache-Line die am Längsten nicht gebraucht (gelesen oder geschrieben) wurde wird als Nächstes überschrieben. Entsprechend werden diese Tag-Bits auch als "Least Recently Used Bits" oder "LRU-Bits" bezeichnet. Die Auswertung und das Aktualisieren der LRU-Bits wird vom Cache-Controller durchgeführt. "Least recently used" Algorithmen werden im Allgemeinen (und aus Kostengründen)  nur bei 4-Way Associative Caches verwendet, da bei "Fully Associative Caches" die nötige Anzahl der LRU-Bits (im Prinzip kann jede Cache-Line ersetzt werden, bei 4-Way Associative nur eine von vier) den Rahmen sprengen würde. Bei "Fully associative Caches" verwendet man einen "Zufalls-Algorithmus" um die nächste zu ersetzende Cache-Line auszuwählen.

Der Cache Controller

Ein Cache Controller ist ein komplexes System das eine Reihe verschiedener Aufgaben erfüllt:

Adressen Überwachung (Adress-Monitoring)

Die auf dem Prozessor-Bus (look through cache) oder dem System-Bus (look aside cache) auftretenden Adressen oder besser Speicheradressen (der Cache Controller behandelt keine I/O Adressen!) werden vom Cache Controller überprüft und mit den Einträgen im Tag-RAM (Adressfeld) verglichen. Dieser Vergleich soll ohne nennenswerte Verzögerung ablaufen und wird daher durch eine feste Logik mit allen "gültigen" (Valid-Bit) Adresseinträgen parallel durchgeführt. Die Entscheidung eines Cache-Hits oder eines Cache-Miss wird durch diesen Vergleich getroffen.

Speicher-Bus Beobachtung (Bus-Snooping)

Das Monitoring der Adressen beschränkt sich nicht nur auf einen vom Prozessor initiierten Adress-Zyklus. Sollte ein externer Bus-Master oder DMA-Controller ohne Zutun des Prozessors Daten in den Hauptspeicher schreiben, so muss der Cache Controller dieser Aktion entsprechend überwachen. Eine Änderung im Hauptspeicher muss vom Cache Controller erkannt werden und falls ein entsprechender Eintrag in einer Cache-Line existiert, muss das Valid-Bit dieser Cache-Line auf "non-valid " zurückgesetzt werden. D.h. beim nächsten Zugriff der CPU auf diese Adresse werden die Daten neu in den Cache geladen.

Ausschluss von Speicherbereichen aus dem Cache (None-cachable regions control)

In einigen Fällen kann es vorkommen, dass bestimmte Speicherbereiche nicht "ge-cached" werden sollen. Als Beispiel ist hier ein I/O-Device (memory mapped, als mit einer Speicherbus Adresse) zu nennen. Da sich die Daten an diesem Device ändern können ohne dass ein Bus-Zyklus durchgeführt wird, würde der Cache-Controller trotz Bus-Snooping dies nicht bemerken und immer dieselben Daten aus dem Cache liefern. Es besteht aber die Möglichkeit bestimmte Adressbereiche im gesamten Adressraum aus dem Cache-Vorgang auszuklammern.

Daten zwischen Cache und Hauptspeicher angleichen (Cache Fill Request)

Der Cache Controller arbeitet bei internen Caches sehr eng mit dem eigentlichen "Bus-Controller" für den DRAM-Speicherbus zusammen. Bei "Look-Through Caches " wird kein Bus-Zyklus zum DRAM durchgeführt, falls dies nicht nötig ist (Cache Hit). Falls aber ein Zugriff nötig wird (Cache Miss) fordert der Cache Controller vom Bus-Controller einen "Burst Read" an, der eine komplette Cache-Line füllt. Dies tritt natürlich auch bei Schreib-Operationen in den Hauptspeicher auf (Write-Back oder Write-Through) wobei auch hier eine komplette Cache-Line geschrieben wird (Burst Write).

Behandlung der Cache-TAG-Flags (TAG Update)

Der Cache Controller übernimmt ebenfalls die Aufgabe die Felder im Tag-RAM zu verwalten und zu aktualisieren. Er setzt oder löscht die Valid-Bits um eine Cache-Line als gültig oder ungültig zu markieren. Falls implementiert werden auch die "Dirty-Tags" vom Cache-Controller gehandhabt und die Auswertung im Falle eines Write-Back durchgeführt. Die LRU-Bits werden ebenfalls nach dem implementierten Algorithmus gesetzt bzw. ausgewertet.

Daten vom/zum Prozessor speichern/liefern (Data Content Management)

Der Cache Controller liefert letztendlich auch die nutzbaren Daten bei einem Cache-Hit (der eigentliche Sinn eines Caches) in möglichst kurzer Zeit bzw. schreibt die Daten in den Cache ohne nennenswerte Verzögerung.

Unified Caches

Die bisher beschriebenen Caches speichern alle Daten die über den Speicherbus angefordert werden im Cache-Speicher. Bei diesen Daten kann es sich dabei sowohl um Daten im eigentlichen Sinn, also um Variablen, Konstanten oder Strings handeln, als auch um Instruktionen für die CPU. Diese Art eines Caches wird als "Unified Cache" bezeichnet, da sowohl Daten als auch Instruktionen im selben Speicher ge-„cached“ werden. Demgegenüber steht eine Cache-Architektur die aus zwei unabhängigen Caches besteht. Man spricht von einem dedizierten "Data Cache" und einem "Instruction Cache" oder in den entsprechenden Abkürzungen von "D-Caches" oder "I-Caches".

Multi Level Caches

Leistungsfähige Computersysteme verwenden heute mehrere Cache-Level, d.h. üblicher-weise besitzt der Prozessor einen integrierten "First Level Cache" der größenordnungsmäßig im Bereich von 8 kByte bis 64 kByte liegt. Dieser Cache ist vom Prozessor gesehen nach außen hin transparent und ermöglicht so zwischen dem Prozessorbus und dem Speicherbus einen weiteren Cache extern zu implementieren. Dieser sogenannte "Second Level Cache" ist nur dann sinnvoll wenn er wesentlich größer als der "First Level Cache" ist. Übliche Größen für "Second Level Caches" sind heute 512 kByte bis zu 2 MByte, also durchaus in der Größe früherer Hauptspeicher. Auch der "Second Level Cache" ist nur sinnvoll wenn der  Hauptspeicher wesentlich größer ist (ca. 32 MByte bis einige GByte).

Viele Prozessor-Architekturen (zumindest 32 Bit und 64 Bit Prozessoren) besitzen heute einen integrierten "First Level Cache" und die meisten auch einen „Second Level Cache“. Die Eingangs genannten Fortschritte in der Halbleiter-Technologie werden eine weitere Erhöhung der Cache-Kapazitäten ermöglichen. Caches auf dem Prozessor-Chip haben den großen Vorteil, dass Zugriffe darauf ohne "Wait-States" erfolgen können und keine Input/Output-Buffer (Pad-Treiber) unnötige Verzögerungszeiten verursachen. Die Limitierung der On-Chip-Cache Größe liegt wie bei SRAM´s (nichts anderes ist ein Cache Speicher) in der Silizium-Fläche und damit bei den Kosten.

Cache Integrität bei Multi Prozessor Systemen

Da Caches und insbesondere Caches die im "Write Back" Modus betrieben werden, zeitweise unterschiedliche Daten im Cache und im Hauptspeicher aufweisen, sind bei Multiprozessor Systemen spezielle Vorkehrungen zu treffen. Mehr-Prozessor Systeme kommunizieren über gemeinsame Datenbereiche und es muss sichergestellt sein, dass die Integrität der Daten gewährleistet wird. Cache-Controller die einen Multi-Prozessor Betrieb unterstützen stellen deshalb weitere Tags im Tag-Speicher bzw. im Translation-Look-Aside Buffer (TLB) der Memory Management Unit zur Verfügung (letzteres nur auf einer per-Page Basis). Die Daten im Cache können neben den schon erwähnten Valid-Tag oder Dirty-Tag noch mit weiteren Tags, also weiteren Cache-Line Zuständen (States) gekennzeichnet werden.

So können Daten einer Cache-Line als "exclusive" oder als "shared" gekennzeichnet werden. Eine Cache-Line aus einer Page bei der das "Exclusive-Attribut" gesetzt ist, kann von einem Prozessor über einen "Coherent Block Read Request" angefordert werden und steht dann dem Prozessor solange "exclusive" zur Verfügung bis die Cache-Line zurückgeschrieben wird. Ist das "Shareable-Attribut" gesetzt sind die Daten in der zugeordneten Cache-Line auch für andere Prozessoren zugänglich, die Daten können also in verschiedenen Caches auch verschiedener Prozessoren gleichzeitig vorhanden sein und der Cache-Controller muss für die Daten-Kohärenz Sorge tragen. Für solche Multiprozessor Systeme wurde in den entsprechenden Cache-Controllern/Prozessoren ein eigenes "Cache Coherency Protocol" implementiert, das eine genaue Einhaltung der Schreib-/Lesezugriffe und deren Ordnung gewährleistet, diesen Vorgang bezeichnet man als "Strong Ordering". Neben den oben genannten Attributen werden noch weitere, wie "Noncacheable-Attribut", "Noncoherent-Attribut", "Update-Attribut" , "Write Through Attribut" und/oder "Guarded Memory Attribut" in verschiedenen Hardware-Implementierungen verwendet.

Multi-Prozessor-fähige Prozessoren stellen auch eigene Instruktionen zur Verfügung um den Cache gegebenenfalls zu einer erzwungenen Aktion (z.B das Rückspeichern einer Cache-Line) zu bewegen.

Cache Konzepte

Das Konzept eines Caches kann grundsätzlich auf alle Arten von langsamen Speichern übertragen werden. Langsame Massenspeicher wie Festplatten oder CD-ROM Laufwerke besitzen eigene Hardware-Caches (ebenfalls SRAM)  im Bereich von einigen hundert Kilo-Bytes bis einigen Mega-Bytes um die Latenzzeit dieser Systeme zu umgehen. Der Ursprung geht dabei auf die Idee der "RAM-Disk" zurück. Ein Teil des Arbeitsspeichers des Systems wurde als Disk-Cache eingerichtet um Zugriffe auf Floppy-Laufwerke oder langsame Harddisks zu beschleunigen.

Der Begriff Cache wird auch im zunehmenden Maße mit der Benutzung des Internets verwendet. Hier werden die doch eher langsamen Zugriffe auf einzelne Web-Server auf der Festplatte ge-„cached". Will man eine zuvor bereits aufgerufene Internet-Seite wieder ansehen, so wird diese nicht noch einmal aus dem Netz geladen sondern aus einem vom Browser verwalteteten "Zwischenspeicher" von der doch wesentlich schnelleren Harddisk geholt.

Literatur Hinweise

[1] The T9000 Transputer Hardware Reference Manual, STMicroelectronics,1993

[2] 80486 System Architecture, Third Edition, Tom Shanley, 1995

[3] MIPS4000 Microprocessors Users Manual, Second Edition, Joe Heinrich,1994

[4] Power PC 740/750 Microprocessor User’s Manual, IBM Microelectronic, 1999

Copyright Notiz

( Copyright Dipl.Ing.(FH) Franz Henkel  / 19.6.2015 )

Dieses Dokument sowie dessen Inhalt, insbesondere Texte, Fotografien und Grafiken, unterliegt dem Copyright (© 2015) und sind nur mit einer schriftlicher Zustimmung des Autors, Dipl.Ing.(FH) Franz Henkel zur vollständigen oder auszugsweisen Weiterverwendung in Form einer gedruckten oder elektronischen Kopie oder Replikation bzw. einer vollständigen oder auszugsweisen Bereitstellung des Inhalts in schriftlicher, gedruckter oder elektronischer Form, zu verwenden.