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

Lilli Thompson
Lilli Thompson

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

لورد كلفن

لتشغيل ألعاب HTML5 بشكل أسرع، عليك أولاً تحديد المؤثِّرات السلبية في الأداء، ولكن قد يكون ذلك صعبًا. يُعد تقييم بيانات اللقطات في الثانية بداية، ولكن لرؤية الصورة الكاملة، عليك إدراك الفروق الطفيفة في أنشطة Chrome.

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

مرحبا حول:التتبع

تمنحك أداة حول:التتبع في Chrome نافذة على جميع أنشطة Chrome خلال فترة زمنية محددة بدرجة كبيرة قد تكون مربكة في البداية. تم إعداد العديد من الدوال في Chrome للتتبع خارج الصندوق، لذلك بدون إجراء أي أدوات يدوية، يظل بإمكانك استخدام حول: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");

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

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

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

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

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

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

عمليات تتبع وحدة معالجة الرسومات ووحدة المعالجة المركزية (CPU)

يمكنك ملاحظة أنّ كل لقطة من لعبتك تتسبب في عمل وحدة المعالجة المركزية (CPU) في CrRendererMain وكذلك في وحدة معالجة الرسومات. يوضِّح التتبُّع أعلاه حالة استخدام بسيطة للغاية، حيث تكون كلّ من وحدة المعالجة المركزية (CPU) ووحدة معالجة الرسومات غير نشِطة لمدة معظم كل إطار تبلغ مدته 16 ملي ثانية.

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

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

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

سيظهر لك الآن أثر يشبه كما يلي:

عمليات تتبع وحدة معالجة الرسومات ووحدة المعالجة المركزية (CPU)

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

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

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

#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);
  }
}

كيف يبدو تتبُّع الرمز باستخدام أداة التظليل هذه؟

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

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

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

أمثلة حقيقية

الآن دعنا نتحقق من شكل بيانات التتبع من لعبة حقيقية. أحد الأشياء الرائعة حول الألعاب التي يتم إنشاؤها باستخدام تقنيات الويب المفتوحة هو أنه يمكنك معرفة ما يجري في منتجاتك المفضلة. إذا كنت ترغب في اختبار أدوات التوصيف، يمكنك اختيار عنوانك المفضل لـ WebGL من سوق Chrome الإلكتروني وتكوين ملف شخصي باستخدام about:tracing. هذا مثال على التتبع المأخوذ من لعبة WebGL Skid Racer الممتازة.

تتبُّع مباراة حقيقية
ممارسة لعبة حقيقية

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

الخاتمة

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

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

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

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