HugePages-ի առավելություններն ու թերությունները

HugePages-ի առավելություններն ու թերությունները

Դասընթացի ուսանողների համար պատրաստված հոդվածի թարգմանությունը «Linux Administrator».

Նախկինում ես խոսեցի այն մասին, թե ինչպես փորձարկել և միացնել Hugepages-ը Linux-ում:
Այս հոդվածը օգտակար կլինի միայն այն դեպքում, եթե դուք իսկապես տեղ ունեք Hugepages-ից օգտվելու համար: Ես հանդիպել եմ շատ մարդկանց, ովքեր խաբված են այն հեռանկարով, որ Hugepages-ը կախարդական կերպով կբարելավի արտադրողականությունը: Այնուամենայնիվ, հսկայական էջերը բարդ թեմա է և կարող է վատթարացնել կատարողականությունը, եթե սխալ օգտագործվի:

Մաս 1. Ստուգում, որ հսկայական էջերը միացված են Linux-ում (օրիգինալ այստեղ)

Problem:
Դուք պետք է ստուգեք, արդյոք HugePages-ը միացված է ձեր համակարգում:

լուծում:
Դա բավականին պարզ է.

cat /sys/kernel/mm/transparent_hugepage/enabled

Դուք կստանաք նման բան.

always [madvise] never

Դուք կտեսնեք առկա ընտրանքների ցանկը (միշտ, խելագար, երբեք), իսկ ներկայումս ակտիվ տարբերակը կփակվի փակագծերում (ըստ լռելյայն խենթացնել).

խենթացնել նշանակում է, որ transparent hugepages միացված է միայն հիշողության տարածքների համար, որոնք բացահայտորեն պահանջում են հսկայական էջեր օգտագործելով խելագարություն (2).

միշտ նշանակում է, որ transparent hugepages միշտ միացված է բոլոր գործընթացների համար: Սա սովորաբար բարելավում է կատարումը, բայց եթե դուք ունեք օգտագործման դեպք, երբ շատ գործընթացներ սպառում են փոքր քանակությամբ հիշողություն, ապա ընդհանուր հիշողության ծանրաբեռնվածությունը կարող է կտրուկ աճել:

երբեք նշանակում է, որ transparent hugepages չի ներառվի նույնիսկ այն դեպքում, երբ պահանջվում է օգտագործելով madvise: Ավելին իմանալու համար դիմեք փաստաթղթավորում Linux միջուկներ.

Ինչպես փոխել լռելյայն արժեքը

Ընտրանք 1Անմիջապես փոխել sysfs (վերագործարկումից հետո պարամետրը կվերադառնա իր լռելյայն արժեքին).

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

Ընտրանք 2Փոխեք համակարգի լռելյայնությունը՝ վերակոմպիլացնելով միջուկը փոփոխված կազմաձևով (այս տարբերակը խորհուրդ է տրվում միայն այն դեպքում, եթե դուք օգտագործում եք հատուկ միջուկ):

  • Միշտ լռելյայն սահմանելու համար օգտագործեք՝
    CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y
    # Comment out CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y
  • Madvise-ը որպես լռելյայն սահմանելու համար օգտագործեք՝
    CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y
    # Comment out CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y

Մաս 2. HugePages-ի առավելություններն ու թերությունները

Մենք կփորձենք ընտրողաբար բացատրել Hugepages-ի օգտագործման առավելությունները, թերությունները և հնարավոր թակարդները: Քանի որ տեխնոլոգիապես բարդ և մանկական հոդվածը, հավանաբար, դժվար կլինի հասկանալ այն մարդկանց համար, ովքեր մոլորության մեջ են, որ Hugepages-ը համադարման միջոց է, ես կզոհաբերեմ ճշգրտությունը պարզության համար: Պարզապես արժե նկատի ունենալ, որ շատ թեմաներ իսկապես բարդ են և, հետևաբար, շատ պարզեցված:

