מדריכים

שיקולים נוספים לגבי ביצועים

קריאה של 8 דקות
3 Authors
Ben Weiss, Breana Tate, Jossi Wolf

כדאי להירגע ולתת לנו להסביר לכם עוד על הביצועים.

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

אופטימיזציה מבוססת-פרופיל

פרופילים של Baseline ופרופילים להפעלה הם הבסיס לשיפור הביצועים של אפליקציה ל-Android בזמן ההפעלה ובזמן הריצה. הם חלק מקבוצה של אופטימיזציות לשיפור הביצועים שנקראת Profile Guided Optimization (אופטימיזציה מונחית פרופיל).

כשיוצרים חבילה של אפליקציה, הכלי d8 dexer לוקח מחלקות ושיטות ומאכלס את קובצי classes.dex של האפליקציה. כשמשתמש פותח את האפליקציה, קובצי ה-dex האלה נטענים, אחד אחרי השני, עד שהאפליקציה יכולה להתחיל לפעול. כשמספקים פרופיל הפעלה, כלי d8 יודע אילו מחלקות ושיטות לארוז בקובצי classes.dex הראשונים. המבנה הזה מאפשר לאפליקציה לטעון פחות קבצים, וכך לשפר את מהירות ההפעלה.

פרופילים של Baseline מעבירים ביעילות את שלבי ההידור Just in Time (JIT) ממכשירי המשתמשים למכונות של המפתחים. הוכח שהקוד המהודר שנוצר מראש (AOT) מפחית את זמן ההפעלה ואת בעיות העיבוד.

Trello ופרופילים של Baseline

שאלנו מהנדסים באפליקציית Trello איך פרופילים של Baseline השפיעו על הביצועים של האפליקציה שלהם. אחרי ש-Trello יישמו פרופילים של Baseline במסלול המשתמש הראשי שלהם, הם נהנו מקיצור משמעותי של זמן הפעלת האפליקציה ב-25%.

image.png

חברת Trello הצליחה לשפר את זמן ההפעלה של האפליקציה ב-25 % באמצעות פרופילים של Baseline.

פרופילים של Baseline ב-Meta

בנוסף, מהנדסים ב-Meta פרסמו לאחרונה מאמר על האצת אפליקציות Android באמצעות פרופילי Baseline.

image.png

בכל האפליקציות של Meta, הצוותים ראו שיפור של עד 40 % במדדים קריטיים שונים אחרי שהם יישמו פרופילים של Baseline.

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

איך מתחילים לעבוד עם פרופילים של Baseline

כדי ליצור פרופיל Baseline או פרופיל הפעלה, כותבים בדיקת macrobenchmark שמפעילה את האפליקציה. במהלך הבדיקה נאספים נתוני פרופיל שישמשו במהלך קומפילציית האפליקציה. הבדיקות נכתבות באמצעות UiAutomator API החדש, שנסביר עליו מחר.

כתיבת מדד השוואה כזה היא פשוטה, ואפשר לראות את הדוגמה המלאה ב-GitHub.

@Test

fun profileGenerator() {

    rule.collect(

        packageName = TARGET_PACKAGE,

        maxIterations = 15,

        stableIterations = 3,

        includeInStartupProfile = true

    ) {

        uiAutomator {

            startApp(TARGET_PACKAGE)

        }

    }


}

שיקולים

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

תחילת העבודה עם אופטימיזציה מונחית פרופיל

כדי להבין איך פועלים פרופילים של Baseline, אפשר לצפות בסרטון הזה מ-Android Developers Summit:

כדאי גם לצפות בפרק בנושא זמן בנייה ב-Android בסדרה Profile Guided Optimization כדי לקבל עוד מידע מעמיק: 

בנוסף, יש לנו מדריכים מקיפים על פרופילים של Baseline ועל פרופילים להפעלה.

שיפורים בביצועים של Jetpack Compose

