HugePages priekšrocības un trūkumi

HugePages priekšrocības un trūkumi

Kursa studentiem sagatavots raksta tulkojums "Linux administrators".

Iepriekš es runāju par to, kā pārbaudīt un iespējot Hugepages operētājsistēmā Linux.
Šis raksts būs noderīgs tikai tad, ja jums patiešām ir vieta, kur izmantot Hugepages. Esmu saticis daudzus cilvēkus, kurus apmāna izredzes, ka Hugepages maģiski uzlabos produktivitāti. Tomēr milzīgā lapošana ir sarežģīta tēma un var pasliktināt veiktspēju, ja to lieto nepareizi.

1. daļa. Pārbaude, vai operētājsistēmā Linux ir iespējotas milzīgas lapas (oriģināls šeit)

Problēma:
Jums jāpārbauda, ​​vai jūsu sistēmā ir iespējots HugePages.

šķīdums:
Tas ir diezgan vienkārši:

cat /sys/kernel/mm/transparent_hugepage/enabled

Jūs saņemsiet kaut ko līdzīgu šim:

always [madvise] never

Jūs redzēsit pieejamo opciju sarakstu (vienmēr, madvise, nekad), un pašlaik aktīvā opcija tiks ievietota iekavās (pēc noklusējuma madvise).

madvise nozīmē to transparent hugepages iespējots tikai tiem atmiņas apgabaliem, kas skaidri pieprasa milzīgas lapas Madvise (2).

vienmēr nozīmē to transparent hugepages vienmēr iespējots visiem procesiem. Tas parasti uzlabo veiktspēju, taču, ja jums ir lietošanas gadījums, kad daudzi procesi patērē nelielu daudzumu atmiņas, kopējā atmiņas slodze var ievērojami palielināties.

nekad nozīmē to transparent hugepages netiks iekļauts pat tad, ja to pieprasa, izmantojot madvise. Lai uzzinātu vairāk, sazinieties dokumentācija Linux kodoli.

Kā mainīt noklusējuma vērtību

iespēja 1: tieši mainīt sysfs (pēc pārstartēšanas parametrs atgriezīsies tā noklusējuma vērtībā):

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

iespēja 2: mainiet sistēmas noklusējuma iestatījumus, pārkompilējot kodolu ar modificētu konfigurāciju (šī opcija ir ieteicama tikai tad, ja izmantojat pielāgotu kodolu):

  • Lai pēc noklusējuma iestatītu vienmēr, izmantojiet:
    CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y
    # Comment out CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y
  • Lai iestatītu madvise kā noklusējumu, izmantojiet:
    CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y
    # Comment out CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y

2. daļa: HugePages priekšrocības un trūkumi

Mēs centīsimies selektīvi izskaidrot Hugepages lietošanas priekšrocības, trūkumus un iespējamās nepilnības. Tā kā tehnoloģiski sarežģīts un pedantisks raksts, visticamāk, būs grūti saprotams cilvēkiem, kuri ir maldināti, domājot, ka Hugepages ir panaceja, es upurēšu precizitāti vienkāršības dēļ. Ir tikai vērts paturēt prātā, ka daudzas tēmas ir patiešām sarežģītas un tāpēc ievērojami vienkāršotas.

Lūdzu, ņemiet vērā, ka mēs runājam par 64 bitu x86 sistēmām, kurās darbojas Linux, un es vienkārši pieņemu, ka sistēma atbalsta caurspīdīgas lielas lapas (jo tas nav trūkums, ka lielas lapas netiek pārrakstītas), kā tas ir gandrīz jebkurā mūsdienu Linux. vidi.

Sīkāku tehnisko aprakstu pievienošu zemāk esošajās saitēs.

Virtuālā atmiņa

Ja esat C++ programmētājs, jūs zināt, ka objektiem atmiņā ir noteiktas adreses (rādītāja vērtības).

Tomēr šīs adreses ne vienmēr atspoguļo fiziskās adreses atmiņā (RAM adreses). Tie apzīmē adreses virtuālajā atmiņā. Procesoram ir īpašs MMU (atmiņas pārvaldības vienības) modulis, kas palīdz kodolam kartēt virtuālo atmiņu uz fizisko vietu.

Šai pieejai ir daudz priekšrocību, bet vissvarīgākās no tām ir:

  • Veiktspēja (dažādu iemeslu dēļ);
  • Programmas izolācija, tas ir, neviena programma nevar nolasīt no citas programmas atmiņas.

Kas ir lapas?

Virtuālā atmiņa ir sadalīta lapās. Katra atsevišķa lapa norāda uz noteiktu fizisko atmiņu, tā var norādīt uz apgabalu RAM vai uz adresi, kas piešķirta fiziskai ierīcei, piemēram, videokartei.

Lielākā daļa lapu, ar kurām strādājat, norāda uz RAM vai tiek apmainītas, kas nozīmē, ka tās tiek saglabātas jūsu cietajā diskā vai SSD. Kodols pārvalda katras lapas fizisko izkārtojumu. Ja tiek piekļūta viltota lapa, kodols aptur pavedienu, kas mēģina piekļūt atmiņai, nolasa lapu no cietā diska/SSD RAM un pēc tam turpina pavediena izpildi.

Šis process ir straumes caurspīdīgs, kas nozīmē, ka tas ne vienmēr tiek nolasīts tieši no HDD/SSD. Parasto lapu izmērs ir 4096 baiti. Milzīgu lapu izmērs ir 2 megabaiti.

Tulkošanas-asociatīvais buferis (TLB)

Kad programma piekļūst atmiņas lapai, centrālajam procesoram ir jāzina, no kuras fiziskās lapas nolasīt datus (tas ir, jābūt virtuālai adreses kartei).

Kodolam ir datu struktūra (lapu tabula), kurā ir visa informācija par izmantotajām lapām. Izmantojot šo datu struktūru, varat kartēt virtuālo adresi ar fizisko adresi.

Tomēr lapas tabula ir diezgan sarežģīta un lēna, tāpēc mēs vienkārši nevaram analizēt visu datu struktūru katru reizi, kad process piekļūst atmiņai.

Par laimi, mūsu procesoram ir TLB, kas kešatmiņā saglabā kartēšanu starp virtuālajām un fiziskajām adresēm. Tas nozīmē, ka, lai gan mums ir jāparsē lapas tabula pirmajā piekļuves mēģinājumā, visas turpmākās piekļuves lapai var tikt apstrādātas TLB, tādējādi nodrošinot ātru darbību.

Tā kā tā ir ieviesta kā fiziska ierīce (kas, pirmkārt, padara to ātru), tās jauda ir ierobežota. Tātad, ja vēlaties piekļūt vairākām lapām, TLB nevarēs saglabāt kartējumus par tām visām, tādējādi jūsu programma darbosies daudz lēnāk.

Hugepages nāk palīgā

Tātad, ko mēs varam darīt, lai izvairītos no TLB pārpildes? (Mēs pieņemam, ka programmai joprojām ir nepieciešams tāds pats atmiņas apjoms).

Šeit parādās Hugepages. Tā vietā, lai 4096 baitiem būtu nepieciešams tikai viens TLB ieraksts, viens TLB ieraksts tagad var norādīt uz milzīgiem 2 megabaitiem. Pieņemsim, ka TLB ir 512 ieraksti, šeit bez Hugepages mēs varam saskaņot:

4096 b⋅512=2 MB

Tad kā mēs varam ar viņiem salīdzināt:

2 MB⋅512=1 GB

Tāpēc Hugepages ir lieliska. Tie var uzlabot produktivitāti bez lielas piepūles. Bet šeit ir būtiski brīdinājumi.

Milzīgu lapu viltošana

Kodols automātiski uzrauga, cik bieži tiek izmantota katra atmiņas lapa. Ja nepietiek fiziskās atmiņas (RAM), kodols pārvietos mazāk svarīgas (retāk izmantotās) lapas uz cieto disku, lai atbrīvotu daļu RAM svarīgākām lapām.
Principā tas pats attiecas uz Hugepages. Tomēr kodols var apmainīt tikai visas lapas, nevis atsevišķus baitus.

Pieņemsim, ka mums ir šāda programma:

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

Šajā gadījumā kodolam būs jāaizstāj (nolasa) pat 2 megabaiti informācijas no cietā diska/SSD, lai jūs varētu nolasīt vienu baitu. Kas attiecas uz parastajām lapām, no cietā diska/SSD ir jānolasa tikai 4096 baiti.

Tāpēc, ja milzīga lapa ir ignorēta, tā lasīšana ir ātrāka tikai tad, ja jums ir nepieciešams piekļūt visai lapai. Tas nozīmē, ka, ja jūs mēģināt nejauši piekļūt dažādām atmiņas daļām un lasāt tikai pāris kilobaitus, jums vajadzētu izmantot parastās lapas un neuztraukties ne par ko citu.

No otras puses, ja jums ir nepieciešams secīgi piekļūt lielai atmiņas daļai, milzīgas lapas uzlabos jūsu veiktspēju. Tomēr jums tas ir jāpārbauda pašam (nevis ar abstraktu programmatūru) un jāskatās, kas darbojas ātrāk.

Sadalījums atmiņā

Ja rakstāt C, jūs zināt, ka varat pieprasīt patvaļīgi mazus (vai gandrīz patvaļīgi lielus) atmiņas apjomus no kaudzes, izmantojot malloc(). Pieņemsim, ka jums ir nepieciešami 30 baiti atmiņas:

char* mymemory = malloc(30);

Programmētājam var šķist, ka jūs “pieprasāt” 30 baitus atmiņas no operētājsistēmas un atgriežat rādītāju uz kādu virtuālo atmiņu. Bet patiesībā malloc () ir tikai C funkcija, kas izsauc no funkcijas iekšpuses brk un sbrk lai pieprasītu vai atbrīvotu atmiņu no operētājsistēmas.

Tomēr pieprasīt arvien vairāk atmiņas katram piešķīrumam ir neefektīva; visticamāk, kāds atmiņas segments jau ir atbrīvots (free()), un mēs varam to izmantot atkārtoti. malloc() ievieš diezgan sarežģītus algoritmus atbrīvotās atmiņas atkārtotai izmantošanai.

Tajā pašā laikā tev viss notiek nemanot, tad kāpēc lai tas tevi satrauc? Bet tāpēc, ka izaicinājums free() tas nenozīmē atmiņa nekavējoties tiek atgriezta operētājsistēmā.

Ir tāda lieta kā atmiņas sadrumstalotība. Ārkārtējos gadījumos ir kaudzes segmenti, kuros tiek izmantoti tikai daži baiti, bet viss pa vidu ir atbrīvots (free()).

Lūdzu, ņemiet vērā, ka atmiņas fragmentācija ir neticami sarežģīta tēma, un pat nelielas programmas izmaiņas var būtiski ietekmēt. Vairumā gadījumu programmas neizraisīs ievērojamu atmiņas sadrumstalotību, taču jums jāapzinās, ka, ja kādā kaudzes apgabalā rodas sadrumstalotības problēma, lielas lapas var pasliktināt situāciju.

Selektīva lielu lapu izmantošana

Pēc šī raksta izlasīšanas jūs noskaidrojāt, kuras jūsu programmas daļas var gūt labumu no milzīgu lapu izmantošanas un kuras ne. Tātad, vai milzīgas lapas vispār ir jāiespējo?

Par laimi jūs varat izmantot madvise()lai iespējotu milzīgo lapošanu tikai tiem atmiņas apgabaliem, kur tas būtu noderīgi.

Vispirms pārbaudiet, vai hugepages darbojas madvise() režīmā, izmantojot instrukcijas raksta sākumā.

Pēc tam izmantojiet madvise()lai precīzi pateiktu kodolam, kur izmantot milzīgas lapas.

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

Ņemiet vērā, ka šī metode ir vienkārši padoms kodolam, kā pārvaldīt atmiņu. Tas nenozīmē, ka kodols konkrētajai atmiņai automātiski izmantos milzīgas lapas.

Skatiet dokumentāciju (manpage)madviselai uzzinātu vairāk par atmiņas pārvaldību un madvise(), šai tēmai ir neticami strauja mācīšanās līkne. Tāpēc, ja vēlaties iegūt patiešām labus rezultātus, sagatavojieties lasīšanai un pārbaudi dažas nedēļas, pirms sagaidāt pozitīvus rezultātus.

Ko lasīt?

Vai jums ir jautājums? Raksti komentāros!

Avots: www.habr.com

Pievieno komentāru