Avantatges i desavantatges de HugePages

Avantatges i desavantatges de HugePages

Traducció de l'article preparat per als estudiants del curs "Administrador Linux".

Anteriorment, vaig parlar sobre com provar i habilitar Hugepages a Linux.
Aquest article només serà útil si realment teniu un lloc per utilitzar Hugepages. He conegut moltes persones que es veuen enganyades per la perspectiva que Hugepages millorarà màgicament la productivitat. Tanmateix, l'enorme pàgina és un tema complex i pot degradar el rendiment si s'utilitza incorrectament.

Part 1: verificació que les pàgines enormes estiguin habilitades a Linux (original aquí)

Problema:
Heu de comprovar si HugePages està habilitat al vostre sistema.

solució:
És bastant senzill:

cat /sys/kernel/mm/transparent_hugepage/enabled

Obtindreu alguna cosa com això:

always [madvise] never

Veureu una llista d'opcions disponibles (sempre, boig, mai), i l'opció activa actualment es tancarà entre parèntesis (per defecte boig).

boig significa això transparent hugepages habilitat només per a àrees de memòria que sol·liciten explícitament pàgines enormes bogeria (2).

sempre significa això transparent hugepages sempre habilitat per a tots els processos. Això normalment millora el rendiment, però si teniu un cas d'ús en què molts processos consumeixen una petita quantitat de memòria, aleshores la càrrega de memòria global pot augmentar dràsticament.

mai significa això transparent hugepages no s'inclourà fins i tot quan es sol·liciti mitjançant madvise. Per saber-ne més, contacteu documentació nuclis de Linux.

Com canviar el valor predeterminat

Opció 1: Canvia directament sysfs (després de reiniciar el paràmetre tornarà al seu valor predeterminat):

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

Opció 2: Canvieu el sistema predeterminat recompilant el nucli amb una configuració modificada (aquesta opció només es recomana si feu servir un nucli personalitzat):

  • Per configurar sempre per defecte, utilitzeu:
    CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y
    # Comment out CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y
  • Per establir madvise com a predeterminat, utilitzeu:
    CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y
    # Comment out CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y

Part 2: Avantatges i desavantatges d'HugePages

Intentarem explicar de manera selectiva els avantatges, els inconvenients i els possibles inconvenients d'utilitzar Hugepages. Com que un article tecnològicament complex i pedant serà difícil d'entendre per a les persones que s'enganyen fent pensar que Hugepages és una panacea, sacrificaré la precisió per la simplicitat. Només val la pena tenir en compte que molts dels temes són realment complexos i, per tant, molt simplificats.

Tingueu en compte que estem parlant de sistemes x64 de 86 bits que executen Linux, i que simplement estic suposant que el sistema admet pàgines enormes transparents (ja que no és un desavantatge que les pàgines enormes no es sobreescriuen), com és el cas de gairebé qualsevol Linux modern. medi ambient.

Adjuntaré més descripció tècnica als enllaços següents.

Memòria virtual

Si sou un programador de C++, sabeu que els objectes de la memòria tenen adreces específiques (valors de punter).

Tanmateix, aquestes adreces no reflecteixen necessàriament adreces físiques a la memòria (adreces RAM). Representen adreces a la memòria virtual. El processador té un mòdul MMU (unitat de gestió de memòria) especial que ajuda el nucli a mapejar la memòria virtual a una ubicació física.

Aquest enfocament té molts avantatges, però els més importants són:

  • Rendiment (per diverses raons);
  • Aïllament del programa, és a dir, cap programa pot llegir de la memòria d'un altre programa.

Què són les pàgines?

La memòria virtual es divideix en pàgines. Cada pàgina individual apunta a una memòria física específica, pot apuntar a una àrea de la RAM o pot apuntar a una adreça assignada a un dispositiu físic, com ara una targeta de vídeo.

La majoria de les pàgines amb què tractes apunten a la memòria RAM o s'intercanvien, és a dir, s'emmagatzemen al disc dur o SSD. El nucli gestiona el disseny físic de cada pàgina. Si s'accedeix a una pàgina falsificada, el nucli atura el fil que està intentant accedir a la memòria, llegeix la pàgina des del disc dur/SSD a la memòria RAM i, a continuació, continua executant el fil.

Aquest procés és transparent, és a dir, no necessàriament es llegeix directament des de l'HDD/SSD. La mida de les pàgines normals és de 4096 bytes. La mida de les pàgines enormes és de 2 megabytes.

Buffer associatiu de traducció (TLB)

