مزایا و معایب HugePages

مزایا و معایب HugePages

ترجمه مقاله تهیه شده برای دانشجویان دوره "مدیر لینوکس".

قبلاً در مورد چگونگی تست و فعال کردن Hugepages در لینوکس صحبت کردم.
این مقاله تنها زمانی مفید خواهد بود که واقعاً مکانی برای استفاده از Hugepages داشته باشید. من با افراد زیادی ملاقات کرده ام که فریب این چشم انداز را می خورند که Hugepages به طور جادویی بهره وری را بهبود می بخشد. با این حال، صفحه‌بندی بزرگ موضوع پیچیده‌ای است و در صورت استفاده نادرست، می‌تواند عملکرد را کاهش دهد.

قسمت 1: بررسی فعال بودن صفحات بزرگ در لینوکس (اصلی اینجا)

مشکل:
باید بررسی کنید که HugePages در سیستم شما فعال است یا خیر.

راه حل:
خیلی ساده است:

cat /sys/kernel/mm/transparent_hugepage/enabled

چیزی شبیه این دریافت خواهید کرد:

always [madvise] never

لیستی از گزینه های موجود را مشاهده خواهید کرد (همیشه، دیوانه، هرگز، و گزینه فعال فعلی در داخل پرانتز قرار می گیرد (به طور پیش فرض دیوانه کردن).

دیوانه کردن یعنی که transparent hugepages فقط برای مناطق حافظه فعال است که صریحاً با استفاده از صفحات بزرگ درخواست می کنند دیوانه (2).

همیشه یعنی که transparent hugepages همیشه برای همه فرآیندها فعال است. این معمولاً عملکرد را بهبود می بخشد، اما اگر مورد استفاده ای دارید که در آن بسیاری از فرآیندها مقدار کمی از حافظه را مصرف می کنند، بار کلی حافظه می تواند به طور چشمگیری افزایش یابد.

هرگز یعنی که transparent hugepages حتی در صورت درخواست با استفاده از madvise شامل نخواهد شد. برای کسب اطلاعات بیشتر، تماس بگیرید مستندات هسته های لینوکس

نحوه تغییر مقدار پیش فرض

گزینه 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 یک دارو است، دشوار خواهد بود، من دقت را فدای سادگی می‌کنم. فقط ارزش این را دارد که در نظر داشته باشید که بسیاری از موضوعات واقعا پیچیده هستند و بنابراین بسیار ساده شده اند.

لطفاً توجه داشته باشید که ما در مورد سیستم‌های 64 بیتی x86 که لینوکس را اجرا می‌کنند صحبت می‌کنیم، و من به سادگی فرض می‌کنم که این سیستم از صفحات عظیم شفاف پشتیبانی می‌کند (زیرا این مشکلی نیست که صفحات عظیم بازنویسی نمی‌شوند)، همانطور که تقریباً در هر لینوکس مدرن وجود دارد. محیط.

توضیحات فنی بیشتری را در لینک های زیر پیوست خواهم کرد.

حافظه مجازی

اگر یک برنامه نویس ++C هستید، می دانید که اشیاء در حافظه دارای آدرس های خاصی هستند (مقادیر اشاره گر).

با این حال، این آدرس ها لزوما آدرس های فیزیکی در حافظه (آدرس های RAM) را منعکس نمی کنند. آنها آدرس ها را در حافظه مجازی نشان می دهند. پردازنده دارای یک ماژول ویژه MMU (واحد مدیریت حافظه) است که به هسته کمک می کند حافظه مجازی را به یک مکان فیزیکی ترسیم کند.

این روش مزایای زیادی دارد، اما مهمترین آنها عبارتند از:

  • عملکرد (به دلایل مختلف)؛
  • جداسازی برنامه، یعنی هیچ برنامه ای نمی تواند از حافظه برنامه دیگری بخواند.

صفحات چیست؟

حافظه مجازی به صفحات تقسیم می شود. هر صفحه به یک حافظه فیزیکی خاص اشاره می کند، می تواند به یک منطقه در RAM اشاره کند، یا می تواند به آدرسی که به یک دستگاه فیزیکی اختصاص داده شده است، مانند کارت ویدیو اشاره کند.

اکثر صفحاتی که با آنها سر و کار دارید یا به رم اشاره می کنند یا تعویض می شوند، یعنی روی هارد دیسک یا SSD شما ذخیره می شوند. هسته چینش فیزیکی هر صفحه را مدیریت می کند. اگر به یک صفحه جعلی دسترسی پیدا کرد، هسته رشته‌ای را که می‌خواهد به حافظه دسترسی پیدا کند متوقف می‌کند، صفحه را از هارد دیسک/SSD به RAM می‌خواند و سپس به اجرای رشته ادامه می‌دهد.

این فرآیند شفاف است، به این معنی که لزوماً مستقیماً از HDD/SSD خوانده نمی‌شود. حجم صفحات معمولی 4096 بایت است. حجم صفحات بزرگ 2 مگابایت است.

بافر Translation-Asociative (TLB)

هنگامی که یک برنامه به صفحه ای از حافظه دسترسی پیدا می کند، CPU باید بداند که از کدام صفحه فیزیکی داده ها را بخواند (یعنی نقشه آدرس مجازی داشته باشد).

هسته دارای یک ساختار داده (جدول صفحه) است که شامل تمام اطلاعات مربوط به صفحات مورد استفاده است. با استفاده از این ساختار داده، می توانید یک آدرس مجازی را به یک آدرس فیزیکی نگاشت کنید.

با این حال، جدول صفحه بسیار پیچیده و کند است، بنابراین ما نمی‌توانیم کل ساختار داده را هر بار که یک فرآیند به حافظه دسترسی پیدا می‌کند، تجزیه و تحلیل کنیم.

خوشبختانه، پردازنده ما یک 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 را جایگزین (خواندن) کند تا بتوانید یک بایت را بخوانید. در مورد صفحات معمولی، فقط 4096 بایت باید از هارد دیسک/SSD خوانده شود.

بنابراین، اگر صفحه بزرگ لغو شود، فقط در صورتی که نیاز به دسترسی به کل صفحه داشته باشید، خواندن آن سریعتر است. این بدان معنی است که اگر سعی می کنید به طور تصادفی به بخش های مختلف حافظه دسترسی پیدا کنید و فقط چند کیلوبایت را مطالعه می کنید، باید از صفحات معمولی استفاده کنید و نگران چیز دیگری نباشید.

از طرف دیگر، اگر نیاز به دسترسی متوالی به بخش بزرگی از حافظه دارید، صفحات عظیم عملکرد شما را بهبود می بخشد. با این حال، باید خودتان آن را تست کنید (نه با نرم افزار انتزاعی) و ببینید چه چیزی سریعتر کار می کند.

تخصیص در حافظه

اگر C بنویسید، می‌دانید که می‌توانید مقادیر دلخواه کوچک (یا تقریباً دلخواه بزرگ) حافظه را با استفاده از پشته درخواست کنید. malloc(). فرض کنید به 30 بایت حافظه نیاز دارید:

char* mymemory = malloc(30);

برای یک برنامه نویس، ممکن است به نظر برسد که شما 30 بایت حافظه از سیستم عامل درخواست می کنید و یک اشاره گر را به حافظه مجازی برمی گردانید. اما در واقع malloc () فقط یک تابع C است که از داخل تابع فراخوانی می کند برک و اسبرک برای درخواست یا آزاد کردن حافظه از سیستم عامل.

با این حال، درخواست حافظه بیشتر و بیشتر برای هر تخصیص ناکارآمد است. به احتمال زیاد بخشی از حافظه قبلاً آزاد شده است (free())و ما می توانیم دوباره از آن استفاده کنیم. malloc() الگوریتم های بسیار پیچیده ای را برای استفاده مجدد از حافظه آزاد شده پیاده سازی می کند.

در عین حال، همه چیز برای شما بدون توجه اتفاق می افتد، پس چرا باید شما را نگران کند؟ اما به دلیل چالش free() به این معنی نیست حافظه لزوماً بلافاصله به سیستم عامل بازگردانده می شود.

چیزی به نام تکه تکه شدن حافظه وجود دارد. در موارد شدید، بخش‌های پشته‌ای وجود دارد که در آن تنها چند بایت استفاده می‌شود، در حالی که همه چیز در این بین آزاد شده است (free()).

لطفاً توجه داشته باشید که تکه تکه شدن حافظه موضوعی فوق العاده پیچیده است و حتی تغییرات جزئی در یک برنامه می تواند تأثیر قابل توجهی داشته باشد. در بیشتر موارد، برنامه ها باعث تکه تکه شدن حافظه قابل توجهی نمی شوند، اما باید توجه داشته باشید که اگر مشکلی با تکه تکه شدن در قسمتی از هیپ وجود داشته باشد، صفحات بزرگ می توانند وضعیت را بدتر کنند.

استفاده انتخابی از صفحات بزرگ

پس از خواندن این مقاله، مشخص کرده اید که کدام بخش از برنامه شما می تواند از استفاده از صفحات عظیم بهره مند شود و کدام بخش نمی تواند. بنابراین آیا صفحات عظیم باید اصلاً فعال شوند؟

خوشبختانه می توانید استفاده کنید madvise()برای فعال کردن صفحه بزرگ فقط برای آن مناطق حافظه که در آن مفید است.

ابتدا بررسی کنید که largepages در حالت 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()، این مبحث دارای منحنی یادگیری فوق العاده شیب دار است. بنابراین اگر قصد دارید واقعاً در آن مهارت داشته باشید، قبل از اینکه انتظار هر گونه نتیجه مثبتی داشته باشید، چند هفته برای خواندن و آزمایش آماده شوید.

چه بخوانیم؟

سوالی دارید؟ در نظرات بنویسید!

منبع: www.habr.com

اضافه کردن نظر