إنشاء ملف تعريفي للعبة WebGL باستخدام علامة about:تتبّع

Lilli Thompson
Lilli Thompson

إذا لم تتمكّن من قياسه، لن تتمكّن من تحسينه.

Lord Kelvin

لتشغيل ألعاب HTML5 بشكل أسرع، عليك أولاً تحديد نقاط الاختناق في الأداء، ولكن قد يكون ذلك صعبًا. يُعدّ تقييم بيانات عدد اللقطات في الثانية (FPS) بداية جيدة، ولكن لمعرفة الصورة الكاملة، عليك فهم الفروق الدقيقة في أنشطة Chrome.

توفّر أداة about:tracing الإحصاءات التي تساعدك في تجنُّب الحلول المؤقتة المتسرّعة التي تهدف إلى تحسين الأداء، ولكنها في الأساس تخمينات حسنة النية. سيساعدك ذلك في توفير الكثير من الوقت والجهد، والحصول على صورة أوضح لما يفعله Chrome مع كل لقطة، واستخدام هذه المعلومات لتحسين لعبتك.

مرحبًا about:tracing

تمنحك أداة about:tracing في Chrome نظرة على جميع أنشطة Chrome على مدار فترة زمنية معيّنة بدقة عالية قد تبدو لك مربكة في البداية. تمّت تجهيز العديد من الدوالّ في Chrome لتتبُّع الأداء تلقائيًا، لذا يمكنك استخدام about:tracing لتتبُّع أدائك بدون إجراء أيّ عملية تجهيز يدوية. (اطّلِع على قسم لاحق حول قياس أداء JavaScript يدويًا).

للاطّلاع على عرض التتبّع، ما عليك سوى كتابة about:tracing في مربّع Chrome المتعدّد الاستخدامات (شريط العناوين).

مربّع Chrome المتعدّد الاستخدامات
اكتب about:tracing في مربّع Chrome المتعدّد الاستخدامات
.

من أداة التتبّع، يمكنك بدء التسجيل وتشغيل لعبتك لبضع ثوانٍ، ثم عرض بيانات التتبّع. في ما يلي مثال على الشكل الذي قد تظهر به البيانات:

نتيجة تتبُّع بسيطة
نتيجة التتبّع البسيطة

نعم، هذا أمر مربك. لنتحدّث عن كيفية قراءته.

يمثّل كل صف عملية يتم تحليلها، ويشير المحور من اليمين إلى اليسار إلى الوقت، وكل مربّع ملون هو عبارة عن طلب دالة تم قياس أدائه. تتوفّر صفوف لعدد من الأنواع المختلفة من الموارد. إنّ أكثر الوظائف التي تهمّك في تحليل أداء الألعاب هي CrGpuMain التي تعرض ما تفعله وحدة معالجة الرسومات (GPU) وCrRendererMain. يحتوي كلّ تتبع على أسطر CrRendererMain لكلّ علامة تبويب مفتوحة خلال فترة التتبّع (بما في ذلك علامة التبويب about:tracing نفسها).

عند قراءة بيانات التتبّع، تكون مهمتك الأولى هي تحديد صف CrRendererMain الذي يتوافق مع لعبتك.

نتيجة تتبُّع بسيطة مميّزة
نتيجة التتبّع البسيطة مميّزة

في هذا المثال، المرشحان هما: 2216 و6516. لا تتوفّر حاليًا طريقة مُحسَّنة لاختيار تطبيقك إلا البحث عن السطر الذي يُجري الكثير من التعديلات الدورية (أو إذا كنت قد زوّدت الرمز يدويًا بنقاط تتبُّع، ابحث عن السطر الذي يحتوي على بيانات التتبُّع). في هذا المثال، يبدو أنّ 6516 يشغّل حلقة رئيسية من تكرار التعديلات. إذا أغلقت جميع علامات التبويب الأخرى قبل بدء التتبُّع، سيكون من الأسهل العثور على CrRendererMain الصحيح. ولكن قد تظل هناك صفوف CrRendererMain لعمليات أخرى غير لعبتك.

العثور على الإطار

بعد تحديد الصف الصحيح في أداة التتبّع للعبة، تكون الخطوة التالية هي العثور على الحلقة الرئيسية. تبدو حلقة التكرار الرئيسية مثل نمط متكرر في بيانات التتبّع. يمكنك التنقّل في بيانات التتبُّع باستخدام مفاتيح W وA وS وD: A وD للانتقال لليسار أو لليمين (للخلف والأمام في الوقت) وW وS للتكبير والتصغير في البيانات. من المفترض أن تكون حلقة الألعاب الرئيسية عبارة عن نمط يتكرر كل 16 ملي ثانية إذا كانت اللعبة تعمل بمعدّل 60 هرتز.

