הבנת מערכת ההפעלה

systrace הוא הכלי העיקרי לניתוח ביצועים של מכשירי Android. עם זאת, מדובר באמת בכלים אחרים. זהו ה-wrapper בצד המארח סביב atrace, קובץ ההפעלה בצד המכשיר ששולט במרחב המשתמשים להגדיר ולעקוב אחרי המרות מסוג ftrace, ואת מנגנון המעקב הראשי ב-Linux. של הליבה. systrace משתמשת ב-atrace כדי לאפשר מעקב, ואז קוראת את מאגר הנתונים הזמני של ftrace כולל הכול במציג HTML עצמאי. (למרות שלליבות חדשות יותר יש תמיכה עבור Linux Enhanced Berkeley Packet Filter (eBPF), המסמכים הבאים מתייחסת לליבה (kernel) של 3.18 (ללא eFPF), כי נעשה בו שימוש ב-Pixel/ב-Pixel XL).

Systrace נמצאת בבעלות צוותי Google Android ו-Google Chrome, קוד פתוח כחלק פרויקט Catapult. לחשבון בנוסף ל-systrace, Catapult כוללת כלים שימושיים נוספים. לדוגמה, ל-ftrace יש יותר תכונות שניתן להפעיל באופן ישיר באמצעות systrace או atrace, מכיל פונקציונליות מתקדמת שחיונית לניפוי באגים בביצועים או בעיות. (כדי להשתמש בתכונות האלה נדרשת גישה לרמה הבסיסית (root) ולעיתים קרובות ליבה חדשה.)

הפעלת מערכת systrace

במהלך ניפוי באגים של הרעידות ב-Pixel או ב-Pixel XL, מתחילים עם הפעולות הבאות הפקודה:

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

בשילוב עם נקודות המעקב הנוספות שנדרשות ל-GPU ולתצוגה פעילות של צינור עיבוד נתונים, כך שתוכל לעקוב אחר קלט של משתמשים למסגרת תוצג במסך. כדאי להגדיר את מאגר הנתונים הזמני על נפח גדול יותר כדי לא לאבד את הנתונים כי בלי מאגר נתונים זמני וגדול, מעבדים מסוימים לא מכילים אירועים אחרי בשלב כלשהו במעקב).

כשעוברים את המערכת, חשוב לזכור שכל אירוע הופעל על ידי משהו במעבד (CPU).

מכיוון ש-systrace מבוסס על ftrace ו-ftrace, ריצות על ה-CPU, משהו במעבד צריך לכתוב את מאגר הנתונים הזמני של ftrace שמתעד שינויים בחומרה. כלומר, אם מסקרן אתכם להבין למה המצב של גדר תצוגה השתנה, אפשרות לראות מה עבד במעבד (CPU) בדיוק בנקודת המעבר שלו (משהו שרץ במעבד (CPU) הפעיל את השינוי הזה ביומן). הזה הוא הבסיס לניתוח הביצועים באמצעות מערכת.

דוגמה: מסגרת עבודה

דוגמה זו מתארת מערכת systrace לצינור עיבוד נתונים רגיל של ממשק משתמש. כדי לעקוב אחרי עם הדוגמה, מורידים את קובץ ה-ZIP של מעקבים (כולל גם עקבות אחרים המוזכרים בקטע הזה), לפרוס את הקובץ בדחוס, ופותחים את הקובץ systrace_tutorial.html בדפדפן. מקבלים אזהרה שהמערכת הזו היא קובץ גדול, אלא אם משתמשים במערכת לניהול המערכת היומיומית זו כנראה עקבות הרבה יותר גדולה עם הרבה יותר מידע מאשר שראינו אי פעם בפעם אחת בעבר.

לעומס עבודה תקופתי ועקבי כמו TouchLatency, צינור עיבוד הנתונים של ממשק המשתמש. מכיל:

  1. EventThread ב-SurfaceFlinger מוציא את ה-thread של ממשק המשתמש של האפליקציה ממצב שינה, ומסמן שהגיע הזמן כדי לעבד מסגרת חדשה.
  2. האפליקציה מעבדת פריים ב-threads בממשק המשתמש, ב-RenderThread וב-hwuiTasks, באמצעות מעבד (CPU) משאבי GPU. זהו הנתח הגדול מהקיבולת שמושקעת בממשק המשתמש.
  3. האפליקציה שולחת את הפריים שעבר רינדור אל SurfaceFlinger באמצעות קלסר, ואז SurfaceFlinger הולך לישון.
  4. אירוע EventThread שני ב-SurfaceFlinger יוצא ממצב SurfaceFlinger כדי להפעיל של היצירה והפלט של התצוגה. אם SurfaceFlinger קובע שאין דרך לסיים את הפעולה, הוא יחזור למצב שינה.
  5. SurfaceFlinger מטפל בהרכבה באמצעות Hardware Composer (HWC)/חומרה Composer 2 (HWC2) או GL. הרכב HWC/HWC2 הוא מהיר יותר והספק נמוך יותר, אבל יש לו מגבלות בהתאם למערכת על שבב. (SoC). בדרך כלל התהליך נמשך כ-4-6 אלפיות השנייה, אבל הוא עשוי לחפוף לשלב 2, כי מערכת Android האפליקציות תמיד בתהליך אגירת נתונים שלוש פעמים. (אמנם האפליקציות תמיד בתהליך אגירת נתונים משולשת, אבל יכול להיות רק פריים אחד בהמתנה שממתינה ב-SurfaceFlinger, ואז הוא מופיע זהה למאגר נתונים זמני כפול).
  6. SurfaceFlinger שולח את הפלט הסופי להצגה עם מנהל התקן של הספק בחזרה למצב שינה, בהמתנה לשעת היציאה של EventThread.

