ستكون هذه المقالة هي المقالة الثانية في سلسلة تحسين أداء JVM (المقال الأول: البوابة)، وسيكون مترجم Java هو المحتوى الأساسي الذي تمت مناقشته في هذه المقالة.
في هذه المقالة، يقدم المؤلف (Eva Andreasson) أولاً أنواعًا مختلفة من المترجمين ويقارن الأداء الجاري للتجميع من جانب العميل والمترجم من جانب الخادم والترجمة متعددة الطبقات. بعد ذلك، في نهاية المقالة، تم تقديم العديد من طرق تحسين JVM الشائعة، مثل إزالة التعليمات البرمجية الميتة، وتضمين التعليمات البرمجية، وتحسين نص الحلقة.
الميزة الأكثر فخرًا في Java، "استقلال النظام الأساسي"، تأتي من مترجم Java. يبذل مطورو البرامج قصارى جهدهم لكتابة أفضل تطبيقات Java الممكنة، ويعمل المترجم خلف الكواليس لإنتاج تعليمات برمجية فعالة قابلة للتنفيذ استنادًا إلى النظام الأساسي المستهدف. المترجمات المختلفة مناسبة لمتطلبات التطبيقات المختلفة، وبالتالي تنتج نتائج تحسين مختلفة. لذلك، إذا كان بإمكانك فهم كيفية عمل المترجمين بشكل أفضل ومعرفة المزيد من أنواع المترجمين، فيمكنك تحسين برنامج Java الخاص بك بشكل أفضل.
تسلط هذه المقالة الضوء على الاختلافات بين برامج التحويل البرمجي المختلفة لجهاز Java الظاهري وتشرحها. وفي الوقت نفسه، سأناقش أيضًا بعض حلول التحسين التي يشيع استخدامها من قبل المترجمين في الوقت المناسب (JIT).
ما هو المترجم؟
ببساطة، يأخذ المترجم برنامج لغة البرمجة كمدخل وبرنامج لغة آخر قابل للتنفيذ كمخرج. Javac هو المترجم الأكثر شيوعًا. إنه موجود في جميع JDKs. يأخذ Javac كود Java كمخرج ويحوله إلى كود JVM القابل للتنفيذ - bytecode. يتم تخزين هذه الرموز الثانوية في ملفات تنتهي بـ .class ويتم تحميلها في بيئة تشغيل Java عند بدء تشغيل برنامج Java.
لا يمكن قراءة الرمز الثانوي مباشرة بواسطة وحدة المعالجة المركزية، كما يجب ترجمته إلى لغة تعليمات الآلة التي يمكن للنظام الأساسي الحالي فهمها. يوجد مترجم آخر في JVM مسؤول عن ترجمة الكود الثانوي إلى تعليمات قابلة للتنفيذ بواسطة النظام الأساسي المستهدف. تتطلب بعض برامج التحويل البرمجي JVM عدة مستويات من مراحل كود البايت كود. على سبيل المثال، قد يحتاج المترجم إلى المرور بعدة أشكال مختلفة من المراحل المتوسطة قبل ترجمة الكود الثانوي إلى تعليمات الآلة.
من منظور لا يعتمد على النظام الأساسي، نريد أن تكون التعليمات البرمجية الخاصة بنا مستقلة عن النظام الأساسي قدر الإمكان.
ولتحقيق ذلك، فإننا نعمل على المستوى الأخير من الترجمة — بدءًا من أدنى تمثيل للشفرة الثانوية وحتى كود الآلة الحقيقي — الذي يربط فعليًا الكود القابل للتنفيذ ببنية منصة معينة. من أعلى مستوى، يمكننا تقسيم المترجمين إلى مترجمين ثابتين ومترجمين ديناميكيين. يمكننا اختيار المترجم المناسب بناءً على بيئة التنفيذ المستهدفة لدينا، ونتائج التحسين التي نرغب فيها، وقيود الموارد التي نحتاج إلى تلبيتها. في المقالة السابقة ناقشنا بإيجاز المترجمات الثابتة والمترجمات الديناميكية، وفي الأقسام التالية سنشرحها بمزيد من التعمق.
التجميع الثابت مقابل التجميع الديناميكي
يعد javac الذي ذكرناه سابقًا مثالاً على التجميع الثابت. باستخدام المترجم الثابت، يتم تفسير كود الإدخال مرة واحدة، ويكون الإخراج هو الشكل الذي سيتم تنفيذ البرنامج به في المستقبل. ما لم تقم بتحديث الكود المصدري وإعادة الترجمة (من خلال المترجم)، فإن نتيجة تنفيذ البرنامج لن تتغير أبدًا: وذلك لأن الإدخال هو إدخال ثابت والمترجم هو مترجم ثابت.
مع التحويل البرمجي الثابت، البرنامج التالي:
انسخ رمز الكود كما يلي:
staticint add7(int x ){return x+7;}
سيتم تحويله إلى رمز بايت مشابه لما يلي:
انسخ رمز الكود كما يلي:
iload0 bipush 7 iadd ireturn
يقوم المترجم الديناميكي بتجميع لغة واحدة ديناميكيًا إلى لغة أخرى. يشير ما يسمى بالديناميكية إلى التجميع أثناء تشغيل البرنامج - التجميع أثناء التشغيل! تتمثل ميزة التجميع والتحسين الديناميكي في أنه يمكنه التعامل مع بعض التغييرات عند تحميل التطبيق. غالبًا ما يعمل وقت تشغيل Java في بيئات غير متوقعة أو حتى متغيرة، لذا فإن التجميع الديناميكي مناسب جدًا لوقت تشغيل Java. تستخدم معظم JVMs مترجمات ديناميكية، مثل مترجمات JIT. تجدر الإشارة إلى أن التجميع الديناميكي وتحسين التعليمات البرمجية يتطلبان استخدام بعض هياكل البيانات الإضافية والخيوط وموارد وحدة المعالجة المركزية. كلما كان المُحسِّن أو مُحلل سياق الكود الثانوي أكثر تقدمًا، زاد استهلاك الموارد. لكن هذه التكاليف لا تذكر مقارنة بالتحسينات الكبيرة في الأداء.
أنواع JVM واستقلالية النظام الأساسي لـ Java
الميزة المشتركة لجميع تطبيقات JVM هي تجميع الكود الثانوي في تعليمات الجهاز. تقوم بعض أجهزة JVM بتفسير التعليمات البرمجية عند تحميل التطبيق وتستخدم عدادات الأداء للعثور على التعليمات البرمجية "الساخنة"؛ بينما يقوم البعض الآخر بذلك من خلال التحويل البرمجي. المشكلة الرئيسية في التجميع هي أن المركزية تتطلب الكثير من الموارد، ولكنها تؤدي أيضًا إلى تحسين الأداء.
إذا كنت جديدًا على Java، فمن المؤكد أن تعقيدات JVM ستجعلك في حيرة من أمرك. ولكن الخبر السار هو أنك لا تحتاج إلى معرفة ذلك! سيقوم JVM بإدارة تجميع التعليمات البرمجية وتحسينها، ولا داعي للقلق بشأن تعليمات الجهاز وكيفية كتابة التعليمات البرمجية لتتناسب بشكل أفضل مع بنية النظام الأساسي الذي يعمل عليه البرنامج.
من Java bytecode إلى الملف القابل للتنفيذ
بمجرد تجميع كود جافا الخاص بك إلى كود بايت، فإن الخطوة التالية هي ترجمة تعليمات كود البايت إلى كود الجهاز. يمكن تنفيذ هذه الخطوة من خلال مترجم أو من خلال مترجم.
يشرح
التفسير هو أبسط طريقة لتجميع الكود الثانوي. يعثر المترجم على تعليمات الأجهزة المقابلة لكل تعليمات رمز ثانوي في شكل جدول بحث، ثم يرسلها إلى وحدة المعالجة المركزية للتنفيذ.
يمكنك التفكير في المترجم الفوري مثل القاموس: لكل كلمة محددة (تعليمات الكود الثانوي)، هناك ترجمة محددة (تعليمات كود الآلة) المقابلة لها. نظرًا لأن المترجم ينفذ التعليمات فورًا في كل مرة يقرأها فيها، فلا يمكن لهذه الطريقة تحسين مجموعة التعليمات. في الوقت نفسه، في كل مرة يتم فيها استدعاء رمز ثانوي، يجب تفسيره على الفور، لذلك يعمل المترجم ببطء شديد. يقوم المترجم بتنفيذ التعليمات البرمجية بطريقة دقيقة للغاية، ولكن نظرًا لعدم تحسين مجموعة تعليمات الإخراج، فقد لا ينتج نتائج مثالية لمعالج النظام الأساسي المستهدف.
ترجمة
يقوم المترجم بتحميل كافة التعليمات البرمجية ليتم تنفيذها في وقت التشغيل. بهذه الطريقة يمكن أن يشير إلى سياق وقت التشغيل بالكامل أو جزء منه عندما يترجم الرمز الثانوي. تعتمد القرارات التي تتخذها على نتائج تحليل الرسم البياني للكود. مثل مقارنة فروع التنفيذ المختلفة والإشارة إلى بيانات سياق وقت التشغيل.
بعد ترجمة تسلسل الرمز الثانوي إلى مجموعة تعليمات رمز الجهاز، يمكن إجراء التحسين بناءً على مجموعة تعليمات رمز الجهاز هذه. يتم تخزين مجموعة التعليمات المحسنة في بنية تسمى المخزن المؤقت للتعليمات البرمجية. عند تنفيذ هذه الرموز الثانوية مرة أخرى، يمكن الحصول على الكود المحسن مباشرة من المخزن المؤقت للكود هذا وتنفيذه. في بعض الحالات، لا يستخدم المترجم المحسن لتحسين التعليمات البرمجية، ولكنه يستخدم تسلسل تحسين جديد - "حساب الأداء".
ميزة استخدام ذاكرة التخزين المؤقت للتعليمات البرمجية هي أنه يمكن تنفيذ تعليمات مجموعة النتائج على الفور دون الحاجة إلى إعادة التفسير أو التجميع!
يمكن أن يؤدي ذلك إلى تقليل وقت التنفيذ بشكل كبير، خاصة بالنسبة لتطبيقات Java حيث يتم استدعاء الطريقة عدة مرات.
تحسين
مع إدخال الترجمة الديناميكية، لدينا الفرصة لإدراج عدادات الأداء. على سبيل المثال، يقوم المترجم بإدراج عداد أداء يتم زيادته في كل مرة يتم فيها استدعاء كتلة من الكود الثانوي (المقابلة لطريقة معينة). يستخدم المترجم هذه العدادات للعثور على "الكتل الفعالة" حتى يتمكن من تحديد كتل التعليمات البرمجية التي يمكن تحسينها لتحقيق أكبر قدر من تحسين الأداء للتطبيق. يمكن أن تساعد بيانات تحليل أداء وقت التشغيل المترجم على اتخاذ المزيد من قرارات التحسين في حالة الاتصال بالإنترنت، وبالتالي تحسين كفاءة تنفيذ التعليمات البرمجية. نظرًا لأننا نحصل على المزيد والمزيد من بيانات تحليل أداء التعليمات البرمجية الدقيقة، فيمكننا العثور على المزيد من نقاط التحسين واتخاذ قرارات تحسين أفضل، مثل: كيفية تسلسل التعليمات بشكل أفضل، وما إذا كان سيتم استخدام مجموعة تعليمات أكثر كفاءة، و ما إذا كان سيتم القضاء على العمليات الزائدة عن الحاجة، وما إلى ذلك.
على سبيل المثال
خذ بعين الاعتبار كود جافا التالي انسخ الكود الكود كما يلي:
staticint add7(int x ){return x+7;}
سوف يقوم Javac بترجمته بشكل ثابت إلى الكود الثانوي التالي:
انسخ رمز الكود كما يلي:
iload0
بيبوش 7
iadd
com.ireturn
عند استدعاء هذه الطريقة، سيتم تجميع الكود الثانوي ديناميكيًا في تعليمات الجهاز. قد يتم تحسين الطريقة عندما يصل عداد الأداء (إن وجد) إلى حد محدد. قد تبدو النتائج المحسنة مثل مجموعة تعليمات الجهاز التالية:
انسخ رمز الكود كما يلي:
ليا راكس،[rdx+7] ريت
المترجمون المختلفون مناسبون لتطبيقات مختلفة
التطبيقات المختلفة لها احتياجات مختلفة. عادةً ما تحتاج تطبيقات الخادم الخاصة بالمؤسسات إلى التشغيل لفترة طويلة، لذلك تحتاج عادةً إلى المزيد من تحسين الأداء، بينما قد تحتاج التطبيقات الصغيرة من جانب العميل إلى أوقات استجابة أسرع واستهلاك أقل للموارد. دعونا نناقش ثلاثة مترجمين مختلفين وإيجابياتهم وسلبياتهم.
المترجمين من جانب العميل
C1 هو مترجم تحسين معروف. عند بدء تشغيل JVM، أضف المعلمة -client لبدء تشغيل المترجم. من خلال اسمه يمكننا أن نجد أن C1 هو مترجم عميل. إنه مثالي لتطبيقات العميل التي لديها القليل من موارد النظام المتاحة أو التي تتطلب بدء تشغيل سريع. ينفذ C1 تحسين التعليمات البرمجية باستخدام عدادات الأداء. هذه طريقة تحسين بسيطة مع تدخل أقل في الكود المصدري.
المترجمين من جانب الخادم
بالنسبة للتطبيقات طويلة التشغيل (مثل تطبيقات المؤسسات من جانب الخادم)، قد لا يكون استخدام برنامج التحويل البرمجي من جانب العميل كافيًا. في هذا الوقت يجب علينا اختيار مترجم من جانب الخادم مثل C2. يمكن بدء المُحسِّن عن طريق إضافة خادم إلى سطر بدء تشغيل JVM. نظرًا لأن معظم التطبيقات من جانب الخادم عادةً ما تكون طويلة التشغيل، فستتمكن من جمع المزيد من بيانات تحسين الأداء باستخدام برنامج التحويل البرمجي C2 مقارنةً بالتطبيقات من جانب العميل خفيفة الوزن وقصيرة التشغيل. لذلك ستتمكن أيضًا من تطبيق تقنيات وخوارزميات التحسين الأكثر تقدمًا.
نصيحة: قم بتسخين المترجم من جانب الخادم الخاص بك
بالنسبة لعمليات النشر على جانب الخادم، قد يستغرق المترجم بعض الوقت لتحسين هذه الرموز "الساخنة". لذلك غالبًا ما يتطلب النشر من جانب الخادم مرحلة "الإحماء". لذا، عند إجراء قياسات الأداء على عمليات النشر على جانب الخادم، تأكد دائمًا من وصول تطبيقك إلى حالة مستقرة! إن منح المترجم وقتًا كافيًا للتجميع سيجلب العديد من الفوائد لتطبيقك.
يمكن للمترجم من جانب الخادم الحصول على بيانات ضبط الأداء أكثر من المترجم من جانب العميل، حتى يتمكن من إجراء تحليل فرعي أكثر تعقيدًا والعثور على مسارات التحسين بأداء أفضل. كلما زاد عدد بيانات تحليل الأداء لديك، كانت نتائج تحليل التطبيق أفضل. وبطبيعة الحال، يتطلب إجراء تحليل أداء واسع النطاق المزيد من موارد المترجم. على سبيل المثال، إذا كان JVM يستخدم مترجم C2، فسوف يحتاج إلى استخدام المزيد من دورات وحدة المعالجة المركزية، وذاكرة تخزين مؤقت أكبر للتعليمات البرمجية، وما إلى ذلك.
تجميع متعدد المستويات
يمزج التجميع متعدد الطبقات بين التجميع من جانب العميل والتجميع من جانب الخادم. كان Azul أول من قام بتنفيذ تجميع متعدد الطبقات في Zing JVM الخاص به. في الآونة الأخيرة، تم اعتماد هذه التقنية بواسطة Oracle Java Hotspot JVM (بعد Java SE7). يجمع التجميع متعدد المستويات بين مزايا المترجمين من جانب العميل والخادم. يكون برنامج التحويل البرمجي للعميل نشطًا في حالتين: عند بدء تشغيل التطبيق، وعندما تصل عدادات الأداء إلى عتبات المستوى الأدنى لإجراء تحسينات في الأداء. يقوم المترجم العميل أيضًا بإدراج عدادات الأداء وإعداد مجموعة التعليمات لاستخدامها لاحقًا بواسطة المترجم من جانب الخادم من أجل التحسين المتقدم. التجميع متعدد الطبقات هو طريقة لتحليل الأداء مع استخدام عالي للموارد. ونظرًا لأنه يجمع البيانات أثناء نشاط برنامج التحويل البرمجي منخفض التأثير، فيمكن استخدام هذه البيانات لاحقًا في تحسينات أكثر تقدمًا. يوفر هذا الأسلوب معلومات أكثر من تحليل العدادات باستخدام التعليمات البرمجية التفسيرية.
يصف الشكل 1 مقارنة أداء المترجمين الفوريين، والتجميع من جانب العميل، والتجميع من جانب الخادم، والتجميع متعدد الطبقات. المحور X هو وقت التنفيذ (وحدة الوقت)، والمحور Y هو الأداء (عدد العمليات لكل وحدة زمنية)
الشكل 1. مقارنة أداء المترجم
بالنسبة للتعليمات البرمجية المفسرة بشكل بحت، فإن استخدام مترجم من جانب العميل يمكن أن يؤدي إلى تحسين الأداء بحوالي 5 إلى 10 مرات. يعتمد مقدار مكاسب الأداء التي تكتسبها على كفاءة المترجم، وأنواع أدوات التحسين المتاحة، ومدى توافق تصميم التطبيق مع النظام الأساسي المستهدف. ولكن بالنسبة لمطوري البرامج، غالبا ما يمكن تجاهل الأخير.
بالمقارنة مع المترجمين من جانب العميل، يمكن للمترجمين من جانب الخادم في كثير من الأحيان تحقيق تحسينات في الأداء بنسبة 30٪ إلى 50٪. في معظم الحالات، غالبًا ما تأتي تحسينات الأداء على حساب استهلاك الموارد.
يجمع التجميع متعدد المستويات بين مزايا كلا المترجمين. يتميز التجميع من جانب العميل بوقت بدء تشغيل أقصر ويمكن أن يؤدي إلى تحسين سريع؛ ويمكن أن يؤدي التجميع من جانب الخادم إلى عمليات تحسين أكثر تقدمًا أثناء عملية التنفيذ اللاحقة.
بعض التحسينات الشائعة للمترجم
لقد ناقشنا حتى الآن ما يعنيه تحسين التعليمات البرمجية وكيف ومتى يقوم JVM بتحسين التعليمات البرمجية. بعد ذلك، سأنهي هذه المقالة بتقديم بعض طرق التحسين التي يستخدمها المترجمون بالفعل. يحدث تحسين JVM فعليًا في مرحلة الكود الثانوي (أو مرحلة تمثيل اللغة ذات المستوى الأدنى)، ولكن سيتم استخدام لغة Java هنا لتوضيح طرق التحسين هذه. من المستحيل تغطية جميع طرق تحسين JVM في هذا القسم بالطبع، آمل أن تلهمك هذه المقدمات لتعلم المئات من طرق التحسين الأكثر تقدمًا والابتكار في تكنولوجيا المترجمات.
إزالة الكود الميت
إزالة التعليمات البرمجية الميتة، كما يوحي الاسم، هي إزالة التعليمات البرمجية التي لن يتم تنفيذها أبدًا - أي التعليمات البرمجية "الميتة".
إذا وجد المترجم بعض التعليمات الزائدة أثناء التشغيل، فسيقوم بإزالة هذه التعليمات من مجموعة تعليمات التنفيذ. على سبيل المثال، في القائمة 1، لن يتم استخدام أحد المتغيرات أبدًا بعد تعيينه، لذلك يمكن تجاهل بيان التعيين تمامًا أثناء التنفيذ. وفقًا للعملية على مستوى الرمز الثانوي، لا يلزم أبدًا تحميل قيمة المتغير في السجل. عدم الحاجة إلى التحميل يعني استهلاك وقت أقل لوحدة المعالجة المركزية، وبالتالي تسريع تنفيذ التعليمات البرمجية، مما يؤدي في النهاية إلى تطبيق أسرع - إذا تم استدعاء كود التحميل عدة مرات في الثانية، فسيكون تأثير التحسين أكثر وضوحًا.
تستخدم القائمة 1 كود Java لتوضيح مثال لتعيين قيمة لمتغير لن يتم استخدامه أبدًا.
القائمة 1. رمز رمز نسخ الرمز الميت هو كما يلي:
int timeToScaleMyApp(booleanEndendOfResources){
int reArchitect =24;
int patchByClustering =15;
int useZing =2;
إذا (لا نهاية لها من الموارد)
إرجاع reArchitect + useZing;
آخر
عودة استخدام زينج؛
}
خلال مرحلة الكود الثانوي، إذا تم تحميل متغير ولكن لم يتم استخدامه مطلقًا، فيمكن للمترجم اكتشاف وإزالة الكود الميت، كما هو موضح في القائمة 2. إذا لم تقم مطلقًا بإجراء عملية التحميل هذه، فيمكنك توفير وقت وحدة المعالجة المركزية وتحسين سرعة تنفيذ البرنامج.
القائمة 2. كود نسخ الكود الأمثل هو كما يلي:
int timeToScaleMyApp(booleanEndendOfResources){
int reArchitect =24; // تمت إزالة العملية غير الضرورية هنا...
int useZing =2;
إذا (لا نهاية لها من الموارد)
إرجاع reArchitect + useZing;
آخر
عودة استخدام زينج؛
}
يعد التخلص من التكرار طريقة تحسين تعمل على تحسين أداء التطبيق عن طريق إزالة التعليمات المكررة.
تحاول العديد من التحسينات إزالة تعليمات القفز على مستوى تعليمات الجهاز (مثل JMP في بنية x86 التي ستغير تعليمات الانتقال سجل مؤشر التعليمات، وبالتالي تحويل تدفق تنفيذ البرنامج). تعتبر تعليمات الانتقال السريع هذه أمرًا يستهلك الكثير من الموارد مقارنةً بتعليمات التجميع الأخرى. ولهذا السبب نريد تقليل هذا النوع من التعليمات أو إزالته. يعد تضمين التعليمات البرمجية طريقة تحسين عملية ومعروفة للغاية لإزالة تعليمات النقل. نظرًا لأن تنفيذ تعليمات الانتقال أمر مكلف، فإن تضمين بعض الأساليب الصغيرة التي يُطلق عليها كثيرًا في نص الوظيفة سيجلب العديد من الفوائد. توضح القائمة 3-5 فوائد التضمين.
القائمة 3. رمز نسخ طريقة الاتصال الرمز هو كما يلي:
int WhenToEvaluateZing(int y){ returndaysLeft(y)+daysLeft(0)+daysLeft(y+1);}
القائمة 4. رمز كود نسخ الطريقة يسمى كما يلي:
int dayLeft(int x){ if(x ==0) return0;
القائمة 5. كود نسخ الطريقة المضمنة هو كما يلي:
int متىToEvaluateZing(int y){
درجة الحرارة المؤقتة = 0؛
إذا (ص==0)
درجة الحرارة +=0;
آخر
درجة الحرارة += ص -1؛
إذا (0==0)
درجة الحرارة +=0;
آخر
درجة الحرارة +=0-1؛
إذا (ص+1==0)
درجة الحرارة +=0;
آخر
درجة الحرارة +=(ص +1)-1;
درجة حرارة العودة؛
}
في القائمة 3-5 يمكننا أن نرى أن طريقة صغيرة يتم استدعاؤها ثلاث مرات في نص طريقة آخر، وما نريد توضيحه هو: تكلفة تضمين الطريقة المستدعى مباشرة في الكود ستكون أقل من تنفيذ ثلاث قفزات. تعليمات النقل.
إن تضمين طريقة لا يتم استدعاؤها غالبًا قد لا يحدث فرقًا كبيرًا، ولكن تضمين ما يسمى بالطريقة "الساخنة" (وهي الطريقة التي يتم استدعاؤها غالبًا) يمكن أن يؤدي إلى الكثير من تحسينات الأداء. غالبًا ما يمكن تحسين الكود المضمن بشكل أكبر، كما هو موضح في القائمة 6.
القائمة 6. بعد تضمين الكود، يمكن تحقيق المزيد من التحسين عن طريق نسخ الكود على النحو التالي:
int WhenToEvaluateZing(int y){ if(y ==0)return y; elseif(y ==-1)return y -1; elsereturn y + y -1;}
تحسين الحلقة
يلعب تحسين الحلقة دورًا مهمًا في تقليل التكلفة الإضافية لتنفيذ جسم الحلقة. تشير التكلفة الإضافية هنا إلى القفزات الباهظة الثمن، والكثير من عمليات التحقق من الحالة، وخطوط الأنابيب غير المحسنة (أي سلسلة من مجموعات التعليمات التي لا تقوم بعمليات فعلية وتستهلك دورات وحدة المعالجة المركزية الإضافية). هناك العديد من أنواع تحسينات الحلقة فيما يلي بعض تحسينات الحلقة الأكثر شيوعًا:
دمج جسم الحلقة: عندما يقوم جسمان متجاوران بتنفيذ نفس العدد من الحلقات، سيحاول المترجم دمج جسمي الحلقة. إذا كان جسمان حلقيان مستقلين تمامًا عن بعضهما البعض، فمن الممكن أيضًا تنفيذهما في وقت واحد (بالتوازي).
حلقة الانعكاس: في أبسط صورها، يمكنك استبدال حلقة while بحلقة do-while. يتم وضع حلقة do-while هذه داخل عبارة if. سيؤدي هذا الاستبدال إلى تقليل عمليتين للقفز، ولكنه سيزيد من الحكم الشرطي، وبالتالي يزيد من كمية التعليمات البرمجية. يعد هذا النوع من التحسين مثالًا رائعًا على تداول المزيد من الموارد للحصول على تعليمات برمجية أكثر كفاءة - حيث يزن المترجم التكاليف والفوائد ويتخذ القرارات ديناميكيًا في وقت التشغيل.
إعادة تنظيم نص الحلقة: قم بإعادة تنظيم نص الحلقة بحيث يمكن تخزين نص الحلقة بالكامل في ذاكرة التخزين المؤقت.
قم بتوسيع نص الحلقة: قم بتقليل عدد عمليات التحقق من حالة الحلقة والقفزات. يمكنك التفكير في هذا على أنه تنفيذ عدة تكرارات "مضمنة" دون الحاجة إلى إجراء فحص شرطي. يؤدي فتح جسم الحلقة أيضًا إلى بعض المخاطر، لأنه قد يقلل من الأداء من خلال التأثير على خط الأنابيب وعدد كبير من عمليات جلب التعليمات المتكررة. مرة أخرى، الأمر متروك للمترجم ليقرر ما إذا كان سيتم فتح نص الحلقة في وقت التشغيل، ومن المفيد أن يؤدي ذلك إلى تحسين أكبر في الأداء.
ما ورد أعلاه هو نظرة عامة على كيفية قيام المترجمين على مستوى الكود الثانوي (أو المستوى الأدنى) بتحسين أداء التطبيقات على النظام الأساسي المستهدف. ما ناقشناه هو بعض طرق التحسين الشائعة والشائعة. ونظرا لضيق المساحة، فإننا نعطي فقط بعض الأمثلة البسيطة. هدفنا هو إثارة اهتمامك بالدراسة المتعمقة للتحسين من خلال المناقشة البسيطة المذكورة أعلاه.
الخلاصة: نقاط التأمل والنقاط الرئيسية
اختر مترجمين مختلفين وفقًا لأغراض مختلفة.
1. المترجم الفوري هو أبسط شكل من أشكال ترجمة الكود الثانوي إلى تعليمات الآلة. يعتمد تنفيذه على جدول بحث التعليمات.
2. يمكن للمترجم التحسين بناءً على عدادات الأداء، ولكنه يتطلب استهلاك بعض الموارد الإضافية (ذاكرة التخزين المؤقت للتعليمات البرمجية، وسلسلة التحسين، وما إلى ذلك).
3. يمكن لمترجم العميل تحسين الأداء بمقدار 5 إلى 10 مرات مقارنة بالمترجم الفوري.
4. يمكن للمترجم من جانب الخادم أن يحقق تحسينًا في الأداء بنسبة 30% إلى 50% مقارنةً بالمترجم من جانب العميل، ولكنه يتطلب المزيد من الموارد.
5. تجميع متعدد الطبقات يجمع بين مزايا كليهما. استخدم التحويل البرمجي من جانب العميل للحصول على أوقات استجابة أسرع، ثم استخدم المحول البرمجي من جانب الخادم لتحسين التعليمات البرمجية التي يتم الاتصال بها بشكل متكرر.
هناك العديد من الطرق الممكنة لتحسين الكود هنا. إحدى المهام المهمة للمترجم هي تحليل جميع طرق التحسين الممكنة، ثم موازنة تكاليف طرق التحسين المختلفة مقابل تحسين الأداء الناتج عن تعليمات الجهاز النهائية.