Runtime: تقديم JIT المتدرج

تم إنشاؤها على ١٤ أبريل ٢٠١٦  ·  63تعليقات  ·  مصدر: dotnet/runtime

لماذا NET JIT غير متدرج؟

لدى JIT هدفان أساسيان في التصميم: وقت بدء التشغيل السريع وإنتاجية الحالة المستقرة العالية.

في البداية ، تبدو هذه الأهداف متناقضة. ولكن مع تصميم JIT من مستويين ، يمكن تحقيق كلاهما:

  1. يبدأ تفسير كل التعليمات البرمجية. ينتج عن هذا وقت بدء تشغيل سريع للغاية (أسرع من RyuJIT). مثال: الطريقة Main دائمًا ما تكون باردة والنفط مضيعة للوقت.
  2. يتم تشغيل الكود الذي يتم تشغيله غالبًا باستخدام منشئ أكواد عالي الجودة. عدد قليل جدًا من الطرق سيكون ساخنًا (1٪؟). لذلك ، فإن إنتاجية JIT عالية الجودة لا تهم كثيرًا. يمكن أن يقضي الكثير من الوقت الذي يقضيه مترجم لغة سي لتوليد كود جيد جدًا. أيضا ، يمكن أن يستنتج أن الكود ساخن. يمكن أن تكون مضمنة مثل الحلقات المجنونة وغير الملتفة. حجم الكود ليس مصدر قلق.

لا يبدو الوصول إلى هذه البنية مكلفًا للغاية:

  1. تبدو كتابة المترجم الفوري رخيصة مقارنة بـ JIT.
  2. يجب إنشاء مولد رمز عالي الجودة. يمكن أن يكون هذا مشروع VC أو LLILC.
  3. يجب أن يكون من الممكن نقل التعليمات البرمجية قيد التشغيل المفسرة إلى التعليمات البرمجية المترجمة. هذا ممكن؛ JVM يفعل ذلك. يتم استدعاؤه عند استبدال المكدس (OSR).

هل هذه الفكرة يتبعها فريق JIT؟

يعمل .NET على مئات الملايين من الخوادم. أشعر أن الكثير من الأداء متروك على الطاولة ويتم إهدار ملايين الخوادم للعملاء بسبب عام الكود دون المستوى الأمثل.

الفئة: الإنتاجية
الموضوع: رهانات كبيرة
مستوى المهارة: خبير
التكلفة: كبير جدًا

area-CodeGen-coreclr enhancement optimization tenet-performance

التعليق الأكثر فائدة

باستخدام العلاقات العامة الحديثة (https://github.com/dotnet/coreclr/pull/17840 ، https://github.com/dotnet/sdk/pull/2201) لديك أيضًا القدرة على تحديد التجميع المتدرج باعتباره runtimeconfig. json أو عقار مشروع msbuild. سيتطلب استخدام هذه الوظيفة أن تكون في تصميمات حديثة جدًا بينما كان متغير البيئة موجودًا لفترة من الوقت.

ال 63 كومينتر

تصنيفGSPP هو موضوع ثابت في التخطيط للمحادثات. انطباعي أن الأمر يتعلق بوقت ، وليس _if ، إذا كان ذلك يوفر أي عزاء. بالنسبة إلى _لماذا_ لم يكن موجودًا بالفعل ، أعتقد أنه بسبب ، تاريخيًا ، المكاسب المحتملة المتصورة لا تبرر موارد التطوير الإضافية اللازمة لإدارة التعقيد المتزايد ومخاطر أوضاع التشفير المتعددة. أود حقًا أن أترك الخبراء يتحدثون عن هذا ، لذا سأضيفهم.

/ cc @ dotnet / jit- Contribrussellhadley

بطريقة ما أشك في أن هذا لا يزال ذا صلة في عالم من crossgen / ngen ، جاهز للتشغيل والتوجيه.

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

ولكن حتى الآن ، حاولت جميع مولدات الأكواد الخاصة بـ .NET تحقيق توازن مستحيل بين الهدفين ، ولم تحقق أي منهما بشكل جيد. دعنا نتخلص من فعل التوازن هذا حتى نتمكن من تحويل التحسينات إلى 11.

ولكن حتى الآن ، حاولت جميع مولدات الأكواد الخاصة بـ .NET تحقيق توازن مستحيل بين الهدفين ، ولم تحقق أي منهما بشكل جيد. دعنا نتخلص من فعل التوازن هذا حتى نتمكن من تحويل التحسينات إلى 11.

أوافق ولكن إصلاح هذا لا يتطلب أشياء مثل المترجم الفوري. مجرد مترجم crossgen جيد ، سواء كان أفضل RyuJIT أو LLILC.

أعتقد أن الميزة الأكبر هي للتطبيقات التي تحتاج إلى إنشاء رمز في وقت التشغيل. وتشمل هذه اللغات الديناميكية وحاويات الخادم.

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

يجب ألا تحتاج تطبيقات الويب إلى أي معالجة بأسلوب ngen. لا يتناسب بشكل جيد مع خط أنابيب النشر. يستغرق الأمر وقتًا طويلاً لإنشاء نظام ثنائي كبير (حتى لو كانت جميع الرموز تقريبًا ميتة أو باردة ديناميكيًا).

أيضًا ، عند تصحيح أخطاء تطبيق الويب واختباره ، لا يمكنك الاعتماد على ngen لمنحك أداءً واقعيًا.

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

يحل التصنيف كل شيء في كل سيناريو إلى الأبد. تقريبًا :) يمكن أن يقودنا هذا في الواقع إلى وعد JITs: تحقيق الأداء _beyond_ ما يمكن أن يفعله مترجم C.