Խնդրում ենք նկատի ունենալ, որ մենք խոսում ենք Linux-ով աշխատող 64-բիթանոց x86 համակարգերի մասին, և որ ես պարզապես ենթադրում եմ, որ համակարգը աջակցում է թափանցիկ հսկայական էջեր (քանի որ թերություն չէ, որ հսկայական էջերը չեն վերագրվում), ինչպես դա տեղի է ունենում գրեթե ցանկացած ժամանակակից Linux-ում: միջավայրը։

Ես կցեմ ավելի շատ տեխնիկական նկարագրություն ստորև բերված հղումներում:

Վիրտուալ հիշողություն

Եթե ​​դուք C++ ծրագրավորող եք, գիտեք, որ հիշողության մեջ գտնվող օբյեկտներն ունեն հատուկ հասցեներ (ցուցիչի արժեքներ):

Այնուամենայնիվ, այս հասցեները պարտադիր չէ, որ արտացոլեն ֆիզիկական հասցեները հիշողության մեջ (RAM հասցեներ): Նրանք ներկայացնում են հասցեներ վիրտուալ հիշողության մեջ: Պրոցեսորն ունի հատուկ MMU (հիշողության կառավարման միավոր) մոդուլ, որն օգնում է միջուկին վիրտուալ հիշողությունը քարտեզագրել ֆիզիկական վայրում:

Այս մոտեցումը շատ առավելություններ ունի, բայց ամենակարևորներն են.

  • Կատարում (տարբեր պատճառներով);
  • Ծրագրի մեկուսացում, այսինքն՝ ոչ մի ծրագիր չի կարող կարդալ մեկ այլ ծրագրի հիշողությունից։

Ի՞նչ են էջերը:

Վիրտուալ հիշողությունը բաժանված է էջերի։ Յուրաքանչյուր առանձին էջ մատնանշում է որոշակի ֆիզիկական հիշողություն, այն կարող է մատնանշել RAM-ի տարածքը կամ կարող է մատնանշել ֆիզիկական սարքին հատկացված հասցե, օրինակ՝ վիդեո քարտ:

Էջերի մեծ մասը, որոնց հետ գործ ունեք, կա՛մ մատնանշում են RAM-ը, կա՛մ փոխվում են, այսինքն՝ դրանք պահվում են ձեր կոշտ սկավառակի կամ SSD-ի վրա: Միջուկը կառավարում է յուրաքանչյուր էջի ֆիզիկական դասավորությունը: Եթե ​​կեղծված էջ մուտք է գործում, միջուկը դադարեցնում է շարանը, որը փորձում է մուտք գործել հիշողություն, կարդում է էջը կոշտ սկավառակից/SSD-ից դեպի RAM և այնուհետև շարունակում է գործարկել շարանը:

Այս գործընթացը հոսքային թափանցիկ է, ինչը նշանակում է, որ այն պարտադիր չէ, որ կարդալ անմիջապես HDD/SSD-ից: Նորմալ էջերի չափը 4096 բայթ է։ Հսկայական էջերի չափը 2 մեգաբայթ է:

Թարգմանական ասոցիատիվ բուֆեր (TLB)

Երբ ծրագիրը մուտք է գործում հիշողության էջ, պրոցեսորը պետք է իմանա, թե որ ֆիզիկական էջից պետք է կարդալ տվյալները (այսինքն ունենալ վիրտուալ հասցեի քարտեզ):

Միջուկն ունի տվյալների կառուցվածք (էջ աղյուսակ), որը պարունակում է օգտագործվող էջերի մասին ամբողջ տեղեկատվությունը: Օգտագործելով այս տվյալների կառուցվածքը, կարող եք վիրտուալ հասցեն ֆիզիկական հասցեի քարտեզագրել:

Այնուամենայնիվ, էջերի աղյուսակը բավականին բարդ և դանդաղ է, ուստի մենք պարզապես չենք կարող վերլուծել տվյալների ամբողջ կառուցվածքը ամեն անգամ, երբ գործընթացը մուտք է գործում հիշողություն:

Բարեբախտաբար, մեր պրոցեսորն ունի TLB, որը պահում է քարտեզագրումը վիրտուալ և ֆիզիկական հասցեների միջև: Սա նշանակում է, որ չնայած մենք պետք է վերլուծենք էջի աղյուսակը առաջին մուտքի փորձի ժամանակ, էջին հաջորդող բոլոր մուտքերը կարող են կարգավորվել TLB-ում, ինչը թույլ է տալիս արագ գործել:

Քանի որ այն ներդրված է որպես ֆիզիկական սարք (ինչն առաջին հերթին արագացնում է), դրա հզորությունը սահմանափակ է: Այսպիսով, եթե ցանկանում եք մուտք գործել ավելի շատ էջեր, TLB-ն չի կարողանա բոլորի համար քարտեզներ պահել, ինչի պատճառով ձեր ծրագիրը շատ ավելի դանդաղ է աշխատում:

Օգնության է գալիս Hugepages-ը

Այսպիսով, ի՞նչ կարող ենք անել TLB-ի արտահոսքից խուսափելու համար: (Մենք ենթադրում ենք, որ ծրագիրը դեռևս նույն քանակությամբ հիշողության կարիք ունի):

Հենց այստեղ է գալիս Hugepages-ը: 4096 բայթի փոխարեն, որը պահանջում է ընդամենը մեկ TLB մուտք, մեկ TLB մուտքն այժմ կարող է ցույց տալ հսկայական 2 մեգաբայթ: Ենթադրենք, որ TLB-ն ունի 512 գրառում, այստեղ առանց Hugepages մենք կարող ենք համապատասխանել.

4096 b⋅512=2 MB

Այդ դեպքում ինչպես կարող ենք համեմատվել նրանց հետ.

2 MB⋅512=1 GB

Ահա թե ինչու է Hugepages-ը հիանալի: Նրանք կարող են բարելավել արտադրողականությունը առանց մեծ ջանքերի: Բայց այստեղ զգալի նախազգուշացումներ կան:

Հսկայական էջերի կեղծում

Միջուկը ավտոմատ կերպով վերահսկում է, թե որքան հաճախ է օգտագործվում յուրաքանչյուր հիշողության էջը: Եթե ​​բավարար ֆիզիկական հիշողություն (RAM) չկա, միջուկը ավելի քիչ կարևոր (ավելի քիչ հաճախ օգտագործվող) էջերը կտեղափոխի կոշտ սկավառակ՝ ավելի կարևոր էջերի համար որոշ RAM ազատելու համար:
Սկզբունքորեն նույնը վերաբերում է Hugepages-ին։ Այնուամենայնիվ, միջուկը կարող է փոխանակել միայն ամբողջ էջերը, այլ ոչ թե առանձին բայթեր:

Եկեք ասենք, որ մենք ունենք այսպիսի ծրագիր.

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

Այս դեպքում միջուկը պետք է փոխարինի (կարդա) մինչև 2 մեգաբայթ տեղեկատվություն կոշտ սկավառակից/SSD-ից միայն մեկ բայթ կարդալու համար: Ինչ վերաբերում է սովորական էջերին, ապա կոշտ սկավառակից/SSD-ից անհրաժեշտ է կարդալ ընդամենը 4096 բայթ:

Հետևաբար, եթե հսկայական էջը վերացված է, այն ավելի արագ է կարդալ միայն այն դեպքում, եթե ձեզ անհրաժեշտ է մուտք գործել ամբողջ էջ: Սա նշանակում է, որ եթե դուք փորձում եք պատահականորեն մուտք գործել հիշողության տարբեր մասեր և պարզապես կարդում եք մի քանի կիլոբայթ, ապա պետք է օգտագործեք սովորական էջեր և չանհանգստանաք այլ բանի համար:

Մյուս կողմից, եթե ձեզ անհրաժեշտ է հաջորդաբար մուտք գործել հիշողության մեծ մասը, հսկայական էջերը կբարելավեն ձեր կատարումը: Այնուամենայնիվ, դուք պետք է փորձարկեք այն ինքներդ (ոչ վերացական ծրագրաշարով) և տեսնեք, թե ինչն է ավելի արագ աշխատում:

Հիշողության մեջ տեղաբաշխում

