في أي ظروف يمكن أن تنتج الصفحات الكبيرة تسريعًا؟

StackOverflow https://stackoverflow.com/questions/2876377

سؤال

تتمتع وحدة المعالجة المركزية X86 الحديثة بالقدرة على دعم أحجام الصفحات الأكبر من Legacy 4K (أي 2 ميجابايت أو 4 ميجابايت) ، وهناك مرافق نظام التشغيل (لينكس, شبابيك) للوصول إلى هذه الوظيفة.

ينص رابط Microsoft أعلاه على الصفحات الكبيرة "تزيد من كفاءة المخزن المؤقت للترجمة ، والتي يمكن أن تزيد من الأداء للذاكرة التي يتم الوصول إليها بشكل متكرر". هذا ليس مفيدًا للغاية في التنبؤ بما إذا كانت الصفحات الكبيرة ستحسن أي موقف معين. أنا مهتم بالخرسانة ، ويفضل تحديدها كمياً ، وأمثلة على المكان الذي يؤدي فيه نقل بعض منطق البرنامج (أو تطبيق كامل) إلى استخدام صفحات ضخمة إلى بعض تحسين الأداء. أي شخص حصل على أي قصص نجاح؟

هناك حالة واحدة أعرفها نفسي: يمكن استخدام صفحات ضخمة بشكل كبير قلل الوقت اللازم لتخليص عملية كبيرة (من المفترض أن يتم تقليل عدد سجلات TLB التي تحتاج إلى نسخ بعامل حسب 1000). أنا مهتم بما إذا كانت الصفحات الضخمة يمكن أن تكون أيضًا فائدة في سيناريوهات أقل غرابة.

هل كانت مفيدة؟

المحلول 2

حاولت أن أقوم بتنافس بعض الكود مما سيزيد من سحق TLB مع صفحات 4K من أجل فحص المكاسب الممكنة من الصفحات الكبيرة. الأشياء أدناه تعمل 2.6 مرة أسرع (من صفحات 4K) عندما يتم توفير صفحات 2MBYTE بواسطة Libhugetlbfs's Malloc (Intel I7 ، 64bit Debian Lenny) ؛ نأمل أن يكون من الواضح ماذا scoped_timer و random0n فعل.

  volatile char force_result;

  const size_t mb=512;
  const size_t stride=4096;
  std::vector<char> src(mb<<20,0xff);
  std::vector<size_t> idx;
  for (size_t i=0;i<src.size();i+=stride) idx.push_back(i);
  random0n r0n(/*seed=*/23);
  std::random_shuffle(idx.begin(),idx.end(),r0n);

  {
    scoped_timer t
      ("TLB thrash random",mb/static_cast<float>(stride),"MegaAccess");
    char hash=0;
    for (size_t i=0;i<idx.size();++i) 
      hash=(hash^src[idx[i]]);
    force_result=hash;
  }

نسخة أبسط "خط مستقيم" مع فقط hash=hash^src[i] حصل فقط على 16 ٪ من الصفحات الكبيرة ، ولكن (التكهنات البرية) Intel's الأجهزة المسبقة المسبقة قد تساعد حالة 4K عندما تكون الوصول يمكن التنبؤ بها (أفترض أنني أستطيع تعطيل الجذاب مسبق للتحقيق فيما إذا كان هذا صحيحًا).

نصائح أخرى

سيأتي الفرق الأكبر في الأداء عندما تقوم بالوصول العشوائي المتباعد على نطاق واسع إلى منطقة كبيرة من الذاكرة - حيث تعني "كبيرة" أكبر بكثير من النطاق الذي يمكن تعيينه من قبل جميع إدخالات الصفحات الصغيرة في TLBs (والتي عادة لها مستويات متعددة في المعالجات الحديثة).

لجعل الأمور أكثر تعقيدًا ، غالبًا ما يكون عدد إدخالات TLB لصفحات 4 كيلو بايت أكبر من عدد الإدخالات للصفحات 2 ميغابايت ، ولكن هذا يختلف كثيرًا عن طريق المعالج. هناك أيضًا الكثير من التباين في عدد إدخالات "الصفحة الكبيرة" المتوفرة في المستوى 2 TLB.

على سبيل المثال ، على نظام AMD Opteron 10H Revision D ("Istanbul") ، تقارير CPUID:

  • L1 DTLB: 4 كيلو بايت الصفحات: 48 إدخالات ؛ صفحات 2MB: 48 إدخالات ؛ 1 جيجابايت الصفحات: 48 إدخالات
  • L2 TLB: 4 كيلو بايت الصفحات: 512 إدخالات ؛ صفحات 2MB: 128 إدخالات ؛ 1 جيجابايت الصفحات: 16 إدخالات

أثناء وجوده على نظام Intel Xeon 56xx ("Westmere") ، تقارير CPUID:

  • L1 DTLB: 4 كيلو بايت الصفحات: 64 إدخالات ؛ صفحات 2MB: 32 إدخالات
  • L2 TLB: 4 كيلو بايت الصفحات: 512 إدخالات ؛ صفحات 2MB: لا شيء