يبدو أنّه تم تنفيذ ثلاثة إطارات.
يبدو أنّه ثلاثة إطارات تنفيذ

بعد تحديد مدة عرض اللقطة في لعبتك، يمكنك الاطّلاع على ما تفعله التعليمات البرمجية في كل لقطة. استخدِم W وA وS وD للتكبير إلى أن تتمكّن من قراءة النص في مربّعات الدوال.

نظرة تفصيلية على إطار التنفيذ
الاطّلاع على تفاصيل إطار التنفيذ

تعرض هذه المجموعة من المربّعات سلسلة من طلبات الدالة، ويتم تمثيل كل طلب بمربّع ملون. تم استدعاء كل وظيفة من خلال المربّع أعلاها، لذا في هذه الحالة، يمكنك الاطّلاع على أنّ MessageLoop::RunTask استدعى RenderWidget::OnSwapBuffersComplete، الذي استدعى بدوره RenderWidget::DoDeferredUpdate، وما إلى ذلك. من خلال قراءة هذه البيانات، يمكنك الحصول على عرض كامل لما تم استدعاؤه ومدة كل تنفيذ.

ولكن إليك بعض التفاصيل. المعلومات التي يعرضها about:tracing هي طلبات الدالة الأوّلية من رمز مصدر Chrome. يمكنك إجراء تخمينات مدروسة حول ما تفعله كل دالة من خلال الاسم، ولكن المعلومات ليست سهلة الاستخدام تمامًا. من المفيد الاطّلاع على المسار العام للإطار، ولكنك تحتاج إلى تنسيق يسهل فهمه لمعرفة ما يحدث.

إضافة علامات التتبّع

لحسن الحظ، تتوفّر طريقة سهلة لإضافة أدوات قياس يدوية إلى الرمز البرمجي لإنشاء بيانات التتبّع: console.time وconsole.timeEnd.

console.time("update");
update
();
console
.timeEnd("update");
console
.time("render");
update
();
console
.timeEnd("render");

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

العلامات المُضافة يدويًا
العلامات المُضافة يدويًا

باستخدام هذا الإجراء، يمكنك إنشاء بيانات تتبُّع يفهمها الإنسان لتتبُّع النقاط الساخنة في الرمز البرمجي.

وحدة معالجة الرسومات أم وحدة المعالجة المركزية؟

عند استخدام الرسومات المُسرَّعة بالأجهزة، من أهم الأسئلة التي يمكنك طرحها أثناء تحليل الأداء هو: هل هذا الرمز مرتبط بوحدة معالجة الرسومات أم بوحدة المعالجة المركزية؟ مع كل لقطة، ستُجري بعض عمليات المعالجة على وحدة معالجة الرسومات وبعض العمليات المنطقية على وحدة المعالجة المركزية. لفهم ما يجعل لعبتك بطيئة، عليك معرفة كيفية توزيع العمل على الموردَين.

أولاً، ابحث عن السطر في عرض التتبُّع المُسمى CrGPUMain، والذي يشير إلى ما إذا كانت وحدة معالجة الرسومات مشغولة في وقت معيّن.

عمليات تتبُّع وحدة معالجة الرسومات ووحدة المعالجة المركزية

يمكنك ملاحظة أنّ كل لقطة من لعبتك تؤدي إلى تشغيل وحدة المعالجة المركزية في CrRendererMain بالإضافة إلى وحدة معالجة الرسومات. يعرض التتبّع أعلاه حالة استخدام بسيطة جدًا تكون فيها كلّ من وحدة المعالجة المركزية ووحدة معالجة الرسومات في وضع السكون لمعظم كلّ لقطة مدتها 16 ملي ثانية.

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

console.time("update");
doExtraWork
();
update
(Math.min(50, now - time));
console
.timeEnd("update");

console
.time("render");
render
();
console
.timeEnd("render");

سيظهر لك الآن تتبع بالشكل التالي:

عمليات تتبُّع وحدة معالجة الرسومات ووحدة المعالجة المركزية

ماذا يخبرنا هذا التتبّع؟ يمكننا ملاحظة أنّ اللقطة المعروضة تتراوح بين 2270 ملي ثانية و2320 ملي ثانية تقريبًا، ما يعني أنّ كل لقطة تستغرق 50 ملي ثانية تقريبًا (معدّل لقطات يبلغ 20 هرتز). يمكنك رؤية أجزاء من مربّعات ملونة تمثّل وظيفة المعالجة بجانب مربّع التعديل، ولكنّ الإطار يهيمن عليه التعديل نفسه بالكامل.

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

