CPU-Cache - CPU cache

Ein CPU-Cache ist ein Hardware-Cache, der von der Zentraleinheit (CPU) eines Computers verwendet wird , um die durchschnittlichen Kosten (Zeit oder Energie) für den Zugriff auf Daten aus dem Hauptspeicher zu reduzieren . Ein Cache ist ein kleinerer, schnellerer Speicher, der sich näher an einem Prozessorkern befindet und der Kopien der Daten von häufig verwendeten Hauptspeicherorten speichert . Die meisten CPUs haben eine Hierarchie von mehreren Cache- Ebenen (L1, L2, oft L3 und selten sogar L4), mit separaten befehlsspezifischen und datenspezifischen Caches auf Ebene 1.

Es gibt andere Arten von Caches (die nicht auf die "Cache-Größe" der oben genannten wichtigsten Caches angerechnet werden), wie beispielsweise der Translation Lookaside Buffer (TLB), der Teil der Memory Management Unit (MMU) ist, die die meisten CPUs haben.

Überblick

Beim Versuch, von einer Stelle im Hauptspeicher zu lesen oder zu schreiben, prüft der Prozessor, ob sich die Daten von dieser Stelle bereits im Cache befinden. Wenn dies der Fall ist, liest oder schreibt der Prozessor aus dem Cache anstelle des viel langsameren Hauptspeichers.

Die meisten modernen Desktop- und Server- CPUs verfügen über mindestens drei unabhängige Caches: einen Befehlscache zum Beschleunigen des Abrufs ausführbarer Befehle, einen Datencache zum schnelleren Abrufen und Speichern von Daten und einen Übersetzungs-Lookaside-Puffer (TLB) zum Beschleunigen von Virtual-to- physische Adressübersetzung sowohl für ausführbare Befehle als auch für Daten. Ein einzelner TLB kann für den Zugriff sowohl auf Befehle als auch auf Daten bereitgestellt werden, oder es können ein separater Befehls-TLB (ITLB) und Daten-TLB (DTLB) bereitgestellt werden. Der Datencache ist normalerweise als Hierarchie mehrerer Cache-Ebenen organisiert (L1, L2 usw.; siehe auch Multi-Level-Caches weiter unten). Der TLB-Cache ist jedoch Teil der Speicherverwaltungseinheit (MMU) und nicht direkt mit den CPU-Caches verbunden.

Geschichte

Motherboard eines NeXTcube- Computers (1990). Am unteren Bildrand links von der Mitte befindet sich die mit 25 MHz betriebene CPU Motorola 68040 mit zwei separaten Level-1-Caches von je 4 KiB auf dem Chip, einer für den CPU-Teil und einer für die integrierte FPU , und nein externer Cache.

Die ersten CPUs, die einen Cache verwendeten, hatten nur eine Cache-Ebene; im Gegensatz zu einem späteren Cache der Ebene 1 wurde er nicht in L1d (für Daten) und L1i (für Anweisungen) aufgeteilt. Geteilter L1-Cache begann 1976 mit der IBM 801- CPU, wurde Ende der 80er Jahre zum Mainstream und trat 1997 mit dem ARMv5TE in den Embedded-CPU-Markt ein. Im Jahr 2015 teilten sogar Sub-Dollar-SoC den L1-Cache. Sie haben auch L2-Caches und bei größeren Prozessoren auch L3-Caches. Der L2-Cache ist normalerweise nicht geteilt und fungiert als gemeinsames Repository für den bereits geteilten L1-Cache. Jeder Kern eines Mehrkernprozessors verfügt über einen dedizierten L1-Cache und wird normalerweise nicht zwischen den Kernen geteilt. Der L2-Cache und Caches höherer Ebene können von den Kernen gemeinsam genutzt werden. L4 - Cache momentan ungewöhnlich ist, und ist im allgemeinen auf (eine Form von) Dynamic Random Access Memory (DRAM), anstatt sich auf einen statischen Direktzugriffsspeicher (SRAM), auf einem separaten Chip oder Chip (ausnahmsweise die Form, eDRAM ist wird für alle Cache-Ebenen verwendet, bis hinunter zu L1). Das war in der Vergangenheit auch bei L1 der Fall, während größere Chips die Integration von L1 und generell allen Cache-Ebenen, mit Ausnahme der letzten Ebene, ermöglicht haben. Jede zusätzliche Cache-Ebene ist tendenziell größer und anders optimiert.

Caches (wie in der Vergangenheit für RAM) wurden im Allgemeinen in Potenzen von 2, 4, 8, 16 usw. dimensioniert. KiB ; bei bis zu MiB- Größen (dh für größere Nicht-L1) brach das Muster sehr früh zusammen, um größere Caches zu ermöglichen, ohne in das Verdoppelungs-Paradigma gezwungen zu werden, mit z. B. Intel Core 2 Duo mit 3 MiB L2-Cache später 2008. Vieles jedoch für L1 Größen im April, dass nach wie vor nur in geringer Anzahl von KiB zählt jedoch IBM zEC12 ab 2012 ist eine Ausnahme, zu gewinnen ungewöhnlich große 96 KiB L1 - Daten - Cache - Speicher für seine Zeit, und zB des IBM z13 mit einem 96 KiB L1-Befehlscache (und 128 KiB L1-Datencache) und Intel Ice Lake- basierte Prozessoren aus dem Jahr 2018 mit 48 KiB L1-Daten-Cache und 48 KiB L1-Befehlscache. Im Jahr 2020 haben einige Intel Atom- CPUs (mit bis zu 24 Kernen) (ein Vielfaches von) 4,5 MiB und 15 MiB Cache-Größen.

Cache-Einträge

Daten werden zwischen Speicher und Cache in Blöcken fester Größe übertragen, die als Cache-Lines oder Cache-Blöcke bezeichnet werden . Wenn eine Cache-Zeile aus dem Speicher in den Cache kopiert wird, wird ein Cache-Eintrag erzeugt. Der Cache-Eintrag enthält die kopierten Daten sowie den angeforderten Speicherplatz (als Tag bezeichnet).

Wenn der Prozessor eine Speicherstelle lesen oder schreiben muss, prüft er zuerst, ob ein entsprechender Eintrag im Cache vorhanden ist. Der Cache prüft den Inhalt der angeforderten Speicherstelle in allen Cache-Zeilen, die diese Adresse enthalten könnten. Wenn der Prozessor feststellt, dass sich die Speicherstelle im Cache befindet, ist ein Cache-Treffer aufgetreten. Wenn der Prozessor jedoch die Speicherstelle im Cache nicht findet, ist ein Cache-Fehltreffer aufgetreten. Bei einem Cache-Treffer liest oder schreibt der Prozessor sofort die Daten in die Cache-Zeile. Bei einem Cache-Miss ordnet der Cache einen neuen Eintrag zu und kopiert Daten aus dem Hauptspeicher, dann wird die Anforderung vom Inhalt des Cache erfüllt.

Richtlinien

Ersatzrichtlinien

Um bei einem Cache-Fehltreffer Platz für den neuen Eintrag zu schaffen, muss der Cache möglicherweise einen der vorhandenen Einträge räumen. Die Heuristik, die verwendet wird, um den zu entfernenden Eintrag auszuwählen, wird als Ersetzungsrichtlinie bezeichnet. Das grundlegende Problem bei jeder Ersetzungsrichtlinie besteht darin, dass sie vorhersagen muss, welcher vorhandene Cache-Eintrag in Zukunft am wenigsten wahrscheinlich verwendet wird. Die Zukunft vorherzusagen ist schwierig, daher gibt es keine perfekte Methode, um aus der Vielzahl der verfügbaren Ersatzversicherungen auszuwählen. Eine beliebte Ersetzungsrichtlinie, am wenigsten zuletzt verwendet (LRU), ersetzt den Eintrag, auf den am wenigsten kürzlich zugegriffen wurde.

Das Markieren einiger Speicherbereiche als nicht zwischenspeicherbar kann die Leistung verbessern, indem das Zwischenspeichern von Speicherbereichen vermieden wird, auf die selten erneut zugegriffen wird. Dies vermeidet den Aufwand, etwas in den Cache zu laden, ohne dass es wiederverwendet werden muss. Cache-Einträge können je nach Kontext auch deaktiviert oder gesperrt werden.

Richtlinien schreiben

Wenn Daten in den Cache geschrieben werden, müssen sie irgendwann auch in den Hauptspeicher geschrieben werden; das Timing dieses Schreibvorgangs wird als Schreibrichtlinie bezeichnet. In einem Write-Through- Cache verursacht jeder Schreibvorgang in den Cache einen Schreibvorgang in den Hauptspeicher. Alternativ werden in einem Write-Back- oder Copy-Back-Cache Schreibvorgänge nicht sofort in den Hauptspeicher gespiegelt, und der Cache verfolgt stattdessen, welche Stellen überschrieben wurden, und markiert sie als schmutzig . Die Daten an diesen Stellen werden nur dann in den Hauptspeicher zurückgeschrieben, wenn diese Daten aus dem Cache entfernt werden. Aus diesem Grund kann ein Read-Miss in einem Write-Back-Cache manchmal zwei Speicherzugriffe zur Bedienung erfordern: einen, um zuerst die schmutzige Stelle in den Hauptspeicher zu schreiben, und dann einen weiteren, um die neue Stelle aus dem Speicher zu lesen. Außerdem kann ein Schreiben in einen Hauptspeicherort, der noch nicht in einem Write-Back-Cache abgebildet ist, einen bereits schmutzigen Ort verdrängen, wodurch dieser Cache-Speicherplatz für den neuen Speicherort freigegeben wird.

Es gibt auch Zwischenpolitiken. Der Cache kann ein Durchschreiben sein, aber die Schreibvorgänge können vorübergehend in einer Speicherdatenwarteschlange gehalten werden, normalerweise damit mehrere Speichervorgänge zusammen verarbeitet werden können (was Busumkehrungen reduzieren und die Busauslastung verbessern kann).

Zwischengespeicherte Daten aus dem Hauptspeicher können von anderen Einheiten geändert werden (z. B. Peripheriegeräte, die direkten Speicherzugriff (DMA) verwenden, oder einen anderen Kern in einem Mehrkernprozessor ). In diesem Fall kann die Kopie im Cache veraltet sein oder altbacken. Wenn alternativ eine CPU in einem Multiprozessorsystem Daten im Cache aktualisiert, werden Kopien von Daten in Caches, die anderen CPUs zugeordnet sind, veraltet. Kommunikationsprotokolle zwischen den Cache-Managern, die die Daten konsistent halten, werden als Cache-Kohärenzprotokolle bezeichnet .

