Prednosti in slabosti HugePages

Prednosti in slabosti HugePages

Prevod članka pripravljen za študente "Linux Administrator".

Prej sem govoril o tem, kako preizkusiti in omogočiti Hugepages v Linuxu.
Ta članek bo koristen le, če dejansko imate prostor za uporabo Hugepages. Spoznal sem veliko ljudi, ki jih preslepi možnost, da bodo Hugepages čudežno izboljšali produktivnost. Vendar pa je hugepaging zapletena tema in lahko zmanjša učinkovitost, če se uporablja nepravilno.

1. del: Preverjanje, ali so hugepages omogočene v Linuxu (izvirni tukaj)

Težava:
Preverite, ali je HugePages omogočen v vašem sistemu.

raztopina:
Precej preprosto je:

cat /sys/kernel/mm/transparent_hugepage/enabled

Dobili boste nekaj takega:

always [madvise] never

Videli boste seznam razpoložljivih možnosti (vedno, madvise, nikoli), trenutno aktivna možnost pa bo v oklepajih (privzeto madvise).

madvise pomeni, da transparent hugepages omogočeno samo za področja pomnilnika, ki izrecno zahtevajo uporabo ogromnih strani madvise (2).

vedno pomeni, da transparent hugepages vedno omogočeno za vse procese. To običajno izboljša zmogljivost, vendar če imate primer uporabe, kjer veliko procesov porabi majhno količino pomnilnika, se lahko skupna obremenitev pomnilnika močno poveča.

nikoli pomeni, da transparent hugepages ne bo vključen niti, ko bo zahtevan z madvise. Če želite izvedeti več, kontaktirajte dokumentacijo Jedra Linuxa.

Kako spremeniti privzeto vrednost

Možnost 1: Neposredna sprememba sysfs (po ponovnem zagonu se bo parameter vrnil na privzeto vrednost):

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

Možnost 2: Spremenite privzeto sistemsko nastavitev tako, da ponovno prevedete jedro s spremenjeno konfiguracijo (ta možnost je priporočljiva le, če uporabljate jedro po meri):

  • Če želite vedno nastaviti privzeto, uporabite:
    CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y
    # Comment out CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y
  • Če želite madvise nastaviti kot privzetega, uporabite:
    CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y
    # Comment out CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y

2. del: Prednosti in slabosti HugePages

Poskušali bomo selektivno razložiti prednosti, slabosti in morebitne pasti uporabe Hugepages. Ker bo tehnološko zapleten in pedanten članek verjetno težko razumljiv ljudem, ki se zavajajo, da je Hugepages zdravilo, bom žrtvoval natančnost zaradi preprostosti. Upoštevati je treba le, da je veliko tem res zapletenih in zato zelo poenostavljenih.

Upoštevajte, da govorimo o 64-bitnih sistemih x86, ki poganjajo Linux, in da preprosto predpostavljam, da sistem podpira pregledne ogromne strani (saj ni pomanjkljivost, da ogromne strani niso prepisane), kot je to v skoraj vsakem sodobnem Linuxu okolju.

Več tehničnih opisov bom priložil na spodnjih povezavah.

Navidezni pomnilnik

Če ste programer C++, veste, da imajo objekti v pomnilniku določene naslove (vrednosti kazalcev).

Vendar ti naslovi ne odražajo nujno fizičnih naslovov v pomnilniku (naslovi RAM). Predstavljajo naslove v virtualnem pomnilniku. Procesor ima poseben modul MMU (memory management unit), ki pomaga jedru preslikati navidezni pomnilnik na fizično lokacijo.

Ta pristop ima številne prednosti, najpomembnejše pa so:

  • Učinkovitost (iz različnih razlogov);
  • Izolacija programa, to pomeni, da noben program ne more brati iz pomnilnika drugega programa.

Kaj so strani?

Navidezni pomnilnik je razdeljen na strani. Vsaka posamezna stran kaže na določen fizični pomnilnik, lahko kaže na območje v RAM-u ali pa na naslov, dodeljen fizični napravi, kot je video kartica.

Večina strani, s katerimi imate opravka, kaže na RAM ali so zamenjane, kar pomeni, da so shranjene na vašem trdem disku ali SSD. Jedro upravlja fizično postavitev vsake strani. Če se dostopa do lažne strani, jedro ustavi nit, ki poskuša dostopati do pomnilnika, prebere stran s trdega diska/SSD-ja v RAM in nato nadaljuje z izvajanjem niti.

Ta postopek je pregleden za tok, kar pomeni, da ni nujno, da bere neposredno s trdega diska/SSD. Velikost običajnih strani je 4096 bajtov. Velikost Hugepages je 2 megabajta.

Translation-associative buffer (TLB)

Ko program dostopa do strani pomnilnika, mora CPE vedeti, s katere fizične strani mora prebrati podatke (to pomeni, imeti navidezni zemljevid naslovov).

Jedro ima podatkovno strukturo (tabelo strani), ki vsebuje vse informacije o straneh, ki se uporabljajo. Z uporabo te podatkovne strukture lahko preslikate navidezni naslov v fizični naslov.

Vendar pa je tabela strani precej zapletena in počasna, zato preprosto ne moremo analizirati celotne strukture podatkov vsakič, ko proces dostopa do pomnilnika.

Na srečo ima naš procesor TLB, ki predpomni preslikavo med virtualnimi in fizičnimi naslovi. To pomeni, da čeprav moramo tabelo strani razčleniti ob prvem poskusu dostopa, lahko vse nadaljnje dostope do strani obravnavamo v TLB, kar omogoča hitro delovanje.

