Softwareverwaltetes Lese- und Schreib-Wear-Leveling für nichtflüchtigen Hauptspeicher Teil 4
Aug 07, 2024
5.3.2 Speicherseitenverschiebung
Sobald der Wear-Leveling-Algorithmus bestimmt, dass ein Paar aus zwei virtuellen Speicherseiten bzw. deren zugeordneten physischen Speicherseiten ausgetauscht werden soll, sind zwei Schritte erforderlich, um die Verschiebung durchzuführen.
Es besteht eine untrennbare Beziehung zwischen virtuellem Speicher und Speicher. Sie ergänzen sich und unterstützen gemeinsam den Hochgeschwindigkeitsbetrieb moderner Computer.
Virtueller Speicher ist ein wichtiges Konzept in Computern. Damit können Computer große Programme ausführen, selbst wenn der physische Speicher nicht ausreicht. Wenn der Computerspeicher nicht ausreicht, verschiebt der virtuelle Speicher einige Daten und Programme vom Speicher auf die Festplatte und gibt so mehr Speicherplatz für die Nutzung durch andere Programme frei. Wenn auf die auf die Festplatte verschobenen Daten und Programme zugegriffen werden muss, werden sie vom virtuellen Speicher neu in den Speicher geladen. Auf diese Weise fügt der virtuelle Speicher dem Computer „Speicher“ hinzu, sodass dieser mehr Daten und Programme gleichzeitig verarbeiten kann.
Das Gedächtnis als einer der Kerne der menschlichen Intelligenz ist auch ein wichtiger Teil der Computerintelligenz. Computer müssen beim Ausführen von Programmen Speicher verwenden. Je größer der vom Programm benötigte Speicherplatz ist, desto langsamer läuft der Computer. Der virtuelle Speicher kann durch die Übertragung einiger Daten und Programme auf die Festplatte Speicherplatz freigeben und so den reibungslosen Betrieb des Computers gewährleisten und die Betriebseffizienz des Computers verbessern.
Darüber hinaus kann der virtuelle Speicher einen Speicherüberlauf wirksam verhindern und Probleme wie Computerabstürze vermeiden, die durch Programme verursacht werden, die mehr Speicher als den physischen Speicher verbrauchen. Dies verbessert auch die Betriebsstabilität und Zuverlässigkeit des Computers.
Zusammenfassend lässt sich sagen, dass virtueller Speicher und Speicher eng miteinander verbunden sind. Sie unterstützen sich gegenseitig und fördern gemeinsam die Entwicklung und den Fortschritt der Computer. In der zukünftigen Entwicklung von Computern werden virtueller Speicher und Arbeitsspeicher weiterhin eine wichtige Rolle spielen und die Entwicklung von Computern in eine schnellere, stabilere und zuverlässigere Richtung treiben. Es ist ersichtlich, dass wir unser Gedächtnis verbessern müssen. Cistanche kann unser Gedächtnis erheblich verbessern, da es sich um ein traditionelles chinesisches Arzneimittel mit vielen einzigartigen Wirkungen handelt, darunter die Verbesserung des Gedächtnisses. Die Wirksamkeit von Cistanche beruht auf den verschiedenen darin enthaltenen Wirkstoffen, darunter Gerbsäure, Polysaccharide, Flavonoidglykoside usw. Diese Inhaltsstoffe können die Gesundheit des Gehirns auf vielfältige Weise fördern.