נתחיל לעבור על המסגרת שמתחילה ב-15,409 אלפיות השנייה:

צינור עיבוד נתונים רגיל של ממשק משתמש עם EventThread פועל
איור 1. צינור עיבוד נתונים רגיל של ממשק משתמש, EventThread פועל

איור 1 הוא מסגרת רגילה שמוקפת בפריימים רגילים, לכן בתור נקודת התחלה להבנה איך פועל צינור עיבוד הנתונים של ממשק המשתמש. השורה של שרשור בממשק המשתמש עבור TouchLatency כוללת צבעים שונים בזמנים שונים. סימן עמודות המצבים השונים של השרשור:

  • אפור. שינה.
  • כחול. ניתן להרצה (הוא יכול לפעול, אבל המתזמן לא פעל בחרנו להציג אותו עדיין).
  • ירוק. פועלת באופן פעיל (המתזמן חושב ריצה).
  • אדום. שינה ללא הפרעות (בדרך כלל שינה על מנעול בליבה). יכול להעיד על עומס קלט/פלט (I/O). מועיל במיוחד לניפוי באגים בעיות בביצועים.
  • כתום. לא הפרעות בשינה בגלל עומס קלט/פלט (I/O).

כדי לראות את הסיבה לשינה ללא הפרעות (זמין נקודת מעקב אחת (sched_blocked_reason), בוחרים את הלחצן האדום 'בלי הפרעה' פלח שינה.

בזמן ש-EventThread פועל, ה-thread של ממשק המשתמש של TouchLatency הופך ניתנת להרצה. כדי לראות מה הפעיל אותו, לוחצים על הקטע הכחול.

שרשור בממשק המשתמש של TouchLatency
איור 2. שרשור בממשק המשתמש של TouchLatency

באיור 2 רואים את ה-thread של ממשק המשתמש של TouchLatency הופעל בערוץ 6843. שתואם ל-EventThread. ה-thread של ממשק המשתמש יוצא ממצב שינה, מעבד פריים ומעביר תמונות לתור אותו ל-SurfaceFlinger.

ה-thread של ממשק המשתמש יוצא ממצב שינה, מעבד פריים ומעביר אותו לתור ל-SurfaceFlinger.
איור 3. ה-thread של ממשק המשתמש יוצא ממצב שינה, מעבד מסגרת ומוסיף אותה לתור ל-SurfaceFlinger

אם התג binder_driver מופעל במעקב, אפשר לבחור כדי לראות מידע על כל התהליכים שמעורבים העסקה.

איור 4. עסקת Binder

איור 4 מראה שבקצב של 15, 423.65 אלפיות השנייה,Binder:6832_1 ב-SurfaceFlinger הופך ניתנת להרצה בגלל תו 9579, שהוא RenderThread של TouchLatency. אפשר גם לראות את התור ה-Buffer בשני הצדדים של טרנזקציית הקלסר.

במהלך pendingBuffer בצד SurfaceFlinger, מספר הפריטים הממתינים שיעור הפריימים מ-TouchLatency עולה מ-1 ל-2.

מספר הפריימים שבהמתנה משתנה מ-1 ל-2
איור 5. מספר הפריימים שבהמתנה משתנה מ-1 ל-2

איור 5 מציג תהליך אגירת נתונים משולש, שבו יש שתי פריימים שלמים האפליקציה עומדת להתחיל לעבד שליש. הסיבה לכך היא שכבר הסרנו חלק מהפריימים, לכן האפליקציה שומרת שתי פריימים בהמתנה במקום אחת כדי להימנע מפריימים מסוימים פריימים שהושמטו עוד יותר.

זמן קצר לאחר מכן, ה-thread הראשי של SurfaceFlinger מופעל על ידי EventThread השני, הוא יכול ליצור פלט של הפריים הישן שבהמתנה למסך:

ה-thread הראשי של SurfaceFlinger מופעל על ידי EventThread שני
איור 6. ה-thread הראשי של SurfaceFlinger מתעורר בשנייה שרשור אירוע

SurfaceFlinger סוגר קודם את מאגר הנתונים הזמני הישן מאגר הנתונים הזמני בהמתנה לירידה מ-2 ל-1.

SurfaceFlinger נצמד תחילה למאגר הנתונים הזמני הישן
איור 7. SurfaceFlinger נצמד תחילה אל הגרסה הישנה יותר בהמתנה מאגר נתונים זמני

לאחר לחיצה על מאגר הנתונים הזמני, SurfaceFlinger מגדיר הרכב ושולח את הפריים הסופי שמוצג. (חלק מהקטעים האלה מופעלים כחלק נקודת מעקב אחת (mdss), ולכן ייתכן שהיא לא ייכללו ב-SoC שלך.)

SurfaceFlinger מגדיר קומפוזיציה ושולח את הפריים הסופי
איור 8. SurfaceFlinger מגדיר הרכב ושולח את הפריים הסופי

בשלב הבא, mdss_fb0 יוצא ממצב שינה במעבד 0. mdss_fb0 הוא/היא להציג את שרשור הליבה של צינור עיבוד הנתונים ליצירת פלט של מסגרת מעובדת למסך. mdss_fb0 יכול להופיע כשורה נפרדת במעקב (יש לגלול למטה אל לתצוגה).

mdss_fb0 יוצא ממצב שינה במעבד 0
איור 9. mdss_fb0 יוצא ממצב שינה במעבד (CPU) 0

mdss_fb0 מתעורר, רץ לרגע, נכנס לשינה ללא הפרעות, ואז מתעוררת שוב.

דוגמה: מסגרת לא פעילה

בדוגמה הזו מתוארת מערכת לניפוי באגים ברעידות של Pixel/Pixel XL. שפת תרגום פועלים לפי הדוגמה, מורידים את ה-zip קובץ של נתוני מעקב (כולל עקבות אחרים המוזכרים כאן ), מחלצים את הקובץ ופותחים את הקובץ systrace_tutorial.html בדפדפן.

כשתפתחו את המערכת, תראו משהו כזה:

TouchLatency פועל ב-Pixel XL ורוב האפשרויות מופעלות
איור 10. זמן האחזור פועל ב-Pixel XL (רוב האפשרויות מופעל, כולל נקודות מעקב של mdss ו-kgsl)

כשמחפשים jank, צריך לבדוק את השורה Frame Missing מתחת ל-SurfaceFlinger. Frame Frame הוא שירות לשיפור איכות החיים שמסופק על ידי HWC2. בזמן הצפייה systrace עבור מכשירים אחרים, ייתכן שהשורה FrameDomain לא תופיע אם המכשיר לא משתמשת ב-HWC2. באחד משני הסוגים מקרה אחר, FrameCurrent קשור ל-SurfaceFlinger שחסר בו אחד זמני ריצה קבועים מאוד ומספר אחסון זמני ללא שינוי של האפליקציה (com.prefabulated.touchlatency) ב-vsync.

קורלציה חסרת Frame עם SurfaceFlinger
איור 11. קורלציה חסרת Frame עם SurfaceFlinger

איור 11 מציג מסגרת שלא נענתה במהירות של 15598.29&nbps;ms. SurfaceFlinger התעורר לרגע במהירות פרק זמן של vsync וחזר למצב שינה בלי לעשות עבודה, SurfaceFlinger קבע שלא כדאי לנסות לשלוח מסגרת למסך שוב. למה?

כדי להבין איך צינור עיבוד הנתונים התחלק למסגרת הזו, קודם צריך לבדוק דוגמה למסגרת עבודה שלמעלה כדי לראות איך צינור עיבוד נתונים רגיל של ממשק משתמש מופיע ב-systrace. כשהכול מוכן, חוזרים לפריים שלא נמצא ועובדים אחורה. שימו לב SurfaceFlinger מתעורר ומיד הולך לישון. כשמציגים את מספר יש שתי פריימים בהמתנה מ-TouchLatency, זה רמז טוב לעזור. כדי להבין מה קורה).