التنفيذ الحالي لـ RyuJIT كما هو الآن جيد بما يكفي للمستوى 1 ... السؤال هو: هل سيكون من المنطقي أن يكون لديك JIT للتحسين الأقصى من المستوى 2 للمسارات الساخنة التي يمكن تشغيلها بعد الحقيقة؟ بشكل أساسي عندما نكتشف أو لدينا معلومات كافية عن وقت التشغيل لنعرف أن هناك شيئًا ساخنًا أو عندما يُطلب منك استخدامه بدلاً من ذلك من البداية.

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

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

أعتقد أن هذا لن يكون سيئًا للغاية ويمكن استخدامه كاستراتيجية v1. تتوفر أفكار التخفيف مثل سمة تحدد طريقة ما على أنها ساخنة (يجب أن يكون هذا موجودًا على أي حال حتى مع استراتيجية JIT الحالية).

GSPP هذا صحيح ، لكن هذا لا يعني أنك لن تعرف ذلك في الجولة التالية. إذا أصبحت التعليمات البرمجية والأدوات Jitted ثابتة ، فستظل تحصل على رمز المستوى 2 في التنفيذ الثاني (على حساب بعض وقت بدء التشغيل) - والذي لم أكن أهتم به شخصيًا لأنني أكتب في الغالب رمز الخادم.

تبدو كتابة المترجم الفوري رخيصة مقارنة بـ JIT.

بدلاً من كتابة مترجم فوري جديد ، هل من المنطقي تشغيل RyuJIT مع تعطيل التحسينات؟ هل سيؤدي ذلك إلى تحسين وقت بدء التشغيل بدرجة كافية؟

يجب إنشاء مولد رمز عالي الجودة. يمكن أن يكون هذا VC

هل تتحدث عن C2 ، الواجهة الخلفية لـ Visual C ++؟ هذا ليس عبر الأنظمة الأساسية وليس مفتوح المصدر. أشك في أن إصلاح كليهما سيحدث في أي وقت قريب.

فكرة جيدة مع تعطيل التحسينات. ومع ذلك ، لا تزال مشكلة OSR قائمة. لست متأكدًا من مدى صعوبة إنشاء رمز يسمح لوقت التشغيل باشتقاق الحالة المعمارية لـ IL (السكان المحليون والمكدس) في وقت التشغيل في نقطة آمنة ، قم بنسخ ذلك إلى كود من المستوى 2 واستئناف وظيفة منتصف تنفيذ المستوى 2. تقوم JVM بذلك ولكن من يدري كم من الوقت استغرق تنفيذه.

نعم ، كنت أتحدث عن C2. أعتقد أنني أتذكر أن واحدة على الأقل من أجهزة سطح المكتب JITs تعتمد على كود C2. ربما لا يعمل مع CoreCLR ولكن ربما لسطح المكتب. أنا متأكد من أن Microsoft مهتمة بالحصول على قواعد تعليمات برمجية متوافقة ، لذا فمن المحتمل أن يكون هذا الأمر خارجًا بالفعل. يبدو أن LLVM خيار رائع. أعتقد أن العديد من اللغات مهتمة حاليًا بجعل LLVM تعمل مع GCs وأوقات التشغيل المُدارة بشكل عام.

يبدو أن LLVM خيار رائع. أعتقد أن العديد من اللغات مهتمة حاليًا بجعل LLVM تعمل مع GCs وأوقات التشغيل المُدارة بشكل عام.

مقال مثير للاهتمام حول هذا الموضوع: نقلت Apple مؤخرًا المستوى الأخير من JavaScript JIT بعيدًا عن LLVM: https://webkit.org/blog/5852/introducing-the-b3-jit-compiler/ . من المحتمل أن نواجه مشكلات مماثلة لما واجهوه: أوقات الترجمة البطيئة وافتقار LLVM إلى المعرفة باللغة المصدر.

سيكون أبطأ بـ 10x من RyuJIT مقبولًا تمامًا للطبقة الثانية.

لا أعتقد أن نقص المعرفة باللغة المصدر (وهو مصدر قلق حقيقي) متأصل في بنية LLVM. أعتقد أن هناك فرقًا متعددة مشغولة بنقل LLVM إلى حالة يمكن فيها استخدام معرفة لغة المصدر بسهولة أكبر. _All_ اللغات عالية المستوى غير C تواجه هذه المشكلة عند التحويل البرمجي على LLVM.

يعتبر مشروع WebKIT FTL / B3 في وضع أصعب للنجاح من .NET لأنه يجب أن يتفوق عند تشغيل التعليمات البرمجية التي تستهلك بضع مئات من المللي ثانية من الوقت ثم تخرج. هذه هي طبيعة أعباء عمل JavaScript التي تقود صفحات الويب. NET ليس في هذا المكان.

GSPP أنا متأكد من أنك ربما تعرف عن LLILC . إذا لم يكن كذلك ، الق نظرة.

لقد عملنا لفترة من الوقت على دعم LLVM لمفاهيم CLR واستثمرنا في كل من تحسينات EH و GC. لا يزال هناك الكثير للقيام به على حد سواء. علاوة على ذلك ، يوجد قدر غير معروف من العمل للحصول على تحسينات تعمل بشكل صحيح في وجود GC.

يبدو أن LLILC متوقفة. فعلا؟
في 18 أبريل 2016 ، الساعة 7:32 مساءً ، كتب "Andy Ayers" [email protected] :

GSPP https://github.com/GSPP أنا متأكد من أنك ربما تعرف عن LLILC
https://github.com/dotnet/llilc. إذا لم يكن كذلك ، الق نظرة.

لقد عملنا لفترة من الوقت على دعم LLVM لمفاهيم CLR ولدينا
استثمرت في تحسينات كل من EH و GC. لا يزال هناك الكثير للقيام به
على حد سواء. علاوة على ذلك ، هناك قدر غير معروف من العمل للحصول على تحسينات
يعمل بشكل صحيح في وجود GC.

