
Übersetzung des Artikels für Studierende des Kurses .
Ich habe bereits darüber gesprochen, wie man die Verwendung von Hugepages in Linux überprüft und aktiviert.
Dieser Artikel ist nur dann nützlich, wenn Sie tatsächlich irgendwo Hugepages verwenden können. Ich habe viele Leute getroffen, die sich von der Aussicht täuschen lassen, dass Hugepages die Leistung magisch steigern. Dennoch ist das Thema Hugepaging komplex und kann bei falscher Anwendung die Leistung verschlechtern.
Teil 1: Überprüfen, ob Hugepages in Linux aktiviert sind (Original) )
Problem:
Es muss überprüft werden, ob HugePages in Ihrem System aktiviert sind.
Die Lösung:
Das ist recht einfach:
cat /sys/kernel/mm/transparent_hugepage/enabledSie sollten etwas in der Art erhalten:
always [madvise] neverSie sehen eine Liste der verfügbaren Optionen (always, madvise, never), wobei die aktuell aktive Option in Klammern gesetzt ist (standardmäßig madvise).
madvise bedeutet, dass transparente Hugepages sind nur für Speicherbereiche aktiviert, die ausdrücklich Hugepages mit Hilfe von .
always bedeutet, dass transparente Hugepages aktiviert sind, werden immer und für alle Prozesse aktiviert. Normalerweise steigert dies die Leistung, aber wenn Sie ein Anwendungsszenario haben, in dem viele Prozesse eine geringe Menge an Speicher verbrauchen, kann die gesamte Speicherauslastung stark ansteigen.
never bedeutet, dass transparente Hugepages werden selbst bei einer Anfrage mit madvise nicht aktiviert. Um mehr zu erfahren, wenden Sie sich an Linux-Kerne.
So ändern Sie den Standardwert
Option 1: Direkte Änderung sysfs (nach einem Neustart kehrt der Parameter zum Standardwert zurück):
echo always >/sys/kernel/mm/transparent_hugepage/enabled
echo madvise >/sys/kernel/mm/transparent_hugepage/enabled
echo never >/sys/kernel/mm/transparent_hugepage/enabledOption 2: Ändern Sie den Standardwert des Systems, indem Sie den Kernel mit einer geänderten Konfiguration neu kompilieren (diese Option wird nur empfohlen, wenn Sie einen eigenen Kernel verwenden):
- Um always als Standardwert zu setzen, verwenden Sie:
CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y # Kommentieren Sie CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y aus - Um madvise als Standardwert zu setzen, verwenden Sie:
CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y # Kommentieren Sie CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y aus
Teil 2: Vor- und Nachteile von HugePages
Wir versuchen, selektiv die Vorzüge, Nachteile und möglichen Fehler bei der Verwendung von HugePages zu erläutern. Da es sich um einen technologisch anspruchsvollen und präzisen Artikel handelt, der möglicherweise schwer zu verstehen ist für diejenigen, die in der Überzeugung leben, HugePages seien eine Allheilmittel, werde ich der Einfachheit zuliebe auf Genauigkeit verzichten. Es ist jedoch wichtig zu beachten, dass viele Themen wirklich komplex sind und daher stark vereinfacht werden.
Bitte beachten Sie, dass wir über 64-Bit-x86-Systeme sprechen, die auf Linux basieren, und ich gehe einfach davon aus, dass das System transparent hugepages unterstützt (da es kein Mangel ist, wenn hugepages nicht ersetzt werden), wie es in nahezu jeder modernen Linux-Umgebung der Fall ist.
In den folgenden Links werde ich weitere technische Beschreibungen anhängen.
Virtueller Speicher
Wenn Sie C++-Programmierer sind, wissen Sie, dass Objekte im Speicher spezifische Adressen (Zeigerwerte) haben.
Diese Adressen spiegeln jedoch nicht unbedingt physische Adressen im Speicher (Adressen im RAM) wider. Sie stellen Adressen im virtuellen Speicher dar. Der Prozessor verfügt über ein spezielles Modul, die MMU (Memory Management Unit), die dem Kern hilft, den virtuellen Speicher mit dem physischen Standort abzugleichen.
Dieser Ansatz hat viele Vorteile, aber die grundlegendsten sind:
- Leistung (aus verschiedenen Gründen);
- Isolierung von Programmen, das heißt, kein Programm kann aus dem Speicher eines anderen Programms lesen.
Was sind Seiten?
Der virtuelle Speicher ist in Seiten unterteilt. Jede einzelne Seite verweist auf einen bestimmten physischen Speicher, sie kann auf einen Bereich im Arbeitsspeicher oder auf eine Adresse verweisen, die einem physischen Gerät zugewiesen ist, wie etwa einer Grafikkarte.
Die meisten Seiten, mit denen Sie arbeiten, verweisen entweder auf den RAM oder werden ausgelagert (Swap), was bedeutet, dass sie auf einer Festplatte oder SSD gespeichert sind. Der Kernel verwaltet die physische Zuordnung jeder Seite. Wenn auf eine ausgelagerte Seite zugegriffen wird, stoppt der Kernel den Thread, der versucht, auf den Speicher zuzugreifen, liest die Seite von der Festplatte/SSD in den RAM und setzt dann die Ausführung des Threads fort.
Dieser Prozess ist für den Thread transparent, das heißt, er liest nicht unbedingt direkt von der Festplatte/SSD. Die Größe normaler Seiten beträgt 4096 Byte. Die Größe von Hugepages beträgt 2 Megabyte.
Translation Lookaside Buffer (TLB)
Wenn ein Programm auf eine bestimmte Speicherseite zugreift, muss die zentrale Verarbeitungseinheit (CPU) wissen, von welcher physischen Seite die Daten gelesen werden sollen (d.h. sie muss eine virtuelle Adresskarte haben).
Im Kern gibt es eine Datenstruktur (Seiten Tabelle), die alle Informationen über die verwendeten Seiten enthält. Mit Hilfe dieser Datenstruktur kann eine virtuelle Adresse einer physischen Adresse zugeordnet werden.
Die Seitentabelle ist jedoch recht komplex und arbeitet langsam, weshalb wir nicht jedes Mal die gesamte Datenstruktur analysieren können, wenn ein Prozess auf den Speicher zugreift.
Glücklicherweise verfügt unser Prozessor über eine TLB, die die Zuordnung von virtuellen und physischen Adressen cached. Das bedeutet, dass, obwohl wir die Seitentabelle beim ersten Zugriff analysieren müssen, alle nachfolgenden Zugriffe auf die Seite über die TLB verarbeitet werden können, was eine schnelle Verarbeitung gewährleistet.
Da sie als physisches Gerät implementiert ist (was sie in erster Linie schnell macht), ist ihre Kapazität begrenzt. Daher, wenn Sie auf eine größere Anzahl von Seiten zugreifen möchten, kann die TLB nicht alle Zuordnungen speichern, was dazu führt, dass Ihr Programm deutlich langsamer läuft.
Hugepages kommen zur Hilfe.
Was können wir tun, um eine TLB-Überfüllung zu vermeiden? (Wir nehmen an, dass das Programm immer noch den gleichen Speicherbedarf hat).
Hier kommen Hugepages ins Spiel. Anstatt 4096 Bytes, die nur einen Eintrag im TLB benötigen, kann ein Eintrag im TLB jetzt auf massive 2 Megabyte verweisen. Angenommen, das TLB hat 512 Einträge, ohne Hugepages können wir zuordnen:
4096 b ⋅ 512 = 2 MBWährend wir mit ihnen zuordnen können:
2 MB ⋅ 512 = 1 GBDeshalb sind Hugepages so großartig. Sie können die Leistung steigern, ohne erheblichen Aufwand. Aber es gibt bedeutende Vorbehalte.
Umstellung auf Hugepages
Der Kernel überwacht automatisch die Zugriffshäufigkeit jeder Speicherseite. Wenn nicht genügend physischer Speicher (RAM) vorhanden ist, verschiebt der Kernel weniger wichtige (seltener verwendete) Seiten auf die Festplatte, um Speicherplatz für wichtigere Seiten freizugeben.
Im Prinzip gilt das Gleiche für Hugepages. Der Kernel kann jedoch nur ganze Seiten und nicht einzelne Bytes verschieben.
Angenommen, wir haben folgendes Programm:
char* mymemory = malloc(2*1024*1024); // Betrachten wir dies als eine Hugepage!
// Wir füllen mymemory mit einigen Daten
// Wir machen viele andere Dinge,
// die zu einem Seitenwechsel von mymemory führen
// ...
// Fordern Sie Zugriff nur auf das erste Byte an
putchar(mymemory[0]); In diesem Fall muss der Kernel ganze 2 Megabyte Informationen von der Festplatte/SSD lesen, nur damit Sie ein Byte lesen können. Bei normalen Seiten müssen nur 4096 Byte von der Festplatte/SSD gelesen werden.
Daher, wenn hugepage gewechselt wird, erfolgt das Lesen schneller, aber nur wenn Sie auf die gesamte Seite zugreifen müssen. Das bedeutet, dass wenn Sie zufällig auf verschiedene Teile des Speichers zugreifen und nur ein paar Kilobyte lesen, Sie normale Seiten verwenden sollten und sich um nichts anderes kümmern müssen.
Andererseits, wenn Sie auf einen großen Teil des Speichers sequenziell zugreifen müssen, werden hugepages Ihre Leistung steigern. Dennoch sollten Sie dies selbst überprüfen (nicht anhand einer abstrakten Software) und sehen, was schneller funktioniert.
Speicherallokation
Wenn Sie in C programmieren, wissen Sie, dass Sie beliebig kleine (oder fast beliebig große) Mengen an Speicher aus dem Heap anfordern können mit malloc(). Angenommen, Sie benötigen 30 Byte Speicher:
char* mymemory = malloc(30);Dem Programmierer mag es erscheinen, als würden Sie 30 Byte Speicher vom Betriebssystem „anfordern“ und einen Zeiger auf bestimmten virtuellen Speicher zurückgeben. Tatsächlich malloc() ist einfach eine C-Funktion, die intern die Funktionen aufruft, um Speicher vom Betriebssystem anzufordern oder freizugeben.
Es ist jedoch ineffizient, für jede Zuweisung immer mehr Speicher anzufordern; wahrscheinlicher ist es, dass ein gewisser Speicherbereich bereits freigegeben wurde (free()), und wir können ihn wiederverwenden. malloc() führt ziemlich komplexe Algorithmen zum Wiederverwenden von freigegebenem Speicher durch.
Für Sie geschieht dies jedoch unbemerkt, warum sollte es Sie also interessieren? Weil der Aufruf free() nicht bedeutet, dass .
Es gibt ein Konzept namens Speicherfragmentierung. In extremen Fällen gibt es Bereiche des Heaps, in denen nur wenige Bytes verwendet werden, während alles dazwischen freigegeben wurde. (free()).
Beachten Sie, dass Speicherfragmentierung ein unglaublich komplexes Thema ist und selbst geringfügige Änderungen im Programm einen erheblichen Einfluss darauf haben können. In den meisten Fällen verursachen Programme keine signifikante Speicherfragmentierung, aber Sie sollten im Hinterkopf behalten, dass, wenn es in einem bestimmten Bereich des Heaps ein Problem mit der Fragmentierung gibt, hugepages die Situation nur verschlimmern können.
Selektive Anwendung von hugepages
Nachdem Sie den Artikel gelesen haben, haben Sie festgestellt, welche Teile Ihres Programms von der Anwendung von hugepages profitieren können und welche nicht. Sollten hugepages also überhaupt aktiviert werden?
Glücklicherweise können Sie madvise(), um hugepaging nur für die Bereiche des Speichers zu aktivieren, wo es sinnvoll ist.
Zuerst überprüfen Sie, ob hugepages im madvise()-Modus arbeiten, mit Hilfe von zu Beginn des Artikels.
Verwenden Sie anschließend madvise(), um dem Kernel anzugeben, wo genau hugepages verwendet werden sollen.
#include <sys/mman.h>
// Аллоцируйте большое количество памяти, которую будете использовать
size_t size = 256*1024*1024;
char* mymemory = malloc(size);
// Просто включите hugepages…
madvise(mymemory, size, MADV_HUGEPAGE);
// … и задайте следующее
madvise(mymemory, size, MADV_HUGEPAGE | MADV_SEQUENTIAL)Bitte beachten Sie, dass diese Methode lediglich Empfehlungen für den Umgang des Kernels mit dem Speicher darstellt. Das bedeutet nicht, dass der Kernel automatisch Hugepages für den angegebenen Speicher verwenden wird.
Bitte konsultieren Sie die Dokumentation , um mehr über das Speichermanagement zu erfahren und madvise(), dieses Thema hat eine äußerst steile Lernkurve. Wenn Sie also wirklich gut darin werden möchten, bereiten Sie sich darauf vor, mehrere Wochen mit Lesen und Testen zu verbringen, bevor Sie mit irgendeinem positiven Ergebnis rechnen können.
Was sollten Sie lesen?
Haben Sie Fragen? Hinterlassen Sie einen Kommentar!
Quelle: habr.com