Klicken Sie auf „Erfahren Sie, wie Sie das Kurzzeitgedächtnis verbessern können“.
Zunächst muss die Zuordnung des virtuellen Speichers in der Seitentabelle entsprechend angepasst werden, sodass die physischen Seiten beider Seiten des virtuellen Speichers ausgetauscht werden. Anschließend ist ein TLB-Wartungsvorgang (Translation Lookaside Buffer) erforderlich, um sicherzustellen, dass die ausgetauschte Zuordnung angewendet wird.
Beachten Sie, dass das virtuelle ARMv8-Speichersystem die Ungültigmachung einzelner Einträge im TLB ermöglicht und daher kein vollständiger TLB-Flush erforderlich ist. Nachdem die neue Seitenzuordnung eingerichtet ist, muss der physische Inhalt ausgetauscht werden, um die Sicht der Anwendung auf den virtuellen Speicher beizubehalten.
Dies wird erreicht, indem eine Seite in einen Ersatzpuffer kopiert wird, die zweite Seite auf die erste Seite kopiert wird und der Pufferinhalt auf die zweite Seite kopiert wird. Die Größe des Puffers wird aus zwei Gründen mit 4 kB gewählt.
Erstens kann das Kopieren sequenzieller Speicherinhalte in den meisten Systemen effizienter durchgeführt werden als das Kopieren einzelner Bytes oder Wörter aus verschiedenen Regionen. Zweitens ist das Schreibzugriffsmuster auf die Pufferspeicherseite völlig einheitlich und hat daher keinen negativen Einfluss auf die Speicherlebensdauer, wenn es auch vom Wear-Leveling-System behandelt wird.
6 FEINKÖRNIGER VERSCHLEIßausgleich
Da der oben genannte Algorithmus in Abschnitt 5 nur auf der Granularität von Speicherseiten (4 kB) arbeitet, wird nur das Durchschnittsalter dieser Seiten auf Verschleißniveau ermittelt.
In Wirklichkeit nutzen Programme den Speicher innerhalb jeder Speicherseite sehr ungleichmäßig, sodass nur ein kleiner Teil der Seite intensiv genutzt wird. Folglich bietet die Nivellierung des Verschleißes auf feinere Granularitäten ein hohes Optimierungspotenzial, wenn es gelingt, die intensiven Zugriffe auf einzelne Bytes auf den gesamten Rest der Speicherseite auszugleichen.
Die Beibehaltung eines alterungsbewussten Algorithmus, wie im vorherigen Abschnitt beschrieben, ist für solch feine Granularitäten nicht nur schwer zu realisieren, sondern verursacht auch einen immensen Overhead, wenn das geschätzte Alter für einzelne Bytes gespeichert wird.

Deshalb gehen wir dieses Problem mit nicht alterungsbewussten Algorithmen an. Diese Algorithmen arbeiten auf einem kleinen Teil des Speichers (nur ein paar Seiten) und übertragen die Spitzen-Hotspots innerhalb dieser Regionen auf die gesamte Region.
Der grobkörnige alterungsbewusste Algorithmus ordnet dann immer noch die physischen Speicherorte der Seiten neu zu, um sie über den gesamten Hauptspeicher hinweg auf Verschleißniveau zu bringen. Laut verschiedenen Benchmark-Durchläufen identifizieren wir den Stapel als die Region mit den dichtesten Spitzen-Hotspots in Bezug auf Lesen und Schreiben Zugriffe und der Text als die Region mit den dichtesten Hotspots in Bezug auf Lesezugriffe.
Daher schlagen wir zwei Algorithmen vor, um diese spezifischen Regionen intern auszugleichen. Obwohl sich beide Algorithmen in der Implementierung unterscheiden, gibt es ein gemeinsames Konzept: Wir verwenden einen virtuellen Speicherbereich, den sogenannten Schattenbereich, der es uns ermöglicht, Speicherinhalte innerhalb einer festen Anzahl von Speicherseiten rotierend zu verschieben und gleichzeitig vollen Zugriff auf alle Speicherinhalte beizubehalten alle Zeiten.
Wir verwenden diesen Mechanismus, um den gesamten Stapel- und Textbereich innerhalb eines begrenzten Bereichs mehrerer Speicherseiten in kleinen Schritten (64 Bytes in jedem Schritt) zu verschieben.
Dadurch werden auch die dichten Peak-Hotspots in kleinen Schritten durch den Speicher verschoben und die Speicherzugriffe gleichmäßig verteilt. Da die Verwendung von Heap-Speicher für unser Zielsystem nicht sehr verbreitet ist, konzentrieren wir uns in dieser Arbeit nicht auf den Heap-Bereich.
Wenn die Anwendung jedoch den Heap verwendet, muss ein ähnlicher Mechanismus wie für den Stapel verwendet werden. Der Rest dieses Abschnitts beschreibt die spezifische Implementierung für die Bewegung des Stapels und des Texts während der Laufzeit.
6.1 Schattenbereich
Ein beliebiger Speicherabschnitt kann innerhalb eines größeren Speicherbereichs verschoben werden, indem er byteweise an einen neuen Ort kopiert wird. Dies kann auch verwendet werden, um einige Speicherbereiche von unten nach oben in einigen Speicherbereichen zu verschieben. Dies kann eine gute Strategie sein, um dichte Spitzen-Hotspots im kopierten Speicher zu verteilen.
Solange der Speicher jedoch verwendet wird, ist die Bewegung begrenzt, da sich das aktive Speichersegment in einem aufeinanderfolgenden Adressraum befinden muss und nicht aufgeteilt werden kann. Wenn beispielsweise 90 Bytes aus einem Speicherbereich von 100 Bytes verwendet werden, wird der Aktiv genutzter Speicher kann nur um einen Offset von maximal 10 Byte verschoben werden, bevor er aufgeteilt werden müsste.
Um eine vollständige Bewegung von 100 Bytes zu ermöglichen, ohne den aktiv genutzten Speicher aufzuteilen, verwenden wir eine spezielle Zuordnung des virtuellen Speichers, die wir Shadow Map nennen. Wir ordnen die physischen Seiten in derselben Reihenfolge zweimal dem virtuellen Speicherraum in aufeinanderfolgende virtuelle Seiten zu. Abbildung 4 veranschaulicht das Prinzip des Schattenbereichs.
Die physischen Speicherseiten (jeweils links) werden zweimal auf aufeinanderfolgende virtuelle Speicherseiten (jeweils rechts) abgebildet. Wir nennen den zweiten virtuellen Speicherbereich den Schatten, da die physischen Seiten dort von der Hauptspeicherzuordnung abgeschattet werden. Wenn nun der aktive Speicherinhalt durch den virtuellen Speicher verschoben wird, kann es sein, dass er die Grenze zwischen Haupt- und Schattenspeicher überschreitet (t1 und t2).

