Voor- en nadelen van HugePages

Voor- en nadelen van HugePages

Vertaling van het artikel voorbereid voor cursisten "Linux-beheerder".

Eerder had ik het over het testen en inschakelen van Hugepages op Linux.
Dit artikel zal alleen nuttig zijn als je daadwerkelijk een plek hebt om Hugepages te gebruiken. Ik heb veel mensen ontmoet die zich laten misleiden door het vooruitzicht dat Hugepages op magische wijze de productiviteit zal verbeteren. Hugepaging is echter een complex onderwerp en kan de prestaties nadelig beïnvloeden als het verkeerd wordt gebruikt.

Deel 1: Controleren of hugepages zijn ingeschakeld op Linux (origineel hier)

probleem:
U moet controleren of HugePages op uw systeem is ingeschakeld.

oplossing:
Het is vrij eenvoudig:

cat /sys/kernel/mm/transparent_hugepage/enabled

Je krijgt zoiets als dit:

always [madvise] never

U ziet een lijst met beschikbare opties (altijd, gek, nooit), en de momenteel actieve optie wordt tussen haakjes geplaatst (standaard gek).

gek betekent dat transparent hugepages alleen ingeschakeld voor geheugengebieden die expliciet om enorme pagina's vragen met behulp van gek(2).

altijd betekent dat transparent hugepages altijd ingeschakeld voor alle processen. Dit verbetert doorgaans de prestaties, maar als u een gebruiksscenario heeft waarbij veel processen een kleine hoeveelheid geheugen verbruiken, kan de algehele geheugenbelasting dramatisch toenemen.

nooit betekent dat transparent hugepages wordt niet opgenomen, zelfs niet als u dit via Madvise aanvraagt. Voor meer informatie kunt u contact opnemen met documentatie Linux-kernels.

Hoe u de standaardwaarde kunt wijzigen

optie 1: Direct wijzigen sysfs (na het opnieuw opstarten keert de parameter terug naar de standaardwaarde):

echo always >/sys/kernel/mm/transparent_hugepage/enabled
echo madvise >/sys/kernel/mm/transparent_hugepage/enabled
echo never >/sys/kernel/mm/transparent_hugepage/enabled

optie 2: Wijzig de systeemstandaard door de kernel opnieuw te compileren met een aangepaste configuratie (deze optie wordt alleen aanbevolen als u een aangepaste kernel gebruikt):

  • Om altijd standaard in te stellen, gebruikt u:
    CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y
    # Comment out CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y
  • Om madvise als standaard in te stellen, gebruik je:
    CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y
    # Comment out CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y

Deel 2: Voor- en nadelen van HugePages

We zullen proberen selectief de voordelen, nadelen en mogelijke valkuilen van het gebruik van Hugepages uit te leggen. Aangezien een technologisch complex en pedant artikel waarschijnlijk moeilijk te begrijpen zal zijn voor mensen die zich laten misleiden door te denken dat Hugepages een wondermiddel is, zal ik nauwkeurigheid opofferen voor eenvoud. Het is de moeite waard om in gedachten te houden dat veel van de onderwerpen erg complex zijn en daarom enorm vereenvoudigd.

Houd er rekening mee dat we het hebben over 64-bit x86-systemen waarop Linux draait, en dat ik eenvoudigweg aanneem dat het systeem transparante hugepages ondersteunt (aangezien het geen nadeel is dat hugepages niet worden overschreven), zoals het geval is in vrijwel elke moderne Linux omgeving.

Ik zal meer technische beschrijving bijvoegen in de onderstaande links.

Virtueel geheugen

Als u een C++-programmeur bent, weet u dat objecten in het geheugen specifieke adressen (pointerwaarden) hebben.

Deze adressen weerspiegelen echter niet noodzakelijkerwijs fysieke adressen in het geheugen (RAM-adressen). Ze vertegenwoordigen adressen in het virtuele geheugen. De processor heeft een speciale MMU-module (memory management unit) die de kernel helpt virtueel geheugen toe te wijzen aan een fysieke locatie.

Deze aanpak heeft veel voordelen, maar de belangrijkste zijn:

  • Prestaties (om verschillende redenen);
  • Programma-isolatie, dat wil zeggen dat geen enkel programma uit het geheugen van een ander programma kan lezen.

Wat zijn pagina's?

Virtueel geheugen is verdeeld in pagina's. Elke individuele pagina verwijst naar een specifiek fysiek geheugen, het kan verwijzen naar een gebied in het RAM-geheugen, of het kan verwijzen naar een adres dat is toegewezen aan een fysiek apparaat, zoals een videokaart.

De meeste pagina's die u behandelt, verwijzen naar RAM of zijn verwisseld, wat betekent dat ze op uw harde schijf of SSD worden opgeslagen. De kernel beheert de fysieke lay-out van elke pagina. Als een vervalste pagina wordt geopend, stopt de kernel de thread die toegang probeert te krijgen tot het geheugen, leest de pagina van de harde schijf/SSD in het RAM en gaat vervolgens verder met het uitvoeren van de thread.

Dit proces is stream-transparant, wat betekent dat het niet noodzakelijkerwijs rechtstreeks vanaf de HDD/SSD wordt gelezen. De grootte van normale pagina's is 4096 bytes. De grootte van de enorme pagina's is 2 megabytes.

Translatie-associatieve buffer (TLB)

Wanneer een programma toegang krijgt tot een geheugenpagina, moet de CPU weten van welke fysieke pagina de gegevens moeten worden gelezen (dat wil zeggen: een virtuele adreskaart hebben).

De kernel heeft een datastructuur (paginatabel) die alle informatie bevat over de pagina's die worden gebruikt. Met behulp van deze gegevensstructuur kunt u een virtueel adres toewijzen aan een fysiek adres.

De paginatabel is echter behoorlijk complex en traag, dus we kunnen simpelweg niet de hele datastructuur analyseren telkens wanneer een proces toegang krijgt tot het geheugen.

Gelukkig heeft onze processor een TLB die de mapping tussen virtuele en fysieke adressen in de cache opslaat. Dit betekent dat, hoewel we de paginatabel bij de eerste toegangspoging moeten parseren, alle volgende toegangen tot de pagina kunnen worden afgehandeld in de TLB, waardoor een snelle werking mogelijk is.

Omdat het is geïmplementeerd als een fysiek apparaat (wat het in de eerste plaats snel maakt), is de capaciteit ervan beperkt. Dus als u toegang wilt tot meer pagina's, kan de TLB niet voor alle pagina's toewijzingen opslaan, waardoor uw programma veel langzamer draait.

Hugepages komt te hulp

Dus wat kunnen we doen om TLB-overflow te voorkomen? (We gaan ervan uit dat het programma nog steeds dezelfde hoeveelheid geheugen nodig heeft).

Dit is waar Hugepages in beeld komt. In plaats van dat 4096 bytes slechts één TLB-invoer vereisen, kan één TLB-invoer nu verwijzen naar maar liefst 2 megabytes. Laten we aannemen dat de TLB 512 vermeldingen heeft, hier zonder Hugepages kunnen we matchen:

4096 b⋅512=2 MB

Hoe kunnen we dan met hen vergelijken:

2 MB⋅512=1 GB

Dit is de reden waarom Hugepages geweldig is. Ze kunnen de productiviteit zonder veel moeite verbeteren. Maar er zijn hier belangrijke kanttekeningen.

Spoofing van enorme pagina's

De kernel controleert automatisch hoe vaak elke geheugenpagina wordt gebruikt. Als er niet genoeg fysiek geheugen (RAM) is, zal de kernel minder belangrijke (minder vaak gebruikte) pagina's naar de harde schijf verplaatsen om wat RAM vrij te maken voor belangrijkere pagina's.
Voor Hugepages geldt in principe hetzelfde. De kernel kan echter alleen hele pagina's omwisselen, geen individuele bytes.

Laten we zeggen dat we een programma als dit hebben:

char* mymemory = malloc(2*1024*1024); // Возьмем это за одну Hugepage!
// Заполним mymemory какими-либо данными
// Сделаем много других вещей,
// которые приведут к подмене страницы mymemory
// ...
// Запросим доступ только к первому байту
putchar(mymemory[0]); 

In dit geval zal de kernel maar liefst 2 megabytes aan informatie van de harde schijf/SSD moeten vervangen (lezen), alleen al om één byte te kunnen lezen. Net als bij gewone pagina's hoeven er slechts 4096 bytes van de harde schijf/SSD te worden gelezen.

Als de enorme pagina wordt overschreven, is deze dus alleen sneller te lezen als u toegang tot de hele pagina nodig heeft. Dit betekent dat als u willekeurig toegang probeert te krijgen tot verschillende delen van het geheugen en slechts een paar kilobytes leest, u gewone pagina's moet gebruiken en u zich nergens zorgen over hoeft te maken.

Aan de andere kant, als u sequentieel toegang moet hebben tot een groot deel van het geheugen, zullen hugepages uw prestaties verbeteren. Je moet het echter zelf testen (niet met abstracte software) en kijken wat sneller werkt.

Toewijzing in het geheugen

Als je C schrijft, weet je dat je willekeurig kleine (of bijna willekeurig grote) hoeveelheden geheugen van de heap kunt opvragen met behulp van malloc(). Stel dat u 30 bytes geheugen nodig heeft:

char* mymemory = malloc(30);

Voor een programmeur kan het lijken alsof u 30 bytes geheugen 'opvraagt' bij het besturingssysteem en een verwijzing terugstuurt naar een virtueel geheugen. Maar eigenlijk malloc () is slechts een C-functie die vanuit de functie aanroept brk en sbrk om geheugen van het besturingssysteem aan te vragen of vrij te maken.

Het is echter inefficiënt om voor elke toewijzing steeds meer geheugen aan te vragen; het is zeer waarschijnlijk dat een geheugensegment al is vrijgegeven (free()), en we kunnen het hergebruiken. malloc() implementeert vrij complexe algoritmen voor het hergebruiken van vrijgemaakt geheugen.

Tegelijkertijd gebeurt alles onopgemerkt voor u, dus waarom zou u zich daar zorgen over maken? Maar omdat de uitdaging free() betekent dat niet geheugen wordt noodzakelijkerwijs onmiddellijk teruggestuurd naar het besturingssysteem.

Er bestaat zoiets als geheugenfragmentatie. In extreme gevallen zijn er heap-segmenten waar slechts een paar bytes worden gebruikt, terwijl alles daartussenin is vrijgegeven (free()).

Houd er rekening mee dat geheugenfragmentatie een ongelooflijk complex onderwerp is, en dat zelfs kleine wijzigingen in een programma een aanzienlijke impact kunnen hebben. In de meeste gevallen zullen programma's geen significante geheugenfragmentatie veroorzaken, maar u moet zich ervan bewust zijn dat als er een probleem is met de fragmentatie in een bepaald deel van de heap, enorme pagina's de situatie kunnen verergeren.

Selectief gebruik van grote pagina's

Na het lezen van dit artikel heeft u bepaald welke delen van uw programma baat kunnen hebben bij het gebruik van hugepages en welke niet. Moeten enorme pagina's überhaupt worden ingeschakeld?

Gelukkig kun je gebruiken madvise()om hugepaging alleen in te schakelen voor die geheugengebieden waar dit nuttig zou zijn.

Controleer eerst of hugepages in de modus madvise() draait met behulp van instructies aan het begin van het artikel.

Gebruik dan madvise()om de kernel precies te vertellen waar enorme pagina's moeten worden gebruikt.

#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)

Merk op dat deze methode slechts een advies is aan de kernel over hoe het geheugen moet worden beheerd. Dit betekent niet dat de kernel automatisch enorme pagina's zal gebruiken voor een bepaald geheugen.

Raadpleeg de documentatie (manpage)gekvoor meer informatie over geheugenbeheer en madvise(), heeft dit onderwerp een ongelooflijk steile leercurve. Dus als je van plan bent er echt goed in te worden, bereid je dan voor om een ​​paar weken te lezen en te testen voordat je positieve resultaten verwacht.

Wat te lezen?

Heb je een vraag? Schrijf in de reacties!

Bron: www.habr.com

Voeg een reactie