يمكن أن يقوم كلاهما بتخطيط 2 ميجابايت (512*4 كيلو بايت) باستخدام صفحات صغيرة قبل معاناة المستوى 2 TLB ، في حين يمكن لنظام Westmere تعيين 64 ميجابايت باستخدام إدخالات TLB 32 2 ميجابايت ويمكن أن يقوم نظام AMD بتخطيط 352 ميجابايت باستخدام إدخالات 176 2 ميجابايت في L1 و L2 tlbs. سيحصل أي من النظام على تسريع كبير باستخدام صفحات كبيرة للوصول العشوائي عبر نطاقات الذاكرة التي تزيد عن 2 ميغابايت وأقل من 64 ميجابايت. يجب أن يستمر نظام AMD في إظهار الأداء الجيد باستخدام صفحات كبيرة لنطاقات الذاكرة الأكبر بكثير.

ما تحاول تجنبه في كل هذه الحالات هو أسوأ حالات (ملاحظة 1) لاجتياز جميع المستويات الأربعة لترجمة العنوان الهرمي x86_64.
إذا لم تكن أي من آليات تخزين المؤقت لترجمة العنوان (الملاحظة 2) تعمل ، فهذا يتطلب:

  • 5 رحلات إلى الذاكرة لتحميل البيانات المعينة على صفحة 4 كيلو بايت ،
  • 4 رحلات إلى الذاكرة لتحميل البيانات المعينة على صفحة 2 ميجابايت ، و
  • 3 رحلات إلى الذاكرة لتحميل البيانات المعينة على صفحة 1 جيجابايت.

في كل حالة ، تتمثل الرحلة الأخيرة إلى الذاكرة في الحصول على البيانات المطلوبة ، في حين أن الرحلات الأخرى مطلوبة للحصول على أجزاء مختلفة من معلومات ترجمة الصفحة. أفضل وصف رأيته هو في القسم 5.3 من "AMD64 Architecture Programmer's Volume 2: System Programming" (المنشور 24593) http://support.amd.com/us/embedded_techdocs/24593.pdf

الملاحظة 1: الأرقام المذكورة أعلاه ليست حقا أسوأ قضية. التشغيل تحت جهاز افتراضي يجعل هذه الأرقام أسوأ. تشغيل في بيئة تسبب الذاكرة التي تحتفظ بمستويات مختلفة من جداول الصفحة التي يتم تبديلها على القرص يجعل الأداء كثير أسوأ.

ملاحظة 2: لسوء الحظ ، حتى أن معرفة هذا المستوى من التفاصيل لا يكفي ، لأن جميع المعالجات الحديثة لديها ذاكرة التخزين المؤقت الإضافية للمستويات العليا من التسلسل الهرمي لترجمة الصفحة. بقدر ما أستطيع أن أقول أن هذه موثقة بشكل سيء للغاية في الأماكن العامة.

لقد رأيت تحسنًا في بعض سيناريوهات HPC/GRID - وتحديداً حزم الفيزياء مع طرز كبيرة جدًا على الآلات التي تحتوي على الكثير والكثير من ذاكرة الوصول العشوائي. أيضا العملية التي تشغيل النموذج كانت الشيء الوحيد النشط على الجهاز. أظن ، رغم أنه لم يتم قياسه ، أن بعض وظائف DB (مثل الواردات بالجملة) ستستفيد أيضًا.

أنا شخصياً أعتقد أنه ما لم يكن لديك ملف تعريف الوصول إلى الذاكرة بشكل جيد للغاية/مفهومة ، فإنه يقوم بالكثير من الوصول إلى الذاكرة الكبير ، فمن غير المرجح أن ترى أي تحسن كبير.

هذا هو الحصول على الباطنية ، ولكن صفحات TLB ضخمة تحدث فرقًا كبيرًا في بنية Intel Xeon Phi (MIC) عند إجراء عمليات نقل ذاكرة DMA (من مضيف إلى PHI عبر PCIe). يصف رابط Intel هذا كيفية تمكين الصفحات الضخمة. لقد وجدت زيادة أحجام نقل DMA تتجاوز 8 ميغابايت مع حجم صفحة TLB العادية (4K) في تقليل الأداء ، من حوالي 3 جيجابايت/ثانية إلى أقل من 1 جيجابايت/ثانية بمجرد بلوغ حجم النقل 512 ميجابايت.

بعد تمكين صفحات TLB ضخمة (2 ميجابايت) ، استمر معدل البيانات في الزيادة إلى أكثر من 5 جيجابايت/ثانية لنقل DMA من 512 ميغابايت.

أحصل على تسريع ~ 5 ٪ على الخوادم مع الكثير من الذاكرة (> = 64 جيجابايت) تشغيل عمليات كبيرة. على سبيل المثال لعملية Java 16 جيجا بايت ، هذه صفحات 4M × 4KB ولكن فقط 4K × 4 ميليجابايت.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top