. NET الأساسية: x86_64 الجوهرية على الأجهزة الظاهرية

نحن نعيش في عصر هيمنة العمارة x86. جميع المعالجات المتوافقة مع x86 متشابهة ، ولكنها كلها مختلفة قليلاً. وليس فقط الشركة المصنعة ، وتواتر وعدد النوى.

شهدت بنية x86 أثناء وجودها (وشعبيتها) العديد من التحديثات الرئيسية (على سبيل المثال ، الامتداد إلى 64 بت - x86_64) وإضافة "مجموعات التعليمات الموسعة". يجب على المترجمين ، الذين يقومون بشكل افتراضي بإنشاء رمز شائع قدر الإمكان لجميع المعالجات ، أن يتكيفوا مع هذا. ولكن من بين التعليمات الموسعة ، هناك العديد من للاهتمام ومفيد. على سبيل المثال ، في برامج الشطرنج ، غالبًا ما يتم استخدام تعليمات العمل مع البتات: POPCNT ، BSF / BSR (أو نظائرها الحديثة TZCNT / LZCNT ) ، PDEP ، BSWAP ، إلخ.

في المترجمين C و C ++ ، يتم تنفيذ الوصول الصريح لهذه التعليمات من خلال "الوظائف الجوهرية لهذا المعالج". example1 example2

لم يكن هناك مثل هذا الوصول المريح لـ .NET و C # ، لذلك قمت ذات مرة بإنشاء الغلاف الخاص بي ، والذي يوفر محاكاة لمثل هذه الوظائف ، ولكن إذا كانت وحدة المعالجة المركزية تدعمها ، فقد قمت باستبدال مكالمتها مباشرة في رمز الاتصال. لحسن الحظ ، تم وضع معظم العناصر الجوهرية التي أحتاجها في 5 بايت من كود تشغيل CALL. يمكن قراءة التفاصيل على المحور في هذا الرابط .

لقد مرت سنوات عديدة منذ ذلك الحين ، في الجوهر الطبيعي. NET لم يظهر أبدًا. ولكن خرج .NET Core ، حيث تم تصحيح الوضع. جاءت أولاً تعليمات المتجه ، ثم تقريبًا مجموعة * System.Runtime.Intrinsics.X86 بأكملها تقريبًا .
* - لا يوجد BSF و BSR "قديم" ،

وبدا كل شيء لطيفًا ومريحًا. باستثناء أن تعريف الدعم لكل مجموعة من التعليمات كان دائمًا مربكًا (يتم تضمين بعضها على الفور من قبل المجموعات ، بالنسبة للبعض هناك إشارات منفصلة). لذا فإن NET Core أربكتنا أكثر مع حقيقة أن هناك أيضًا بعض التبعيات بين المجموعات "المسموح بها".

ظهر هذا عندما حاولت تشغيل الكود على جهاز افتراضي باستخدام برنامج مراقبة الأجهزة الافتراضية KVM: سقطت الأخطاء System.PlatformNotSupportedException: Operation is not supported on this platform at System.Runtime.Intrinsics.X86.Bmi1.X64.TrailingZeroCount(UInt64 value). وبالمثل بالنسبة لـ System.Runtime.Intrinsics.X86.Popcnt.X64.PopCount. ولكن إذا كان من الممكن بالنسبة لـ POPCNT وضع علامة واضحة إلى حد ما في معلمات المحاكاة الافتراضية ، فإن TZCNT قادني إلى طريق مسدود. في الصورة التالية ، ناتج الأداة التي تتحقق من توافر الجوهرية في netcore (الرمز والثنائي في نهاية المقالة) و CPU-Z المعروفة:



وهنا إخراج الأداة المأخوذة من صفحة MSDN حول CPUID : على



الرغم من حقيقة أن تقارير المعالج تدعم كل شيء مطلوب ، Intrinsics.X86.Bmi1.X64.TrailingZeroCountلا تزال التعليمات تنخفض مع التنفيذ System.PlatformNotSupportedException.

