HugePages-ning afzalliklari va kamchiliklari

HugePages-ning afzalliklari va kamchiliklari

Kurs talabalari uchun tayyorlangan maqolaning tarjimasi "Linux administratori".

Ilgari men Linuxda Hugepagesni qanday sinab ko'rish va yoqish haqida gapirgan edim.
Ushbu maqola faqat Hugepages-dan foydalanish uchun joyingiz bo'lsa foydali bo'ladi. Men Hugepagesning mahsuldorlikni sehrli tarzda oshirishiga aldangan ko'plab odamlarni uchratdim. Biroq, ulkan sahifalash murakkab mavzu bo'lib, noto'g'ri ishlatilsa, unumdorlikni pasaytirishi mumkin.

1-qism: Linuxda ulkan sahifalar yoqilganligini tekshirish (original shu yerda)

Muammo:
Tizimingizda HugePages yoqilganligini tekshirishingiz kerak.

yechim:
Bu juda oddiy:

cat /sys/kernel/mm/transparent_hugepage/enabled

Siz shunga o'xshash narsani olasiz:

always [madvise] never

Siz mavjud variantlar ro'yxatini ko'rasiz (har doim, aqldan ozgan, hech qachon) va hozirda faol parametr qavslar ichiga olinadi (sukut bo'yicha aqldan ozgan).

aqldan ozgan shuni anglatadiki transparent hugepages faqat foydalanish katta sahifalarni aniq talab qiladigan xotira maydonlari uchun yoqilgan madvise(2).

har doim shuni anglatadiki transparent hugepages har doim barcha jarayonlar uchun yoqilgan. Bu odatda ishlashni yaxshilaydi, lekin agar sizda ko'p jarayonlar kichik hajmdagi xotirani iste'mol qiladigan holatlar mavjud bo'lsa, unda umumiy xotira yuki keskin oshishi mumkin.

hech qachon shuni anglatadiki transparent hugepages madvise yordamida so'ralganda ham kiritilmaydi. Qo'shimcha ma'lumot olish uchun murojaat qiling hujjatlar Linux yadrolari.

Standart qiymatni qanday o'zgartirish mumkin

variant 1: To'g'ridan-to'g'ri o'zgartirish sysfs (qayta ishga tushirilgandan so'ng parametr standart qiymatiga qaytadi):

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