Եթե ​​գրում եք C, դուք գիտեք, որ դուք կարող եք կամայականորեն փոքր (կամ գրեթե կամայականորեն մեծ) հիշողություն պահանջել կույտից՝ օգտագործելով malloc(). Ենթադրենք, ձեզ անհրաժեշտ է 30 բայթ հիշողություն.

char* mymemory = malloc(30);

Ծրագրավորողին կարող է թվալ, որ դուք օպերացիոն համակարգից «պահանջում եք» 30 բայթ հիշողություն և ցուցիչ եք վերադարձնում որոշ վիրտուալ հիշողություն: Բայց իրականում malloc () պարզապես C ֆունկցիա է, որը կանչում է ֆունկցիայի ներսից բրկ և սբրկ օպերացիոն համակարգից հիշողություն պահանջելու կամ ազատելու համար:

Այնուամենայնիվ, յուրաքանչյուր տեղաբաշխման համար ավելի ու ավելի շատ հիշողություն պահանջելը անարդյունավետ է. Ամենայն հավանականությամբ, հիշողության որոշ հատված արդեն ազատվել է (free()), և մենք կարող ենք նորից օգտագործել այն: malloc() իրականացնում է բավականին բարդ ալգորիթմներ ազատված հիշողության վերօգտագործման համար:

Միևնույն ժամանակ, ձեզ մոտ ամեն ինչ աննկատ է տեղի ունենում, ինչու՞ դա պետք է ձեզ անհանգստացնի։ Բայց քանի որ մարտահրավեր free() դա չի նշանակում հիշողությունը անպայմանորեն անմիջապես վերադարձվում է օպերացիոն համակարգ.

Կա հիշողության մասնատվածություն: Ծայրահեղ դեպքերում կան կույտային հատվածներ, որտեղ օգտագործվում են ընդամենը մի քանի բայթ, մինչդեռ միջև եղած ամեն ինչ ազատվել է (free()).

Խնդրում ենք նկատի ունենալ, որ հիշողության մասնատումը աներևակայելի բարդ թեմա է, և նույնիսկ ծրագրի աննշան փոփոխությունները կարող են զգալի ազդեցություն ունենալ: Շատ դեպքերում ծրագրերը չեն առաջացնի հիշողության զգալի մասնատում, բայց դուք պետք է տեղյակ լինեք, որ եթե կույտի որոշ հատվածում մասնատման խնդիր կա, հսկայական էջերը կարող են վատթարացնել իրավիճակը:

Հսկայական էջերի ընտրովի օգտագործում

Այս հոդվածը կարդալուց հետո դուք որոշել եք, թե ձեր ծրագրի որ մասերը կարող են օգուտ քաղել հսկայական էջերից, որոնք՝ ոչ: Այսպիսով, հսկայական էջերը պետք է ընդհանրապես միացվեն:

Բարեբախտաբար դուք կարող եք օգտագործել madvise()միացնել հսկայական էջերը միայն այն հիշողության տարածքների համար, որտեղ դա օգտակար կլինի:

Նախ, ստուգեք, որ հսկայական էջերը աշխատում են madvise() ռեժիմով, օգտագործելով հրահանգներ հոդվածի սկզբում։

Այնուհետև օգտագործեք madvise()միջուկին հստակ ասել, թե որտեղ օգտագործել հսկայական էջերը:

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

Նկատի ունեցեք, որ այս մեթոդը պարզապես խորհուրդ է միջուկին, թե ինչպես կառավարել հիշողությունը: Սա չի նշանակում, որ միջուկը ավտոմատ կերպով կօգտագործի հսկայական էջեր տվյալ հիշողության համար:

Դիտեք փաստաթղթերը (manpage)madviseավելին իմանալ հիշողության կառավարման և madvise(), այս թեման ունի աներևակայելի կտրուկ ուսուցման կոր: Այսպիսով, եթե դուք մտադիր եք իսկապես լավ լինել դրանում, պատրաստվեք կարդալ և փորձարկել մի քանի շաբաթ՝ նախքան որևէ դրական արդյունք ակնկալելը:

Ի՞նչ կարդալ.

Հարց ունե՞ք։ Գրեք մեկնաբանություններում!

Source: www.habr.com

Добавить комментарий