Cache-Leistung

Die Messung der Cacheleistung ist in letzter Zeit wichtig geworden, da die Geschwindigkeitslücke zwischen der Speicherleistung und der Prozessorleistung exponentiell zunimmt. Der Cache wurde eingeführt, um diese Geschwindigkeitslücke zu verringern. Daher ist es gerade bei Hochleistungssystemen wichtig zu wissen, wie gut der Cache die Geschwindigkeitslücke von Prozessor und Speicher überbrücken kann. Die Cache-Hit-Rate und die Cache-Miss-Rate spielen eine wichtige Rolle bei der Bestimmung dieser Leistung. Um die Cache-Leistung zu verbessern, wird die Reduzierung der Fehltrefferrate neben anderen Schritten zu einem der notwendigen Schritte. Eine Verringerung der Zugriffszeit auf den Cache erhöht auch die Leistung.

CPU-Störungen

Die Zeit, die benötigt wird, um eine Cache-Zeile aus dem Speicher zu holen ( Leselatenz aufgrund eines Cache-Fehltreffers), ist von Bedeutung, da der CPU die Aufgaben ausgehen, während sie auf die Cache-Zeile warten. Wenn eine CPU diesen Zustand erreicht, wird dies als Stillstand bezeichnet. Da CPUs im Vergleich zum Hauptspeicher schneller werden, verdrängen Blockierungen aufgrund von Cache-Fehltreffern mehr potenzielle Berechnungen; Moderne CPUs können Hunderte von Befehlen in der Zeit ausführen, die benötigt wird, um eine einzelne Cache-Zeile aus dem Hauptspeicher zu holen.

Es wurden verschiedene Techniken verwendet, um die CPU während dieser Zeit beschäftigt zu halten, einschließlich einer Ausführung außerhalb der Reihenfolge, bei der die CPU versucht, unabhängige Befehle nach dem Befehl auszuführen, der auf die Cache-Fehltrefferdaten wartet. Eine andere Technologie, die von vielen Prozessoren verwendet wird, ist simultanes Multithreading (SMT), das es einem alternativen Thread ermöglicht, den CPU-Kern zu verwenden, während der erste Thread darauf wartet, dass die erforderlichen CPU-Ressourcen verfügbar werden.

Assoziativität

Eine Illustration verschiedener Möglichkeiten, wie Speicherorte von bestimmten Cache-Speicherorten zwischengespeichert werden können

Die Platzierungsrichtlinie entscheidet, wohin im Cache eine Kopie eines bestimmten Eintrags des Hauptspeichers verschoben wird. Wenn die Platzierungsrichtlinie einen beliebigen Eintrag im Cache zum Speichern der Kopie frei wählen kann, wird der Cache als vollständig assoziativ bezeichnet . Im anderen Extremfall, wenn jeder Eintrag im Hauptspeicher nur an einer Stelle im Cache abgelegt werden kann, wird der Cache direkt abgebildet . Viele Caches implementieren einen Kompromiss, bei dem jeder Eintrag im Hauptspeicher zu jedem von N Plätzen im Cache gehen kann und werden als N-Wege-Set-assoziativ beschrieben. Zum Beispiel ist der Level-1-Datencache in einem AMD Athlon bidirektional satzassoziativ , was bedeutet, dass jeder bestimmte Ort im Hauptspeicher an einem von zwei Orten im Level-1-Datencache zwischengespeichert werden kann.

Die Wahl des richtigen Wertes der Assoziativität erfordert einen Kompromiss . Wenn es zehn Orte gibt, denen die Platzierungsrichtlinie einen Speicherort hätte zuordnen können, müssen zehn Cache-Einträge durchsucht werden, um zu überprüfen, ob dieser Ort im Cache ist. Das Überprüfen von mehr Stellen erfordert mehr Leistung und Chipfläche und möglicherweise mehr Zeit. Auf der anderen Seite erleiden Caches mit mehr Assoziativität weniger Misses (siehe Konflikt-Miss, unten), sodass die CPU weniger Zeit mit dem Lesen aus dem langsamen Hauptspeicher verschwendet. Als allgemeine Richtlinie gilt, dass eine Verdoppelung der Assoziativität, von direkt abgebildet auf Zweiwege oder von Zweiwege auf Vierwege, ungefähr den gleichen Effekt auf die Erhöhung der Trefferquote hat wie eine Verdoppelung der Cachegröße. Eine Erhöhung der Assoziativität um mehr als vier verbessert jedoch die Trefferrate nicht so sehr und wird im Allgemeinen aus anderen Gründen durchgeführt (siehe virtuelles Aliasing unten). Einige CPUs können die Assoziativität ihrer Caches in Energiesparzuständen dynamisch reduzieren, was als Energiesparmaßnahme dient.

Von schlechter aber einfach zu besser aber komplex geordnet:

  • Direkt zugeordneter Cache – gute Best-Case-Zeit, aber unvorhersehbar im schlimmsten Fall
  • Zwei-Wege-Satz-assoziativer Cache
  • Zweifach verzerrter assoziativer Cache
  • Assoziativer 4-Wege-Cache
  • Acht-Wege-Satz-assoziativer Cache, eine häufige Wahl für spätere Implementierungen
  • 12-Wege-Satz-Assoziativ-Cache, ähnlich wie Acht-Wege
  • Vollassoziativer Cache – die besten Missraten, aber nur für eine kleine Anzahl von Einträgen praktisch

Direkt zugeordneter Cache

In dieser Cache-Organisation kann jede Stelle im Hauptspeicher nur in einen Eintrag im Cache gehen. Daher kann ein direkt abgebildeter Cache auch als "unidirektionaler satzassoziativer" Cache bezeichnet werden. Es hat keine Platzierungsrichtlinie als solche, da es keine Wahl gibt, welcher Inhalt des Cache-Eintrags entfernt werden soll. Das bedeutet, dass, wenn zwei Orte demselben Eintrag zugeordnet sind, sie sich ständig gegenseitig ausknocken können. Obwohl es einfacher ist, muss ein direkt abgebildeter Cache viel größer sein als ein assoziativer, um eine vergleichbare Leistung zu erzielen, und er ist unvorhersehbarer. Sei x die Blocknummer im Cache, y die Blocknummer des Speichers und n die Anzahl der Blöcke im Cache, dann erfolgt die Abbildung mit Hilfe der Gleichung x = y mod n .

Zwei-Wege-Satz-assoziativer Cache

Wenn jeder Ort im Hauptspeicher an einem von zwei Orten im Cache zwischengespeichert werden kann, lautet eine logische Frage: Welcher der beiden? Das einfachste und am häufigsten verwendete Schema, das in der rechten Abbildung oben gezeigt ist, besteht darin, die niedrigstwertigen Bits des Index der Speicherstelle als Index für den Cache-Speicher zu verwenden und zwei Einträge für jeden Index zu haben. Ein Vorteil dieses Schemas besteht darin, dass die im Cache gespeicherten Tags nicht den Teil der Hauptspeicheradresse enthalten müssen, der durch den Index des Cache-Speichers impliziert wird. Da die Cache-Tags weniger Bits haben, benötigen sie weniger Transistoren, nehmen weniger Platz auf der Prozessorplatine oder auf dem Mikroprozessorchip ein und können schneller gelesen und verglichen werden. Auch LRU ist besonders einfach, da für jedes Paar nur ein Bit gespeichert werden muss.

Spekulative Ausführung

Einer der Vorteile eines direkt abgebildeten Caches besteht darin, dass er eine einfache und schnelle Spekulation ermöglicht . Sobald die Adresse berechnet wurde, ist der eine Cache-Index bekannt, der eine Kopie dieser Stelle im Speicher haben könnte. Dieser Cache-Eintrag kann gelesen werden, und der Prozessor kann mit diesen Daten weiterarbeiten, bevor er die Überprüfung beendet, ob das Etikett tatsächlich mit der angeforderten Adresse übereinstimmt.

Die Idee, dass der Prozessor die zwischengespeicherten Daten verwendet, bevor die Tag-Übereinstimmung abgeschlossen ist, kann auch auf assoziative Caches angewendet werden. Eine Teilmenge des Tags, die als Hint bezeichnet wird , kann verwendet werden, um nur einen der möglichen Cache-Einträge auszuwählen, die der angeforderten Adresse zugeordnet sind. Der durch den Hinweis ausgewählte Eintrag kann dann parallel zur Überprüfung des vollständigen Tags verwendet werden. Die Hinweistechnik funktioniert am besten, wenn sie im Kontext der Adressübersetzung verwendet wird, wie unten erläutert.

Zweifach verzerrter assoziativer Cache

Andere Schemata wurden vorgeschlagen, wie zum Beispiel der verzerrte Cache , bei dem der Index für Weg 0 direkt ist, wie oben, aber der Index für Weg 1 wird mit einer Hash-Funktion gebildet . Eine gute Hash-Funktion hat die Eigenschaft, dass Adressen, die mit der direkten Zuordnung in Konflikt stehen, bei der Zuordnung mit der Hash-Funktion nicht zu Konflikten neigen, so dass es weniger wahrscheinlich ist, dass ein Programm aufgrund eines pathologischen Zugriffs unter unerwartet vielen Konflikt-Fehltreffern leidet Muster. Der Nachteil ist die zusätzliche Latenz durch die Berechnung der Hash-Funktion. Wenn es an der Zeit ist, eine neue Zeile zu laden und eine alte Zeile zu entfernen, kann es außerdem schwierig sein, festzustellen, welche vorhandene Zeile zuletzt am wenigsten verwendet wurde, da die neue Zeile in jeder Hinsicht mit Daten an unterschiedlichen Indizes in Konflikt steht; Das LRU- Tracking für nicht verzerrte Caches erfolgt normalerweise pro Satz. Nichtsdestotrotz haben schief-assoziative Caches große Vorteile gegenüber herkömmlichen mengenassoziativen Caches.

Pseudo-assoziativer Cache

Ein echter satzassoziativer Cache testet alle möglichen Wege gleichzeitig und verwendet so etwas wie einen inhaltsadressierbaren Speicher . Ein pseudo-assoziativer Cache testet jeden möglichen Weg nacheinander. Ein Hash-Rehash-Cache und ein spalten-assoziativer Cache sind Beispiele für einen pseudo-assoziativen Cache.

Im allgemeinen Fall des Findens eines Treffers auf die erste getestete Weise ist ein pseudo-assoziativer Cache so schnell wie ein direkt abgebildeter Cache, aber er hat eine viel niedrigere Konflikt-Miss-Rate als ein direkt abgebildeter Cache, näher an der Miss-Rate eines voll assoziativen Caches.

