فهم تتبُّع النظام

‫systrace هي الأداة الأساسية لتحليل أداء أجهزة Android. ومع ذلك، فإنّه في الواقع عبارة عن حزمة أدوات أخرى. وهو عبارة عن أداة تغليف من جانب المضيف حول atrace، وهي أداة تنفيذية من جانب الجهاز تتحكّم في تتبُّع مساحة المستخدم وإعداد ftrace، وآلية التتبُّع الأساسية في ملف معالجة Linux. يستخدم systrace أداة atrace لتفعيل التتبُّع، ثم يقرأ مخزن مؤقت ftrace ويجمعه في أداة عرض HTML مكتفية ذاتيًا. (على الرغم من أنّ الإصدارات الأحدث من نواة Linux تتيح استخدام "فلتر الحِزم المحسَّن من Berkeley" (eBPF)، فإنّ المستندات التالية تتعلّق بالإصدار 3.18 من نواة Linux (بدون eBPF) لأنّه هو الإصدار المستخدَم في هواتف Pixel/Pixel XL).

تعود ملكية أداة systrace لفِرق Google Android وGoogle Chrome، وهي مفتوحة المصدر كجزء من مشروع Catapult. بالإضافة إلى systrace، يتضمّن Catapult أدوات مفيدة أخرى. على سبيل المثال، يحتوي ملف تعريف الأداء ftrace على ميزات أكثر من تلك التي يمكن تفعيلها مباشرةً من خلال systrace أو atrace، ويحتوي على بعض الوظائف المتقدّمة التي تُعدّ ضرورية لتصحيح أخطاء الأداء. (تتطلّب هذه الميزات إذن الوصول إلى الجذر وغالبًا نواة جديدة).

تشغيل systrace

عند تصحيح أخطاء الارتعاش على هواتف Pixel/Pixel XL، ابدأ باستخدام العبارة التالية:

./systrace.py sched freq idle am wm gfx view sync binder_driver irq workq input -b 96000

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

عند مراجعة systrace، تذكَّر أنّ كل حدث يبدأ بأمر من وحدة المعالجة المركزية.

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

مثال: إطار عمل

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

بالنسبة إلى عبء العمل المتسق والمتكرّر، مثل TouchLatency، يحتوي مسار معالجة واجهة المستخدم على ما يلي:

  1. يوقِّع EventThread في SurfaceFlinger سلسلة مهام واجهة مستخدم التطبيق، ما يشير إلى أنّه حان وقت عرض إطار جديد.
  2. يعرض التطبيق إطارًا في سلسلة مهام واجهة المستخدم وRenderThread وhwuiTasks، باستخدام موارد وحدة المعالجة المركزية ووحدة معالجة الرسومات. هذه هي معظم السعة المستخدَمة في واجهة المستخدم.
  3. يُرسِل التطبيق الإطار المعروض إلى SurfaceFlinger باستخدام أداة ربط، ثم ينتقل SurfaceFlinger إلى وضع السكون.
  4. يوقِّظ EventThread الثاني في SurfaceFlinger عملية SurfaceFlinger لبدء عملية التركيب وعرض الإخراج. إذا رصد SurfaceFlinger أنّه ما مِن عمل يجب إكماله، يعود إلى وضع السكون.
  5. يعالج SurfaceFlinger عملية التركيب باستخدام أداة Hardware Composer (HWC)/Hardware Composer 2 (HWC2) أو GL. إنّ تركيبة HWC/HWC2 أسرع وتستهلك طاقة أقل، ولكنّها تتضمّن قيودًا تعتمد على النظام على الرقاقة (SoC). تستغرق هذه العملية عادةً من 4 إلى 6 ملي ثانية تقريبًا، ولكن يمكن أن تتداخل مع الخطوة 2 لأنّ تطبيقات Android تستخدم دائمًا ميزة "التخزين المؤقت الثلاثي". (على الرغم من أنّ التطبيقات تستخدم دائمًا وضع التخزين المؤقت الثلاثي، قد يكون هناك إطار واحد فقط في انتظار المعالجة في SurfaceFlinger، ما يجعله يبدو متطابقًا مع وضع التخزين المؤقت المزدوج).
  6. يُرسِل SurfaceFlinger الإخراج النهائي للعرض باستخدام برنامج تشغيل موفِّر ويعود إلى وضع السكون في انتظار تنشيط EventThread.

لنطّلِع على اللقطة بدءًا من 15409 ملي ثانية:

مسار واجهة المستخدم العادي مع تشغيل EventThread
الشكل 1. مسار واجهة المستخدم العادي، EventThread قيد التشغيل

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

  • الرمادي النوم
  • الأزرق: قابل للتنفيذ (يمكن تنفيذه، ولكن لم يختَره جدول التشغيل بعد)
  • الأخضر: قيد التشغيل (يعتقد المخطِّط أنّه قيد التشغيل).
  • الأحمر: وضع السكون غير القابل للمقاطعة (يكون عادةً في وضع السكون على قفل في النواة). يمكن أن يشير ذلك إلى حمولة الإدخال/الإخراج. مفيدة للغاية لتصحيح أخطاء الأداء
  • البرتقالي: وضع السكون غير القابل للانقطاع بسبب حمولة الإدخال/الإخراج

للاطّلاع على سبب وضع "الاستراحة غير القابلة للمقاطعة" (متاح من نقطة التتبّع sched_blocked_reason)، اختَر شريحة "الاستراحة غير القابلة للمقاطعة" الحمراء.

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

سلسلة واجهة المستخدم لـ TouchLatency
الشكل 2. سلسلة واجهة المستخدم لـ TouchLatency

يوضِّح الشكل 2 أنّ سلسلة مهام واجهة المستخدم TouchLatency تم تنشيطها بواسطة رقم تعريف العملية 6843، والذي يتوافق مع EventThread. يوقّع مؤشر تسلسل واجهة المستخدم ويعرض لقطة ويضيفها إلى "قائمة الانتظار" لاستهلاكها من خلال SurfaceFlinger.

سلسلة واجهة المستخدم تستيقظ وتُعرِض إطارًا وتضيفه إلى قائمة الانتظار ليستخدمه SurfaceFlinger
الشكل 3. يتم تنشيط سلسلة واجهة المستخدم وعرض لقطة ووضعها في قائمة الانتظار ليستخدمها SurfaceFlinger

إذا كانت علامة binder_driver مفعّلة في أحد عمليات التتبّع، يمكنك اختيار معاملة binder لعرض معلومات عن جميع العمليات المضمّنة في تلك المعاملة.

الشكل 4. معاملة وحدات تنظيم السحابة الإلكترونية

يوضِّح الشكل 4 أنّه بعد مرور 15,423.65 ملي ثانية، يصبح الرمز البرمجي Binder:6832_1 في SurfaceFlinger قابلاً للتنفيذ بسبب رقم تعريف العملية 9579، وهو RenderThread في TouchLatency. يمكنك أيضًا الاطّلاع على queueBuffer على جانبَي معاملة الربط.

أثناء استخدام queueBuffer من جانب SurfaceFlinger، يتراوح عدد اللقطات التي لم تكتمل من TouchLatency بين 1 و2.

تتراوح قيمة "الإطارات في انتظار المراجعة" بين 1 و2.
الشكل 5. تتراوح قيمة الإطارات في انتظار المراجعة بين 1 و2.

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

بعد ذلك بوقت قصير، يتم تنشيط سلسلة التعليمات الرئيسية في SurfaceFlinger بواسطة سلسلة EventThread ثانية كي تتمكّن من عرض الإطار الأقدم في انتظار المعالجة على الشاشة:

يتم تنشيط سلسلة التعليمات الرئيسية في SurfaceFlinger بواسطة سلسلة تعليمات EventThread ثانية.
الشكل 6. يتم تنشيط سلسلة التعليمات الرئيسية في SurfaceFlinger من خلال سلسلتَي تعليمات ثانية EventThread

