systrace هي الأداة الأساسية لتحليل أداء جهاز Android. ومع ذلك ، فهو حقًا غلاف حول الأدوات الأخرى. إنه غلاف جانب المضيف حول atrace ، وهو الملف التنفيذي من جانب الجهاز الذي يتحكم في تتبع مساحة المستخدمين وإعداد ftrace ، وآلية التتبع الأساسية في Linux kernel. يستخدم systrace atrace لتمكين التتبع ، ثم يقرأ المخزن المؤقت ftrace ويلف كل شيء في عارض HTML مستقل. (على الرغم من أن النوى الأحدث تدعم Linux Enhanced Berkeley Packet Filter (eBPF) ، فإن الوثائق التالية تتعلق بـ 3.18 kernel (بدون eFPF) كما تم استخدامه على Pixel / Pixel XL.)
systrace مملوك من قبل فرق Google Android و Google Chrome وهو مفتوح المصدر كجزء من مشروع Catapult . بالإضافة إلى systrace ، يتضمن Catapult أدوات مساعدة أخرى مفيدة. على سبيل المثال ، يحتوي ftrace على ميزات أكثر مما يمكن تمكينه بشكل مباشر بواسطة systrace أو atrace ويحتوي على بعض الوظائف المتقدمة التي تعتبر ضرورية لتصحيح مشاكل الأداء. (تتطلب هذه الميزات الوصول إلى الجذر وغالبًا نواة جديدة.)
نظام الجري
عند تصحيح أخطاء الاهتزاز على Pixel / Pixel XL ، ابدأ بالأمر التالي:
./systrace.py sched freq idle am wm gfx view sync binder_driver irq workq input -b 96000
عند دمجها مع نقاط التتبع الإضافية المطلوبة لوحدة معالجة الرسومات ونشاط خط أنابيب العرض ، يمنحك هذا القدرة على التتبع من مدخلات المستخدم إلى الإطار المعروض على الشاشة. عيّن حجم المخزن المؤقت إلى شيء كبير لتجنب فقدان الأحداث (لأنه بدون وجود مخزن مؤقت كبير ، لا تحتوي بعض وحدات المعالجة المركزية على أي أحداث بعد نقطة معينة في التتبع).
عند المرور بنظام systrace ، ضع في اعتبارك أن كل حدث يتم تشغيله بواسطة شيء موجود على وحدة المعالجة المركزية .
نظرًا لأن systrace مبني على قمة ftrace ويتم تشغيل ftrace على وحدة المعالجة المركزية ، يجب أن يكتب شيء ما على وحدة المعالجة المركزية المخزن المؤقت الذي يسجل تغييرات الأجهزة. هذا يعني أنه إذا كنت مهتمًا بمعرفة سبب تغيير حالة سياج العرض ، فيمكنك رؤية ما كان يعمل على وحدة المعالجة المركزية في النقطة المحددة للانتقال (شيء ما قيد التشغيل على وحدة المعالجة المركزية تسبب في هذا التغيير في السجل). هذا المفهوم هو أساس تحليل الأداء باستخدام النظام.
مثال: إطار العمل
يصف هذا المثال نظامًا لخط أنابيب عادي لواجهة المستخدم. لمتابعة المثال ، قم بتنزيل ملف zip للتتبعات (والذي يتضمن أيضًا آثارًا أخرى مشار إليها في هذا القسم) ، وفك ضغط الملف ، وافتح ملف systrace_tutorial.html
في متصفحك. كن حذرًا من أن هذا النظام هو ملف كبير ؛ ما لم تستخدم نظام systrace في عملك اليومي ، فمن المحتمل أن يكون هذا أثرًا أكبر بكثير يحتوي على معلومات أكثر بكثير مما رأيته في أي أثر من قبل.
للحصول على أعباء عمل دورية متسقة مثل TouchLatency ، يحتوي خط أنابيب واجهة المستخدم على ما يلي:
- يعمل EventThread في SurfaceFlinger على تنشيط مؤشر ترابط واجهة المستخدم للتطبيق ، مما يشير إلى أن الوقت قد حان لعرض إطار جديد.
- يعرض التطبيق إطارًا في مؤشر ترابط UI و RenderThread و hwuiTasks باستخدام موارد وحدة المعالجة المركزية ووحدة معالجة الرسومات. هذا هو الجزء الأكبر من السعة التي يتم إنفاقها على واجهة المستخدم.
- يرسل التطبيق الإطار الذي تم عرضه إلى SurfaceFlinger باستخدام رابط ، ثم ينتقل SurfaceFlinger إلى وضع السكون.
- يقوم EventThread الثاني في SurfaceFlinger بتنبيه SurfaceFlinger لتشغيل التكوين وعرض الإخراج. إذا قرر SurfaceFlinger أنه لا يوجد عمل يتعين القيام به ، فإنه يعود إلى وضع السكون.
- يعالج SurfaceFlinger التكوين باستخدام مؤلف الأجهزة (HWC) / Hardware Composer 2 (HWC2) أو GL. تكوين HWC / HWC2 أسرع وأقل قوة ولكن له قيود اعتمادًا على النظام الموجود على شريحة (SoC). يستغرق هذا عادةً حوالي 4-6 مللي ثانية ، ولكن يمكن أن يتداخل مع الخطوة 2 لأن تطبيقات Android دائمًا ما تكون مخزنة ثلاث مرات. (على الرغم من أن التطبيقات يتم تخزينها ثلاث مرات دائمًا ، فقد يكون هناك إطار واحد معلق ينتظر في SurfaceFlinger ، مما يجعله يبدو مماثلاً للتخزين المؤقت المزدوج.)
- يرسل SurfaceFlinger الإخراج النهائي لعرضه مع برنامج تشغيل البائع ويعود إلى وضع السكون ، في انتظار تنبيه EventThread.
لننتقل عبر الإطار الذي يبدأ عند 15409 مللي ثانية:

الشكل 1 عبارة عن إطار عادي محاط بإطارات عادية ، لذا فهو يمثل نقطة انطلاق جيدة لفهم كيفية عمل خط أنابيب واجهة المستخدم. يتضمن صف سلسلة UI لـ TouchLatency ألوانًا مختلفة في أوقات مختلفة. تشير الأشرطة إلى حالات مختلفة للخيط:
- رمادي . نائم.
- أزرق. قابل للتشغيل (يمكن تشغيله ، لكن المجدول لم يختاره للتشغيل بعد).
- لون أخضر. يعمل بنشاط (يعتقد المجدول أنه يعمل).
- أحمر. النوم المتواصل (النوم بشكل عام على قفل في النواة). يمكن أن يشير إلى تحميل الإدخال / الإخراج. مفيد للغاية لتصحيح مشاكل الأداء.
- البرتقالي. سكون غير متقطع بسبب تحميل الإدخال / الإخراج.
لعرض سبب السكون غير المنقطع (متاح من نقطة sched_blocked_reason
) ، حدد شريحة السكون الحمراء غير المنقطعة.
أثناء تشغيل EventThread ، يصبح مؤشر ترابط واجهة المستخدم لـ TouchLatency قابلاً للتشغيل. لمعرفة ما الذي أيقظه ، انقر فوق القسم الأزرق.

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

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

يوضح الشكل 4 أنه عند 15،423.65 مللي ثانية Binder: 6832_1 في SurfaceFlinger يصبح قابلاً للتشغيل بسبب tid 9579 ، وهو RenderThread الخاص بـ TouchLatency. يمكنك أيضًا مشاهدة queueBuffer على كلا جانبي معاملة Binder.
أثناء queueBuffer على جانب SurfaceFlinger ، ينتقل عدد الإطارات المعلقة من TouchLatency من 1 إلى 2.

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

يقوم SurfaceFlinger أولاً بإغلاق المخزن المؤقت المعلق الأقدم ، مما يتسبب في تقليل عدد المخزن المؤقت المعلق من 2 إلى 1.

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

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

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

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

يوضح الشكل 11 إطارًا مفقودًا عند 15598.29 & nbps؛ ms. استيقظ SurfaceFlinger لفترة وجيزة في الفاصل الزمني المتزامن وعاد إلى النوم دون القيام بأي عمل ، مما يعني أن SurfaceFlinger قرر أنه لا يستحق محاولة إرسال إطار إلى الشاشة مرة أخرى. لماذا ا؟
لفهم كيفية تعطل خط الأنابيب لهذا الإطار ، راجع أولاً مثال إطار العمل أعلاه لترى كيف يظهر خط أنابيب عادي لواجهة المستخدم في النظام. عندما تصبح جاهزًا ، عد إلى الإطار المفقود واعمل للخلف. لاحظ أن SurfaceFlinger يستيقظ وينام فورًا. عند عرض عدد الإطارات المعلقة من TouchLatency ، يوجد إطاران (دليل جيد للمساعدة في معرفة ما يحدث).

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

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

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

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

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