Cache-Eintragsstruktur

Cache-Zeileneinträge haben normalerweise die folgende Struktur:

Schild Datenblock Flag-Bits

Der Datenblock (Cache-Zeile) enthält die eigentlichen Daten, die aus dem Hauptspeicher geholt werden. Das Tag enthält (einen Teil davon) die Adresse der eigentlichen Daten, die aus dem Hauptspeicher geholt wurden. Die Flag-Bits werden unten diskutiert .

Die "Größe" des Cache ist die Menge der Hauptspeicherdaten, die er aufnehmen kann. Diese Größe kann berechnet werden als die Anzahl der in jedem Datenblock gespeicherten Bytes mal der Anzahl der im Cache gespeicherten Blöcke. (Die Tag-, Flag- und Fehlerkorrekturcode- Bits sind nicht in der Größe enthalten, obwohl sie den physischen Bereich eines Caches beeinflussen.)

Eine effektive Speicheradresse, die mit der Cachezeile (Speicherblock) einhergeht , wird aufgeteilt ( MSB zu LSB ) in das Tag, den Index und den Blockoffset.

Schild Index Blockversatz

Der Index beschreibt, in welchem ​​Cache-Set die Daten abgelegt wurden. Die Indexlänge beträgt Bits für s Cache-Sets.

Der Block-Offset spezifiziert die gewünschten Daten innerhalb des gespeicherten Datenblocks innerhalb der Cache-Zeile. Normalerweise ist die effektive Adresse in Bytes angegeben, sodass die Block-Offset-Länge Bits beträgt , wobei b die Anzahl der Bytes pro Datenblock ist. Das Tag enthält die höchstwertigen Bits der Adresse, die mit allen Zeilen im aktuellen Satz (der Satz wurde durch den Index abgerufen) verglichen wird, um zu sehen, ob dieser Satz die angeforderte Adresse enthält. Wenn dies der Fall ist, tritt ein Cache-Treffer auf. Die Tag-Länge in Bit ist wie folgt:

tag_length = address_length - index_length - block_offset_length

Einige Autoren bezeichnen den Block-Offset einfach als "Offset" oder "Displacement".

Beispiel

Der ursprüngliche Pentium 4- Prozessor hatte einen 4-Wege-Set-assoziativen L1-Daten-Cache von 8  KiB Größe mit 64-Byte-Cache-Blöcken. Somit gibt es 8 KiB / 64 = 128 Cache-Blöcke. Die Anzahl der Sätze ist gleich der Anzahl der Cache-Blöcke dividiert durch die Anzahl der Assoziativitätswege, was zu 128/4 = 32 Sätzen und somit zu 2 5  = 32 verschiedenen Indizes führt. Es gibt 2 6  = 64 mögliche Offsets. Da die CPU-Adresse 32 Bit breit ist, bedeutet dies 32 - 5 - 6 = 21 Bit für das Tag-Feld.

Der ursprüngliche Pentium-4-Prozessor hatte auch einen acht-Wege-Satz-assoziativen L2-integrierten Cache mit einer Größe von 256 KiB und 128-Byte-Cache-Blöcken. Dies impliziert 32 – 8 – 7 = 17 Bits für das Tag-Feld.

Flag-Bits

Ein Befehlscache erfordert nur ein Flagbit pro Cachezeileneintrag: ein gültiges Bit. Das Valid-Bit zeigt an, ob ein Cache-Block mit gültigen Daten geladen wurde oder nicht.

Beim Einschalten setzt die Hardware alle gültigen Bits in allen Caches auf "ungültig". Einige Systeme setzen ein gültiges Bit auch zu anderen Zeiten auf "ungültig", beispielsweise wenn Multi-Master- Bus-Snooping- Hardware im Cache eines Prozessors eine Adressübertragung von einem anderen Prozessor hört und erkennt, dass bestimmte Datenblöcke im lokalen Cache jetzt veraltet und sollte als ungültig markiert werden.

Ein Daten-Cache erfordert typischerweise zwei Flag-Bits pro Cache-Zeile – ein gültiges Bit und ein schmutziges Bit . Ein gesetztes Dirty-Bit zeigt an, dass die zugehörige Cache-Zeile geändert wurde, seit sie aus dem Hauptspeicher gelesen wurde ("dirty"), was bedeutet, dass der Prozessor Daten in diese Zeile geschrieben hat und der neue Wert sich nicht bis zum Hauptspeicher ausgebreitet hat .

Cache-Fehltreffer

Ein Cache-Miss ist ein fehlgeschlagener Versuch, ein Datenelement in den Cache zu lesen oder zu schreiben, was zu einem Hauptspeicherzugriff mit viel längerer Latenz führt. Es gibt drei Arten von Cache-Fehlschlägen: Befehlslesefehler, Datenlesefehler und Datenschreibfehler.

Cache - Lesefehltreffer von einem Befehlscache im allgemeinen die größte Verzögerung verursachen, weil der Prozessor, oder zumindest der Ausführungs - Thread , muss warten (Stall) , bis der Befehl aus dem Hauptspeicher geholt wird. Cache-Lesefehler von einem Daten- Cache verursachen normalerweise eine kleinere Verzögerung, da Befehle, die nicht vom Cache-Lesevorgang abhängig sind, ausgegeben werden und die Ausführung fortsetzen können, bis die Daten aus dem Hauptspeicher zurückgegeben werden und die abhängigen Befehle die Ausführung wieder aufnehmen können. Cache-Schreibfehler in einen Daten- Cache verursachen im Allgemeinen die kürzeste Verzögerung, da das Schreiben in eine Warteschlange gestellt werden kann und es wenige Einschränkungen bei der Ausführung nachfolgender Befehle gibt; der Prozessor kann fortfahren, bis die Warteschlange voll ist. Eine detaillierte Einführung in die Arten von Fehltreffern finden Sie unter Cache-Leistungsmessung und Metrik .

Adressübersetzung

Die meisten Allzweck-CPUs implementieren irgendeine Form von virtuellem Speicher . Zusammenfassend sieht entweder jedes auf der Maschine laufende Programm seinen eigenen vereinfachten Adressraum , der nur Code und Daten für dieses Programm enthält, oder alle Programme laufen in einem gemeinsamen virtuellen Adressraum. Ein Programm wird durch Berechnen, Vergleichen, Lesen und Beschreiben von Adressen seines virtuellen Adressraums ausgeführt, anstatt von Adressen des physischen Adressraums, wodurch Programme einfacher und somit leichter zu schreiben sind.

Der virtuelle Speicher erfordert, dass der Prozessor vom Programm erzeugte virtuelle Adressen in physikalische Adressen im Hauptspeicher übersetzt. Der Teil des Prozessors, der diese Übersetzung durchführt, wird als Speicherverwaltungseinheit (MMU) bezeichnet. Der schnelle Pfad durch die MMU kann jene Übersetzungen ausführen, die im Übersetzungs-Lookaside-Puffer (TLB) gespeichert sind , der ein Cache von Abbildungen aus der Seitentabelle , der Segmenttabelle des Betriebssystems oder beiden ist.

Für die Zwecke der vorliegenden Diskussion gibt es drei wichtige Merkmale der Adressübersetzung:

  • Latenz: Die physikalische Adresse ist einige Zeit, vielleicht einige Zyklen, von der MMU verfügbar, nachdem die virtuelle Adresse vom Adressgenerator verfügbar ist.
  • Aliasing: Mehrere virtuelle Adressen können einer einzelnen physischen Adresse zugeordnet werden. Die meisten Prozessoren garantieren, dass alle Aktualisierungen an dieser einzelnen physischen Adresse in der Programmreihenfolge erfolgen. Um diese Garantie zu erfüllen, muss der Prozessor sicherstellen, dass sich zu jedem Zeitpunkt nur eine Kopie einer physischen Adresse im Cache befindet.
  • Granularität: Der virtuelle Adressraum wird in Seiten aufgeteilt. Beispielsweise könnte ein virtueller Adressraum von 4  GiB in 1.048.576 Seiten mit einer Größe von 4 KiB zerschnitten werden, von denen jede unabhängig zugeordnet werden kann. Es können mehrere Seitengrößen unterstützt werden; siehe virtueller Speicher für die Ausarbeitung.

Einige frühe virtuelle Speichersysteme waren sehr langsam, weil sie vor jedem programmierten Zugriff auf den Hauptspeicher einen Zugriff auf die (im Hauptspeicher gehaltene) Seitentabelle erforderten. Ohne Caches reduziert dies die Geschwindigkeit des Speicherzugriffs effektiv um die Hälfte. Der erste in einem Computersystem verwendete Hardware-Cache war eigentlich kein Daten- oder Befehls-Cache, sondern eher ein TLB.