ההשקעה בביצועים של צוות ההנדסה השתלמה במסגרת ה-UI של Android. החל מגרסה 1.9 של Jetpack Compose, הבעיה של קפיצות בזמן הגלילה ירדה ל-0.2 % במהלך בדיקת ביצועים פנימית של גלילה ארוכה. 

jankyFrames.png

השיפורים האלה התאפשרו בזכות כמה תכונות שנכללות בגרסאות האחרונות.

חלון מטמון שניתן להתאמה אישית

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

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

val dpCacheWindow = LazyLayoutCacheWindow(ahead = 150.dp, behind = 100.dp)

val state = rememberLazyListState(cacheWindow = dpCacheWindow)

LazyColumn(state = state) {

    // column contents

}

שילוב פורמטים עם אפשרות להשהיה

התכונה הזו מאפשרת להשהות קומפוזיציות ולפצל את העבודה שלהן על פני כמה פריים. ממשקי ה-API נכללו בגרסה 1.9, ועכשיו הם משמשים כברירת מחדל בגרסה 1.10 לאחזור מראש של פריסות. היתרון הכי גדול יתקבל בפריטים מורכבים עם זמני קומפוזיציה ארוכים יותר. 

image.png

אופטימיזציות נוספות של הביצועים של התכונה 'כתיבת תוכן'

בגרסאות 1.9 ו-1.10 של Compose, הצוות גם ביצע כמה אופטימיזציות שהן קצת פחות ברורות.

שיפרנו כמה ממשקי API שמשתמשים בקורוטינות מתחת לפני השטח. לדוגמה, כשמשתמשים בפונקציות Draggable ו-Clickable, מפתחים אמורים לראות זמני תגובה מהירים יותר ומספרים משופרים של הקצאות.

שיפורים במעקב אחרי מלבני פריסה שיפרו את הביצועים של משנים כמו onVisibilityChanged() ו-onLayoutRectChanged(). השימוש ב-API האלה מזרז את שלב הפריסה, גם אם לא משתמשים בהם באופן מפורש.

שיפור נוסף בביצועים הוא שימוש בערכים שנשמרו במטמון כשמבצעים מעקב אחר מיקומים באמצעות onPlaced().

טעינה מראש של טקסט ברקע

החל מגרסה 1.9, ב-Compose נוספה האפשרות לאחזר מראש טקסט בשרשור ברקע. האפשרות הזו מאפשרת לכם לחמם מראש את מטמונים כדי להאיץ את פריסת הטקסט, והיא רלוונטית לביצועי העיבוד של האפליקציה. במהלך הפריסה, הטקסט צריך לעבור למסגרת Android, שבה מאוכלס מטמון מילים. כברירת מחדל, הפעולה הזו מתבצעת בשרשור של ממשק המשתמש. העברת האחריות לטעינה מראש ולאכלוס מטמון המילים לשרשור ברקע יכולה לזרז את הפריסה, במיוחד כשמדובר בטקסטים ארוכים. כדי לבצע אחזור מראש בשרשור ברקע, אפשר להעביר executor בהתאמה אישית לכל קומפוזיציה שמשתמשת ב-BasicText מאחורי הקלעים, על ידי העברת LocalBackgroundTextMeasurementExecutor ל-CompositionLocalProvider באופן הבא.

val defaultTextMeasurementExecutor = Executors.newSingleThreadExecutor()

CompositionLocalProvider(

    LocalBackgroundTextMeasurementExecutor provides DefaultTextMeasurementExecutor

) {

    BasicText("Some text that should be measured on a background thread!")


}

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

שיקולים לגבי ביצועים של עבודה ברקע

עבודה ברקע היא חלק חיוני בהרבה אפליקציות. יכול להיות שאתם משתמשים בספריות כמו WorkManager או JobScheduler כדי לבצע משימות כמו:

  • העלאה תקופתית של אירועים אנליטיים
  • סנכרון נתונים בין שירות קצה עורפי למסד נתונים
  • עיבוד מדיה (כלומר שינוי גודל או דחיסה של תמונות)

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

