
Преводът на статията е подготвен за студенти в курса .
По-рано споменах как да проверите и активирате използването на Hugepages в Linux.
Тази статия ще бъде полезна само ако наистина имате място за използване на Hugepages. Срещал съм много хора, които са измамени от перспективата, че Hugepages ще повишат производителността магически. Въпреки това hugepaging е сложна тема, и при неправилна употреба тя може да понижи производителността.
Част 1: проверка дали hugepages са активирани в Linux (оригинал )
Проблема:
Необходимо е да проверите дали HugePages са активирани в системата ви.
Решението:
Това е доста просто:
cat /sys/kernel/mm/transparent_hugepage/enabledЩе получите нещо подобно:
always [madvise] neverЩе видите списък с налични опции (always, madvise, never), като текущата активна опция ще бъде поставена в скоби (по подразбиране madvise).
madvise означава, че transparent hugepages са активирани само за области от паметта, които изрично искат hugepages чрез .
always означава, че transparent hugepages са винаги активирани и за всички процеси. Обикновено това повишава производителността, но ако имате случаи на употреба, при които множество процеси консумират малко количество памет, то общото натоварване на паметта може да нарасне значително.
never означава, че 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: Променете системната стойност по подразбиране, преработвайки ядрото с променена конфигурация (този вариант се препоръчва само ако използвате собствено ядро):
- За да зададете always по подразбиране, използвайте:
CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y # Закоментирайте CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y - За да зададете madvise по подразбиране, използвайте:
CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y # Закоментирайте CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y
Част 2: Предимства и недостатъци на HugePages
Ще се опитаме да обясним подбраните предимства, недостатъци и възможни грешки при използването на Hugepages. Тъй като технологично сложна и педантична статия вероятно ще бъде трудна за разбиране на хората, които са измамени, смятайки Hugepages за панацея, ще жертвам точността в полза на простотата. Просто си струва да имате предвид, че много теми са наистина сложни и следователно силно опростени.
Обърнете внимание, че говорим за 64-разрядни x86 системи, работещи на Linux, и че просто предполагам, че системата поддържа transparent hugepages (тъй като не е недостатък, че hugepages не се заменят), както става практически във всяка съвременна Linux среда.
В линковете по-долу ще приложа повече техническо описание.
Виртуална памет
Ако сте C++ програмист, знаете, че обектите в паметта имат конкретни адреси (стойности на указатели).
Въпреки това, тези адреси не задължително отразяват физическите адреси в паметта (адреси в RAM). Те представляват адреси в виртуалната памет. Процесорът има специален модул MMU (модул за управление на паметта), който помага на ядрото да съпостави виртуалната памет с физическото местоположение.
Този подход има множество предимства, но основните от тях са:
- Производителност (по различни причини);
- Изолация на програмите, т.е. нито една от програмите не може да чете от паметта на друга програма.
Какво представляват страниците?
Виртуалната памет е разделена на страници. Всяка отделна страница посочва определена физическа памет, може да указва област в оперативната памет или адрес, назначен на физическо устройство, като например видеокарта.
Повечето страници, с които се занимавате, указват или на RAM, или се заменят (swap), т.е. съхраняват се на твърдия диск или SSD. Ядрото управлява физическото местоположение на всяка страница. Ако се получи достъп до заменена страница, ядрото спира потока, който се опитва да получи достъп до паметта, прочита страницата от твърдия диск/SSD в оперативната памет и след това продължава изпълнението на потока.
Т този процес е прозрачен за потока, т.е. той не чете задължително директно от твърдия диск/SSD. Размерът на нормалните страници е 4096 байта. Размерът на Hugepages е 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 са страхотни. Те могат да увеличат производителността без значителни усилия. Но тук има съществени забележки.
Замяната на Hugepages
Ядро автоматично следи честотата на използване на всяка страница памет. Ако физическата памет (ОЗУ) не е достатъчна, ядрото премества по-малко важни (по-рядко използвани) страници на твърдия диск, за да освободи част от ОЗУ за по-важни страници.
В принцип това важи и за Hugepages. Въпреки това, ядрото може да разменя само цели страници, а не отделни байтове.
Да предположим, че имаме следната програма:
char* mymemory = malloc(2*1024*1024); \/\/ Нека считаме това за една Hugepage!\n\/\/ Попълваме mymemory с данни\n\/\/ Правим много други неща,\n\/\/ които водят до замяна на страницата mymemory\n\/\/ ...\n\/\/ Искате достъп само до първия байт\nputchar(mymemory[0]); В този случай ядрото ще трябва да замести (прочете) цели 2 мегабайта информация от твърдия диск/SSD само за да прочетете един байт. Що се отнася до обикновените страници, от твърдия диск/SSD трябва да се прочетат само 4096 байта.
Следователно, ако hugepage се замества, нейното четене става по-бързо, само ако трябва да получите достъп до цялата страница. Това означава, че ако се опитвате да получите достъп произволно до различни части от паметта и просто прочитате няколко килобайта, по-добре е да използвате обикновени страници и да не се притеснявате за нищо друго.
От друга страна, ако трябва да получите достъп до голяма част от паметта последователно, hugepages ще увеличат вашата производителност. Все пак, трябва да проверите това сами (а не на примера на абстрактен софтуер) и да видите какво ще работи по-добре.
Алокация в паметта
Ако пишете на C, знаете, че можете да поискасте колкото угодно малки (или почти колкото угодно големи) обеми памет от купчина с помощта на malloc(). Да предположим, че ви трябват 30 байта памет:
char* mymemory = malloc(30);На програмистите може да им се стори, че вие “искате” 30 байта памет от операционната система и връщате указател към някаква виртуална памет. Но всъщност malloc () е просто C функция, която извиква от вътре функциите за да поиска или освободи памет от операционната система.
Обаче, искането на все повече памет за всяка алокация не е ефективно; най-вероятно някой сегмент памет вече е бил освободен (free()), и можем да го повторно използваме. malloc() реализира доста сложни алгоритми за повторно използване на освободената памет.
При това всичко се случва незабелязано, така че защо това трябва да ви интересува? Защото извикването free() не означава, че .
Съществува такова понятие, като фрагментация на паметта. В крайни случаи има сегменти на купчината, където се използват само няколко байта, докато всичко, което се намира между тях, е било освободено. (free()).
Обърнете внимание, че фрагментацията на паметта е изключително сложна тема и дори незначителни промени в програмата могат значително да я повлияят. В повечето случаи програмите не предизвикват значителна фрагментация на паметта, но трябва да имате предвид, че ако има проблем с фрагментацията в определена област на купчината, hugepages могат само да влошат ситуацията.
Изборно прилагане на hugepages
След като прочетете статията, вие определихте кои части от вашата програма могат да се възползват от прилагане на hugepages и кои – не. Трябва ли изобщо да включите hugepages?
За щастие, можете да използвате madvise(), за да включите hugepaging само за онези области на паметта, където това ще бъде полезно.
Първо, проверете, че hugepages работят в режим madvise(), с помощта на в началото на статията.
След това използвайте madvise(), за да укажете на ядрото къде точно да използва 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)Обърнете внимание, че този метод е просто предложение към ядрото за управление на паметта. Това не означава, че ядрото автоматично ще използва hugepages за зададената памет.
Обърнете се към документацията , за да научите повече за управлението на паметта и madvise(), тази тема има изключително стръмна крива на обучение. Затова, ако наистина искате да я разберете добре, се подгответе за четене и тестване в продължение на няколко седмици, преди да разчитате на какъвто и да е положителен резултат.
Какво да прочетете?
Имате въпрос? Напишете в коментарите!
Източник: habr.com