Caches können in vier Typen unterteilt werden, je nachdem, ob der Index oder das Tag physischen oder virtuellen Adressen entspricht:

  • Physikalisch indizierte, physikalisch gekennzeichnete (PIPT) Caches verwenden die physikalische Adresse sowohl für den Index als auch für das Tag. Dies ist zwar einfach und vermeidet Aliasing-Probleme, ist aber auch langsam, da die physikalische Adresse nachgeschlagen werden muss (was einen TLB-Fehltreffer und Zugriff auf den Hauptspeicher beinhalten könnte), bevor diese Adresse im Cache nachgeschlagen werden kann.
  • Virtuell indizierte, virtuell gekennzeichnete (VIVT) Caches verwenden die virtuelle Adresse sowohl für den Index als auch für das Tag. Dieses Caching-Schema kann zu viel schnelleren Lookups führen, da die MMU nicht zuerst konsultiert werden muss, um die physikalische Adresse für eine gegebene virtuelle Adresse zu bestimmen. VIVT leidet jedoch unter Aliasing-Problemen, bei denen mehrere verschiedene virtuelle Adressen auf dieselbe physikalische Adresse verweisen können. Das Ergebnis ist, dass solche Adressen trotz Bezug auf denselben Speicher separat zwischengespeichert werden, was Kohärenzprobleme verursacht. Obwohl Lösungen für dieses Problem existieren, funktionieren sie nicht für Standardkohärenzprotokolle. Ein weiteres Problem sind Homonyme, bei denen dieselbe virtuelle Adresse auf mehrere verschiedene physikalische Adressen abgebildet wird. Es ist nicht möglich, diese Zuordnungen allein durch einen Blick auf den virtuellen Index selbst zu unterscheiden, obwohl mögliche Lösungen umfassen: Leeren des Caches nach einem Kontextwechsel , Erzwingen von Überlappungsfreiheit von Adressräumen, Taggen der virtuellen Adresse mit einer Adressraum-ID (ASID ). Außerdem besteht das Problem, dass sich virtuelle-zu-physische Zuordnungen ändern können, was das Leeren von Cache-Zeilen erfordern würde, da die VAs nicht mehr gültig wären. All diese Probleme treten nicht auf, wenn Tags physikalische Adressen (VIPT) verwenden.
  • Virtuell indizierte, physisch gekennzeichnete (VIPT) Caches verwenden die virtuelle Adresse für den Index und die physische Adresse im Tag. Der Vorteil gegenüber PIPT ist eine geringere Latenz, da die Cache-Line parallel zur TLB-Übersetzung nachgeschlagen werden kann, das Tag jedoch erst dann verglichen werden kann, wenn die physikalische Adresse verfügbar ist. Der Vorteil gegenüber VIVT besteht darin, dass der Cache Homonyme erkennen kann, da das Tag die physikalische Adresse hat. Theoretisch benötigt VIPT mehr Tag-Bits, da sich einige der Index-Bits zwischen der virtuellen und der physikalischen Adresse unterscheiden könnten (z. In der Praxis ist dies kein Problem, da VIPT-Caches zur Vermeidung von Kohärenzproblemen so ausgelegt sind, dass sie keine solchen Indexbits haben (z. ; dies begrenzt die Größe von VIPT-Caches auf die Seitengröße mal die Assoziativität des Caches.
  • Physikalisch indizierte, virtuell markierte (PIVT) Caches werden in der Literatur oft als nutzlos und nicht existent bezeichnet. Der MIPS R6000 verwendet diesen Cache-Typ jedoch als einzige bekannte Implementierung. Der R6000 ist in emittergekoppelter Logik implementiert , einer extrem schnellen Technologie, die für große Speicher wie einen TLB nicht geeignet ist . Der R6000 löst das Problem, indem er den TLB-Speicher in einen reservierten Teil des Second-Level-Cache mit einem winzigen Hochgeschwindigkeits-TLB-"Slice" auf dem Chip einfügt. Der Cache wird durch die vom TLB-Slice erhaltene physikalische Adresse indiziert. Da der TLB-Slice jedoch nur die virtuellen Adressbits übersetzt, die zum Indexieren des Caches notwendig sind und keine Tags verwendet, können falsche Cache-Treffer auftreten, was durch Tagging mit der virtuellen Adresse behoben wird.

Die Geschwindigkeit dieser Wiederholung (die Ladelatenz ) ist entscheidend für die CPU-Leistung, und so werden die meisten modernen Level-1-Caches virtuell indiziert, was es zumindest ermöglicht, dass der TLB-Lookup der MMU parallel zum Abrufen der Daten aus dem Cache-RAM abläuft.

Die virtuelle Indizierung ist jedoch nicht für alle Cache-Ebenen die beste Wahl. Die Kosten für den Umgang mit virtuellen Aliasen steigen mit der Cachegröße, und daher werden die meisten Caches der Stufe 2 und größer physisch indiziert.

Caches haben in der Vergangenheit sowohl virtuelle als auch physische Adressen für die Cache-Tags verwendet, obwohl virtuelles Tagging jetzt ungewöhnlich ist. Wenn die TLB-Suche vor der Cache-RAM-Suche beendet werden kann, steht die physikalische Adresse rechtzeitig für den Tag-Vergleich zur Verfügung, und es besteht keine Notwendigkeit für virtuelles Tagging. Große Caches neigen dann dazu, physisch markiert zu werden, und nur kleine Caches mit sehr geringer Latenz werden virtuell markiert. In neueren Allzweck-CPUs wurde virtuelles Tagging durch Vhints ersetzt, wie unten beschrieben.

Homonym- und Synonymprobleme

Ein Cache, der auf virtuelles Indizieren und Tagging angewiesen ist, wird inkonsistent, nachdem dieselbe virtuelle Adresse auf verschiedene physikalische Adressen ( Homonyme ) abgebildet wurde , was durch Verwenden der physikalischen Adresse zum Tagging oder durch Speichern der Adressraumkennung in der Cache-Zeile gelöst werden kann. Der letztere Ansatz hilft jedoch nicht gegen das Synonymproblem , bei dem mehrere Cache-Zeilen Daten für dieselbe physikalische Adresse speichern. Das Schreiben an solche Orte kann nur einen Ort im Cache aktualisieren, während die anderen mit inkonsistenten Daten zurückbleiben. Dieses Problem kann gelöst werden, indem nicht überlappende Speicherlayouts für verschiedene Adressräume verwendet werden, oder ansonsten muss der Cache (oder ein Teil davon) geleert werden, wenn sich die Zuordnung ändert.

Virtuelle Tags und Vhints

Der große Vorteil virtueller Tags besteht darin, dass sie bei assoziativen Caches ermöglichen, dass die Tag-Übereinstimmung fortschreitet, bevor die virtuelle in physikalische Übersetzung erfolgt. Kohärenzprüfungen und Räumungen stellen jedoch eine physische Adresse für Maßnahmen dar. Die Hardware muss über einige Mittel verfügen, um die physikalischen Adressen in einen Cache-Index umzuwandeln, im Allgemeinen durch Speichern von physikalischen Tags sowie virtuellen Tags. Zum Vergleich: Ein physisch markierter Cache muss keine virtuellen Tags speichern, was einfacher ist. Wenn eine virtuelle zu einer physischen Abbildung aus dem TLB gelöscht wird, müssen Cache-Einträge mit diesen virtuellen Adressen irgendwie geleert werden. Wenn alternativ Cache-Einträge auf Seiten erlaubt sind, die nicht durch den TLB abgebildet sind, dann müssen diese Einträge geleert werden, wenn die Zugriffsrechte auf diesen Seiten in der Seitentabelle geändert werden.

Es ist auch möglich, dass das Betriebssystem dafür sorgt, dass keine virtuellen Aliase gleichzeitig im Cache resident sind. Das Betriebssystem gewährleistet diese Garantie, indem es die nachfolgend beschriebene Seitenfärbung erzwingt. Einige frühe RISC-Prozessoren (SPARC, RS/6000) verfolgten diesen Ansatz. Es wurde in letzter Zeit nicht verwendet, da die Hardwarekosten für das Erkennen und Entfernen virtueller Aliasnamen gesunken sind und die Softwarekomplexität und Leistungseinbußen bei der perfekten Seitenfärbung gestiegen sind.

Es kann nützlich sein, die beiden Funktionen von Tags in einem assoziativen Cache zu unterscheiden: Sie werden verwendet, um zu bestimmen, welche Art der Eintragsmenge ausgewählt werden soll, und sie werden verwendet, um zu bestimmen, ob der Cache getroffen oder verfehlt wurde. Die zweite Funktion muss immer richtig sein, aber es ist zulässig, dass die erste Funktion errät und gelegentlich die falsche Antwort erhält.

Einige Prozessoren (zB frühe SPARCs) haben Caches mit virtuellen und physischen Tags. Die virtuellen Tags werden zur Wegauswahl verwendet, und die physischen Tags werden zum Bestimmen von Treffern oder Fehlversuchen verwendet. Diese Art von Cache genießt den Latenzvorteil eines virtuell markierten Caches und die einfache Softwareschnittstelle eines physisch markierten Caches. Es trägt jedoch die zusätzlichen Kosten für duplizierte Tags. Außerdem müssen während der Fehltrefferverarbeitung die alternativen Wege der indizierten Cache-Zeile auf virtuelle Aliasnamen untersucht und alle Übereinstimmungen entfernt werden.

Der zusätzliche Bereich (und eine gewisse Latenz) kann abgeschwächt werden, indem virtuelle Hinweise mit jedem Cache-Eintrag anstelle von virtuellen Tags beibehalten werden. Diese Hinweise sind eine Teilmenge oder ein Hash des virtuellen Tags und werden verwendet, um die Art des Caches auszuwählen, aus dem Daten und ein physisches Tag abgerufen werden sollen. Wie bei einem Cache mit virtuellem Tag kann es eine Übereinstimmung des virtuellen Hinweises geben, aber eine Nichtübereinstimmung des physischen Tags. In diesem Fall muss der Cache-Eintrag mit dem übereinstimmenden Hinweis entfernt werden, damit Cache-Zugriffe nach der Cache-Füllung an dieser Adresse nur eine Hinweis-Übereinstimmung haben. Da virtuelle Hinweise weniger Bits haben als virtuelle Tags, die sie voneinander unterscheiden, erleidet ein Cache mit virtuellen Hinweisen mehr Konfliktfehler als ein Cache mit virtuellem Tag.

Die vielleicht ultimative Reduzierung virtueller Hinweise findet sich beim Pentium 4 (Willamette- und Northwood-Kerne). In diesen Prozessoren beträgt der virtuelle Hinweis effektiv zwei Bits, und der Cache ist vierfach satzassoziativ. Effektiv hält die Hardware eine einfache Permutation von der virtuellen Adresse zum Cache-Index aufrecht, so dass kein inhaltsadressierbarer Speicher (CAM) erforderlich ist, um den richtigen der vier abgerufenen Wege auszuwählen.

Seite färben

Große physikalisch indizierte Caches (meist sekundäre Caches) stoßen auf ein Problem: Das Betriebssystem und nicht die Anwendung steuert, welche Seiten im Cache miteinander kollidieren. Unterschiede in der Seitenzuordnung von einem Programmlauf zum nächsten führen zu Unterschieden in den Cache-Kollisionsmustern, die zu sehr großen Unterschieden in der Programmleistung führen können. Diese Unterschiede können es sehr schwierig machen, ein konsistentes und wiederholbares Timing für einen Benchmark-Lauf zu erhalten.

Um das Problem zu verstehen, stellen Sie sich eine CPU mit einem physikalisch indizierten, direkt zugeordneten Level-2-Cache von 1 MiB und virtuellen 4 KiB-Speicherseiten vor. Sequentielle physikalische Seiten werden sequentiellen Positionen im Cache zugeordnet, bis das Muster nach 256 Seiten umläuft. Wir können jede physische Seite mit einer Farbe von 0–255 beschriften, um anzuzeigen, wohin sie im Cache gehen kann. Positionen innerhalb physischer Seiten mit unterschiedlichen Farben können im Cache nicht in Konflikt geraten.

Programmierer, die versuchen, den Cache maximal zu nutzen, können die Zugriffsmuster ihrer Programme so anordnen, dass nur 1 MiB Daten zu einem bestimmten Zeitpunkt zwischengespeichert werden müssen, wodurch Kapazitätsausfälle vermieden werden. Sie sollten aber auch sicherstellen, dass die Zugriffsmuster keine Konfliktfehler aufweisen. Eine Möglichkeit, dieses Problem zu lösen, besteht darin, die virtuellen Seiten, die das Programm verwendet, aufzuteilen und ihnen virtuelle Farben zuzuweisen, auf die gleiche Weise, wie physischen Seiten zuvor physische Farben zugewiesen wurden. Programmierer können dann die Zugriffsmuster ihres Codes so anordnen, dass nicht gleichzeitig zwei Seiten mit der gleichen virtuellen Farbe verwendet werden. Es gibt eine breite Literatur zu solchen Optimierungen (zB Schleifennestoptimierung ), die größtenteils aus der High Performance Computing (HPC) -Community stammt.

Der Haken daran ist, dass alle Seiten, die zu einem bestimmten Zeitpunkt verwendet werden, unterschiedliche virtuelle Farben haben können, einige jedoch die gleichen physischen Farben haben. Wenn das Betriebssystem virtuellen Seiten zufällig und gleichmäßig physische Seiten zuweist, ist es sehr wahrscheinlich, dass einige Seiten dieselbe physische Farbe haben und dann Orte dieser Seiten im Cache kollidieren (dies ist das Geburtstagsparadoxon ).

Die Lösung besteht darin, das Betriebssystem versuchen zu lassen, verschiedenen virtuellen Farben verschiedene physische Farbseiten zuzuweisen, eine Technik, die als Seitenfärbung bezeichnet wird . Obwohl die tatsächliche Zuordnung von virtueller zu physischer Farbe für die Systemleistung irrelevant ist, sind ungerade Zuordnungen schwer zu verfolgen und haben wenig Nutzen. Daher versuchen die meisten Ansätze zum Einfärben von Seiten einfach, physische und virtuelle Seitenfarben gleich zu halten.

Wenn das Betriebssystem garantieren kann, dass jede physikalische Seite nur einer virtuellen Farbe zugeordnet ist, gibt es keine virtuellen Aliasnamen, und der Prozessor kann virtuell indizierte Caches verwenden, ohne dass während der Fehlerbehandlung zusätzliche virtuelle Aliastests erforderlich sind. Alternativ kann das Betriebssystem eine Seite aus dem Cache leeren, wenn sie von einer virtuellen Farbe in eine andere wechselt. Wie oben erwähnt, wurde dieser Ansatz für einige frühe SPARC- und RS/6000-Designs verwendet.

Cache-Hierarchie in einem modernen Prozessor

Speicherhierarchie eines AMD Bulldozer Servers

Moderne Prozessoren haben mehrere interagierende On-Chip-Caches. Der Betrieb eines bestimmten Caches kann vollständig durch die Cache-Größe, die Cache-Blockgröße, die Anzahl der Blöcke in einem Satz, die Cache-Set-Ersetzungsrichtlinie und die Cache-Schreibrichtlinie (Write-Through oder Write-Back) spezifiziert werden.

Während alle Cache-Blöcke in einem bestimmten Cache die gleiche Größe und die gleiche Assoziativität aufweisen, haben die Caches der "niedrigeren Ebene" (genannt Level-1-Cache) normalerweise eine kleinere Anzahl von Blöcken, eine kleinere Blockgröße und weniger Blöcke in einem eingestellt, haben aber sehr kurze Zugriffszeiten. "Higher-Level"-Caches (dh Level 2 und höher) haben eine fortschreitend größere Anzahl von Blöcken, eine größere Blockgröße, mehr Blöcke in einem Satz und relativ längere Zugriffszeiten, sind aber immer noch viel schneller als der Hauptspeicher.

Die Richtlinie zum Ersetzen von Cache-Einträgen wird durch einen Cache-Algorithmus bestimmt, der von den Prozessordesignern zur Implementierung ausgewählt wird. In einigen Fällen werden mehrere Algorithmen für verschiedene Arten von Arbeitsbelastungen bereitgestellt.

Spezialisierte Caches

Pipeline-CPUs greifen von mehreren Punkten in der Pipeline auf den Speicher zu : Befehlsabruf, Übersetzung von virtuellen in physikalische Adressen und Datenabruf (siehe klassische RISC-Pipeline ). Das natürliche Design besteht darin, für jeden dieser Punkte unterschiedliche physische Caches zu verwenden, sodass keine physische Ressource eingeplant werden muss, um zwei Punkte in der Pipeline zu bedienen. Somit endet die Pipeline natürlich mit mindestens drei separaten Caches (Anweisung, TLB und Daten), von denen jeder auf seine besondere Rolle spezialisiert ist.

Opfer-Cache

Ein Opfer-Cache ist ein Cache, der verwendet wird, um Blöcke zu halten, die beim Ersetzen aus einem CPU-Cache entfernt werden. Der Opfercache liegt zwischen dem Hauptcache und seinem Auffüllpfad und enthält nur die Datenblöcke, die aus dem Hauptcache entfernt wurden. Der Opfer-Cache ist normalerweise vollständig assoziativ und soll die Anzahl von Konflikt-Fehlversuchen reduzieren. Viele häufig verwendete Programme erfordern nicht für alle Zugriffe eine assoziative Abbildung. Tatsächlich erfordert nur ein kleiner Bruchteil der Speicherzugriffe des Programms eine hohe Assoziativität. Der Opfer-Cache nutzt diese Eigenschaft aus, indem er nur diesen Zugriffen eine hohe Assoziativität verleiht. Es wurde 1990 von Norman Jouppi von DEC eingeführt.

Intels Crystalwell- Variante seiner Haswell- Prozessoren führte einen integrierten 128 MB eDRAM Level 4-Cache ein, der als Opfer-Cache für den Level 3-Cache der Prozessoren dient. In der Skylake- Mikroarchitektur funktioniert der Level-4-Cache nicht mehr als Opfer-Cache.

Trace-Cache

Eines der extremeren Beispiele für die Cache-Spezialisierung ist der Trace-Cache (auch als Ausführungs-Trace-Cache bekannt ) in den Intel Pentium 4- Mikroprozessoren. Ein Trace-Cache ist ein Mechanismus zum Erhöhen der Befehlsabrufbandbreite und zum Verringern des Stromverbrauchs (im Fall des Pentium 4) durch Speichern von Spuren von Befehlen , die bereits abgerufen und decodiert wurden.

Ein Ablaufverfolgungscache speichert Anweisungen entweder nachdem sie dekodiert wurden oder wenn sie zurückgezogen werden. Im Allgemeinen werden Anweisungen zu Ablaufverfolgungs-Caches in Gruppen hinzugefügt, die entweder einzelne Basisblöcke oder dynamische Anweisungsverfolgungen darstellen. Der Trace-Cache des Pentium 4 speichert Mikrooperationen, die aus der Dekodierung von x86-Befehlen resultieren, und bietet auch die Funktionalität eines Mikrooperations-Cache. Wenn eine Anweisung das nächste Mal benötigt wird, muss sie daher nicht erneut in Mikrooperationen dekodiert werden.

Coalescing Cache (WCC) schreiben

Write Coalescing Cache ist ein spezieller Cache, der Teil des L2 - Cache in ist AMD ‚s Bulldozer - Mikroarchitektur . Speicher aus beiden L1D-Caches im Modul durchlaufen den WCC, wo sie gepuffert und zusammengeführt werden. Die Aufgabe des WCC besteht darin, die Anzahl der Schreibvorgänge in den L2-Cache zu reduzieren.

Mikrooperations-Cache (μop oder uop)

Eine Mikrooperation Cache ( μop Cache , UOP - Cache oder UC ) ist eine spezielle Cache, speichern Mikrooperationen der decodierten Befehle, wie direkt aus den empfangenen Befehlsdecodierer oder aus dem Befehls - Cache. Wenn ein Befehl dekodiert werden muss, wird der μop-Cache auf seine dekodierte Form überprüft, die, falls zwischengespeichert, wiederverwendet wird; wenn sie nicht verfügbar ist, wird die Anweisung decodiert und dann zwischengespeichert.

Eine der frühen Arbeiten, die μop-Cache als alternatives Frontend für die Intel P6-Prozessorfamilie beschreiben, ist das 2001 erschienene Papier „Micro-Operation Cache: A Power Aware Frontend for Variable Instruction Length ISA“ . Später hat Intel μop-Caches in seine Sandy-Bridge- Prozessoren und in aufeinanderfolgende Mikroarchitekturen wie Ivy Bridge und Haswell eingebaut . AMD hat in seiner Zen-Mikroarchitektur einen μop-Cache implementiert .

Das Abrufen vollständiger vordecodierter Befehle beseitigt die Notwendigkeit, komplexe Befehle variabler Länge wiederholt in einfachere Mikrooperationen fester Länge zu decodieren, und vereinfacht den Prozess des Vorhersagens, Abrufens, Rotierens und Ausrichtens abgerufener Befehle. Ein μop-Cache entlädt effektiv die Abruf- und Decodierungshardware, wodurch der Stromverbrauch verringert und die Frontend-Versorgung decodierter Mikrooperationen verbessert wird. Der μop-Cache erhöht auch die Leistung, indem er dekodierte Mikrooperationen konsistenter an das Backend liefert und verschiedene Engpässe in der Abruf- und Dekodierungslogik der CPU beseitigt.

Ein µop-Cache hat viele Ähnlichkeiten mit einem Ablaufverfolgungs-Cache, obwohl ein µop-Cache viel einfacher ist und somit eine bessere Energieeffizienz bietet; Dadurch ist es besser für Implementierungen auf batteriebetriebenen Geräten geeignet. Der Hauptnachteil des Trace-Cache, der zu seiner Leistungsineffizienz führt, ist die Hardwarekomplexität, die für seine heuristische Entscheidung über das Caching und die Wiederverwendung von dynamisch erstellten Befehls-Traces erforderlich ist .

Verzweigungsziel-Befehlscache

Ein Branch Target Cache oder Branch Target Instruction Cache , der Name, der bei ARM-Mikroprozessoren verwendet wird , ist ein spezialisierter Cache, der die ersten paar Befehle am Ziel einer genommenen Verzweigung hält. Dies wird von Prozessoren mit geringer Leistung verwendet, die keinen normalen Befehlscache benötigen, da das Speichersystem Befehle schnell genug liefern kann, um die CPU ohne einen zu befriedigen. Dies gilt jedoch nur für nacheinander aufeinanderfolgende Anweisungen; es dauert immer noch mehrere Latenzzyklen, um den Befehlsabruf an einer neuen Adresse neu zu starten, was einige Zyklen von Pipeline-Blasen nach einer Steuerübertragung verursacht. Ein Verzweigungsziel-Cache stellt Anweisungen für diese wenigen Zyklen bereit, wodurch eine Verzögerung nach den meisten genommenen Verzweigungen vermieden wird.

Dies ermöglicht einen Vollgeschwindigkeitsbetrieb mit einem viel kleineren Cache als ein herkömmlicher Vollzeit-Befehlscache.

Intelligenter Cache

Smart Cache ist eine von Intel entwickelte Level-2- oder Level-3- Caching-Methode für mehrere Ausführungskerne .

Smart Cache teilt den eigentlichen Cache-Speicher zwischen den Kernen eines Multi-Core-Prozessors . Im Vergleich zu einem dedizierten Cache pro Kern sinkt die Gesamt- Cache-Miss- Rate, wenn nicht alle Kerne gleiche Teile des Cache-Speicherplatzes benötigen. Folglich kann ein einzelner Kern den vollständigen Level-2- oder Level-3-Cache verwenden, wenn die anderen Kerne inaktiv sind. Darüber hinaus beschleunigt der gemeinsam genutzte Cache die gemeinsame Nutzung von Speicher zwischen verschiedenen Ausführungskernen.

Mehrstufige Caches

Ein weiteres Problem ist der grundlegende Kompromiss zwischen Cache-Latenz und Trefferrate. Größere Caches haben bessere Trefferraten, aber eine längere Latenz. Um diesen Kompromiss zu beheben, verwenden viele Computer mehrere Cache-Ebenen, wobei kleine schnelle Caches von größeren, langsameren Caches gesichert werden. Caches mit mehreren Ebenen arbeiten im Allgemeinen, indem sie zuerst den schnellsten Cache der Ebene 1 ( L1 ) prüfen ; wenn er trifft, fährt der Prozessor mit hoher Geschwindigkeit fort. Wenn dieser kleinere Cache verfehlt, wird der nächstschnellste Cache ( Ebene 2 , L2 ) überprüft und so weiter, bevor auf den externen Speicher zugegriffen wird.

Da der Latenzunterschied zwischen Hauptspeicher und dem schnellsten Cache größer geworden ist, haben einige Prozessoren damit begonnen, bis zu drei Ebenen des On-Chip-Cache zu verwenden. Preissensitive Designs nutzten dies, um die gesamte Cache-Hierarchie auf den Chip zu ziehen, aber in den 2010er Jahren kehrten einige der leistungsstärksten Designs zu großen Off-Chip-Caches zurück, die oft in eDRAM implementiert und auf einem Multi-Chip-Modul montiert sind , als vierte Cache-Ebene. In seltenen Fällen, wie bei der Mainframe-CPU IBM z15 (2019), werden alle Ebenen bis hinunter zu L1 durch eDRAM implementiert, wodurch SRAM vollständig ersetzt wird (für Cache wird SRAM weiterhin für Register verwendet). Das ARM-basierte Apple M1 verfügt über einen ungewöhnlich großen 192 KB L1-Cache für jeden der vier Hochleistungskerne; die vier hocheffizienten Kerne verfügen jedoch nur über 128 KB.

Die Vorteile von L3- und L4-Caches hängen von den Zugriffsmustern der Anwendung ab. Beispiele für Produkte mit L3- und L4-Caches sind die folgenden:

  • Alpha 21164 (1995) verfügt über 1 bis 64 MB Off-Chip-L3-Cache.
  • IBM POWER4 (2001) hat Off-Chip-L3-Caches von 32 MB pro Prozessor, die von mehreren Prozessoren geteilt werden.
  • Itanium 2 (2003) verfügt über einen 6 MB Unified Level 3 (L3) Cache auf dem Chip; das Itanium 2 (2003) MX 2-Modul enthält zwei Itanium 2-Prozessoren zusammen mit einem gemeinsamen 64 MB L4-Cache auf einem Multi-Chip-Modul , das mit einem Madison-Prozessor pinkompatibel war.
  • Intels Xeon MP-Produkt mit dem Codenamen "Tulsa" (2006) verfügt über 16 MB On-Die-L3-Cache, der von zwei Prozessorkernen geteilt wird.
  • AMD Phenom II (2008) verfügt über bis zu 6 MB On-Die Unified L3-Cache.
  • Intel Core i7 (2008) verfügt über einen 8 MB On-Die Unified L3-Cache, der inklusive ist und von allen Kernen geteilt wird.
  • Intel Haswell- CPUs mit integrierter Intel Iris Pro-Grafik verfügen über 128 MB eDRAM, das im Wesentlichen als L4-Cache fungiert.

Am anderen Ende der Speicherhierarchie schließlich kann die CPU- Registerdatei selbst als der kleinste und schnellste Cache im System betrachtet werden, mit der besonderen Eigenschaft, dass sie in der Software geplant wird – normalerweise von einem Compiler, da sie Register zuweist, die zu halten sind Werte, die aus dem Hauptspeicher abgerufen werden, zum Beispiel für die Schleifennestoptimierung . Bei der Registerumbenennung werden die meisten Compiler-Registerzuweisungen jedoch dynamisch von der Hardware zur Laufzeit in eine Registerbank neu zugewiesen, was es der CPU ermöglicht, falsche Datenabhängigkeiten zu durchbrechen und somit Pipeline-Gefahren zu verringern.

Registerdateien haben manchmal auch eine Hierarchie: Der Cray-1 (ca. 1976) hatte acht Adressregister "A" und acht Skalardatenregister "S", die allgemein verwendbar waren. Es gab auch einen Satz von 64 Adressregistern "B" und 64 Skalardatenregistern "T", deren Zugriff länger dauerte, aber schneller als der Hauptspeicher waren. Die Register "B" und "T" wurden bereitgestellt, weil der Cray-1 keinen Datencache hatte. (Der Cray-1 hatte jedoch einen Befehlscache.)

Multi-Core-Chips

Bei der Betrachtung eines Chips mit mehreren Kernen stellt sich die Frage, ob die Caches gemeinsam oder lokal für jeden Kern verwendet werden sollen. Die Implementierung eines gemeinsamen Cache führt unweigerlich zu mehr Verdrahtung und Komplexität. Wenn man jedoch einen Cache pro Chip anstelle des Kerns hat , verringert sich der benötigte Speicherplatz erheblich, und somit kann man einen größeren Cache einschließen.

Typischerweise ist die gemeinsame Nutzung des L1-Cache unerwünscht, da die resultierende Erhöhung der Latenz dazu führen würde, dass jeder Kern erheblich langsamer läuft als ein Single-Core-Chip. Für den Cache der höchsten Ebene, den letzten, der vor dem Zugriff auf den Speicher aufgerufen wird, ist jedoch ein globaler Cache aus mehreren Gründen wünschenswert, z Threads, um zwischengespeicherte Daten gemeinsam zu nutzen und die Komplexität der verwendeten Cache-Kohärenzprotokolle zu reduzieren. Zum Beispiel kann ein Achtkernchip mit drei Ebenen einen L1-Cache für jeden Kern, einen L2-Zwischencache für jedes Kernpaar und einen L3-Cache, der von allen Kernen geteilt wird, umfassen.

Der gemeinsam genutzte Cache der höchsten Ebene, der vor dem Zugriff auf den Speicher aufgerufen wird, wird normalerweise als Last-Level-Cache (LLC) bezeichnet. Zusätzliche Techniken werden verwendet, um den Grad der Parallelität zu erhöhen, wenn LLC von mehreren Kernen geteilt wird, einschließlich des Aufteilens in mehrere Teile, die bestimmte Bereiche von Speicheradressen adressieren und auf die unabhängig zugegriffen werden kann.

Getrennt versus vereint

In einer separaten Cache-Struktur werden Anweisungen und Daten getrennt zwischengespeichert, was bedeutet, dass eine Cache-Zeile verwendet wird, um entweder Anweisungen oder Daten zwischenzuspeichern, aber nicht beides; verschiedene Vorteile wurden mit separaten Daten - und Befehlsübersetzungs - Lookaside - Puffern demonstriert . In einer vereinheitlichten Struktur ist diese Einschränkung nicht vorhanden, und Cache-Zeilen können verwendet werden, um sowohl Befehle als auch Daten zwischenzuspeichern.

Exklusiv versus Inklusiv

Caches mit mehreren Ebenen führen zu neuen Designentscheidungen. Bei einigen Prozessoren müssen sich beispielsweise alle Daten im L1-Cache auch irgendwo im L2-Cache befinden. Diese Caches werden strikt inklusiv genannt . Andere Prozessoren (wie der AMD Athlon ) haben exklusive Caches: Daten befinden sich garantiert in höchstens einem der L1- und L2-Caches, niemals in beiden. Wieder andere Prozessoren (wie der Intel Pentium II , III und 4 ) erfordern nicht, dass sich Daten im L1-Cache auch im L2-Cache befinden, obwohl dies häufig der Fall ist. Es gibt keinen allgemein akzeptierten Namen für diese Zwischenpolitik; zwei gebräuchliche Namen sind "nicht ausschließlich" und "teilweise einschließend".

Der Vorteil von exklusiven Caches ist, dass sie mehr Daten speichern. Dieser Vorteil ist größer, wenn der exklusive L1-Cache mit dem L2-Cache vergleichbar ist, und verringert sich, wenn der L2-Cache um ein Vielfaches größer ist als der L1-Cache. Wenn die L1 verfehlt und die L2 bei einem Zugriff trifft, wird die treffende Cache-Zeile in der L2 mit einer Zeile in der L1 ausgetauscht. Dieser Austausch ist um einiges mehr Arbeit, als nur eine Zeile von L2 nach L1 zu kopieren, was ein inklusiver Cache tut.

Ein Vorteil von strikt einschließenden Caches besteht darin, dass, wenn externe Geräte oder andere Prozessoren in einem Mehrprozessorsystem eine Cache-Zeile aus dem Prozessor entfernen möchten, sie nur den Prozessor den L2-Cache überprüfen lassen müssen. In Cache-Hierarchien, die keine Inklusion erzwingen, muss auch der L1-Cache überprüft werden. Als Nachteil besteht eine Korrelation zwischen den Assoziativitäten von L1- und L2-Caches: Wenn der L2-Cache nicht mindestens so viele Wege hat wie alle L1-Caches zusammen, ist die effektive Assoziativität der L1-Caches eingeschränkt. Ein weiterer Nachteil des inklusiven Caches besteht darin, dass immer dann, wenn eine Räumung im L2-Cache stattfindet, die (möglicherweise) entsprechenden Zeilen in L1 ebenfalls geräumt werden müssen, um die Inklusivität aufrechtzuerhalten. Dies ist ziemlich viel Arbeit und würde zu einer höheren L1-Fehlerrate führen.

Ein weiterer Vorteil von Inclusive-Caches besteht darin, dass der größere Cache größere Cache-Zeilen verwenden kann, was die Größe der sekundären Cache-Tags verringert. (Exklusive Caches erfordern, dass beide Caches Cache-Zeilen der gleichen Größe aufweisen, damit Cache-Zeilen bei einem L1-Fehltreffer, L2-Treffer ausgetauscht werden können.) Wenn der sekundäre Cache eine Größenordnung größer als der primäre ist und die Cache-Daten ein Größenordnung größer als die Cache-Tags, kann dieser gespeicherte Tag-Bereich mit dem inkrementellen Bereich vergleichbar sein, der zum Speichern der L1-Cache-Daten im L2 benötigt wird.

Scratchpad-Speicher

Scratchpad-Speicher (SPM), in der Computerterminologie auch als Scratchpad, Scratchpad-RAM oder lokaler Speicher bezeichnet, ist ein interner Hochgeschwindigkeitsspeicher, der zum temporären Speichern von Berechnungen, Daten und anderen laufenden Arbeiten verwendet wird.

Beispiel: der K8

Um sowohl die Spezialisierung als auch das Multi-Level-Caching zu veranschaulichen, hier die Cache-Hierarchie des K8-Kerns in der AMD Athlon 64- CPU.

Cache-Hierarchie des K8-Kerns in der AMD Athlon 64 CPU.

Der K8 hat vier spezialisierte Caches: einen Befehlscache, einen Befehls- TLB , einen Daten-TLB und einen Daten-Cache. Jeder dieser Caches ist spezialisiert:

  • Der Befehlscache hält Kopien von 64-Byte-Speicherzeilen und ruft 16 Bytes pro Zyklus ab. Jedes Byte in diesem Cache wird in zehn Bits statt in acht gespeichert, wobei die zusätzlichen Bits die Grenzen von Befehlen markieren (dies ist ein Beispiel für eine Vordecodierung). Der Cache hat nur Paritätsschutz anstelle von ECC , da die Parität kleiner ist und alle beschädigten Daten durch neue Daten aus dem Speicher ersetzt werden können (der immer eine aktuelle Kopie der Anweisungen enthält).
  • Der Befehls-TLB hält Kopien von Seitentabelleneinträgen (PTEs). Die virtuelle Adresse des Befehlsabrufs jedes Zyklus wird durch diesen TLB in eine physikalische Adresse übersetzt. Jeder Eintrag ist entweder vier oder acht Bytes im Speicher. Da der K8 eine variable Seitengröße hat, ist jeder der TLBs in zwei Abschnitte unterteilt, einen für PTEs, die 4-KB-Seiten zuordnen, und einen für PTEs, die 4-MB- oder 2-MB-Seiten zuordnen. Die Aufteilung ermöglicht, dass die vollständig assoziative Anpassungsschaltung in jedem Abschnitt einfacher ist. Das Betriebssystem bildet verschiedene Abschnitte des virtuellen Adressraums mit PTEs unterschiedlicher Größe ab.
  • Der Daten-TLB hat zwei Kopien, die identische Einträge enthalten. Die zwei Kopien ermöglichen zwei Datenzugriffe pro Zyklus, um virtuelle Adressen in physikalische Adressen zu übersetzen. Wie der Befehls-TLB ist dieser TLB in zwei Arten von Einträgen aufgeteilt.
  • Der Datencache hält Kopien von 64-Byte-Speicherzeilen. Es ist in 8 Bänke aufgeteilt (von denen jede 8 KB Daten speichert) und kann in jedem Zyklus zwei 8-Byte-Daten abrufen, solange sich diese Daten in verschiedenen Bänken befinden. Es gibt zwei Kopien der Tags, da jede 64-Byte-Zeile auf alle acht Bänke verteilt ist. Jede Tag-Kopie verarbeitet einen der beiden Zugriffe pro Zyklus.

Der K8 hat auch mehrstufige Caches. Es gibt Befehls- und Daten-TLBs der zweiten Ebene, die nur PTEs speichern, die 4 KB abbilden. Sowohl Befehls- als auch Datencaches und die verschiedenen TLBs können aus dem großen einheitlichen L2-Cache gefüllt werden . Dieser Cache ist sowohl für den L1-Befehls- als auch den Daten-Cache exklusiv, was bedeutet, dass jede 8-Byte-Zeile nur in einem von dem L1-Befehls-Cache, dem L1-Daten-Cache oder dem L2-Cache sein kann. Es ist jedoch möglich, dass eine Zeile im Datencache einen PTE hat, der sich auch in einem der TLBs befindet – das Betriebssystem ist dafür verantwortlich, die TLBs kohärent zu halten, indem Teile davon geleert werden, wenn die Seitentabellen im Speicher aktualisiert werden.

Der K8 speichert auch Informationen, die nie im Speicher gespeichert werden – Vorhersageinformationen. Diese Caches sind im obigen Diagramm nicht dargestellt. Wie für diese CPU-Klasse üblich, verfügt der K8 über eine ziemlich komplexe Verzweigungsvorhersage , mit Tabellen, die helfen, vorherzusagen, ob Verzweigungen genommen werden, und anderen Tabellen, die die Ziele von Verzweigungen und Sprüngen vorhersagen. Einige dieser Informationen sind sowohl im Befehlscache der Ebene 1 als auch im vereinheitlichten sekundären Cache mit Befehlen verknüpft.

Der K8 verwendet einen interessanten Trick, um Vorhersageinformationen mit Anweisungen im sekundären Cache zu speichern. Zeilen im sekundären Cache werden entweder durch ECC oder parity vor versehentlicher Datenverfälschung (z. B. durch einen Alpha-Partikel- Einschlag) geschützt , je nachdem, ob diese Zeilen aus den primären Daten- oder Befehls-Caches entfernt wurden. Da der Paritätscode weniger Bits benötigt als der ECC-Code, haben Zeilen aus dem Befehlscache einige freie Bits. Diese Bits werden verwendet, um Verzweigungsvorhersageinformationen, die diesen Befehlen zugeordnet sind, zwischenzuspeichern. Das Nettoergebnis ist, dass der Verzweigungsprädiktor eine größere effektive Verlaufstabelle und somit eine bessere Genauigkeit hat.

Mehr Hierarchien

Andere Prozessoren haben andere Arten von Prädiktoren (z. B. den Store-to-Load-Bypass-Prädiktor im DEC Alpha 21264 ), und verschiedene spezialisierte Prädiktoren werden wahrscheinlich in zukünftigen Prozessoren gedeihen.

Diese Prädiktoren sind Caches, da sie Informationen speichern, deren Berechnung teuer ist. Einige der bei der Diskussion von Prädiktoren verwendeten Terminologien sind die gleichen wie für Caches (man spricht von einem Treffer in einem Verzweigungsprädiktor), aber Prädiktoren werden im Allgemeinen nicht als Teil der Cache-Hierarchie betrachtet.

Der K8 hält die Befehls- und Daten-Caches in Hardware kohärent , was bedeutet, dass ein Speichern in einen Befehl, der dem Speicherbefehl eng folgt, den folgenden Befehl ändert. Andere Prozessoren, wie die der Alpha- und MIPS-Familie, haben sich auf Software verlassen, um den Befehlscache kohärent zu halten. Es wird nicht garantiert, dass Speicher im Befehlsstrom angezeigt werden, bis ein Programm eine Betriebssystemeinrichtung aufruft, um die Kohärenz sicherzustellen.

Tag-RAM

In der Computertechnik wird ein Tag-RAM verwendet, um anzugeben, welcher der möglichen Speicherplätze gerade in einem CPU-Cache gespeichert ist. Für ein einfaches, direkt abgebildetes Design kann schnelles SRAM verwendet werden. Höhere assoziative Caches verwenden normalerweise inhaltsadressierbaren Speicher .

Implementierung

Cache- Lesevorgänge sind die häufigste CPU-Operation, die mehr als einen einzelnen Zyklus dauert. Die Programmausführungszeit neigt dazu, sehr empfindlich auf die Latenz eines Level-1-Daten-Cache-Treffers zu reagieren. Es wird viel Designaufwand und oft Strom und Siliziumfläche aufgewendet, um die Caches so schnell wie möglich zu machen.

Der einfachste Cache ist ein virtuell indizierter Direct-Mapping-Cache. Die virtuelle Adresse wird mit einem Addierer berechnet, der relevante Teil der Adresse extrahiert und verwendet, um einen SRAM zu indizieren, der die geladenen Daten zurückgibt. Die Daten werden in einem Byte-Shifter byteweise ausgerichtet und von dort an die nächste Operation übergeben. Eine Tag-Prüfung in der inneren Schleife ist nicht erforderlich – die Tags müssen nicht einmal gelesen werden. Später in der Pipeline, aber bevor der Ladebefehl zurückgezogen wird, muss das Tag für die geladenen Daten gelesen und mit der virtuellen Adresse verglichen werden, um sicherzustellen, dass ein Cache-Treffer aufgetreten ist. Bei einem Fehlschlag wird der Cache mit der angeforderten Cache-Zeile aktualisiert und die Pipeline wird neu gestartet.

Ein assoziativer Cache ist komplizierter, da irgendeine Form von Tag gelesen werden muss, um zu bestimmen, welcher Eintrag des Caches ausgewählt werden soll. Ein satzassoziativer Level-1-Cache mit N-Wege liest normalerweise alle N möglichen Tags und N Daten parallel und wählt dann die Daten aus, die dem übereinstimmenden Tag zugeordnet sind. Level-2-Caches sparen manchmal Strom, indem sie zuerst die Tags lesen, sodass nur ein Datenelement aus dem Daten-SRAM gelesen wird.

Lesepfad für einen 2-Wege-assoziativen Cache

Die nebenstehende Grafik soll die Verwendung der verschiedenen Felder der Adresse verdeutlichen. Adressbit 31 ist höchstwertig, Bit 0 ist niedrigstwertig. Das Diagramm zeigt die SRAMs, Indizierung und Multiplexing für einen 4 KB, 2-Wege satzassoziativen, virtuell indizierten und virtuell markierten Cache mit 64 Byte (B) Zeilen, einer 32-Bit-Lesebreite und einer 32-Bit-virtuellen Adresse.

Da der Cache 4 KB groß ist und 64 B-Zeilen hat, gibt es nur 64 Zeilen im Cache, und wir lesen jeweils zwei aus einem Tag-SRAM mit 32 Zeilen mit jeweils einem Paar von 21-Bit-Tags. Obwohl jede Funktion der virtuellen Adreßbits 31 bis 6 verwendet werden könnte, um die Tag- und Daten-SRAMs zu indizieren, ist es am einfachsten, die niedrigstwertigen Bits zu verwenden.

In ähnlicher Weise ist der Daten-SRAM 512 Zeilen mal 8 Byte breit, da der Cache 4 KB groß ist und einen 4 B-Lesepfad hat und für jeden Zugriff auf zwei Arten liest.

Ein modernerer Cache könnte 16 KB groß sein, 4-fach satzassoziativ, virtuell indiziert, virtuell mit Hinweisen versehen und physisch markiert sein, mit 32 B Zeilen, 32 Bit Lesebreite und 36 Bit physischen Adressen. Die Wiederholung des Lesepfads für einen solchen Cache sieht dem obigen Pfad sehr ähnlich. Anstelle von Tags werden Vhints gelesen und mit einer Teilmenge der virtuellen Adresse abgeglichen. Später in der Pipeline wird die virtuelle Adresse vom TLB in eine physikalische Adresse übersetzt und das physikalische Tag wird gelesen (nur ein Tag, da der vhint angibt, welche Art des Caches gelesen werden soll). Schließlich wird die physische Adresse mit dem physischen Tag verglichen, um festzustellen, ob ein Treffer aufgetreten ist.

Einige SPARC-Designs haben die Geschwindigkeit ihrer L1-Caches um einige Gatterverzögerungen verbessert, indem der virtuelle Adressaddierer in die SRAM-Decoder zusammengelegt wurde. Siehe Summenadressierter Decoder .

Geschichte

Die frühe Geschichte der Cache-Technologie ist eng mit der Erfindung und Verwendung des virtuellen Speichers verbunden. Aufgrund der Knappheit und der Kosten von Halbleiterspeichern verwendeten frühe Großrechner in den 1960er Jahren eine komplexe Hierarchie von physischem Speicher, der auf einen flachen virtuellen Speicherplatz abgebildet wurde, der von Programmen verwendet wird. Die Speichertechnologien würden Halbleiter, Magnetkern, Trommel und Scheibe umfassen. Von Programmen gesehener und verwendeter virtueller Speicher wäre flach, und Caching würde verwendet, um Daten und Anweisungen vor dem Prozessorzugriff in den schnellsten Speicher zu holen. Umfangreiche Studien wurden durchgeführt, um die Cache-Größen zu optimieren. Es wurde festgestellt, dass die optimalen Werte stark von der verwendeten Programmiersprache abhängen, wobei Algol die kleinsten und Fortran und Cobol die größten Cache-Größen benötigen.

In den frühen Tagen der Mikrocomputertechnologie war der Speicherzugriff nur geringfügig langsamer als der Registerzugriff . Doch seit den 1980er Jahren wächst die Leistungslücke zwischen Prozessor und Speicher. Mikroprozessoren haben fortschrittliche viel schneller als Speicher, vor allem im Hinblick auf ihre Betriebsfrequenz , so Speicher eine Leistung wurde Engpass . Während es technisch möglich war, den gesamten Hauptspeicher so schnell wie die CPU zu haben, wurde ein ökonomischer Weg eingeschlagen: Verwenden Sie viel Low-Speed-Speicher, aber führen Sie auch einen kleinen High-Speed-Cache-Speicher ein, um die Leistungslücke zu schließen. Dies bot eine Größenordnung mehr Kapazität – zum gleichen Preis – bei nur geringfügig reduzierter kombinierter Leistung.

Erste TLB-Implementierungen

Die ersten dokumentierten Verwendungen eines TLB waren auf dem GE 645 und dem IBM 360/67 , die beide einen assoziativen Speicher als TLB verwendeten.

Erster Instruktions-Cache

Die erste dokumentierte Verwendung eines Instruktions-Cache war auf der CDC 6600 .

Erster Datencache

Die erste dokumentierte Verwendung eines Datencaches war auf dem IBM System/360 Model 85.

In 68k Mikroprozessoren

Der 1982 veröffentlichte 68010 verfügt über einen "Schleifenmodus", der als kleiner Befehlscache für Sonderfälle betrachtet werden kann, der Schleifen beschleunigt, die nur aus zwei Befehlen bestehen. Der 68020 , der 1984 auf den Markt kam, ersetzte diesen durch einen typischen Instruktions-Cache von 256 Bytes und war der erste Prozessor der 68k-Serie, der über echten On-Chip-Cache-Speicher verfügte.

Der 1987 veröffentlichte 68030 ist im Grunde ein 68020-Kern mit einem zusätzlichen 256-Byte-Daten-Cache, einer On-Chip- Speicherverwaltungseinheit (MMU), einer Prozessverkleinerung und einem zusätzlichen Burst-Modus für die Caches. Der 1990 veröffentlichte 68040 verfügt über geteilte Befehls- und Datencaches von jeweils vier Kilobyte. Der 1994 veröffentlichte 68060 hat folgendes: 8 KB Datencache (vierfach assoziativ), 8 KB Befehlscache (vierfach assoziativ), 96-Byte FIFO-Befehlspuffer, 256-Einträge Verzweigungs-Cache und 64 Einträge Adreßübersetzungscache-MMU-Puffer (Vier-Wege-Assoziativ).

In x86-Mikroprozessoren

Als die x86- Mikroprozessoren im 386er Taktraten von 20 MHz und mehr erreichten , wurden kleine Mengen von schnellem Cache-Speicher in die Systeme eingebaut, um die Leistung zu verbessern. Dies lag daran, dass der für den Hauptspeicher verwendete DRAM eine erhebliche Latenz von bis zu 120 ns sowie Auffrischungszyklen aufwies. Der Cache wurde aus teureren, aber deutlich schnelleren SRAM- Speicherzellen aufgebaut , die zu dieser Zeit Latenzen von etwa 10–25 ns aufwiesen. Die frühen Caches befanden sich außerhalb des Prozessors und befanden sich normalerweise auf dem Motherboard in Form von acht oder neun DIP- Geräten, die in Sockeln platziert wurden, um den Cache als optionales Extra oder Upgrade-Feature zu aktivieren.

Einige Versionen des Intel 386-Prozessors können 16 bis 256 KB externen Cache unterstützen.

Beim 486er Prozessor wurde ein 8 KB Cache direkt in den CPU-Die integriert. Dieser Cache wurde als Level 1- oder L1-Cache bezeichnet, um ihn vom langsameren Cache auf dem Motherboard oder Level 2 (L2)-Cache zu unterscheiden. Diese Caches auf dem Motherboard waren viel größer, wobei die gängigste Größe 256 KB betrug. Die Popularität des On-Motherboard-Cache setzte sich durch die Pentium MMX- Ära fort, wurde jedoch durch die Einführung von SDRAM und die wachsende Diskrepanz zwischen Bustaktraten und CPU-Taktraten, die dazu führten, dass der On-Motherboard-Cache nur geringfügig schneller war als der Hauptspeicher, obsolet .

Die nächste Entwicklung bei der Cache-Implementierung in den x86-Mikroprozessoren begann mit dem Pentium Pro , der den sekundären Cache auf das gleiche Paket wie der Mikroprozessor brachte, der mit der gleichen Frequenz wie der Mikroprozessor getaktet wurde.

On-Motherboard-Caches erfreuten sich anhaltender Beliebtheit dank der AMD K6-2 und AMD K6-III- Prozessoren, die noch den Sockel 7 verwendeten , der zuvor von Intel mit On-Motherboard-Caches verwendet wurde. K6-III enthielt 256 KB On-Die-L2-Cache und nutzte den On-Board-Cache als Third-Level-Cache, genannt L3 (Motherboards mit bis zu 2 MB On-Board-Cache wurden hergestellt). Nachdem der Sockel 7 veraltet war, verschwand der On-Motherboard-Cache von den x86-Systemen.

Die dreistufigen Caches wurden erstmals mit der Einführung mehrerer Prozessorkerne wieder verwendet, wobei der L3-Cache dem CPU-Die hinzugefügt wurde. Es wurde üblich, dass die Gesamtcachegrößen in neueren Prozessorgenerationen immer größer werden, und in letzter Zeit (Stand 2011) ist es nicht ungewöhnlich, Level-3-Cachegrößen von mehreren zehn Megabyte zu finden.

Intel hat mit der Haswell- Mikroarchitektur einen Level-4-On-Package-Cache eingeführt . Crystalwell Haswell-CPUs, die mit der GT3e- Variante der integrierten Iris-Pro-Grafik von Intel ausgestattet sind, verfügen effektiv über 128 MB eingebetteten DRAM ( eDRAM ) auf demselben Gehäuse. Dieser L4-Cache wird dynamisch zwischen der On-Die-GPU und der CPU geteilt und dient als Opfer-Cache für den L3-Cache der CPU.

In ARM-Mikroprozessoren

Apple M1 CPU hat 128 oder 192 KB Instruktions-L1-Cache für jeden Kern (wichtig für Latenz/Single-Thread-Leistung), je nach Kerntyp ungewöhnlich groß für L1-Cache aller CPU-Typen, nicht nur für einen Laptop, während der Gesamt-Cache Die Speichergröße ist für einen Laptop nicht ungewöhnlich groß (die Summe ist wichtiger für den Durchsatz), und viel größere Gesamtgrößen (zB L3 oder L4) sind in IBMs Mainframes verfügbar.

Aktuelle Forschung

Frühe Cache-Designs konzentrierten sich ausschließlich auf die direkten Kosten für Cache und RAM und die durchschnittliche Ausführungsgeschwindigkeit. Neuere Cache-Designs berücksichtigen auch Energieeffizienz , Fehlertoleranz und andere Ziele.

Computerarchitekten stehen mehrere Tools zur Verfügung, um Kompromisse zwischen Cache-Zykluszeit, Energie und Fläche zu untersuchen. der CACTI-Cache-Simulator und der SimpleScalar-Befehlssatz-Simulator sind zwei Open-Source-Optionen.

Cache mit mehreren Ports

Ein Cache mit mehreren Ports ist ein Cache, der mehr als eine Anforderung gleichzeitig bedienen kann. Beim Zugriff auf einen herkömmlichen Cache verwenden wir normalerweise eine einzelne Speicheradresse, während wir in einem Cache mit mehreren Ports möglicherweise N Adressen gleichzeitig anfordern können – wobei N die Anzahl der Ports ist, die über den Prozessor und den Cache verbunden sind. Dies hat den Vorteil, dass ein Pipeline-Prozessor von verschiedenen Phasen in seiner Pipeline auf Speicher zugreifen kann. Ein weiterer Vorteil besteht darin, dass es das Konzept superskalarer Prozessoren durch verschiedene Cache-Ebenen ermöglicht.

Siehe auch

Anmerkungen

Verweise

Externe Links