עם זאת, WorkManager הוא לא פתרון שמתאים לכל המקרים. ב-Android יש גם מספר ממשקי API שעברו אופטימיזציה לצריכת חשמל, ומיועדים במיוחד לתרחישי שימוש נפוצים מסוימים.  

אפשר לעיין ברשימה של כמה מהפעולות האלה בדף הנחיתה בנושא פעולות ברקע,  כולל עדכון ווידג'ט ואיתור מיקום ברקע.

כלים לניפוי באגים מקומיים בעבודה ברקע: תרחישים נפוצים

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

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

ניפוי באגים כדי להבין למה עבודה מתוזמנת לא מבוצעת

יכולות להיות כמה סיבות לעיכוב בעבודה מתוזמנת או לכך שהיא לא מתבצעת בכלל, כולל אי-עמידה במגבלות שצוינו או מגבלות שהוגדרו על ידי המערכת

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

יש כמה כלים לניפוי באגים בתרחיש הזה.

Background Task Inspector

הכלי לבדיקת משימות ברקע הוא כלי מתקדם שמשולב ישירות ב-Android Studio. הוא מספק ייצוג חזותי של כל המשימות ב-WorkManager והמצבים המשויכים שלהן (פועל, בהמתנה, נכשל, הצליח). 

כדי לנפות באגים ולגלות למה עבודות מתוזמנות לא מבוצעות באמצעות הכלי Background Task Inspector, צריך לעיין בסטטוסים של העבודות שמופיעים ברשימה. הסטטוס 'בתור' מציין שהעבודה שלכם תוכננה, אבל היא עדיין ממתינה להרצה.

היתרונות: הכלי הזה מאפשר לכם לראות את כל המשימות בקלות, והוא שימושי במיוחד אם יש לכם עבודה שמתבססת על משימות קודמות. הכלי Background Task Inspector מציע תצוגת גרף שמאפשרת לראות אם כשל במשימה קודמת השפיע על הביצוע של המשימה הבאה.

image.png

תצוגת רשימה ב-Background Task Inspector

image.png

תצוגת תרשים של Background Task Inspector

adb shell dumpsys jobscheduler

הפקודה הזו מחזירה רשימה של כל המשימות הפעילות ב-JobScheduler (כולל WorkManager Workers) יחד עם אילוצים שצוינו ואילוצים שהמערכת כופה. הוא גם מחזיר את היסטוריית המשרות. 

משתמשים באפשרות הזו אם רוצים לראות את העבודה המתוזמנת ואת האילוצים המשויכים בדרך אחרת. בגרסאות של WorkManager שקודמות לגרסה WorkManager 2.10.0, הפונקציה adb shell dumpsys jobscheduler תחזיר רשימה של Workers עם השם הזה:

[package name]/androidx.work.impl.background.systemjob.SystemJobService

אם לאפליקציה שלכם יש כמה Worker, תוכלו לעדכן לגרסה WorkManager 2.10.0 כדי לראות את השמות של ה-Worker ולהבחין בקלות ביניהם:

#WorkerName#@[package name]/androidx.work.impl.background.systemjob.SystemJobService

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

הפעלת רישום נתונים של ניפוי באגים

אפשר להפעיל רישום מותאם אישית ביומן כדי לראות יומנים מפורטים של WorkManager, שיהיה להם WM— מצורף. 

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

WorkInfo.StopReason

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

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

יתרונות: אפשר להשתמש ב-WorkInfo.StopReason כדי לאסוף נתונים מהשטח על הביצועים של העובדים.

ניפוי באגים של משך חסימת מצב שינה ארוך שמשויך ל-WorkManager ומסומן על ידי מדד תפקוד האפליקציה

