
Překlad článku byl připraven pro studenty kurzu .
Dříve jsem popsal, jak zkontrolovat a umožnit použití Hugepages v Linuxu.
Tento článek bude užitečný pouze v případě, že opravdu máte, kde používat Hugepages. Potkal jsem mnoho lidí, kteří se nechávají podvést perspektivou, že Hugepages zázračně zvýší výkon. Nicméně hugepaging je složité téma a při nesprávném použití může výkon snížit.
Část 1: kontrola, zda jsou hugepages povoleny v Linuxu (originál )
Problém:
Je třeba zkontrolovat, zda jsou HugePages ve vaší soustavě povolené.
Řešení:
Je to docela jednoduché:
cat /sys/kernel/mm/transparent_hugepage/enabledZískáte něco jako:
always [madvise] neverUvidíte seznam dostupných možností (always, madvise, never), přičemž aktuálně aktivní možnost bude uzavřena v závorkách (standardně madvise).
madvise znamená, že transparent hugepages jsou povoleny pouze pro oblasti paměti, které explicitně vyžadují hugepages pomocí .
always znamená, že transparent hugepages jsou vždy povoleny a pro všechny procesy. Obvykle to zvyšuje výkon, ale pokud máte variantu použití, kde mnoho procesů spotřebovává malé množství paměti, může celkové zatížení paměti výrazně vzrůst.
never znamená, že transparent hugepages nebudou povoleny ani při žádosti pomocí madvise. Abychom se dozvěděli více, viz jádr Linuxu.
Jak změnit výchozí hodnotu
Možnost 1: Přímo změňte sysfs (po restartování se parametr vrátí na výchozí hodnotu):
echo always >/sys/kernel/mm/transparent_hugepage/enabled
echo madvise >/sys/kernel/mm/transparent_hugepage/enabled
echo never >/sys/kernel/mm/transparent_hugepage/enabledMožnost 2: Změnte systémovou výchozí hodnotu překomplikováním jádra se změněnou konfigurací (tato varianta se doporučuje pouze, pokud používáte vlastní jádro):
- Pro nastavení always jako výchozí použijte:
CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y # Zakomentujte CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y - Pro nastavení madvise jako výchozí použijte:
CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y # Zakomentujte CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y
Část 2: Výhody a nevýhody HugePages
Pokud se pokusíme výběrově vysvětlit výhody, nevýhody a možné chyby při použití Hugepages. Vzhledem k tomu, že technologicky složitý a pedantský článek může být pravděpodobně těžký k pochopení pro lidi, kteří se nechávají podvést a považují Hugepages za panaceu, obětovávám přesnost pro jednoduchost. Jen mějte na paměti, že mnoho témat je skutečně složitých a proto je silně zjednodušeno.
Všimněte si, že mluvíme o 64bitových x86 systémech běžících na Linuxu, a předpokládám, že systém podporuje transparentní hugepages (jelikož to, že hugepages nejsou nahrazovány, není nedostatkem), jak se to děje prakticky v každém moderním prostředí Linuxu.
V níže uvedených odkazech připojím více technického popisu.
Virtuální paměť
Pokud jste programátor C++, víte, že objekty v paměti mají konkrétní adresy (hodnoty ukazatelů).
Tyto adresy však nemusí nezbytně odrážet fyzické adresy v paměti (adresy v RAM). Představují adresy ve virtuální paměti. Procesor má speciální modul MMU (jednotka správy paměti), který pomáhá jádru mapovat virtuální paměť na fyzické umístění.
Tento přístup má mnoho výhod, ale nejzákladnější z nich jsou:
- Výkon (z různých důvodů);
- Izolace programů, tedy žádný z programů nemůže číst z paměti jiného programu.
Co jsou stránky?
Virtuální paměť je rozdělena na stránky. Každá jednotlivá stránka odkazuje na určitou fyzickou paměť, může odkazovat na oblast v operační paměti nebo na adresu přidělenou fyzickému zařízení, například grafické kartě.
Většina stránek, se kterými se setkáváte, odkazuje buď na RAM, nebo jsou nahrazeny (swap), tedy uloženy na pevném disku nebo SSD. Jádro spravuje fyzické umístění každé stránky. Pokud dojde k přístupu k nahrazené stránce, jádro zastaví vlákno, které se pokouší získat přístup k paměti, načte stránku z pevného disku/SSD do operační paměti a poté pokračuje ve vykonávání vlákna.
Tento proces je pro vlákno transparentní, tedy nečte přímo z pevného disku/SSD. Velikost normálních stránek je 4096 bytů. Velikost Hugepages je 2 megabajty.
Vyrovnávací paměť asociativní překladové tabulky (TLB)
Když program přistupuje k určité stránce paměti, centrální procesor musí vědět, z jaké fyzické stránky číst data (tedy mít virtuální mapu adres).
V jádru je datová struktura (tabulka stránek), která obsahuje všechny informace o používaných stránkách. Pomocí této datové struktury je možné mapovat virtuální adresu na fyzickou adresu.
Tabulka stránek je však poměrně složitá a funguje pomalu, takže nemůžeme pokaždé analyzovat celou strukturu dat, když nějaký proces vyžaduje přístup k paměti.
Naštěstí má náš procesor TLB, který ukládá do mezipaměti mapování virtuálních a fyzických adres. To znamená, že ačkoli musíme tabulku stránek analyzovat při prvním pokusu o přístup, všechny následující požadavky na stránku mohou být zpracovány v TLB, což zajišťuje rychlý výkon.
Protože je realizován jako fyzické zařízení (což je v první řadě rychlé), má omezenou kapacitu. Pokud tedy chcete přistupovat k většímu počtu stránek, TLB nebude moci uchovávat mapování pro všechny, což vede k tomu, že váš program bude fungovat mnohem pomaleji.
Hugepages přicházejí na pomoc.
Co tedy můžeme udělat, abychom se vyhnuli přetečení TLB? (Předpokládáme, že programu je stále potřeba stejný objem paměti).
A tady přicházejí Hugepages. Místo 4096 bajtů, které vyžadují pouze jeden záznam v TLB, může nyní jeden záznam v TLB odkazovat na ohromné 2 megabajty. Předpokládejme, že TLB má 512 záznamů, bez Hugepages můžeme mapovat:
4096 b⋅512=2 MBZatímco s nimi můžeme mapovat:
2 MB⋅512=1 GBProto jsou Hugepages úžasné. Mohou zvýšit výkon bez významného úsilí. Ale jsou zde důležité výjimky.
Výměna Hugepages.
Jádro automaticky sleduje frekvenci používání každé stránky paměti. Pokud je fyzická paměť (RAM) nedostatečná, jádro přesune méně důležité (méně často používané) stránky na pevný disk, aby uvolnilo část RAM pro důležitější stránky.
V zásadě to platí i pro Hugepages. Jádro však může vyměňovat pouze celé stránky, nikoli jednotlivé bajty.
Předpokládejme, že máme takový program:
char* mymemory = malloc(2*1024*1024); // Vezmeme to jako jednu Hugepage!
// Naplníme mymemory nějakými daty
// Uděláme spoustu dalších věcí,
// které povedou k výměně stránky mymemory
// ...
// Požádáme o přístup pouze k prvnímu bajtu
putchar(mymemory[0]); V tomto případě jádru bude muset přečíst celých 2 megabyty informací z pevného disku/SSD pouze k tomu, abyste přečetli jeden byt. Co se týče běžných stránek, z pevného disku/SSD je třeba přečíst pouze 4096 bytů.
Pokud tedy dojde k přepnutí hugepage, její čtení probíhá rychleji, pouze pokud potřebujete přistupovat k celé stránce. To znamená, že pokud se pokoušíte náhodně přistupovat k různým částem paměti a jen přečtete pár kilobajtů, měli byste používat běžné stránky a nemít jiné starosti.
Na druhou stranu, pokud potřebujete přistupovat k velké části paměti sekvenčně, hugepages zvýší vaši výkonnost. Nicméně, musíte to ověřit sami (a ne na základě abstraktního softwaru) a zjistit, co bude fungovat rychleji.
Alokace v paměti
Pokud píšete v C, víte, že si můžete vyžádat libovolné malé (nebo téměř libovolně velké) objemy paměti z haldy pomocí malloc(). Předpokládejme, že potřebujete 30 bytů paměti:
char* mymemory = malloc(30);Programátorovi se může zdát, že „žádáte“ 30 bytů paměti od operačního systému a získáváte ukazatel na nějakou virtuální paměť. Ve skutečnosti však malloc () je jen funkce C, která ve svém nitru volá funkce k žádosti o nebo uvolnění paměti z operačního systému.
Nicméně, žádat o stále více a více paměti pro každou alokaci není efektivní; je velmi pravděpodobné, že nějaký segment paměti již byl uvolněn (free()), a můžeme ho znovu využít. malloc() implementuje poměrně složité algoritmy pro opětovné využití uvolněné paměti.
Přitom se pro vás všechno děje bez povšimnutí, tak proč by vás to mělo zajímat? Protože volání free() neznamená, že .
Existuje takový pojem jako fragmentace paměti. V krajních případech jsou zde segmenty haldy, kde se používá pouze několik bytů, zatímco vše, co je mezi nimi, bylo uvolněno. (free()).
Všimněte si, že fragmentace paměti je neuvěřitelně složité téma a i drobné změny v programu mohou mít na ni značný vliv. Ve většině případů programy nezpůsobují významnou fragmentaci paměti, ale mějte na paměti, že pokud došlo k problémům s fragmentací v určité oblasti haldy, hugepages to může situaci jen zhoršit.
Selektivní použití hugepages
Po přečtení článku jste určili, které části vašeho programu mohou mít prospěch z použití hugepages a které ne. Měli byste tedy vůbec hugepages zapnout?
Naštěstí můžete použít madvise(), abyste zapnuli hugepaging pouze pro ty oblasti paměti, kde to bude užitečné.
Nejdříve zkontrolujte, že hugepages fungují v režimu madvise(), pomocí na začátku článku.
Poté použijte madvise(), abyste jádru ukázali, kde přesně používat 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)Všimněte si, že tato metoda je pouze doporučeními pro jádro ohledně správy paměti. To neznamená, že jádro automaticky použije hugepages pro danou paměť.
Odkazujte se na dokumentaci , abyste se dozvěděli více o správě paměti a madvise(), tato tématika má neuvěřitelně strmou křivku učení. Pokud se tedy skutečně chcete dobře orientovat, připravte se na čtení a testování po několik týdnu, než očekáváte nějaké pozitivní výsledky.
Co číst?
Máte dotaz? Napište do komentářů!
Zdroj: habr.com