-
أنت تتلقى هذا لأنك علقت.
قم بالرد على هذا البريد الإلكتروني مباشرة أو قم بعرضه على GitHub
https://github.com/dotnet/coreclr/issues/4331#issuecomment -211630483

drbo - تعمل LLILC في الخلف في الوقت الحالي - ركز فريق MS على الحصول على المزيد من الأهداف التي تم طرحها في RyuJIT بالإضافة إلى إصلاح المشكلات التي تظهر أثناء إطلاق CoreCLR على محركات الأقراص وقد استغرق ذلك وقتنا كثيرًا. إنه مدرج في قائمة المهام الخاصة بي (في وقت فراغي الغزير) لكتابة منشور الدروس المستفادة استنادًا إلى المدى الذي وصلنا إليه (حاليًا) مع LLILC ، لكنني لم أصل إليه بعد.
على المستويات ، أثار هذا الموضوع الكثير من النقاش على مر السنين. أعتقد أنه بالنظر إلى بعض أعباء العمل الجديدة ، بالإضافة إلى الإضافة الجديدة للإصدار الجاهز لتشغيل الصور ، سنلقي نظرة جديدة على كيفية ومكان التصنيف.

russellhadley هل كان لديك وقت فراغ لكتابة المنشور؟

أفترض أنه يجب أن يكون هناك شيء ما حول عدم الترويج لفتحات المكدس و gcroots التي تكسر الاختيارات ووقت التشغيل البطيء ... يجب أن ألقي نظرة أفضل على كود المشروع.

أتساءل أيضًا عما إذا كان من الممكن والمربح القفز مباشرة إلى SelectionDAG وأداء جزء من LLVM backend. على الأقل بعض نشر ثقب الباب والنسخ ... إذا كان ، على سبيل المثال ، ترويج gcroot للسجلات مدعومًا في LLILC

لدي فضول لمعرفة حالة LLILC بما في ذلك الاختناقات الحالية وكيف تتعامل مع RyuJIT. يجب أن يكون لدى LLVM مترجم كامل "القوة الصناعية" ثروة كبيرة من التحسينات المتاحة لـ OSS. كانت هناك بعض المحادثات حول تسلسل / إلغاء تسلسل أكثر كفاءة وأسرع لتنسيق رمز البت في القائمة البريدية ؛ أتساءل عما إذا كان هذا مفيدًا لشركة LLILC.

هل كان هناك المزيد من الأفكار حول هذا؟ russellhadley تم إصدار CoreCLR وتم نقل RyuJIT إلى (على الأقل) x86 - ما الخطوة التالية في خريطة الطريق؟

انظر dotnet / coreclr # 10478 لبدايات العمل على هذا.

أيضًا dotnet / coreclr # 12193

noahfalk ، هل يمكنك من فضلك توفير طريقة لإخبار وقت التشغيل بفرض تجميع من المستوى 2 بعيدًا عن الكود المُدار نفسه؟ يُعد التجميع المتدرج فكرة جيدة جدًا لمعظم حالات الاستخدام ، لكني أعمل في مشروع لا يكون فيه وقت بدء التشغيل مهمًا ولكن الإنتاجية ووقت الاستجابة المستقر ضروريان.

من فوق رأسي ، يمكن أن يكون هذا إما:

  • إعداد جديد في ملف التكوين ، مفتاح مثل <gcServer enabled="true" /> لإجبار JIT على تخطي المستوى 1 دائمًا
  • أو شيء من هذا القبيل RuntimeHelpers.PrepareMethod ، والذي سيتم استدعاؤه بواسطة الكود في جميع الطرق التي تعد جزءًا من المسار السريع (نحن نستخدم هذا في ما قبل JIT رمزنا عند بدء التشغيل). يتميز هذا بميزة منح درجة أكبر من الحرية للمطور الذي يجب أن يعرف ما هو المسار السريع. سيكون الحمل الزائد الإضافي لهذه الطريقة على ما يرام.

منحت ، القليل من المشاريع ستستفيد من هذا ، لكنني أشعر بالقلق نوعًا ما من تخطي JIT للتحسينات افتراضيًا ، ولا أتمكن من إخبار ذلك ، فأنا أفضل أن أجعله يعمل على تحسين الكود بشكل كبير بدلاً من ذلك.

أعلم أنك كتبت ما يلي في مستند التصميم:

أضف مرحلة خط أنابيب جديدة يمكن الوصول إليها من واجهات برمجة تطبيقات التعليمات البرمجية المدارة للقيام بالتعليمات البرمجية ذاتية التعديل.

الذي يبدو ممتعًا جدًا 😁 لكنني لست متأكدًا تمامًا من أنه يغطي ما أطلبه هنا.


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

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

في 29 حزيران (يونيو) 2017 الساعة 7:01 مساءً ، تلقيت "Lucas Trzesniewski" [email protected]
كتب:

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

من فوق رأسي ، يمكن أن يكون هذا إما:

  • إعداد جديد في ملف التكوين ، مثل التبديل مُمكّن = "true" /> لإجبار JIT على تخطي المستوى 1 دائمًا
  • أو شيء مثل RuntimeHelpers.PrepareMethod ، والذي سيكون
    تم استدعاؤها بواسطة الكود على جميع الطرق التي تعد جزءًا من المسار الساخن (نحن
    باستخدام هذا لإجراء ما قبل JIT رمزنا عند بدء التشغيل). هذا له ميزة
    إعطاء قدر أكبر من الحرية للمطور الذي يجب أن يعرف ماذا
    المسار الساخن. سيكون الحمل الزائد الإضافي لهذه الطريقة على ما يرام.

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

أعلم أنك كتبت ما يلي في مستند التصميم:

قم بإضافة مرحلة مسار بناء جديدة يمكن الوصول إليها من واجهات برمجة تطبيقات التعليمات البرمجية المدارة للقيام بها
كود التعديل الذاتي.