במדד תפקוד האפליקציה ל-Android יש מדד של שימוש מוגזם בחסימה חלקית של מצב השינה, שמדגיש את חסימות מצב השינה שגורמות להתרוקנות הסוללה. יכול להיות שתופתעו לגלות ש-WorkManager מקבל נעילות השכמה כדי להריץ משימות, ואם נעילות ההשכמה חורגות מהסף שנקבע על ידי Google Play, זה יכול להשפיע על הנראות של האפליקציה. איך אפשר לנפות באגים כדי להבין למה משך חסימת מצב שינה שמשויך לעבודה שלכם כל כך ארוך? אפשר להשתמש בכלים הבאים.

לוח הבקרה של תפקוד האפליקציה

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

Perfetto

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

בקטע 'מצב המכשיר: משימות' אפשר לראות את כל העובדים שהופעלו ואת נעילות ההשכמה שמשויכות אליהם.

deviceState.png

הקטע Device State (מצב המכשיר) ב-Perfetto, שבו מוצגת ההפעלה של CleanupWorker ו-BlurWorker.

מקורות מידע

בדף בנושא ניפוי באגים ב-WorkManager יש סקירה כללית של שיטות ניפוי באגים שזמינות לתרחישים אחרים שאולי תיתקלו בהם.

כדי לנסות כמה מהשיטות האלה בפועל ולקבל מידע נוסף על ניפוי באגים ב-WorkManager, כדאי לעיין ב-codelab בנושא WorkManager ובדיקות למתקדמים.

השלבים הבאים

היום הרחבנו את הדיון מעבר לצמצום קוד, והסברנו איך סביבת הריצה של Android ו-Jetpack Compose מעבדות את האפליקציה. בין אם מדובר בהידור מראש של נתיבים קריטיים באמצעות פרופילים של Baseline או בהחלקת מצבי גלילה באמצעות התכונות החדשות של Compose 1.9 ו-1.10, הכלים האלה מתמקדים בתחושה של האפליקציה. בנוסף, הסברנו לעומק את שיטות העבודה המומלצות לניפוי באגים של פעולות שמתבצעות ברקע.

שליחת שאלה ל-Android

ביום שישי נארח מפגש שאלות ותשובות בשידור חי בנושא ביצועים. אתם יכולים לשאול שאלות באמצעות ההאשטאג #AskAndroid ולקבל תשובות מהמומחים.

האתגר

ביום שני ביקשנו ממך להפעיל את R8. היום אנחנו מבקשים ממך ליצור פרופיל Baseline אחד לאפליקציה שלך.

עם Android Studio Otter, אשף המודולים Baseline Profile Generator מאפשר לעשות את זה בקלות רבה יותר מאי פעם. בוחרים את חוויית המשתמש ההכרחית (CUJ) הכי חשובה – גם אם מדובר רק בהפעלה של האפליקציה והתחברות – ויוצרים פרופיל.

אחרי שיוצרים אותו, מריצים Macrobenchmark כדי להשוות בין CompilationMode.None לבין CompilationMode.Partial.

אתם יכולים לשתף ברשתות החברתיות את השיפורים בזמן ההפעלה באמצעות ההאשטאג #optimizationEnabled.

כדאי לצפות מחר

הקטנתם את האפליקציה באמצעות R8 וביצעתם אופטימיזציה של זמן הריצה באמצעות Profile Guided Optimization (אופטימיזציה מבוססת-פרופיל). אבל איך מוכיחים את ההצלחות האלה לבעלי העניין? ואיך אתם מזהים רגרסיות לפני שהן מגיעות לסביבת הייצור?

מוזמנים להצטרף אלינו מחר ליום 4: מדריך לשיפור הביצועים, שבו נסביר בדיוק איך למדוד את ההצלחה שלכם, מנתוני שטח ב-Play Vitals ועד מעקב מקומי מעמיק באמצעות Perfetto.

נכתב על ידי:

להמשך הקריאה