systrace هي الأداة الأساسية لتحليل أداء أجهزة Android. ومع ذلك، فهي في الواقع غلاف لأدوات أخرى. وهو برنامج تضمين من جهة المضيف حول atrace، وهو ملف تنفيذي من جهة الجهاز يتحكّم في تتبُّع مساحة المستخدم ويضبط ftrace، وآلية التتبُّع الأساسية في نواة Linux. يستخدم systrace برنامج atrace لتفعيل التتبُّع، ثم يقرأ المخزن المؤقت لـ ftrace ويضمّن كل ذلك في عارض HTML مستقل. (على الرغم من أنّ الإصدارات الأحدث من النواة تتوافق مع ميزة "فلتر حزمة بيركلي المحسّن" (eBPF) في نظام التشغيل Linux، فإنّ هذه الصفحة تتناول النواة 3.18 (بدون eFPF) لأنّها الإصدار الذي تم استخدامه على هاتفَي Pixel وPixel XL).
يملك فريقا Google Android وGoogle Chrome أداة systrace، وهي أداة مفتوحة المصدر كجزء من مشروع 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
وعند دمجها مع نقاط التتبُّع الإضافية المطلوبة لنشاط مسار عرض وحدة معالجة الرسومات، يتيح لك ذلك تتبُّع البيانات من إدخال المستخدم إلى الإطار المعروض على الشاشة. اضبط حجم المخزن المؤقت على قيمة كبيرة لتجنُّب فقدان الأحداث (لأنّه بدون مخزن مؤقت كبير، لن تحتوي بعض وحدات المعالجة المركزية على أي أحداث بعد نقطة معيّنة في التتبُّع).
عند مراجعة بيانات systrace، تذكَّر أنّ كل حدث يتم تشغيله بواسطة عملية على وحدة المعالجة المركزية.
بما أنّ أداة systrace تستند إلى ftrace، وبما أنّ ftrace تعمل على وحدة المعالجة المركزية، يجب أن يكتب شيء ما على وحدة المعالجة المركزية في مخزن ftrace المؤقت الذي يسجّل تغييرات الأجهزة. وهذا يعني أنّه إذا أردت معرفة سبب تغيُّر حالة سياج العرض، يمكنك الاطّلاع على ما كان يتم تنفيذه على وحدة المعالجة المركزية في النقطة الزمنية المحدّدة التي حدث فيها الانتقال (أدى أحد العمليات التي يتم تنفيذها على وحدة المعالجة المركزية إلى حدوث هذا التغيير في السجلّ). يشكّل هذا المفهوم الأساس لتحليل الأداء باستخدام systrace.
مثال: إطار العمل
يصف هذا المثال عملية systrace لعملية عادية لتنفيذ واجهة المستخدم. للاطّلاع على المثال، نزِّل ملف ZIP الخاص بعمليات التتبُّع
(الذي يتضمّن أيضًا عمليات تتبُّع أخرى مشار إليها في هذا القسم)، وفك ضغط الملف،
وافتح ملف systrace_tutorial.html
في المتصفّح.
بالنسبة إلى عبء العمل المتسق والدوري، مثل TouchLatency، يتبع مسار عرض واجهة المستخدم التسلسل التالي:
- يوقظ EventThread في SurfaceFlinger سلسلة محادثات واجهة المستخدم للتطبيق، مشيرًا إلى أنّه حان الوقت لعرض إطار جديد.
- يعرض التطبيق إطارًا في سلسلة UI وRenderThread ومهام HWUI، وذلك باستخدام موارد وحدة المعالجة المركزية (CPU) ووحدة معالجة الرسومات (GPU). هذا هو الجزء الأكبر من السعة المستخدَمة لواجهة المستخدم.
- يرسل التطبيق الإطار المعروض إلى SurfaceFlinger باستخدام رابط، ثم ينتقل SurfaceFlinger إلى وضع السكون.
- يؤدي EventThread الثاني في SurfaceFlinger إلى تنبيه SurfaceFlinger لتفعيل عملية الإنشاء وعرض الناتج. إذا حدّد SurfaceFlinger أنّه لا يوجد أي عمل يجب تنفيذه، يعود إلى وضع السكون.
- يتولّى SurfaceFlinger عملية الدمج باستخدام Hardware Composer (HWC) أو Hardware Composer 2 (HWC2) أو GL. تكون عملية إنشاء الطبقات باستخدام HWC وHWC2 أسرع وتستهلك طاقة أقل، ولكنّها تتضمّن قيودًا حسب نظام التشغيل على الشريحة (SoC). تستغرق هذه العملية عادةً من 4 إلى 6 مللي ثانية، ولكن يمكن أن تتداخل مع الخطوة 2 لأنّ تطبيقات Android تستخدم دائمًا التخزين المؤقت الثلاثي. (على الرغم من أنّ التطبيقات تستخدم دائمًا التخزين المؤقت الثلاثي، قد يكون هناك إطار واحد فقط في انتظار المعالجة في SurfaceFlinger، ما يجعلها تبدو مماثلة للتخزين المؤقت المزدوج).
- يرسل SurfaceFlinger الناتج النهائي إلى الشاشة باستخدام برنامج تشغيل خاص بالمورّد، ثم يعود إلى وضع السكون في انتظار تنبيه EventThread.
في ما يلي مثال على تسلسل اللقطات الذي يبدأ عند 15409 مللي ثانية:
الشكل 1. مسار واجهة المستخدم العادي، يتم تشغيل EventThread.
الشكل 1 هو إطار عادي محاط بإطارات عادية، لذا فهو نقطة بداية جيدة لفهم طريقة عمل مسار عرض واجهة المستخدم. يتضمّن صف سلسلة محادثات واجهة المستخدم في مقياس TouchLatency ألوانًا مختلفة في أوقات مختلفة. تشير الأشرطة إلى حالات مختلفة للسلسلة:
- رمادي النوم
- الأزرق قابلة للتنفيذ (يمكن تنفيذها، ولكن لم يحدّدها المجدول بعد).
- الأخضر: قيد التشغيل بشكل نشط (يعتقد المجدول أنّه قيد التشغيل).
- أحمر: وضع السكون غير القابل للمقاطعة (النوم بشكل عام على قفل في النواة). يمكن أن يشير ذلك إلى حمل الإدخال/الإخراج. مفيدة للغاية لتصحيح الأخطاء في مشاكل الأداء.
- Orange. النوم غير القابل للانقطاع بسبب تحميل الإدخال/الإخراج
للاطّلاع على سبب النوم غير القابل للانقطاع (المتاح من نقطة التتبُّع sched_blocked_reason
)، اختَر شريحة النوم غير القابل للانقطاع الحمراء.
أثناء تشغيل EventThread، يصبح سلسلة UI الخاصة بـ TouchLatency قابلة للتشغيل. لمعرفة ما أدى إلى تنشيطه، انقر على القسم الأزرق.
الشكل 2. سلسلة واجهة المستخدم الخاصة بمقياس TouchLatency
تعرض الصورة 2 أنّ سلسلة TouchLatency لواجهة المستخدم تم تنشيطها بواسطة المعرّف 6843، وهو المعرّف الذي يتوافق مع EventThread. يتم تنشيط سلسلة محادثات واجهة المستخدم، ويتم عرض إطار، ويتم وضعه في قائمة الانتظار ليستهلكه SurfaceFlinger.
الشكل 3. يتم تنشيط سلسلة التعليمات الخاصة بواجهة المستخدم، ويتم عرض لقطة، ثم يتم وضعها في قائمة الانتظار ليستهلكها SurfaceFlinger.
إذا تم تفعيل العلامة binder_driver
في عملية تتبُّع، يمكنك اختيار معاملة binder لعرض معلومات عن جميع العمليات المعنية بهذه المعاملة.
الشكل 4 معاملة باستخدام بطاقة ربط
يوضّح الشكل 4 أنّه في 15,423.65 ms، يصبح Binder:6832_1 في SurfaceFlinger قابلاً للتنفيذ بسبب المعرّف 9579، وهو RenderThread الخاص بـ TouchLatency. يمكنك أيضًا الاطّلاع على queueBuffer على كلا جانبي معاملة Binder.
أثناء عملية queueBuffer على جانب SurfaceFlinger، يزداد عدد اللقطات المعلقة من TouchLatency من 1 إلى 2.
الشكل 5. تتراوح الإطارات في انتظار المراجعة بين 1 و2.
تعرض الصورة 5 التخزين المؤقت الثلاثي، حيث يتوفّر إطاران مكتملان ويوشك التطبيق على بدء عرض إطار ثالث. ويرجع ذلك إلى أنّنا سبق أن أسقطنا بعض اللقطات، لذا يحتفظ التطبيق بلقطتَين معلّقتَين بدلاً من واحدة لمحاولة تجنُّب إسقاط المزيد من اللقطات.
بعد ذلك بوقت قصير، يتم تنبيه سلسلة التعليمات الرئيسية في SurfaceFlinger من خلال EventThread ثانية، ليتم عرض إطار أقدم معلّق على الشاشة:
الشكل 6. يتم تنبيه سلسلة التعليمات الرئيسية في SurfaceFlinger من خلال EventThread ثانية.
في البداية، يثبّت SurfaceFlinger المخزن المؤقت القديم المعلق، ما يؤدي إلى انخفاض عدد المخازن المؤقتة المعلقة من 2 إلى 1:
الشكل 7. يتم أولاً ربط SurfaceFlinger بالمخزن المؤقت القديم المعلق.
بعد قفل المخزن المؤقت، يضبط SurfaceFlinger عملية الدمج ويرسل الإطار النهائي إلى الشاشة. (يتم تفعيل بعض هذه الأقسام كجزء من نقطة التتبُّع mdss
، لذا قد لا يتم تضمينها في نظامك على الشريحة).
الشكل 8. يُعدِّ SurfaceFlinger عملية التجميع ويرسل الإطار النهائي.
بعد ذلك، يتم تنشيط mdss_fb0
على وحدة المعالجة المركزية 0. mdss_fb0
هو سلسلة تعليمات kernel الخاصة بمسار العرض لإخراج إطار معروض على الشاشة.
لاحظ أنّ mdss_fb0
هو صفّه الخاص في التتبُّع (عليك الانتقال للأسفل للاطّلاع عليه):
الشكل 9: يستأنف mdss_fb0 العمل على وحدة المعالجة المركزية 0.
يستيقظ mdss_fb0
، ويعمل لفترة وجيزة، ثم يدخل في وضع السكون غير القابل للمقاطعة،
ثم يستيقظ مرة أخرى.
مثال: إطار غير صالح
يصف هذا المثال عملية تتبُّع النظام المستخدَمة لتصحيح أخطاء التشويش في Pixel أو Pixel XL. للاطّلاع على المثال، نزِّل ملف zip الخاص بعمليات التتبُّع (الذي يتضمّن عمليات تتبُّع أخرى مشار إليها في هذا القسم)، وفك ضغط الملف، وافتح ملف systrace_tutorial.html
في المتصفّح.
عند فتح systrace، سيظهر لك شيء مشابه للشكل التالي:
الشكل 10. تطبيق TouchLatency يعمل على هاتف Pixel XL مع تفعيل معظم الخيارات.
في الشكل 10، يتم تفعيل معظم الخيارات، بما في ذلك نقاط التتبُّع mdss
وkgsl
.
عند البحث عن jank، تحقَّق من صف FrameMissed ضمن SurfaceFlinger.
FrameMissed هي تحسين لجودة الحياة توفّره واجهة HWC2. عند عرض
systrace لأجهزة أخرى، قد لا يظهر الصف FrameMissed إذا كان الجهاز لا يستخدم
HWC2. في كلتا الحالتين، يرتبط FrameMissed بعدم تنفيذ SurfaceFlinger لأحد أوقات التشغيل العادية وعدد المخزن المؤقت المعلق غير المتغير للتطبيق (com.prefabulated.touchlatency
) في VSync.
الشكل 11. ارتباط FrameMissed بـ SurfaceFlinger
يعرض الشكل 11 لقطة لم يتم عرضها في 15598.29 مللي ثانية. استيقظ SurfaceFlinger لفترة وجيزة عند فاصل VSync وعاد إلى وضع السكون بدون تنفيذ أي عمل، ما يعني أنّ SurfaceFlinger قرّر أنّه لا يستحق محاولة إرسال لقطة إلى الشاشة مرة أخرى.
لفهم سبب تعذُّر عرض هذه اللقطة، راجِع أولاً مثال اللقطة التي تعمل بشكل سليم أعلاه لمعرفة كيف يظهر مسار واجهة المستخدم العادي في systrace. عندما تكون مستعدًا، ارجع إلى اللقطة الفائتة وابدأ العمل من الخلف. لاحظ أنّ SurfaceFlinger يستيقظ ثم ينتقل إلى وضع السكون على الفور. عند عرض عدد اللقطات المعلقة من TouchLatency، ستظهر لقطتان (وهذا دليل جيد يساعد في تحديد ما يحدث).
الشكل 12: يتم تنشيط SurfaceFlinger ثم يتم إيقافه على الفور.
بما أنّ هناك إطارات في SurfaceFlinger، فهذه ليست مشكلة في التطبيق. بالإضافة إلى ذلك، يتم تنشيط SurfaceFlinger في الوقت الصحيح، لذا لا يبدو أنّ المشكلة مرتبطة به. إذا كان كلّ من SurfaceFlinger والتطبيق يبدوان طبيعيين، من المحتمل أن تكون المشكلة في برنامج التشغيل.
بما أنّ نقاط التتبُّع mdss
وsync
مفعّلة، يمكنك الحصول على معلومات حول الحواجز (المشترَكة بين برنامج تشغيل العرض وSurfaceFlinger) التي تتحكّم في وقت إرسال اللقطات إلى الشاشة.
يتم إدراج هذه الحدود ضمن mdss_fb0_retire
، ما يشير إلى وقت عرض اللقطة. يتم توفير هذه الحدود كجزء من فئة التتبُّع sync
. تعتمد الأسوار التي تتوافق مع أحداث معيّنة في SurfaceFlinger على نظام التشغيل على الشريحة (SOC) ومجموعة برامج التشغيل، لذا عليك التواصل مع مورّد نظام التشغيل على الشريحة (SOC) لفهم معنى فئات الأسوار في عمليات التتبُّع.
الشكل 13. أسوار mdss_fb0_retire.
تعرض الصورة 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 مللي ثانية.