الذي يبدو ممتعًا جدًا 😁 لكنني لست متأكدًا تمامًا من أنه يغطي ما

أنا أسأل هنا.

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

-
أنت تتلقى هذا لأنه تم ذكرك.
قم بالرد على هذا البريد الإلكتروني مباشرة ، وقم بعرضه على GitHub
https://github.com/dotnet/coreclr/issues/4331#issuecomment-312130920 ،
أو كتم الخيط
https://github.com/notifications/unsubscribe-auth/AGGWB2WbZ2qVBjRIQWS86MStTSa1ODfoks5sJCzOgaJpZM4IHWs8
.

ltrzesniewski - شكرًا على ملاحظاتك! بالتأكيد آمل أن يكون التجميع المتدرج مفيدًا للغالبية العظمى من المشاريع ، لكن المفاضلات قد لا تكون مثالية لكل مشروع. لقد كنت أتوقع أننا سنترك متغير بيئة في مكانه لتعطيل القفز المتدرج ، وفي هذه الحالة تحافظ على سلوك وقت التشغيل الذي لديك الآن بجودة أعلى (ولكن أبطأ في التوليد) في المقدمة. هل تعيين متغير البيئة أمر معقول ليقوم به تطبيقك؟ الخيارات الأخرى ممكنة أيضًا ، أنا فقط أنجذب إلى متغير البيئة لأنه أحد أبسط خيارات التكوين التي يمكننا استخدامها.

أيضا سؤال ذو صلة: متى ستبدأ تمريرة JIT الثانية؟

هذه سياسة من المحتمل جدًا أن تتطور بمرور الوقت. يستخدم تنفيذ النموذج الأولي الحالي سياسة مبسطة: "هل تم استدعاء الطريقة> = 30 مرة"
https://github.com/dotnet/coreclr/blob/master/src/vm/tieredcompilation.cpp#L89
https://github.com/dotnet/coreclr/blob/master/src/vm/tieredcompilation.cpp#L122

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

DemiMarie - ليس لدينا أي شيء يتتبع تكرار الحلقات كجزء من السياسة الآن ، ولكنه احتمال مثير للاهتمام للمستقبل.

هل كانت هناك أية أفكار حول التنميط والتحسين التخميني و
deoptimization؟ يقوم JVM بكل هذا.

في 29 حزيران (يونيو) 2017 الساعة 8:58 مساءً ، كتب "نوح فالك" [email protected] :

ltrzesniewski https://github.com/ltrzesniewski - شكرًا على
تعليق! بالتأكيد آمل أن يكون التجميع المتدرج مفيدًا للملفات الكبيرة
غالبية المشاريع ولكن المفاضلات قد لا تكون مثالية لكل مشروع.
لقد كنت أتوقع أننا سنترك متغير البيئة في مكانه
تعطيل jitting jitting المتدرج ، وفي هذه الحالة تحافظ على سلوك وقت التشغيل لك
لديك الآن بجودة أعلى (ولكن أبطأ في التوليد) تتنقل في المقدمة. يكون
تعيين متغير بيئة شيء معقول لتطبيقك أن يفعله؟
الخيارات الأخرى ممكنة أيضًا ، أنا فقط أنجذب إلى البيئة
متغير لأنه أحد أبسط خيارات التكوين التي يمكننا استخدامها.

أيضا سؤال ذو صلة: متى ستبدأ تمريرة JIT الثانية؟

هذه سياسة من المحتمل جدًا أن تتطور بمرور الوقت. الحالي
يستخدم تنفيذ النموذج الأولي سياسة مبسطة: "هل تم تنفيذ الطريقة
يسمى> = 30 مرة "
https://github.com/dotnet/coreclr/blob/master/src/vm/
tieredcompilation.cpp # L89
https://github.com/dotnet/coreclr/blob/master/src/vm/
tieredcompilation.cpp # L122

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

DemiMarie https://github.com/demimarie - ليس لدينا أي شيء
يتتبع التكرارات الحلقية كجزء من السياسة الآن ، لكنه مثير للاهتمام
احتمالية المستقبل.

-
أنت تتلقى هذا لأنه تم ذكرك.
قم بالرد على هذا البريد الإلكتروني مباشرة ، وقم بعرضه على GitHub
https://github.com/dotnet/coreclr/issues/4331#issuecomment-312146470 ،
أو كتم الخيط
https://github.com/notifications/unsubscribe-auth/AGGWB5m2qCnOKJsaXFCFigI3J6Ql8PMQks5sJEgZgaJpZM4IHWs8
.

noahfalk @ متغير بيئي بالتأكيد ليس حلاً يسمح لك بالتحكم في هذا التطبيق عن طريق التطبيق. بالنسبة لتطبيقات الخادم / الخدمة ، لا تهتم عادةً بالوقت الذي يستغرقه التطبيق لبدء التشغيل (أعلم أننا لا نفعل ذلك على حساب الأداء). عند تطوير محرك قاعدة بيانات ، يمكنني أن أخبرك بشكل مباشر ، فنحن بحاجة إليه للعمل بأسرع ما يمكن من البداية وحتى على المسارات غير الاستثنائية أو المعايير التي يقوم بها العملاء الجدد المحتملون.

من ناحية أخرى ، بالنظر إلى أنه في البيئات النموذجية يمكن قياس وقت التشغيل بأسابيع في كل مرة ، لا نهتم إذا استغرق الأمر حتى 30 ثانية ؛ ما يهمنا هو أن إجبار المستخدم على إصدار مفتاح عام (الكل أو لا شيء) أو حتى جعل المستخدم يهتم به (مثل التعيين افتراضيًا من ملفات التكوين) هو 10 خطوات للخلف.

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

تحرير: بعض قضايا النمط.

redknightlois - شكرًا على المتابعة

متغير بيئي بالتأكيد ليس حلاً يسمح لك بالتحكم في هذا التطبيق عن طريق التطبيق.

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