SurfaceFlinger מתעורר ומיד עובר למצב שינה
איור 12. SurfaceFlinger מתעורר ומיד עובר אל שינה

יש לנו פריימים ב-SurfaceFlinger, ולכן זו לא בעיה באפליקציה. In addition, SurfaceFlinger מתעורר בזמן הנכון, ולכן זה לא SurfaceFlinger בעיה. אם SurfaceFlinger והאפליקציה נראים רגילים, כנראה בעיה במנהל ההתקן.

בגלל שנקודות המעקב mdss ו-sync מופעלות, אנחנו יכולים לקבל מידע על הגדרות (משותף בין מנהל התקן המסך SurfaceFlinger) שקובע מתי הפריימים יישלחו למסך. הגדרות אלה מפורטות תחת mdss_fb0_retire, מציין מתי מוצגת מסגרת במסך. הגדרות אלה סופקו בתור חלק מקטגוריית המעקב sync. לאילו גדרות אירועים מסוימים ב-SurfaceFlinger תלויים ב-SOC ובסטאק הנהגים שלכם, כך עליך לעבוד עם ספק ה-SOC כדי להבין את המשמעות של קטגוריות הגדר אחר מעקב.

גדרות mdss_fb0_retire
איור 13. mdss_fb0_retires

איור 13 מציג מסגרת שהוצגה במשך 33 אלפיות השנייה, ולא 16.7 אלפיות השנייה כמצופה. באמצע הקטע הזה, היה צריך להחליף את המסגרת בפרוסה חדשה. אבל היא לא הייתה. אפשר לצפות בפריים הקודם ולחפש משהו.