لمعرفة ذلك ، نحتاج إلى النظر إلى المعالج من خلال عيون NETCore. أي مصادر تكمن في جيثب. دعونا نبحث عن كيوبيد هناك ونخرج إلى الطريقة ، EEJitManager::SetCpuInfo()

فهناك الكثير من الظروف المختلفة فيها ، وبعضها متداخل. أخذت هذه الطريقة وقمت بنسخها في مشروع فارغ. بالإضافة إلى ذلك ، كان عليّ أن ألتقط طريقتين أخريين وملف مجمع كامل ( كيفية إضافة asm إلى استوديو جديد ). نتيجة التنفيذ:



كما ترى ، InstructionSet_BMI1لا يزال يتم تعيين العلم (على الرغم من عدم تعيين بعض الآخرين).

إذا كنت تبحث عن هذه العلامة في المستودع ، يمكنك أن تجد هذا الرمز :

if (resultflags.HasInstructionSet(InstructionSet_BMI1) && !resultflags.HasInstructionSet(InstructionSet_AVX))
    resultflags.RemoveInstructionSet(InstructionSet_BMI1);

لذا هي إدماننا! إذا لم يتم تحديد AVX ، فسيتم تعطيل BMI1 (وبعض المجموعات الأخرى). ما هو المنطق ، لم يتضح لي بعد ، لكننا نأمل أن لا يزال موجودًا. الآن يبقى أن نفهم لماذا ترى cpu-z وغيرها من الأدوات AVX ، لكن netcore لا.

دعونا نرى كيف يختلف ناتج أداتنا على المعالجات المختلفة:

>diff a b
7c7,8
< Test ((buffer[8] & 0x02) != 0) -> 0
---
> Test ((buffer[8] & 0x02) != 0) -> 1
> ==> Set InstructionSet_PCLMULQDQ
18c19,32
< Test ((buffer[11] & 0x18) == 0x18) -> 0
---
> Test ((buffer[11] & 0x18) == 0x18) -> 1
> Test (hMod == NULL) -> 0
> Test (pfnGetEnabledXStateFeatures == NULL) -> 0
> Test ((FeatureMask & XSTATE_MASK_AVX) == 0) -> 0
> Test (DoesOSSupportAVX() && (xmmYmmStateSupport() == 1)) -> 1
> Test (hMod == NULL) -> 0
> Test (pfnGetEnabledXStateFeatures == NULL) -> 0
> Test ((FeatureMask & XSTATE_MASK_AVX) == 0) -> 0
> ==> Set InstructionSet_AVX
> Test ((buffer[9] & 0x10) != 0) -> 1
> ==> Set InstructionSet_FMA
> Test (maxCpuId >= 0x07) -> 1
> Test ((buffer[4] & 0x20) != 0) -> 1
> ==> Set InstructionSet_AVX2

  1. فشل المخزن المؤقت الاختيار [8] & 0x02 ، هذا هو PCLMULQDQ
  2. فشل المخزن المؤقت [11] و 0x18 ، إنه AVX & OSXSAVE ، تم تعيين AVX بالفعل (CPU-Z يرى هذا) ، OSXSAVE مطلوب
  3. وخلفه توجد فحوصات أخرى تؤدي إلى علامة InstructionSet_AVX

فماذا تفعل مع الفيروسية؟ إذا كان ذلك ممكنًا ، فمن الأفضل وضع libvirt.cpu_mode في host-passthrough أو host-model .

ولكن إذا لم يكن ذلك ممكنًا ، فعليك إضافة كل الحساء من التعليمات ، على وجه الخصوص ssse3, sse4.1, sse4.2, sse4a, popcnt, abm, bmi1, bmi2, avx, avx2, osxsave, xsave, pclmulqdq. هنا أقول مرحبا وشكرا لكمvdsina_m؛)

ويمكنك التحقق من المضيف أو الجهاز الظاهري للحصول على دعم التعليمات وكيف ينظر إليها .NET Core باستخدام هذه الأداة: (في الوقت الحالي ، zip ، سأقوم بنشره في github لاحقًا).


All Articles