set COMPLUS_EXPERIMENTAL_TieredCompilation=1
MyApp.exe
set COMPLUS_EXPERIMENTAL_TieredCompilation=0

ما يهمنا هو أننا [لا] نجبر المستخدم ... على الاهتمام به

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

أيضًا تنبيه - على افتراض أننا نواصل السير في مسار التجميع المتدرج بطرق لائقة ، يمكنني بسهولة أن أتخيل أننا وصلنا إلى نقطة حيث تمكين التجميع المتدرج ليس فقط أسرع بدء تشغيل ، ولكنه أيضًا يتفوق على أداء الحالة المستقرة الحالية. إن أداء بدء التشغيل الآن هو هدفي ، لكنه ليس حدًا لما يمكننا فعله به:)

هل كانت هناك أية أفكار حول التنميط والتحسين التخميني و
deoptimization؟

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

noahfalk @ نعم ، كونك غير أنيق يعني أيضًا أن العملية المعتادة لتشغيلها يمكن (ومن المحتمل جدًا) أن تصبح عرضة للخطأ وهذه هي المشكلة الأساسية (الطريقة الوحيدة للتأكد تمامًا من عدم تعرض أي شخص للخطأ هي القيام بذلك على مستوى النظام). البديل الذي نعرف أنه يعمل هو أنه بنفس الطريقة التي يمكنك تكوينها إذا كنت ستستخدم خادم GC مع إدخال في app.config يمكنك فعل الشيء نفسه مع التجميع المتدرج (على الأقل حتى يمكن أن تتغلب المتدرجة باستمرار على أداء الحالة المستقرة). نظرًا لكونك JIT ، يمكنك أيضًا القيام بذلك لكل مجموعة باستخدام assembly.config وستعطي درجة من الإمكانات غير الموجودة حاليًا إذا كان من الممكن تحديد المقابض الأخرى بهذه الطريقة أيضًا.

غالبًا ما يتم تعيين متغيرات البيئة لكل مستخدم أو لكل نظام ، مما له تأثير سلبي محتمل للتأثير على جميع هذه العمليات ، عبر إصدارات متعددة من وقت التشغيل. يبدو أن ملف التكوين لكل تطبيق هو حل أفضل بكثير (حتى إذا كان كل مستخدم / لكل نظام متاحًا أيضًا) - شيء مثل قيم تكوين سطح المكتب التي يمكن تعيينها في app.config ، ولكن أيضًا استخدم env vars أو ريجستري .

أعتقد أننا سنطبق المسار الأكثر شيوعًا وهو لكل تطبيق. قد تكون الإعدادات على مستوى النظام مفيدة أيضًا ، لكن لا أعتقد أنه يتعين علينا التفكير في الأمر قبل تنفيذ الميزة.

يرجى ملاحظة أننا لم نضع أي تفاصيل حول ما يجب أن تفعله المرحلة الثانية من أجل التحسين ، على الرغم من أن لدينا بعض الأفكار. قد تفعل ما تفعله جيت اليوم ، ولكن من المحتمل جدًا أنها ستفعل المزيد.

لذا اسمحوا لي أن أشير إلى بعض المضاعفات المحتملة ....

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

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

ما قيل...

أعتقد أن سمة أسلوب "التحسين العدواني" منطقية - قد يطلب أحدهم من jit أن يتصرف إلى حد ما مثل jit من الدرجة الثانية قد يتصرف مع طرق معينة ، وربما تخطي هذه الأساليب أثناء الإنجاز المسبق (نظرًا لأن الشفرة الجاهزة تعمل بشكل أبطأ من الشفرة المحجوزة ، خاصة بالنسبة لـ R2R). لكن تطبيق هذه الفكرة على تجميع كامل أو على جميع التجميعات في تطبيق ما لا يبدو جذابًا.

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

AndyAyersMS أعتقد أنك ضربت المسمار هناك. من المحتمل أن تحل سمة معالجة JIT "التحسين القوي" معظم المشكلات المتعلقة بعدم القدرة على الحصول على معلومات كافية لـ JIT لإنتاج كود أفضل عند العزل دون أن يكون لدى فريق المستوى الأول الوقت لتقديم تلك الملاحظات.

redknightlois لن تعمل السمة إذا أردنا المزيد من التدرج: - T3 JIT ، T4 JIT ، ... لست متأكدًا مما إذا كان المستويان غير كافيين ، ولكن يجب على الأقل النظر في هذا الاحتمال.

سيكون من الرائع أن تكون قادرًا على استخدام شيء مشابه لـ MPGO لبدء التشغيل باستخدام كود jitted من الدرجة الثانية. التقديم السريع للطبقة الأولى بدلاً من تجاوزها تمامًا.

AndyAyersMS ، هل حقيقة أن Azul نفذت JIT مُدار لـ JVM باستخدام LLVM جعلت من الأسهل دمج LLVM في CLR؟ من الواضح أنه تم دفع التغييرات في اتجاه المنبع إلى LLVM في هذه العملية.