ماذا لو كان رمز برنامج تشويش الألوان بطيئًا ووحدة معالجة الرسومات مشغولة جدًا؟ ماذا لو أزلنا العمل غير الضروري من وحدة المعالجة المركزية وأضفنا بدلاً من ذلك بعض الأعمال في رمز برنامج Shader للشرائح؟ في ما يلي برنامج تشويش مكلف بشكل غير ضروري:

#ifdef GL_ES
precision highp
float;
#endif
void main(void) {
 
for(int i=0; i<9999; i++) {
    gl_FragColor
= vec4(1.0, 0, 0, 1.0);
 
}
}

كيف يبدو تتبع الرمز الذي يستخدم هذا المخطِّط اللوني؟

عمليات تتبُّع وحدة معالجة الرسومات ووحدة المعالجة المركزية عند استخدام رمز برمجي بطيء لوحدة معالجة الرسومات
تتبُّع وحدة معالجة الرسومات ووحدة المعالجة المركزية عند استخدام رمز وحدة معالجة الرسومات البطيء

يُرجى ملاحظة مدة الإطار مرة أخرى. في هذا المثال، يتراوح النمط المتكرر بين 2750 و2950 ملي ثانية، أي مدة 200 ملي ثانية (معدل عرض اللقطات 5 هرتز تقريبًا). يكون سطر CrRendererMain فارغًا بالكامل تقريبًا، ما يعني أنّ وحدة المعالجة المركزية تكون في وضع السكون معظم الوقت، بينما تكون وحدة معالجة الرسومات مشغولة بشكل زائد. هذه علامة أكيدة على أنّ تأثيرات التظليل ثقيلة جدًا.

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

أمثلة حقيقية

لنلقِ نظرة الآن على شكل بيانات التتبّع من لعبة حقيقية. من الميزات الرائعة للألعاب المُنشأة باستخدام تكنولوجيات الويب المفتوحة أنّها تتيح لك الاطّلاع على آخر الأخبار حول منتجاتك المفضّلة. إذا أردت اختبار أدوات التحليل، يمكنك اختيار عنوان WebGL المفضّل لديك من "سوق Chrome الإلكتروني" وتحليله باستخدام about:tracing. في ما يلي مثال على عملية تتبُّع مأخوذة من لعبة Skid Racer الرائعة التي تعمل على WebGL.

تتبُّع لعبة حقيقية
تتبُّع لعبة حقيقية

يبدو أنّ كل لقطة تستغرق 20 ملي ثانية تقريبًا، ما يعني أنّ عدد اللقطات في الثانية يبلغ 50 لقطة تقريبًا. يمكنك ملاحظة أنّ العمل متوازن بين وحدة المعالجة المركزية ووحدة معالجة الرسومات، ولكن وحدة معالجة الرسومات هي المورد الأكثر طلبًا. إذا أردت الاطّلاع على أمثلة حقيقية لتحليل أداء ألعاب WebGL، جرِّب بعض عناوين "سوق Chrome الإلكتروني" التي تم إنشاؤها باستخدام WebGL، بما في ذلك:

الخاتمة

إذا كنت تريد تشغيل لعبتك بمعدّل 60 هرتز، يجب أن تتوافق جميع عملياتك مع مدة 16 ملي ثانية لوحدة المعالجة المركزية و16 ملي ثانية لوحدة معالجة الرسومات لكل لقطة. لديك موردان يمكن استخدامهما بشكل موازٍ، ويمكنك نقل العمل بينهما لتحقيق أفضل أداء. about:tracing عرض Chrome هو أداة قيّمة للحصول على إحصاءات حول ما يفعله الرمز البرمجي في الواقع، وسيساعدك في زيادة وقت التطوير إلى أقصى حد من خلال معالجة المشاكل المناسبة.

ما هي الخطوات التالية؟

بالإضافة إلى وحدة معالجة الرسومات، يمكنك أيضًا تتبُّع أجزاء أخرى من وقت تشغيل Chrome. تم تجهيز Chrome Canary، وهو إصدار Chrome في المرحلة المبكرة، لتتبُّع عمليات I/O وIndexedDB والعديد من الأنشطة الأخرى. عليك قراءة هذه المقالة حول Chromium لفهم الحالة الحالية لأحداث التتبّع بشكلٍ أعمق.

إذا كنت من مطوّري ألعاب الويب، يُرجى مشاهدة الفيديو أدناه. يعرض هذا الفيديو عرضًا تقديميًا من فريق "مناصرة مطوّري الألعاب" في Google في مؤتمر GDC لعام 2012 حول تحسين أداء ألعاب Chrome: