Voor- en nadelen van HugePages

Voor- en nadelen van HugePages

Vertaling van het artikel voorbereid voor cursisten "Beheerder Linux».

Eerder heb ik uitgelegd hoe je het gebruik van Hugepages kunt controleren en inschakelen. Linux.
Dit artikel is alleen nuttig als u daadwerkelijk een plek hebt waar u Hugepages kunt gebruiken. Ik heb veel mensen ontmoet die geloven dat Hugepages op magische wijze hun productiviteit zal verhogen. Hugepaging is echter een complex onderwerp en kan de prestaties verslechteren als het verkeerd wordt gebruikt.

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

probleem:
Controleer of HugePages op uw systeem is ingeschakeld.

oplossing:
Het is heel eenvoudig:

cat /sys/kernel/mm/transparent_hugepage/enabled

Je krijgt dan zoiets:

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 enorme pagina's aanvragen met behulp van madvise(2).

altijd betekent dat transparent hugepages zijn altijd ingeschakeld en voor alle processen. Meestal verbetert dit de prestaties, maar als u een situatie hebt waarbij veel processen een kleine hoeveelheid geheugen gebruiken, kan de algehele geheugenbelasting aanzienlijk toenemen.

nooit betekent dat transparent hugepages worden niet opgenomen, zelfs niet als dit via madvise wordt aangevraagd. Voor meer informatie kunt u contact opnemen met documentatie de kernen Linux.

Hoe de standaardwaarde te 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 de gewijzigde configuratie (deze optie wordt alleen aanbevolen als u een aangepaste kernel gebruikt):

  • Om dit altijd als 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, gebruikt u:
    CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y
    # Comment out CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y

Deel 2: Voordelen en nadelen van HugePages

We zullen proberen de voor- en nadelen en mogelijke fouten bij het gebruik van Hugepages selectief uit te leggen. Omdat een technologisch complex en pedant artikel waarschijnlijk moeilijk te begrijpen zal zijn voor mensen die denken dat Hugepages een wondermiddel is, zal ik precisie opofferen voor eenvoud. Houd er rekening mee dat veel onderwerpen in feite complex zijn en daardoor sterk vereenvoudigd.

Houd er rekening mee dat we het hebben over 64-bits x86-systemen die draaien op LinuxEn ik ga er simpelweg van uit dat het systeem transparante hugepages ondersteunt (aangezien het geen nadeel is dat hugepages niet worden vervangen), zoals in vrijwel elke moderne omgeving het geval is. Linux.

Ik zal via onderstaande links een meer technische beschrijving bijvoegen.

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 de fysieke adressen in het geheugen (RAM-adressen). Ze representeren adressen in het virtuele geheugen. De processor beschikt over een speciale MMU-module (Memory Management Unit) die de kernel helpt bij het toewijzen van virtueel geheugen aan de fysieke locatie.

Deze aanpak kent veel voordelen, maar de belangrijkste zijn:

  • Productiviteit (om verschillende redenen);
  • Programma-isolatie, wat betekent dat geen enkel programma het geheugen van een ander programma kan lezen.

Wat zijn pagina's?

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

De meeste pagina's die u bekijkt, verwijzen naar het RAM-geheugen of zijn verwisseld. Dit betekent dat ze op een harde schijf of SSD zijn opgeslagen. De kernel beheert de fysieke lay-out van elke pagina. Als er toegang wordt verkregen tot een omgewisselde pagina, 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 transparant voor de stream, wat betekent dat de gegevens niet noodzakelijkerwijs rechtstreeks van de harde schijf/SSD worden gelezen. De grootte van normale pagina's is 4096 bytes. De enorme paginagrootte bedraagt ​​2 megabyte.

Vertaal Lookaside Buffer (TLB)

Wanneer een programma een pagina in het geheugen benadert, moet de CPU weten van welke fysieke pagina de gegevens moeten worden gelezen (dat wil zeggen, er moet een virtueel adres zijn).

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

De paginatabel is echter vrij complex en traag, dus we kunnen niet elke keer dat een proces het geheugen benadert, de volledige gegevensstructuur analyseren.

Gelukkig beschikt onze processor over een TLB die de toewijzing tussen virtuele en fysieke adressen cachet. Dit betekent dat, ook al moeten we de paginatabel scannen als we deze voor de eerste keer willen openen, alle daaropvolgende paginatoegangen in de TLB kunnen worden afgehandeld, waardoor een snelle werking wordt gegarandeerd.

Omdat het een fysiek apparaat is (en daardoor sowieso al snel is), is de capaciteit ervan beperkt. Als u dus meer pagina's wilt openen, kan de TLB de toewijzing niet voor alle pagina's opslaan. Uw programma wordt dan veel langzamer.

Hugepages schiet te hulp

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

Hier komt Hugepages in beeld. In plaats van 4096 bytes waarvoor slechts één TLB-vermelding nodig was, kan één TLB-vermelding nu verwijzen naar maar liefst 2 megabytes. Laten we aannemen dat de TLB 512 vermeldingen heeft. Zonder Hugepages kunnen we dan het volgende in kaart brengen:

4096 b⋅512=2 MB

Hoe kunnen we ze dan vergelijken met:

2 MB⋅512=1 GB

Daarom is Hugepages zo geweldig. Ze kunnen de productiviteit zonder veel moeite verhogen. Maar er zijn hierbij belangrijke kanttekeningen te maken.

Vervanging van Hugepages

De kernel houdt automatisch bij hoe vaak elke geheugenpagina wordt gebruikt. Als het fysieke geheugen (RAM) onvoldoende is, verplaatst de kernel minder belangrijke (minder vaak gebruikte) pagina's naar de harde schijf om 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 aannemen dat we een programma hebben zoals dit:

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

In dit geval moet de kernel maar liefst 2 megabyte aan informatie van de harde schijf/SSD vervangen (lezen), zodat u één byte kunt lezen. Voor normale pagina's hoeven slechts 4096 bytes van de HDD/SSD te worden gelezen.

Als hugepage wordt vervangen, is het alleen sneller om te lezen als je de hele pagina nodig hebt. Dit betekent dat als u toegang probeert te krijgen tot willekeurige delen van het geheugen en u slechts een paar kilobytes leest, u gewone pagina's kunt gebruiken en u zich nergens anders zorgen over hoeft te maken.

Als u daarentegen een groot deel van het geheugen sequentieel moet benaderen, zullen hugepages uw prestaties verbeteren. U moet dit echter zelf testen (niet op een abstract softwarevoorbeeld) en kijken wat sneller werkt.

Geheugentoewijzing

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 hebt:

char* mymemory = malloc(30);

Voor een programmeur kan het lijken alsof u 30 bytes geheugen "opvraagt" van het besturingssysteem en een pointer naar virtueel geheugen retourneert. Maar in werkelijkheid malloc () - het is gewoon een C-functie die functies van binnenuit aanroept brk en sbrk om geheugen op te vragen of vrij te geven van het besturingssysteem.

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

Tegelijkertijd gebeurt alles ongemerkt, dus waarom zou het jou iets kunnen schelen? Omdat het een uitdaging is free() betekent niet dat het geheugen wordt noodzakelijkerwijs onmiddellijk teruggestuurd naar het besturingssysteem.

Er bestaat zoiets als geheugenfragmentatie. In extreme gevallen zijn er heap-segmenten waarbij slechts enkele bytes worden gebruikt, terwijl alles daartussen is vrijgegeven. (free()).

Houd er rekening mee dat geheugenfragmentatie een uiterst complex onderwerp is en dat zelfs kleine wijzigingen in een programma een aanzienlijke impact kunnen hebben. In de meeste gevallen veroorzaken programma's geen noemenswaardige geheugenfragmentatie, maar u moet er rekening mee houden dat als fragmentatie een probleem vormt in een bepaald gebied van de heap, hugepages het probleem kunnen verergeren.

Selectief gebruik van enorme pagina's

Nadat u het artikel hebt gelezen, weet u welke onderdelen van uw programma baat kunnen hebben bij hugepages en welke niet. Moeten hugepages überhaupt ingeschakeld worden?

Gelukkig kun je gebruik maken van madvise()om hugepaging alleen mogelijk te maken voor die geheugengebieden waar het nuttig zal zijn.

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

Gebruik dan madvise()om de kernel precies te vertellen waar hugepages gebruikt moeten worden.

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

Houd er rekening mee dat deze methode simpelweg een aanbeveling aan de kernel is over hoe het geheugen beheerd moet worden. Dit betekent niet dat de kernel automatisch enorme pagina's gebruikt voor een bepaald geheugen.

Raadpleeg de documentatie (manpagina) madviseom meer te leren over geheugenbeheer en madvise(), dit onderwerp heeft een ongelooflijk steile leercurve. Dus als je er echt goed in wilt worden, bereid je er dan op voor dat je een aantal weken lang veel moet lezen en testen voordat je positieve resultaten kunt verwachten.

Wat moet ik lezen?

Heeft u een vraag? Schrijf in de reacties!

Bron: www.habr.com

Koop betrouwbare hosting voor sites met DDoS-bescherming, VPS VDS-servers 🔥 Koop betrouwbare websitehosting met DDoS-bescherming, VPS- en VDS-servers | ProHoster