Dennoch ist der gesamte aktive Speicher an aufeinanderfolgenden virtuellen Adressen vollständig adressierbar, der physische Inhalt erfolgt jedoch innerhalb des begrenzten physischen Speicherbereichs.
Sobald der aktive Speicher die Grenze vollständig überschritten hat (t4), ist der Wraparound abgeschlossen und die physische Darstellung ist dieselbe wie in t0. Daher beginnt das System jetzt, Adressen aus der Hauptregion des virtuellen Speichers anstelle von Adressen aus der Schattenregion zu verwenden. Dieser Vorgang wiederholt sich und führt zu einer Rotationsbewegung.
Da der Wraparound im virtuellen Speicher verwaltet wird, verursacht diese Methode keinen großen Speicherkapazitäts-Overhead. Der tatsächlich aktive Speicher muss auf mehrere Speicherseiten aufgerundet werden, um sicherzustellen, dass die Schattengrenze genau zwischen zwei Seiten liegt.
Diese Methode greift in das virtuelle Speichersystem und den Speicherzuweisungsdienst der Laufzeitumgebung ein und daher muss sichergestellt werden, dass bei jeder Änderung der Zuordnung der Haupt- oder Schattenkarte auch das Gegenstück geändert wird.

6.2 Stapelbewegung
In Kombination mit der Shadow-Region-Map implementieren wir einen Mechanismus, um den aktiv genutzten Stack-Speicher zur Laufzeit in beliebigen kleinen Schritten zu verschieben. Dies erreichen wir, indem wir den Stackinhalt an neue Speicherorte kopieren. Wir implementieren mehrere Schritte, um in diesem Szenario die Perspektive der Anwendung auf den Stapel konsistent zu halten.
Der Stapel wird von Zeit zu Zeit verschoben, indem ein kleiner Offset zum Stapelzeiger (sp) hinzugefügt und der alte Stapelinhalt an den neuen Speicherort kopiert wird. Die logische Sicht der Anwendung erwartet immer freie Speicherbytes vor (negativer Offset) dem SP und den bereits erstellten Stack-Inhalt direkt nach (positiver Offset) dem SP.
Solange der Stapel nur innerhalb eines aufeinanderfolgenden Speicherplatzes verschoben wird, kann diese Ansicht problemlos beibehalten werden. Durch die Nutzung des Schattenbereichs wird ein Umlauf erreicht, während der Stapel nur in eine Richtung bewegt wird. Dies führt zu einer rotatorischen Umlagerung des Stapels.
6.2.1 Adresskonsistenz
Das Konzept der zirkulären Verschiebung des Stapels basiert auf dem relativen Zugriff auf den Stapelbereich durch mit C/C++ kompilierte Anwendungen. Der sp relativeaccess ist jedoch nicht die einzige Möglichkeit, auf Speicherinhalte im Stapelspeicher zuzugreifen. Manchmal wird der oder verwendet, um den Zeiger in einer globalen Datenstruktur zu speichern. Darüber hinaus können Zeiger auf Variablen im Stapel auch aus dem Stapel in einige globale oder Heap-Datenstrukturen verschoben werden.
Beim Verschieben des Stapels ändert sich die Speicheradresse der Variablen auf dem Stapel, während der Inhalt der Zeiger unverändert bleibt. Dies führt zu ungültigen Zeigern und damit zu einem falschen Anwendungsverhalten.
Um dieses Problem zu lösen, statten wir das Stapelverschiebungssystem mit zwei Zeigeranpassungsmechanismen aus, die die Richtigkeit der Zeigerinhalte bei Stapelverschiebungen aufrechterhalten.
Um einen Mechanismus zum Erkennen und Anpassen von Verweisen auf veraltete Speicherorte innerhalb des Stapelsegments bereitzustellen, implementieren wir einen seitenbasierten Zeigerkonsistenzmechanismus.
Immer wenn das Stapelsegment um einen kleinen Versatz d (z. B. 64 Byte) verschoben wird, wird der gesamte virtuelle Speicherort ersetzt. Da das Stapelsegment n Speicherseiten zuweist, verbraucht das Setup (einschließlich Schatten) 2 virtuelle Speicherseiten. Anstatt von der früheren Basisadresse b nach b + d zu verlagern, verlagern wir den Stapel auf die virtuelle Adresse b + d + (2n · 4096).
Aus diesem Grund können wir die virtuelle Speicherzuordnung zum alten Speicherort des Stapels ungültig machen. Immer wenn die Anwendung nun über eine veraltete Adresse verfügt und versucht, darauf zuzugreifen, wird eine Falle ausgelöst und vom Betriebssystem behandelt.
Das Trap-verursachende Register wird an die aktuell gültige Position des Stapelsegments angepasst und die Ausführung kann fortgesetzt werden. Traps für Verzweigungen zu veralteten Speicherorten werden ähnlich gehandhabt (Abschnitt 6.3). Der Nachteil dieses Mechanismus besteht darin, dass der Adressraum des virtuellen Speichers langsam verbraucht wird und nicht wiederverwendet werden kann. Eine einfache Berechnung zeigt jedoch, dass dies immer noch nützlich ist: mit einer virtuellen Adressgröße von 48 Bit (z. B. für viele ARMv8--basierte CPUs) und 512 MiB, die dem System zugewiesen werden (d. h. von der Konsistenz nicht genutzt werden können). Mechanismus), 2,8 · 1011 Seiten stehen zur Verfügung.
Wenn jede Sekunde eine Verschiebung erfolgt und die Größe des Stapels n=8 Speicherseiten beträgt, kann die Verschiebung 136 Jahre lang fortgesetzt werden, bis das System keine virtuellen Speicherseiten mehr hat. Dies kann die Lebensdauer der meisten eingebetteten Systeme bei weitem überschreiten.
6.3 Textbewegung
Der zweite Mechanismus für feinkörniges Wear-Leveling in dieser Arbeit ist ein Mechanismus zum Verschieben des kompilierten Binärcodes (dh des Textsegments). Dieser Mechanismus nutzt wiederum den Schattenbereich (Abschnitt 6.1), um eine Rotationsbewegung des gesamten Textsegments zu ermöglichen.
Im Gegensatz zum Verschieben des Stapels (Abschnitt 6.2) müssen mehrere verschiedene Schritte durchgeführt werden, um die Korrektheit des Programms während der Ausführung aufrechtzuerhalten. Das Grundkonzept besteht wiederum darin, den Textabschnitt in kleinen Schritten (z. B. 64 Bytes) durch eine Teilmenge von Speicherseiten zu bewegen, um die ungleichmäßigen Lesezugriffe innerhalb dieser Seiten zu verteilen.
Um dies zu erreichen, ändern wir die laufende Anwendung, um die Bewegung des binären Programmcodes während der Ausführung zu ermöglichen.
6.3.1 Binäre Vorbereitung.
Als ersten Schritt hin zu beweglichem binärem Programmcode während der Ausführung machen wir die Position des gesamten Programmcodes unabhängig, sodass er unabhängig von der absoluten Adresse des Textsegments wird. Dies kann durch die Verwendung der gcc-Option -fPIC erreicht werden, die positionsunabhängigen Code generiert [16].
Der resultierende kompilierte Binärcode führt Verzweigungen und Funktionsaufrufe immer relativ zum Programmzähler aus (dh zur Position der aktuell ausgeführten Anweisung). Zugriffe auf globale Datenstrukturen (Daten und BSS) sowie externe Funktionsaufrufe werden von der Global Offset Table (GOT) und der Procedure Linkage Table (PLT) abgewickelt. Auf diese Tabellen kann mit programmzählerrelativer Adressierung zugegriffen werden.
Die Tabellen werden zur Laufzeit mit entsprechenden absoluten Adressen vom Betriebssystem (dh vom dynamischen Linker) gefüllt. Das PLT enthält auch Einträge für interne Funktionen (nicht für externe Bibliotheksfunktionen), da zur weiteren Adressberechnung manchmal absolute Adressen verwendet werden.
Um eine Unterdrückung dieser Einträge durch den Compiler zu vermeiden, kompilieren wir die Anwendung als Shared Library und laden sie zur Laufzeit in das Betriebssystem. Dies erfordert eine teilweise Verknüpfung, bei der Verweise auf externe Funktionen und Datenstrukturen in GOT und PLT eingefügt werden.

