Fordeler og ulemper med HugePages

Fordeler og ulemper med HugePages

Oversettelse av artikkelen utarbeidet for kursstudenter "Linux-administrator".

Tidligere snakket jeg om hvordan du tester og aktiverer Hugepages på Linux.
Denne artikkelen vil bare være nyttig hvis du faktisk har et sted å bruke Hugepages. Jeg har møtt mange mennesker som lar seg lure av utsiktene til at Hugepages på magisk vis vil forbedre produktiviteten. Imidlertid er hugepaging et komplekst emne og kan redusere ytelsen hvis det brukes feil.

Del 1: Bekrefte at hugepages er aktivert på Linux (original her)

problem:
Du må sjekke om HugePages er aktivert på systemet ditt.

løsning:
Det er ganske enkelt:

cat /sys/kernel/mm/transparent_hugepage/enabled

Du vil få noe sånt som dette:

always [madvise] never

Du vil se en liste over tilgjengelige alternativer (alltid, gale, aldri), og det aktive alternativet vil være omsluttet i parentes (som standard madvise).

madvise betyr at transparent hugepages aktivert bare for minneområder som eksplisitt ber om enorme sider ved hjelp av madvise (2).

alltid betyr at transparent hugepages alltid aktivert for alle prosesser. Dette forbedrer vanligvis ytelsen, men hvis du har et brukstilfelle der mange prosesser bruker en liten mengde minne, kan den totale minnebelastningen øke dramatisk.

aldri betyr at transparent hugepages vil ikke inkluderes selv når du blir bedt om det ved hjelp av madvise. For å finne ut mer, kontakt dokumentasjon Linux-kjerner.

Hvordan endre standardverdien

Alternativ 1: Endre direkte sysfs (etter omstart vil parameteren gå tilbake til standardverdien):

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

Alternativ 2: Endre systemets standard ved å rekompilere kjernen med en modifisert konfigurasjon (dette alternativet anbefales kun hvis du bruker en tilpasset kjerne):

  • For å angi alltid som standard, bruk:
    CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y
    # Comment out CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y
  • For å angi madvise som standard, bruk:
    CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y
    # Comment out CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y

Del 2: Fordeler og ulemper med HugePages

Vi vil prøve å selektivt forklare fordeler, ulemper og mulige fallgruver ved å bruke Hugepages. Siden en teknologisk kompleks og pedantisk artikkel sannsynligvis vil være vanskelig å forstå for folk som er lurt til å tro at Hugepages er et universalmiddel, vil jeg ofre nøyaktighet for enkelhet. Det er bare verdt å huske på at mange av temaene er veldig komplekse og derfor sterkt forenklet.

Vær oppmerksom på at vi snakker om 64-bit x86-systemer som kjører Linux, og at jeg ganske enkelt antar at systemet støtter transparente hugepages (siden det ikke er en ulempe at hugepages ikke overskrives), slik tilfellet er i nesten alle moderne Linux miljø.

Jeg legger ved mer teknisk beskrivelse i lenkene nedenfor.

Virtuell hukommelse

Hvis du er en C++-programmerer, vet du at objekter i minnet har spesifikke adresser (pekerverdier).

Disse adressene reflekterer imidlertid ikke nødvendigvis fysiske adresser i minnet (RAM-adresser). De representerer adresser i virtuelt minne. Prosessoren har en spesiell MMU-modul (memory management unit) som hjelper kjernen å kartlegge virtuelt minne til en fysisk plassering.

Denne tilnærmingen har mange fordeler, men de viktigste er:

  • Ytelse (av ulike grunner);
  • Programisolasjon, det vil si at intet program kan lese fra minnet til et annet program.

Hva er sider?

Virtuelt minne er delt inn i sider. Hver enkelt side peker til et spesifikt fysisk minne, den kan peke til et område i RAM, eller den kan peke til en adresse som er tilordnet en fysisk enhet, for eksempel et skjermkort.

De fleste sidene du arbeider med peker enten på RAM eller byttes, noe som betyr at de er lagret på harddisken eller SSD-en din. Kjernen styrer det fysiske oppsettet til hver side. Hvis en forfalsket side åpnes, stopper kjernen tråden som prøver å få tilgang til minnet, leser siden fra harddisken/SSD til RAM, og fortsetter deretter å kjøre tråden.

Denne prosessen er strømgjennomsiktig, noe som betyr at den ikke nødvendigvis leser direkte fra HDD/SSD. Størrelsen på vanlige sider er 4096 byte. Hugepages-størrelsen er 2 megabyte.

Translasjonsassosiativ buffer (TLB)

Når et program får tilgang til en side med minne, må CPU vite hvilken fysisk side den skal lese data fra (det vil si ha et virtuelt adressekart).

Kjernen har en datastruktur (sidetabell) som inneholder all informasjon om sidene som brukes. Ved å bruke denne datastrukturen kan du tilordne en virtuell adresse til en fysisk adresse.

Однако таблица страниц довольно сложна и работает медленно, поэтому мы просто не можем каждый раз анализировать всю структуру данных, когда какой-либо процесс обращается к памяти.

Heldigvis har prosessoren vår en TLB som cacher kartleggingen mellom virtuelle og fysiske adresser. Dette betyr at selv om vi trenger å analysere sidetabellen ved det første tilgangsforsøket, kan alle påfølgende tilganger til siden håndteres i TLB, noe som gir rask drift.

Fordi den er implementert som en fysisk enhet (som gjør den rask i utgangspunktet), er kapasiteten begrenset. Så hvis du vil ha tilgang til flere sider, vil ikke TLB kunne lagre tilordninger for dem alle, noe som fører til at programmet kjører mye tregere.

Hugepages kommer til unnsetning

Så hva kan vi gjøre for å unngå TLB-overløp? (Vi antar at programmet fortsatt trenger samme mengde minne).

Det er her Hugepages kommer inn. I stedet for at 4096 byte bare krever én TLB-oppføring, kan én TLB-oppføring nå peke til hele 2 megabyte. La oss anta at TLB har 512 oppføringer, her uten Hugepages kan vi matche:

4096 b⋅512=2 MB

Så hvordan kan vi sammenligne med dem:

2 MB⋅512=1 GB

Dette er grunnen til at Hugepages er fantastisk. De kan forbedre produktiviteten uten mye innsats. Men det er betydelige forbehold her.

Hugepages forfalskning

Kjernen overvåker automatisk hvor ofte hver minneside brukes. Hvis det ikke er nok fysisk minne (RAM), vil kjernen flytte mindre viktige (sjeldnere brukte) sider til harddisken for å frigjøre noe RAM for viktigere sider.
I prinsippet gjelder det samme for Hugepages. Imidlertid kan kjernen bare bytte hele sider, ikke individuelle byte.

La oss si at vi har et program som dette:

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

I dette tilfellet må kjernen erstatte (lese) så mye som 2 megabyte med informasjon fra harddisken/SSD-en bare for at du skal kunne lese én byte. Når det gjelder vanlige sider, trenger kun 4096 byte å leses fra harddisken/SSD.

Derfor, hvis hugepage overstyres, er det bare raskere å lese hvis du trenger å få tilgang til hele siden. Dette betyr at hvis du prøver å få tilgang til forskjellige deler av minnet tilfeldig og bare leser et par kilobyte, bør du bruke vanlige sider og ikke bekymre deg for noe annet.

På den annen side, hvis du trenger å få tilgang til en stor del av minnet sekvensielt, vil enorme sider forbedre ytelsen din. Du må imidlertid teste det selv (ikke med abstrakt programvare) og se hva som fungerer raskere.

Tildeling i minnet

Hvis du skriver C, vet du at du kan be om vilkårlig små (eller nesten vilkårlig store) mengder minne fra haugen ved å bruke malloc(). La oss si at du trenger 30 byte minne:

char* mymemory = malloc(30);

For en programmerer kan det virke som om du "ber om" 30 byte minne fra operativsystemet og returnerer en peker til et virtuelt minne. Men egentlig malloc () er bare en C-funksjon som kaller fra funksjonen brk og sbrk for å be om eller frigjøre minne fra operativsystemet.

Å be om mer og mer minne for hver tildeling er imidlertid ineffektivt; det er mest sannsynlig at et minnesegment allerede er frigjort (free()), og vi kan gjenbruke den. malloc() implementerer ganske komplekse algoritmer for gjenbruk av frigjort minne.

Samtidig skjer alt ubemerket for deg, så hvorfor skulle det bekymre deg? Men fordi utfordringen free() betyr ikke det minne returneres nødvendigvis umiddelbart til operativsystemet.

Det er noe slikt som minnefragmentering. I ekstreme tilfeller er det heap-segmenter der bare noen få byte brukes, mens alt i mellom er frigjort (free()).

Vær oppmerksom på at minnefragmentering er et utrolig komplekst emne, og selv mindre endringer i et program kan ha en betydelig innvirkning. I de fleste tilfeller vil ikke programmer forårsake betydelig minnefragmentering, men du bør være klar over at hvis det er et problem med fragmentering i et område av haugen, kan enorme sider gjøre situasjonen verre.

Selektiv bruk av enorme sider

Etter å ha lest denne artikkelen har du bestemt hvilke deler av programmet som kan dra nytte av å bruke enorme sider og hvilke som ikke kan. Så bør enorme sider være aktivert i det hele tatt?

Heldigvis kan du bruke madvise()for å aktivere hugepaging kun for de minneområdene der det ville være nyttig.

Først, sjekk at hugepages kjører i madvise()-modus ved å bruke instruksjoner i begynnelsen av artikkelen.

Bruk deretter madvise()å fortelle kjernen nøyaktig hvor den skal bruke hugepages.

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

Legg merke til at denne metoden rett og slett er et råd til kjernen om hvordan man administrerer minne. Dette betyr ikke at kjernen automatisk vil bruke enorme sider for et gitt minne.

Se dokumentasjon (manpage)madvisefor å lære mer om minnehåndtering og madvise(), har dette emnet en utrolig bratt læringskurve. Så hvis du har tenkt å bli veldig god på det, forbered deg på å lese og teste i noen uker før du forventer positive resultater.

Hva skal man lese?

Har et spørsmål? Skriv i kommentarfeltet!

Kilde: www.habr.com

Legg til en kommentar