Quan un programa accedeix a una pàgina de memòria, la CPU ha de saber de quina pàgina física llegir les dades (és a dir, tenir un mapa d'adreces virtuals).

El nucli té una estructura de dades (taula de pàgines) que conté tota la informació sobre les pàgines que s'utilitzen. Amb aquesta estructura de dades, podeu assignar una adreça virtual a una adreça física.

Tanmateix, la taula de pàgines és força complexa i lenta, de manera que simplement no podem analitzar tota l'estructura de dades cada vegada que un procés accedeix a la memòria.

Afortunadament, el nostre processador té un TLB que guarda a la memòria cau el mapeig entre adreces virtuals i físiques. Això vol dir que tot i que hem d'analitzar la taula de pàgines en el primer intent d'accés, tots els accessos posteriors a la pàgina es poden gestionar al TLB, permetent un funcionament ràpid.

Com que s'implementa com un dispositiu físic (que el fa ràpid en primer lloc), la seva capacitat és limitada. Per tant, si voleu accedir a més pàgines, el TLB no podrà emmagatzemar mapes per a totes, la qual cosa farà que el vostre programa s'executi molt més lentament.

Hugepages ve al rescat

Aleshores, què podem fer per evitar el desbordament de TLB? (Suposem que el programa encara necessita la mateixa quantitat de memòria).

Aquí és on entra en joc Hugepages. En lloc de 4096 bytes que requereixen només una entrada TLB, una entrada TLB ara pot apuntar a 2 megabytes. Suposem que el TLB té 512 entrades, aquí sense Hugepages podem coincidir:

4096 b⋅512=2 MB

Aleshores, com podem comparar-los:

2 MB⋅512=1 GB

Per això Hugepages és fantàstic. Poden millorar la productivitat sense gaire esforç. Però aquí hi ha advertències importants.

Falsificació de pàgines enormes

El nucli controla automàticament la freqüència amb què s'utilitza cada pàgina de memòria. Si no hi ha prou memòria física (RAM), el nucli mourà pàgines menys importants (s'utilitzen amb menys freqüència) al disc dur per alliberar una mica de RAM per a pàgines més importants.
En principi, el mateix s'aplica a Hugepages. Tanmateix, el nucli només pot intercanviar pàgines senceres, no bytes individuals.

Suposem que tenim un programa com aquest:

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

En aquest cas, el nucli haurà de substituir (llegir) fins a 2 megabytes d'informació del disc dur/SSD només perquè llegiu un byte. Pel que fa a les pàgines normals, només cal llegir 4096 bytes des del disc dur/SSD.

Per tant, si se substitueix hugepage, només serà més ràpid de llegir si necessiteu accedir a tota la pàgina. Això vol dir que si esteu intentant accedir aleatòriament a diferents parts de la memòria i només esteu llegint un parell de kilobytes, hauríeu d'utilitzar pàgines normals i no preocupar-vos de res més.

D'altra banda, si necessiteu accedir a una gran part de la memòria de manera seqüencial, les pàgines enormes milloraran el vostre rendiment. Tanmateix, heu de provar-ho vosaltres mateixos (no amb programari abstracte) i veure què funciona més ràpidament.

Assignació en memòria

Si escriviu C, sabeu que podeu sol·licitar quantitats arbitràriament petites (o gairebé arbitràriament grans) de memòria del munt utilitzant malloc(). Suposem que necessiteu 30 bytes de memòria:

char* mymemory = malloc(30);

Per a un programador, pot semblar que esteu "sol·licitant" 30 bytes de memòria del sistema operatiu i retornant un punter a alguna memòria virtual. Però en realitat malloc () és només una funció C que crida des de la funció brk i sbrk per sol·licitar o alliberar memòria del sistema operatiu.

Tanmateix, demanar cada cop més memòria per a cada assignació és ineficient; el més probable és que algun segment de memòria ja s'hagi alliberat (free()), i el podem reutilitzar. malloc() implementa algorismes força complexos per reutilitzar la memòria alliberada.

Al mateix temps, tot passa desapercebut per a tu, així que per què t'ha de preocupar? Però perquè el repte free() no vol dir això La memòria es retorna necessàriament immediatament al sistema operatiu.

Hi ha una cosa com la fragmentació de la memòria. En casos extrems, hi ha segments de pila on només s'utilitzen uns quants bytes, mentre que tot el que hi ha entre s'ha alliberat (free()).

Tingueu en compte que la fragmentació de la memòria és un tema increïblement complex, i fins i tot els canvis menors a un programa poden tenir un impacte significatiu. En la majoria dels casos, els programes no provocaran una fragmentació significativa de la memòria, però hauríeu de tenir en compte que si hi ha un problema amb la fragmentació en alguna àrea del munt, les pàgines enormes poden empitjorar la situació.

Ús selectiu de pàgines enormes

Després de llegir l'article, heu determinat quines parts del vostre programa es poden beneficiar de l'ús de pàgines enormes i quines no. Aleshores, s'han d'habilitar les pàgines enormes?

Per sort pots utilitzar madvise()per habilitar la paginació enorme només per a aquelles àrees de memòria on seria útil.

Primer, comproveu que hugepages s'està executant en mode madvise() utilitzant instruccions al principi de l'article.

Després, utilitza madvise()per dir-li al nucli exactament on utilitzar les pàgines enormes.

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

Tingueu en compte que aquest mètode és simplement un consell per al nucli sobre com gestionar la memòria. Això no vol dir que el nucli utilitzarà automàticament pàgines enormes per a una memòria determinada.

Consulteu la documentació (pàgina de manual) boigper obtenir més informació sobre la gestió de la memòria i madvise(), aquest tema té una corba d'aprenentatge increïblement pronunciada. Per tant, si teniu intenció d'aconseguir-ho molt bé, prepareu-vos per llegir i provar durant unes setmanes abans d'esperar cap resultat positiu.

Què llegir?

Tens alguna pregunta? Escriu als comentaris!

Font: www.habr.com

Afegeix comentari