يُقفِل SurfaceFlinger أولاً المخزن المؤقت الأقدم في انتظار المعالجة، ما يؤدي إلى تناقص عدد المخازن المؤقتة في انتظار المعالجة من اثنين إلى واحد.

يرتبط SurfaceFlinger أولاً بالمخزن المؤقت الأقدم في انتظار المعالجة.
الشكل 7. يرتبط SurfaceFlinger أولاً بالذاكرة المؤقتة الأقدم التي لم تتم معالجتها

بعد قفل المخزن المؤقت، يُعدّ SurfaceFlinger التركيب ويرسل الإطار النهائي إلى الشاشة. (يتم تفعيل بعض هذه الأقسام كجزء من نقطة التتبّع mdss، لذا قد لا يتم تضمينها في شريحة المعالجة المركزية).

يُعدّ SurfaceFlinger التركيب ويُرسِل الإطار النهائي.
الشكل 8. يُعدّ SurfaceFlinger التركيب ويرسل الإطار النهائي

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

mdss_fb0 يوقظ وحدة المعالجة المركزية 0
الشكل 9: mdss_fb0 يوقِّع وحدة المعالجة المركزية 0

mdss_fb0 يستيقظ، ويعمل لفترة وجيزة، ويدخل في وضع السكون غير القابل للمقاطعة، ثم يستيقظ مرة أخرى.

مثال: إطار لا يعمل

يوضّح هذا المثال تتبع نظام التشغيل الذي تم استخدامه لتصحيح أخطاء الارتعاش في هاتف Pixel/Pixel XL. للتوغّل في المثال، يمكنك تنزيل ملف systrace_tutorial.html المضغوط الذي يتضمّن عمليات التتبّع الأخرى المُشار إليها في هذا القسم، وفك ضغط الملف، وفتح ملف systrace_tutorial.html في متصفحك.

عند فتح systrace، سيظهر لك ما يلي:

تطبيق TouchLatency قيد التشغيل على هاتف Pixel XL مع تفعيل معظم الخيارات
الشكل 10. تطبيق TouchLatency قيد التشغيل على هاتف Pixel XL (معظم الخيارات مفعَّلة، بما في ذلك نقاط تتبُّع mdss وkgsl)

عند البحث عن الارتباك، تحقّق من صف FrameMissed ضمن SurfaceFlinger. FrameMissed هو تحسين في جودة الحياة يوفّره HWC2. عند عرض systrace للأجهزة الأخرى، قد لا يظهر صف FrameMissed إذا كان الجهاز لا يستخدم HWC2. في أيٍّ من الحالتَين، يرتبط حدث FrameMissed بخطأ SurfaceFlinger في أحد مُدد التشغيل المنتظمة للغاية وعدد معدّل تغييرات مخزن الانتظار للتطبيق (com.prefabulated.touchlatency) في وقت vsync.

الارتباط بين FrameMissed وSurfaceFlinger
الشكل 11. الارتباط بين FrameMissed وSurfaceFlinger

يعرض الشكل 11 لقطة تم تفويتها في 15598.29&nbps;ms. تم تفعيل SurfaceFlinger بشكلٍ مؤقت عند فاصل vsync ثم عاد إلى وضع السكون بدون تنفيذ أي عمل، ما يعني أنّه تبيّن لـ SurfaceFlinger أنّه ليس من المفيد محاولة إرسال لقطة إلى الشاشة مجددًا. ما السبب؟

لفهم كيفية تعطُّل مسار الإحالة الناجحة لهذا الإطار، راجِع أولاً مثال الإطار الذي يعمل أعلاه لمعرفة كيفية ظهور مسار إحالة ناجحة عادي لواجهة المستخدم في systrace. عندما تكون مستعدًا، ارجع إلى الإطار الذي لم تتمكّن من تسجيله وانتقِل للخلف. يُرجى ملاحظة أنّه يتم تفعيل ‎ SurfaceFlinger ثم ينتقل إلى وضع السكون على الفور. عند عرض عدد اللقطات المعلّقة من TouchLatency، تظهر لقطةَان (وهو مؤشر جيد للمساعدة في معرفة ما يحدث).