variant 2: Yadroni o'zgartirilgan konfiguratsiya bilan qayta kompilyatsiya qilish orqali tizim standartini o'zgartiring (bu parametr faqat maxsus yadrodan foydalanayotgan bo'lsangiz tavsiya etiladi):

  • Har doim sukut bo'yicha o'rnatish uchun quyidagilardan foydalaning:
    CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y
    # Comment out CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y
  • Madvise-ni sukut bo'yicha o'rnatish uchun quyidagilardan foydalaning:
    CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y
    # Comment out CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y

2-qism: HugePages-ning afzalliklari va kamchiliklari

Biz Hugepages-dan foydalanishning afzalliklari, kamchiliklari va mumkin bo'lgan tuzoqlarini tanlab tushuntirishga harakat qilamiz. Hugepagesni davo deb o'ylaydigan odamlar uchun texnologik jihatdan murakkab va pedantik maqolani tushunish qiyin bo'lishi mumkinligi sababli, men soddalik uchun aniqlikni qurbon qilaman. Shuni yodda tutish kerakki, ko'plab mavzular haqiqatan ham murakkab va shuning uchun juda soddalashtirilgan.

Shuni esda tutingki, biz Linuxda ishlaydigan 64 bitli x86 tizimlar haqida gapiryapmiz va men shunchaki tizim shaffof ulkan sahifalarni qo'llab-quvvatlaydi deb taxmin qilyapman (chunki katta sahifalarning ustiga yozilmasligi kamchilik emas), deyarli har qanday zamonaviy Linuxda bo'lgani kabi muhit.

Qo'shimcha texnik tavsifni quyidagi havolalarga qo'shaman.

Virtual xotira

Agar siz C++ dasturchisi bo'lsangiz, xotiradagi ob'ektlarning aniq manzillari (ko'rsatkich qiymatlari) borligini bilasiz.

Biroq, bu manzillar xotiradagi jismoniy manzillarni (RAM manzillari) aks ettirishi shart emas. Ular virtual xotiradagi manzillarni ifodalaydi. Protsessorda yadro virtual xotirani jismoniy joylashuvga xaritalashda yordam beradigan maxsus MMU (xotirani boshqarish bloki) moduli mavjud.

Ushbu yondashuv juda ko'p afzalliklarga ega, ammo eng muhimlari:

  • Ishlash (turli sabablarga ko'ra);
  • Dastur izolyatsiyasi, ya'ni hech bir dastur boshqa dastur xotirasidan o'qiy olmaydi.

Sahifalar nima?

Virtual xotira sahifalarga bo'lingan. Har bir alohida sahifa ma'lum bir jismoniy xotiraga ishora qiladi, u RAMdagi maydonga ishora qilishi mumkin yoki jismoniy qurilmaga, masalan, video kartaga tayinlangan manzilga ishora qilishi mumkin.

Siz ko'rib chiqayotgan sahifalarning aksariyati RAMga ishora qiladi yoki almashtiriladi, ya'ni ular qattiq diskda yoki SSDda saqlanadi. Yadro har bir sahifaning jismoniy tartibini boshqaradi. Agar soxta sahifaga kirsa, yadro xotiraga kirishga urinayotgan ipni to'xtatadi, sahifani qattiq diskdan/SSDdan RAMga o'qiydi va keyin ipni bajarishni davom ettiradi.

Bu jarayon shaffof oqimdir, ya'ni u to'g'ridan-to'g'ri HDD/SSD dan o'qilishi shart emas. Oddiy sahifalar hajmi 4096 baytni tashkil qiladi. Katta sahifalar hajmi 2 megabayt.

Tarjima-assotsiativ bufer (TLB)

Dastur xotira sahifasiga kirganda, protsessor ma'lumotlarni qaysi jismoniy sahifadan o'qish kerakligini bilishi kerak (ya'ni virtual manzillar xaritasiga ega).

Yadroda foydalanilayotgan sahifalar haqidagi barcha ma'lumotlarni o'z ichiga olgan ma'lumotlar strukturasi (sahifa jadvali) mavjud. Ushbu ma'lumotlar strukturasidan foydalanib, siz virtual manzilni jismoniy manzil bilan taqqoslashingiz mumkin.

Biroq, sahifalar jadvali juda murakkab va sekin, shuning uchun biz har safar jarayon xotiraga kirganda butun ma'lumotlar strukturasini tahlil qila olmaymiz.

Yaxshiyamki, bizning protsessorimizda virtual va jismoniy manzillar o'rtasidagi xaritalashni keshlaydigan TLB mavjud. Bu shuni anglatadiki, biz birinchi kirish urinishida sahifa jadvalini tahlil qilishimiz kerak bo'lsa-da, sahifaga keyingi barcha kirishlar tezkor ishlashga imkon beruvchi TLBda ishlov berilishi mumkin.

U jismoniy qurilma sifatida amalga oshirilganligi sababli (birinchi navbatda uni tezlashtiradi), uning imkoniyatlari cheklangan. Shunday qilib, agar siz ko'proq sahifalarga kirishni istasangiz, TLB ularning barchasi uchun xaritalarni saqlay olmaydi, bu sizning dasturingiz ancha sekinroq ishlashiga olib keladi.

Hugepages yordamga keladi

Xo'sh, TLB to'lib ketishining oldini olish uchun nima qilishimiz mumkin? (Biz dastur hali ham bir xil hajmdagi xotiraga muhtoj deb taxmin qilamiz).

Bu erda Hugepages keladi. Faqat bitta TLB kirishini talab qiladigan 4096 bayt o'rniga, bitta TLB yozuvi endi katta 2 megabaytni ko'rsatishi mumkin. Faraz qilaylik, TLBda 512 ta yozuv bor, bu yerda Hugepagessiz biz mos kelishimiz mumkin:

4096 b⋅512=2 MB

Keyin ular bilan qanday taqqoslashimiz mumkin:

2 MB⋅512=1 GB

Shuning uchun Hugepages ajoyib. Ular unumdorlikni ko'p harakat qilmasdan oshirishlari mumkin. Ammo bu erda muhim ogohlantirishlar mavjud.

Katta sahifalarni aldash

Yadro har bir xotira sahifasining qanchalik tez-tez ishlatilishini avtomatik ravishda kuzatib boradi. Agar etarli jismoniy xotira (RAM) bo'lmasa, yadro muhimroq sahifalar uchun operativ xotirani bo'shatish uchun kamroq muhim (kamroq ishlatiladigan) sahifalarni qattiq diskka o'tkazadi.
Aslida, xuddi shu narsa Hugepagesga ham tegishli. Biroq, yadro alohida baytlarni emas, balki butun sahifalarni almashtirishi mumkin.

Aytaylik, bizda shunday dastur bor:

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

Bunday holda, siz bir baytni o'qishingiz uchun yadro qattiq diskdan/SSDdan 2 megabaytgacha ma'lumotni almashtirishi (o'qishi) kerak bo'ladi. Oddiy sahifalarga kelsak, qattiq diskdan/SSDdan faqat 4096 baytni o'qish kerak.

Shuning uchun, agar ulkan sahifa bekor qilingan bo'lsa, butun sahifaga kirishingiz kerak bo'lsa, uni o'qish tezroq bo'ladi. Bu shuni anglatadiki, agar siz xotiraning turli qismlariga tasodifiy kirishga harakat qilsangiz va bir necha kilobaytni o'qiyotgan bo'lsangiz, oddiy sahifalardan foydalanishingiz va boshqa hech narsa haqida qayg'urmasligingiz kerak.

Boshqa tomondan, agar siz xotiraning katta qismiga ketma-ket kirishingiz kerak bo'lsa, ulkan sahifalar ishlashingizni yaxshilaydi. Biroq, uni o'zingiz sinab ko'rishingiz kerak (mavhum dasturiy ta'minot bilan emas) va nima tezroq ishlashini ko'rishingiz kerak.

Xotirada ajratish

Agar siz C ni yozsangiz, bilasizki, siz o'zboshimchalik bilan kichik (yoki deyarli o'zboshimchalik bilan katta) hajmdagi xotirani to'pdan so'rashingiz mumkin. malloc(). Aytaylik, sizga 30 bayt xotira kerak:

char* mymemory = malloc(30);

Dasturchiga siz operatsion tizimdan 30 bayt xotirani "so'rayapsiz" va qandaydir virtual xotiraga ko'rsatgichni qaytarayotgandek tuyulishi mumkin. Lekin aslida malloc () faqat funksiya ichidan chaqiruvchi C funksiyasi brk va sbrk operatsion tizimdan xotirani so'rash yoki bo'shatish.

Biroq, har bir ajratish uchun ko'proq va ko'proq xotira so'rash samarasiz; ba'zi xotira segmenti allaqachon bo'shatilgan bo'lishi mumkin (free()), va biz uni qayta ishlatishimiz mumkin. malloc() bo'shatilgan xotirani qayta ishlatish uchun juda murakkab algoritmlarni amalga oshiradi.

Shu bilan birga, hamma narsa siz uchun sezilmasdan sodir bo'ladi, shuning uchun nima uchun bu sizni tashvishga solishi kerak? Ammo qiyinchilik tufayli free() bu degani emas xotira darhol operatsion tizimga qaytarilishi shart.

Xotiraning parchalanishi kabi narsa bor. Haddan tashqari holatlarda yig'ma segmentlar mavjud bo'lib, ularda atigi bir necha bayt ishlatiladi, shu bilan birga ularning orasidagi hamma narsa bo'shatilgan. (free()).

Esda tutingki, xotira parchalanishi nihoyatda murakkab mavzu bo'lib, dasturdagi kichik o'zgarishlar ham sezilarli ta'sir ko'rsatishi mumkin. Aksariyat hollarda dasturlar xotiraning sezilarli bo'linishiga olib kelmaydi, ammo shuni yodda tutish kerakki, agar yig'ilishning biron bir qismida parchalanish bilan bog'liq muammo bo'lsa, ulkan sahifalar vaziyatni yomonlashtirishi mumkin.

Katta sahifalardan tanlab foydalanish

Ushbu maqolani o'qib chiqqandan so'ng, siz dasturingizning qaysi qismlari ulkan sahifalardan foydalanishi mumkinligini va qaysi biri foyda keltirmasligini aniqladingiz. Demak, ulkan sahifalar umuman yoqilishi kerakmi?

Yaxshiyamki, siz foydalanishingiz mumkin madvise()faqat foydali bo'lishi mumkin bo'lgan xotira joylari uchun katta sahifalarni yoqish.

Birinchidan, katta sahifalar yordamida madvise() rejimida ishlayotganligini tekshiring ko'rsatmalar maqolaning boshida.

Keyin, foydalaning madvise()yadroga katta sahifalarni qayerda ishlatishni aniq aytib berish.

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

E'tibor bering, bu usul xotirani boshqarish bo'yicha yadroga oddiy maslahatdir. Bu yadro ma'lum bir xotira uchun avtomatik ravishda ulkan sahifalardan foydalanishini anglatmaydi.

Hujjatlarga murojaat qiling (manpage) aqldan ozishxotira boshqaruvi haqida ko'proq ma'lumot olish va madvise(), bu mavzu nihoyatda keskin o'rganish egri chizig'iga ega. Shunday qilib, agar siz buni chindan ham yaxshi qilishni niyat qilsangiz, ijobiy natijalarni kutishdan oldin bir necha hafta davomida o'qish va sinovdan o'tishga tayyorlaning.

Nima o'qish kerak?

Savolingiz bormi? Izohlarda yozing!

Manba: www.habr.com

a Izoh qo'shish