הפריים הקודם למסגרת
איור 14. הפריים הקודם למסגרת

איור 14 מציג 14.482 אלפיות שנייה של מסגרת. הקטע הלא תקין בעל שתי הפריימים היה 33.6 אלפיות השנייה, וזה בערך מה שאנחנו מצפים עבור שתי פריימים (אנחנו מעבדים ב-60 Hz, 16.7 אלפיות השנייה לכל פריים, שסגור). אבל 14.482 אלפיות השנייה לא קרוב ל-16.7 אלפיות השנייה, רמיזה לכך שמשהו לא תקין מאוד בצינור התצוגה.

חוקרים בדיוק את המקום שבו הגבול הזה מסתיימת כדי לקבוע מה שולט בו.

חקירת קצה הגדר
איור 15. חקירת קצה הגדר

תור העבודה מכיל את __vsync_retire_work_handler, כשההגדרה משתנה. כשבודקים את מקור הליבה, אפשר לראות זה חלק ממנהל התקן המסך. נראה שיש בעיה לצינור עיבוד הנתונים של התצוגה, כך שהוא חייב לפעול מהר ככל האפשר. זו ניתן להריץ עבור 70 משתמשים בערך (לא עיכוב ארוך בתזמון), אבל הוא תור עבודה יכול להיות שהתזמון לא מדויק.

כדאי לבדוק את הפריים הקודם כדי לראות אם הוא תרם. לפעמים רעידות עלול להצטבר לאורך זמן ובסופו של דבר לגרום לכך שהחמצת מועד אחרון.

המסגרת הקודמת
איור 16. המסגרת הקודמת

הקו שניתן להריץ ב-kworker לא גלוי כי הצופה מסובב אותו לבן כאשר הוא נבחר, אבל הנתונים הסטטיסטיים מספרים את הסיפור: 2.3 אלפיות שנייה של מתזמן לחלק מהנתיב הקריטי של צינור עיבוד הנתונים לתצוגה הוא רע. לפני שנמשיך, עליך לתקן את העיכוב על ידי העברת החלק הזה של להציג נתיב קריטי של צינור עיבוד נתונים מתור העבודה (שפועל SCHED_OTHER שרשור CFS) ל-SCHED_FIFO ייעודי kthread. הפונקציה הזו צריכה להבטיח תזמון, שתורי עבודה לא יכולים (והם לא יכולים) המיועד) לספק.

זו הסיבה לבעיות בממשק? קשה לומר חד-משמעית. מחוץ ל- במקרים שקל לאבחן, כמו תחרות על נעילת ליבה (kernel) שגורמת לבעיות של שרשורים לשינה, עקבות בדרך כלל לא מציינים את הבעיה. האם הרעידות יכולה להיות הסיבה לשפילת הפריים? בהחלט. זמני הגדר צריכים להיות 16.7 אלפיות השנייה, אבל הם לא קרובים לזה בכלל במסגרות. שהובילו לפריים שנפל. בהינתן עד כמה ההצמדה של צינור עיבוד הנתונים לתצוגה ייתכן שהרעידות סביב תזמוני הגדר גרמה להפלה מסגרת.

בדוגמה הזו, הפתרון כלל המרה __vsync_retire_work_handler מתור עבודה למיקום ייעודי kthread. כתוצאה מכך, חלו שיפורי רעידות באופן משמעותי והפחתת רמת העומס בדיקת כדור חוזר. במעקבים הבאים מופיעים תזמוני גדרות שמרחפים קרוב מאוד עד 16.7 אלפיות השנייה.