
تم إعداد ترجمة لهذه المادة لطلاب دورة Linux Administrator .
في وقت سابق ، تحدثت عن كيفية اختبار وتمكين استخدام Hugepages في لينكس.
ستكون هذه المقالة مفيدة فقط إذا كان لديك حقًا مكان استخدام Hugepages. لقد قابلت العديد من الأشخاص الذين تم خداعهم بسبب احتمال أن تزيد Hugepages من الإنتاجية بشكل سحري. ومع ذلك ، فإن الضخمة الضخمة موضوع معقد ، وإذا تم استخدامه بشكل غير صحيح ، فإنه يمكن أن يقلل الأداء.
الجزء 1: تحقق من تضمين الصفحات الضخمة على Linux (الأصل هنا )
المشكلة:
تحتاج إلى التحقق من تمكين HugePages على نظامك.
الحل:
انها بسيطة جدا:
cat /sys/kernel/mm/transparent_hugepage/enabled
سوف تحصل على شيء مثل هذا:
always [madvise] never
سترى قائمة بالخيارات المتاحة ( دائمًا ، madvise ، أبدًا ) ، بينما سيتم تضمين الخيار النشط الحالي بين قوسين (افتراضيًا ، madvise ).
يعني transparent hugepages
يتم تضمين transparent hugepages
فقط لمناطق الذاكرة التي تطلب صراحة الصفحات الكبيرة مع madvise (2) .
يعني دائمًا أن transparent hugepages
يتم تمكينها دائمًا لجميع العمليات. يعمل هذا عادةً على تحسين الأداء ، ولكن إذا كان لديك حالة استخدام تستهلك فيها العديد من العمليات مقدارًا صغيرًا من الذاكرة ، فيمكن أن يزيد إجمالي حمل الذاكرة بشكل كبير.
لا يعني أبدًا أن transparent hugepages
لن يتم تضمينها حتى عند الطلب باستخدام madvise. راجع وثائق Linux kernel للحصول على مزيد من المعلومات .
كيفية تغيير القيمة الافتراضية
الخيار 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 : تغيير الإعداد الافتراضي للنظام عن طريق إعادة ترجمة النواة بالتكوين المعدل (يوصى بهذا الخيار فقط إذا كنت تستخدم kernel الخاص بك):
الجزء 2: مزايا وعيوب HugePages
سنحاول شرح المزايا والعيوب والأخطاء المحتملة بشكل انتقائي عند استخدام Hugepages. نظرًا لأن المقالة المعقدة تقنياً والميدان من المحتمل أن تكون صعبة على الأشخاص الذين يتم خداعهم من خلال اعتبار Hugepages بمثابة الدواء الشافي ، سأضحي بالدقة من أجل البساطة. يجدر بنا أن نضع في اعتبارنا أن العديد من الموضوعات معقدة للغاية وبالتالي فهي مبسطة إلى حد كبير.
يرجى ملاحظة أننا نتحدث عن أنظمة x86 64 بت التي تعمل على نظام Linux ، وأفترض فقط أن النظام يدعم الصفحات الضخمة الشفافة (لأنه ليس من العيوب عدم استبدال الصفحات الضخمة) ، كما يحدث في أي حديث تقريبًا بيئة لينكس.
في الروابط أدناه سوف أرفق المزيد من الوصف التقني.
الذاكرة الافتراضية
إذا كنت مبرمجًا C ++ ، فأنت تعلم أن الكائنات الموجودة في الذاكرة لها عناوين محددة (قيم المؤشر).
ومع ذلك ، لا تعكس هذه العناوين بالضرورة العناوين الفعلية في الذاكرة (العناوين في RAM). إنها عناوين في الذاكرة الافتراضية. يحتوي المعالج على وحدة MMU (وحدة إدارة الذاكرة) خاصة تساعد kernel على تعيين الذاكرة الظاهرية إلى موقع فعلي.
هذا النهج له العديد من المزايا ، ولكن أهمها:
- الأداء (لأسباب مختلفة) ؛
- عزل البرامج ، أي أنه لا يمكن لأي من البرامج القراءة من ذاكرة برنامج آخر.
ما هي الصفحات؟
الذاكرة الافتراضية مقسمة إلى صفحات. تشير كل صفحة فردية إلى ذاكرة فعلية معينة ، أو يمكن أن تشير إلى منطقة في ذاكرة الوصول العشوائي ، أو يمكن أن تشير إلى عنوان معين لجهاز مادي ، مثل بطاقة الفيديو.
تشير معظم الصفحات التي تتعامل معها إلى ذاكرة الوصول العشوائي أو المبادلة ، أي أنها مخزنة على القرص الصلب أو محرك أقراص الحالة الصلبة. يتحكم النواة في التخطيط الفعلي لكل صفحة. إذا تم الوصول إلى صفحة منتحلة ، فإن النواة تتوقف عن الخيط الذي يحاول الوصول إلى الذاكرة ، ويقرأ الصفحة من القرص الصلب / SSD في ذاكرة الوصول العشوائي ، ثم يواصل تنفيذ الخيط.
هذه العملية شفافة للتيار ، أي أنها لا تقرأ بالضرورة مباشرة من محرك الأقراص الصلبة / محرك أقراص الحالة الصلبة. حجم الصفحات العادية 4096 بايت. حجم الصفحات الضخمة 2 ميغابايت.
الترجمة التحريرية الترابطية (TLB)
عندما يصل أحد البرامج إلى صفحة ذاكرة ، يجب على المعالج المركزي معرفة الصفحة الفعلية لقراءة البيانات منها (على سبيل المثال ، لديه خريطة عنوان افتراضية).
يحتوي الأساسية على بنية بيانات (جدول الصفحة) يحتوي على كافة المعلومات حول الصفحات المستخدمة. باستخدام بنية البيانات هذه ، يمكنك تعيين عنوان افتراضي لعنوان فعلي.
ومع ذلك ، فإن جدول الصفحات معقد إلى حد ما ويعمل ببطء ، لذلك لا يمكننا ببساطة تحليل بنية البيانات بأكملها في كل مرة تصل فيها العملية إلى الذاكرة.
لحسن الحظ ، لدى معالجنا TLB يقوم بتخزين تعيين العناوين الافتراضية والمادية. هذا يعني أنه على الرغم من أننا نحتاج إلى تحليل جدول الصفحات في أول محاولة للوصول ، يمكن معالجة جميع مكالمات الصفحات اللاحقة في TLB ، مما يضمن التشغيل السريع.
نظرًا لأنه يتم تنفيذه كجهاز فعلي (مما يجعله سريعًا بشكل أساسي) ، فإن سعته محدودة. لذلك ، إذا كنت ترغب في الوصول إلى المزيد من الصفحات ، فلن يتمكن TLB من تخزين التعيين لهم جميعًا ، ونتيجة لذلك سيعمل البرنامج بشكل أبطأ.
ضخمة تأتي إلى الإنقاذ
إذن ما الذي يمكننا فعله لتجنب تجاوز سعة TLB؟ (نفترض أن البرنامج لا يزال يحتاج إلى نفس مقدار الذاكرة).
هذا هو المكان الذي تظهر فيه Hugepages. بدلاً من 4096 بايت ، التي تتطلب إدخالًا واحدًا فقط في TLB ، يمكن الآن إدخال واحد في TLB إلى 2 ميغابايت هائلة. سنفترض أن TLB يحتوي على 512 إدخال ، وهنا بدون Hugepages يمكننا مطابقة:
4096 b⋅512=2 MB
بينما يمكننا مقارنة:
2 MB⋅512=1 GB
هذا هو السبب في Hugepages رائع. يمكنهم زيادة الإنتاجية دون بذل جهد كبير. ولكن هناك تحفظات كبيرة.
خداع ضخمة
تقوم النواة تلقائيًا بتتبع وتيرة استخدام كل صفحة من صفحات الذاكرة. إذا كانت الذاكرة الفعلية (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 تستدعي وظائف brk و sbrk من الداخل لطلب أو تحرير ذاكرة من نظام التشغيل.
ومع ذلك ، طلب ذاكرة أكثر وأكثر لكل تخصيص غير فعال؛ على الأرجح أنه قد تم بالفعل تحرير أي شريحة ذاكرة (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)
لاحظ أن هذه الطريقة هي مجرد توصية إلى kernel لإدارة الذاكرة. هذا لا يعني أن النواة ستستخدم تلقائيًا صفحات ضخمة للذاكرة المحددة.
راجع صفحة madvise لمعرفة المزيد عن إدارة الذاكرة و madvise()
، وهو منحنى تعليمي حاد بشكل لا يصدق لهذا الموضوع. لذلك ، إذا كنت تنوي فهمها جيدًا جيدًا ، فاستعد لقراءتها واختبارها لعدة أسابيع قبل الاعتماد على بعض النتائج الإيجابية على الأقل.
ماذا تقرأ؟
لديك سؤال؟ اكتب في التعليقات!