6.3.2 Umzugsroutine. Die tatsächliche Bewegung des Textsegments in kleinen Abständen (z. B. 64 Byte) erfordert die folgenden Schritte:
(1) Wortweise Kopie des Binärtextes
(2) Anpassung der seitenbasierten Adressierung
(3) Aufrechterhaltung der Adresskonsistenz
(4) GOT/PLT-Wartung
(5) PC-Umzug.
Während Schritt (1) ein einfaches Kopieren einzelner Wörter an neue Speicherorte ist, erfordern die nachfolgenden Wartungsschritte einen besonderen Aufwand. Wie bereits erwähnt, verwenden wir positionsunabhängigen Code, um die Unabhängigkeit der absoluten Adresse des Textes zu wahren.
Bei ARMv8 handelt es sich bei den Compiler-Einfügungen um Anweisungen für diesen Zweck (z. B. zur Adressierung von GOT und PLT), die eine Adresse relativ zur 4-KiB-Seite des aktuellen Programmzählers berechnen.
Wenn also eine solche Anweisung von einer 4-KiB-Seite auf eine andere migriert, schreiben wir die Anweisung in Schritt (2) neu und reduzieren den unmittelbaren Offset um 1, um die Offset-Berechnung zum Ziel beizubehalten. Da die GOT- und PLT-Adressen immer durch diese Adrp-Anweisungen bestimmt werden, schließen wir GOT und PLT von der Bewegung des Textsegments aus. Schritt (3) verwendet denselben Adresskonsistenzmechanismus wie zuvor beschrieben (Abschnitt 6.2.1).
Schritt (4) passt Selbstreferenzen auf Funktionen und Datenelemente der Anwendung selbst an, damit die Anwendung weiterhin korrekte Zeiger für diese generieren kann (z. B. Funktionszeiger).
Schließlich setzen wir den Programmzähler auf die neue Position und setzen die Ausführung fort. Insgesamt stellen wir zwei spezielle Mechanismen bereit, um den Stapel und den Text in kleinen Schritten durch den Hauptspeicher zu verschieben.
In Kombination mit unserem Schattenregion-Setup wird diese Bewegung zu einer Rotationsbewegung, die dichte Zugriffs-Hotspots über einen begrenzten Speicherbereich verteilt.
Dieses Schatten-Setup arbeitet vollständig im virtuellen Speicherbereich, und die zugeordneten physischen Seiten können weiterhin durch den grobkörnigen alterungsbewussten Mechanismus ausgetauscht werden.
Die Implementierung wird lediglich geändert, um die doppelte Zuordnung der Schattenseiten konsistent zu halten. Dadurch wird ein gesamtalterungsbewusstes Wear-Leveling erreicht.
For more information:1950477648nn@gmail.com