تنشيط SurfaceFlinger والانتقال إلى وضع السكون على الفور
الشكل 12. يتم استيقاظ SurfaceFlinger وينتقل على الفور إلى وضع السكون

هذه ليست مشكلة في التطبيق، لأنّنا نستخدم إطارات في SurfaceFlinger. بالإضافة إلى ذلك، يتم تشغيل SurfaceFlinger في الوقت الصحيح، لذا ليست هناك مشكلة في SurfaceFlinger. إذا كان كل من SurfaceFlinger والتطبيق يعملان بشكلٍ طبيعي، من المحتمل أنّ المشكلة تتعلّق بالبرنامج المشغِّل.

بما أنّ نقاط التتبّع mdss وsync مفعّلة، يمكننا الحصول على معلومات عن الحواجز (المشترَكة بين برنامج تشغيل الشاشة و SurfaceFlinger) التي تتحكّم في وقت إرسال اللقطات إلى الشاشة. يتم إدراج هذه الأسوار ضمن mdss_fb0_retire، ويشير ذلك إلى متى يكون إطار على الشاشة. يتم توفير هذه الأسوار كهي جزء من فئة التتبّع sync. تعتمد الأسوار التي تتوافق مع أحداث معيّنة في SurfaceFlinger على وحدة المعالجة المركزية (SOC) وحزمة برامج التشغيل، لذا عليك التعاون مع مزوّد وحدة المعالجة المركزية (SOC) لفهم معنى فئات الأسوار في عمليات التتبّع.

mdss_fb0_retire fences
الشكل 13: mdss_fb0_retire fences

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

الإطار السابق للإطار الذي يتضمّن مشكلة
الشكل 14. الإطار السابق للإطار الذي يتضمّن مشكلة

يعرض الشكل 14 مدة 14.482 ملي ثانية لكل إطار. استغرق المقطع المكوّن من لقتَين مكسورتَين 33.6 ملي ثانية، وهو ما يقارب ما نتوقعه من لقتَين (يتم عرض اللقطات بمعدّل 60 هرتز، أي 16.7 ملي ثانية لكل لقطة، وهو ما يقارب ذلك). ولكنّ 14.482 ملي ثانية لا تقترب من 16.7 ملي ثانية على الإطلاق، ما يشير إلى أنّ هناك مشكلة خطيرة في مسار العرض.

ابحث عن مكان انتهاء هذا السياج بالضبط لتحديد العناصر التي تتحكّم فيه.

التحقيق في نهاية السياج
الشكل 15. التحقيق في نهاية السياج

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

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

الإطار السابق
الشكل 16. الإطار السابق

لا يظهر سطر التشغيل في kworker لأنّ المُشاهد يغيّره إلى الأبيض عند اختياره، ولكن الإحصاءات توضّح المشكلة: تأخُّر المخطِّط الذي يبلغ 2.3 ملي ثانية في جزء من المسار الحرج لمسار العرض هو سيء. قبل المتابعة، عليك إصلاح التأخير عن طريق نقل هذا الجزء من مسار معالجة تدفق الشاشة المهم من "قائمة العمل" (التي تعمل كسلسلة محادثات SCHED_OTHER CFS) إلى سلسلة محادثات SCHED_FIFO kthread مخصّصة. وتتطلّب هذه الدالة ضمانات توقيت لا يمكن لقوائم العمل توفيرها (ولا يُقصد تقديمها).

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

في هذا المثال، كان الحلّ هو تحويل __vsync_retire_work_handler من "قائمة عمل" إلى "خيط kthread" مخصّص. وقد أدّى ذلك إلى تحسينات ملحوظة في الارتعاش وانخفاض في الارتباك في اختبار الكرة المرتدة. تعرض عمليات التتبّع اللاحقة أوقات حدود الإطار التي تقترب كثيرًا من 16.7 ملي ثانية.