Ker je implementiran kot fizična naprava (zaradi česar je sploh hiter), je njegova zmogljivost omejena. Torej, če želite dostopati do več strani, TLB ne bo mogel shraniti preslikav za vse, zaradi česar bo vaš program deloval veliko počasneje.

Hugepages priskoči na pomoč

Torej, kaj lahko storimo, da se izognemo prelivanju TLB? (Predvidevamo, da program še vedno potrebuje enako količino pomnilnika).

Tukaj nastopi Hugepages. Namesto 4096 bajtov, ki zahtevajo le en vnos TLB, lahko en vnos TLB zdaj kaže na velika 2 megabajta. Predpostavimo, da ima TLB 512 vnosov, tukaj brez Hugepages se lahko ujemamo:

4096 b⋅512=2 MB

Kako se potem lahko primerjamo z njimi:

2 MB⋅512=1 GB

Zato je Hugepages super. Brez veliko truda lahko izboljšajo produktivnost. Toda tukaj obstajajo pomembna opozorila.

Ponarejanje ogromnih strani

Jedro samodejno spremlja, kako pogosto se uporablja posamezna pomnilniška stran. Če ni dovolj fizičnega pomnilnika (RAM), bo jedro premaknilo manj pomembne (redkeje uporabljene) strani na trdi disk, da sprosti nekaj RAM-a za pomembnejše strani.
Načeloma enako velja za Hugepages. Vendar pa lahko jedro zamenja le celotne strani, ne pa tudi posameznih bajtov.

Recimo, da imamo tak program:

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

V tem primeru bo moralo jedro zamenjati (prebrati) kar 2 megabajta informacij s trdega diska/SSD-ja samo, da boste lahko prebrali en bajt. Kar zadeva običajne strani, je treba s trdega diska/SSD-ja prebrati samo 4096 bajtov.

Torej, če je hugepage preglasena, je branje hitrejše le, če morate dostopati do celotne strani. To pomeni, da če poskušate naključno dostopati do različnih delov pomnilnika in berete le nekaj kilobajtov, morate uporabiti običajne strani in naj vas ne skrbi nič drugega.

Po drugi strani pa, če morate zaporedno dostopati do velikega dela pomnilnika, bo hugepages izboljšal vašo zmogljivost. Vendar ga morate preizkusiti sami (ne z abstraktno programsko opremo) in videti, kaj deluje hitreje.

Dodelitev v pomnilniku

Če pišete C, veste, da lahko zahtevate poljubno majhne (ali skoraj poljubno velike) količine pomnilnika iz kopice z malloc(). Recimo, da potrebujete 30 bajtov pomnilnika:

char* mymemory = malloc(30);

Programerju se lahko zdi, da od operacijskega sistema »zahtevate« 30 bajtov pomnilnika in vračate kazalec na nekaj navideznega pomnilnika. Ampak dejansko malloc () je samo funkcija C, ki kliče znotraj funkcije brk in sbrk zahtevati ali sprostiti pomnilnik iz operacijskega sistema.

Vendar je zahtevanje več in več pomnilnika za vsako dodelitev neučinkovito; najverjetneje je kakšen segment pomnilnika že sproščen (free()), in jo lahko ponovno uporabimo. malloc() izvaja precej zapletene algoritme za ponovno uporabo sproščenega pomnilnika.

Hkrati se za vas vse dogaja neopaženo, zakaj bi vas torej moralo skrbeti? Ampak ker izziv free() ne pomeni to pomnilnik se nujno takoj vrne v operacijski sistem.

Obstaja nekaj takega, kot je fragmentacija spomina. V skrajnih primerih obstajajo segmenti kopice, kjer je uporabljenih le nekaj bajtov, medtem ko je vse vmes osvobojeno (free()).

Upoštevajte, da je razdrobljenost pomnilnika izjemno zapletena tema in da lahko že manjše spremembe programa pomembno vplivajo. V večini primerov programi ne bodo povzročili znatne fragmentacije pomnilnika, vendar se morate zavedati, da če obstaja težava s fragmentacijo na nekem področju kopice, lahko ogromne strani situacijo poslabšajo.

Selektivna uporaba ogromnih strani

Ko ste prebrali ta članek, ste ugotovili, kateri deli vašega programa imajo koristi od uporabe hugepages in kateri ne. Bi torej morali hugepages sploh omogočiti?

Na srečo lahko uporabite madvise()da omogočite hugepaging samo za tista pomnilniška področja, kjer bi bilo koristno.

Najprej preverite, ali se hugepages izvaja v načinu madvise() z uporabo Navodila na začetku članka.

Nato uporabite madvise()da jedru natančno pove, kje naj uporablja 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)

Upoštevajte, da je ta metoda le nasvet jedru, kako upravljati pomnilnik. To ne pomeni, da bo jedro samodejno uporabljalo ogromne strani za določen pomnilnik.

Glejte dokumentacijo (manpage)madviseče želite izvedeti več o upravljanju pomnilnika in madvise(), ima ta tema neverjetno strmo krivuljo učenja. Torej, če nameravate v tem postati res dobri, se pripravite na branje in testiranje nekaj tednov, preden pričakujete pozitivne rezultate.

Kaj brati?

Imate vprašanje? Zapiši v komentar!

Vir: www.habr.com

Dodaj komentar