فقط لمعلوماتك ، لقد أنشأت عددًا من عناصر العمل لبعض الأعمال المحددة التي نحتاج إلى القيام بها للحصول على مستويات متدرجة من الأرض (# 12609 ، dotnet / coreclr # 12610 ، dotnet / coreclr # 12611 ، dotnet / coreclr # 12612 ، dotnet / coreclr # 12617). إذا كان اهتمامك يتعلق مباشرة بأحد هؤلاء ، فلا تتردد في إضافة تعليقاتك إليهم. بالنسبة إلى أي مواضيع أخرى أفترض أن المناقشة ستبقى هنا ، أو يمكن لأي شخص إنشاء مشكلة لموضوع فرعي معين إذا كان هناك اهتمام كافٍ لتقسيمه من تلقاء نفسه.

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

بقدر ما يذهب المستوى العلوي المستند إلى LLVM - من الواضح أننا بحثنا في هذا إلى حد ما مع LLILC ، وفي ذلك الوقت كنا على اتصال متكرر بأفراد Azul ، لذلك نحن على دراية بالعديد من الأشياء التي كانوا يقومون بها LLVM لجعله أكثر قابلية لتجميع اللغات باستخدام GC دقيقة.

كانت هناك (ولا تزال على الأرجح) اختلافات كبيرة في دعم LLVM المطلوب لـ CLR مقابل ما هو مطلوب لـ Java ، في كل من GC و EH ، وفي القيود التي يجب على المرء وضعها على المُحسِّن. للاستشهاد بمثال واحد فقط: لا يمكن لـ CLRs GC حاليًا أن تتسامح مع المؤشرات المُدارة التي تشير إلى نهاية الكائنات. يعالج Java هذا عبر آلية إعداد التقارير المزدوجة الأساسية / المشتقة. سنحتاج إما إلى دعم هذا النوع من التقارير المزدوجة في CLR أو تقييد تصاريح مُحسِّن LLVM لعدم إنشاء هذه الأنواع من المؤشرات مطلقًا. علاوة على ذلك ، كان نقل LLILC بطيئًا ولم نكن متأكدين في النهاية من نوع جودة الشفرة التي قد تنتجها.

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

AndyAyersMS ربما يمكنك تقديم التغييرات المطلوبة في LLVM أيضًا بدلاً من التغلب على قيودها.

هل يعمل Multicore JIT و Profile Optimization مع coreclr؟

benaadams - نعم يعمل JIT متعدد النوى. لا أتذكر أي سيناريوهات (إن وجدت) حيث يتم تمكينها افتراضيًا ، ولكن يمكنك تحويلها عبر التكوين: https://github.com/dotnet/coreclr/blob/master/src/inc/clrconfigvalues.h# L548

لقد كتبت مترجمًا نصف لعبة ولاحظت أنه في معظم الأوقات يمكن إجراء تحسينات الضربات الصعبة بشكل جيد إلى حد ما على نفس البنية التحتية ويمكن القيام بأشياء قليلة جدًا في مُحسِّن المستوى الأعلى.

ما أعنيه هو هذا: إذا تم ضرب وظيفة عدة مرات ، فإن المعلمات على النحو التالي:

  • زيادة عدد التعليمات المضمنة
  • استخدام مخصص تسجيل أكثر "تقدمًا" (أداة تلوين رجعية تشبه LLVM أو أداة تلوين كاملة)
  • القيام بالمزيد من عمليات التحسين ، ربما تخصص بعضها بالمعرفة المحلية. على سبيل المثال: اسمح باستبدال تخصيص الكائن بالكامل في تخصيص المكدس إذا تم التصريح عن الكائن في الطريقة ولم يتم تعيينه في نص دالة مضمنة أكبر.
  • استخدم الموافقة المسبقة عن علم لمعظم الكائنات المصابة حيث لا يكون CHA ممكنًا. حتى StringBuilder على سبيل المثال من المحتمل جدًا ألا يتم تجاوزه ، يمكن إذا تم وضع علامة على الكود في كل مرة يتم فيها ضربه باستخدام StringBuilder ، يمكن وضع جميع الطرق التي يتم استدعاؤها بالداخل بأمان ويتم تعيين type-guard أمام وصول SB.

سيكون من الرائع أيضًا ، ولكن ربما يكون هذا هو حلمي المستيقظ ، أن تقدم خدمات CompilerServices "مترجمًا متقدمًا" ليتم الكشف عنها حتى يمكن الوصول إليها عبر الكود أو البيانات الوصفية ، لذلك يمكن أن تستفيد أماكن مثل الألعاب أو منصات التداول من خلال البدء تجميع في وقت سابق الفئات والطرق التي سيتم "تجميعها بعمق أكثر". هذا ليس NGen ، ولكن إذا كان المترجم غير المتدرج غير ممكن بالضرورة (مرغوب فيه) ، على الأقل ليكون من الممكن استخدام الشفرة المثلى الأثقل للأجزاء الحرجة التي تحتاج إلى هذا الأداء الإضافي. بالطبع ، إذا كان النظام الأساسي لا يقدم التحسينات الثقيلة (دعنا نقول Mono) ، فإن استدعاءات API ستكون في الأساس NO-OP.

لدينا أساس متين لوضع المستويات في المكان الآن بفضل العمل الجاد من noahfalk و @ kouvel وآخرين.

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

هل السلوك الحالي موصوف في مكان ما؟ لقد وجدت هذا فقط ولكن الأمر يتعلق بتفاصيل التنفيذ بدلاً من التصنيف على وجه التحديد.

أعتقد أنه سيكون لدينا نوع من الملخص المتاح قريبًا ، مع بعض البيانات التي جمعناها.

يمكن تمكين التصنيف في 2.1 من خلال تعيين COMPlus_TieredCompilation=1 . إذا جربته ، برجاء الإبلاغ عما تجده ....

باستخدام العلاقات العامة الحديثة (https://github.com/dotnet/coreclr/pull/17840 ، https://github.com/dotnet/sdk/pull/2201) لديك أيضًا القدرة على تحديد التجميع المتدرج باعتباره runtimeconfig. json أو عقار مشروع msbuild. سيتطلب استخدام هذه الوظيفة أن تكون في تصميمات حديثة جدًا بينما كان متغير البيئة موجودًا لفترة من الوقت.

كما ناقشنا من قبل مع jkotas يمكن لـ Tiered JIT تحسين وقت بدء التشغيل. هل تعمل عندما نستخدم الصور الأصلية؟
لقد أجرينا قياسات للعديد من التطبيقات على هاتف Tizen وها هي النتائج:

مكتبات DLL للنظام | مكتبات DLL للتطبيق | Tiered | الوقت ، ثانية
----------- | -------- | ------ | --------
R2R | R2R | لا | 2.68.1
R2R | R2R | نعم | 2.61 (-3٪)
R2R | لا | لا | 4.40
R2R | لا | نعم | 3.63 (-17٪)

سوف نتحقق من وضع FNV أيضًا ، لكن يبدو أنه يعمل بشكل جيد في حالة عدم وجود صور.

CCGBalykov @ nkaretnikov2

لمعلوماتك ، التجميع المتدرج هو الآن الافتراضي لـ .NET Core: https://github.com/dotnet/coreclr/pull/19525

alpencolt ، قد تكون تحسينات وقت بدء التشغيل أقل عند استخدام تجميع AOT مثل R2R. يأتي تحسين وقت بدء التشغيل حاليًا من القفز بسرعة أكبر مع تحسينات أقل ، وعند استخدام تجميع AOT سيكون هناك أقل لـ JIT. بعض الطرق ليست مُنشأة مسبقًا ، مثل بعض الأدوية الجنيسة ، وأوتار IL ، والطرق الديناميكية الأخرى. قد تستفيد بعض الأدوية الجنيسة من التدريج أثناء بدء التشغيل حتى عند استخدام تجميع AOT.

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

kouvel آسف للتعليق على القضية المغلقة. أتساءل عند استخدام تجميع AOT مثل crossgen ، هل سيستفيد التطبيق من تجميع الطبقة الثانية لمسارات رمز النقاط الفعالة؟

@ daxian-dbw نعم كثيرًا جدًا ؛ في وقت التشغيل ، يمكن لـ Jit القيام بالتجميع المتقاطع (بين dlls) ؛ حذف الفرع بناءً على ثوابت وقت التشغيل ( readonly static ) ؛ إلخ

benaadams ولم يستطع مترجم AOT المصمم جيدًا؟

لقد وجدت بعض المعلومات حول هذا في https://blogs.msdn.microsoft.com/dotnet/2018/08/02/tiered-compilation-preview-in-net-core-2-1/ :

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

نعم ، هذا مثال على "ليست AOT مصممة بشكل جيد." 😛

تحتوي الصور المجمعة مسبقًا على قيود الإصدار وقيود تعليمات وحدة المعالجة المركزية التي تحظر بعض أنواع التحسين.

أحد الأمثلة على ذلك هو الأساليب التي تستخدم جوهر الأجهزة. يفترض برنامج التحويل البرمجي AOT (crossgen) أن SSE2 هو هدف الترميز على x86 / x64 ، لذلك سيتم رفض جميع الطرق التي تستخدم جوهر الأجهزة بواسطة crossgen ويتم تجميعها بواسطة JIT التي تعرف معلومات الأجهزة الأساسية.

ولم يستطع مترجم AOT المصمم جيدًا؟

يحتاج مترجم AOT إلى تحسين وقت الارتباط (لتضمين التجميع المتقاطع) والتحسين الموجه بالملف الشخصي (لثوابت وقت التشغيل). وفي الوقت نفسه ، يحتاج مترجم AOT إلى معلومات الأجهزة "النهائية" (مثل -mavx2 في gcc / clang) في وقت الإنشاء لرمز SIMD.

أحد الأمثلة على ذلك هو الأساليب التي تستخدم جوهر الأجهزة. يفترض برنامج التحويل البرمجي AOT (crossgen) أن SSE2 هو هدف الترميز على x86 / x64 ، لذلك سيتم رفض جميع الطرق التي تستخدم جوهر الأجهزة بواسطة crossgen ويتم تجميعها بواسطة JIT التي تعرف معلومات الأجهزة الأساسية.

انتظر ماذا؟ أنا لا أتابع هنا تمامًا. لماذا يرفض مترجم AOT الجوهرات؟

ولم يستطع مترجم AOT المصمم جيدًا؟

يحتاج مترجم AOT إلى تحسين وقت الارتباط (لتضمين التجميع المتقاطع) والتحسين الموجه بالملف الشخصي (لثوابت وقت التشغيل). وفي الوقت نفسه ، يحتاج مترجم AOT إلى معلومات الأجهزة "النهائية" (مثل -mavx2 في gcc / clang) في وقت الإنشاء لرمز SIMD.

نعم ، كما قلت ، "مترجم AOT مصمم جيدًا." 😁

masonwheeler سيناريو مختلف ؛ Crossgen هو AoT الذي يعمل مع Jit ويسمح بخدمة / تصحيح ملفات dll دون الحاجة إلى إعادة ترجمة التطبيق وإعادة التوزيع بالكامل. يقدم كود Gen أفضل من Tier0 مع بدء تشغيل أسرع من Tier1 ؛ لكنها ليست منصة محايدة.

تعمل كل من Tier0 و crossgen و Tier1 معًا كنموذج متماسك في coreclr

للتجميع المتقاطع المضمّن (غير Jit) ، سيتطلب الأمر تجميع ملف واحد قابل للتنفيذ مرتبط بشكل ثابت ويتطلب إعادة ترجمة كاملة وإعادة توزيع للتطبيق لتصحيح أي مكتبة يستخدمها بالإضافة إلى استهداف النظام الأساسي المحدد (ما هو إصدار من SSE و Avx وما إلى ذلك للاستخدام ؛ أقل إصدار مشترك أو إصدار منتج للجميع؟).

corert سيخترق هذا النمط من التطبيق.

ومع ذلك؛ القيام بأنواع معينة من التخلص من الفروع التي يمكن أن يقوم بها Jit تتطلب قدرًا كبيرًا من إنشاء ASM الإضافي للمسارات البديلة ؛ وترقيع وقت تشغيل الشجرة الصحيحة

على سبيل المثال ، أي رمز يستخدم طريقة مثل (حيث ستزيل Tier1 Jit جميع if s)

readonly static _numProcs = Environment.ProcessorCount;

public void DoThing()
{
    if (_numProcs == 1) 
    {
       // Single proc path
    }
    else if (_numProcs == 2) 
    {
       // Two proc path
    }
    else
    {
       // Multi proc path
    }
}

تضمين التغريدة

للتجميع المتقاطع المضمّن (غير Jit) ، سيتطلب الأمر تجميع ملف واحد قابل للتنفيذ مرتبط بشكل ثابت ويتطلب إعادة ترجمة كاملة وإعادة توزيع للتطبيق لتصحيح أي مكتبة يستخدمها بالإضافة إلى استهداف النظام الأساسي المحدد (ما هو إصدار من SSE و Avx وما إلى ذلك للاستخدام ؛ أقل إصدار مشترك أو إصدار منتج للجميع؟).

لا ينبغي أن يتطلب إعادة توزيع كاملة للتطبيق. انظر إلى نظام الترجمة ART الخاص بـ Android: تقوم بتوزيع التطبيق كرمز مُدار (Java في حالتهم ، ولكن نفس المبادئ تنطبق) والمترجم ، الذي يعيش على النظام المحلي ، يقوم AOT بتجميع الكود المُدار في ملف تنفيذي أصلي مُحسَّن للغاية.

إذا قمت بتغيير بعض المكتبات الصغيرة ، فستظل جميع التعليمات البرمجية المدارة موجودة ولن تضطر إلى إعادة توزيع كل شيء ، فقط الشيء الذي يحتوي على التصحيح ، ومن ثم يمكن إعادة تشغيل AOT لإنتاج ملف تنفيذي جديد. (من الواضح أن هذا هو المكان الذي ينهار فيه تشبيه Android ، بسبب نموذج توزيع تطبيقات Android APK ، لكن هذا لا ينطبق على تطوير سطح المكتب / الخادم.)

والمترجم ، الذي يعيش على النظام المحلي ، يجمع AOT الكود المدار ...

هذا هو نموذج NGen السابق الذي استخدمه الإطار الكامل ؛ على الرغم من ألا تعتقد أنه أنشأ تجميعًا واحدًا يتضمن رمز إطار العمل في رمز التطبيقات أيضًا؟ تم تسليط الضوء على الفرق بين طريقتين في Bing.com يعمل على .NET Core 2.1! مشاركة مدونة

صور ReadyToRun

غالبًا ما يكون أداء التطبيقات المُدارة ضعيفًا في بدء التشغيل حيث يجب أولاً تجميع الطرق في JIT إلى رمز الجهاز. NET Framework لديه تقنية تجميع مسبق ، NGEN. ومع ذلك ، يتطلب NGEN حدوث خطوة الترجمة المسبقة على الجهاز الذي سيتم تنفيذ الكود عليه. بالنسبة إلى Bing ، قد يعني ذلك NGENing على آلاف الآلات. سيؤدي هذا إلى جانب دورة نشر قوية إلى تقليل كبير في سعة الخدمة حيث يتم تجميع التطبيق مسبقًا على أجهزة خدمة الويب. علاوة على ذلك ، يتطلب تشغيل NGEN امتيازات إدارية ، والتي غالبًا ما تكون غير متوفرة أو تخضع للتدقيق الشديد في إعداد مركز البيانات. في .NET Core ، تسمح أداة crossgen برمجيًا مسبقًا للشفرة كخطوة ما قبل النشر ، كما هو الحال في معمل الإنشاء ، والصور التي تم نشرها في الإنتاج جاهزة للتشغيل!

masonwheeler يواجه AOT الرياح المعاكسة بالكامل .Net بسبب الطبيعة الديناميكية لعملية .Net. على سبيل المثال ، يمكن تعديل أجسام الطريقة في .Net عبر ملف التعريف في أي وقت ، ويمكن تحميل الفئات أو إنشاؤها عبر الانعكاس ، ويمكن إنشاء رمز جديد في وقت التشغيل حسب الحاجة لأشياء مثل interop - لذلك تعكس معلومات التحليل بين الإجراءات في أفضل الأحوال حالة عابرة عملية التشغيل. يجب إلغاء أي تحليل أو تحسين بين الإجراءات (بما في ذلك التضمين) في .Net في وقت التشغيل.

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

إذا كان بإمكانك بناء آليات للتعامل مع أو تقييد الطبيعة الديناميكية لعمليات .Net ، فيمكن أن تعمل AOT الخالصة بشكل جيد - على سبيل المثال. يأخذ Net Native في الاعتبار تأثير الانعكاس والتداخل ، ويحظر تحميل التجميع ، وانبعاث الانعكاس ، و ( أفترض) إرفاق الملف الشخصي. لكنها ليست بسيطة.

هناك بعض العمل الجاري للسماح لنا بتوسيع نطاق crossgen إلى تجميعات متعددة حتى نتمكن من تجميع AOT جميع الأطر الأساسية (أو جميع تجميعات asp.net) كحزمة. لكن هذا قابل للتطبيق فقط لأننا نمتلك طريقة احتياطية لإعادة البرمجة عندما تتغير الأشياء.

AndyAyersMS لم أصدق مطلقًا أن حل .NET AOT يجب أن يكون حلاً "خالصًا لـ AOT فقط" ، للأسباب التي تصفها هنا بالضبط. من المهم جدًا وجود JIT لإنشاء رمز جديد حسب الحاجة. لكن المواقف التي تحتاج فيها إلى حد كبير في الأقلية ، وبالتالي أعتقد أن قاعدة Anders Hejlsberg لأنظمة الكتابة يمكن تطبيقها بشكل مربح هنا:

ثابت عند الإمكان ، وديناميكي عند الضرورة.

من System.Linq.Expressions
مترجم TDelegate العام (أفضل ترجمة منطقية) ؛

هل التجميع المتدرج يستمر في العمل إذا كان التفسير المفضل صحيحًا؟

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات