מדריכים

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

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

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

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

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

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

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

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

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

שאלנו מהנדסים באפליקציית Trello איך פרופילים של Baseline השפיעו על הביצועים של האפליקציה שלהם. אחרי שהחברה יישמה פרופילים של 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 פיתוח נייטיב

ההשקעה בביצועים של צוות ההנדסה השתלמה במסגרת ה-UI של Android. החל מגרסה 1.9 של Jetpack פיתוח נייטיב, הבעיה של קפיצות בזמן הגלילה ירדה ל-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

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

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

אפשר להפעיל רישום מותאם אישית ביומן כדי לראות יומנים מפורטים של 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‏ (ART) ו-Jetpack פיתוח נייטיב מעבדות את האפליקציה. בין אם מדובר בהידור מראש של נתיבים קריטיים באמצעות פרופילים של Baseline או בהחלקת מצבי גלילה באמצעות התכונות החדשות של פיתוח נייטיב 1.9 ו-1.10, הכלים האלה מתמקדים בתחושה של האפליקציה. בנוסף, הסברנו לעומק את שיטות העבודה המומלצות לניפוי באגים של פעולות שמתבצעות ברקע.

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

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

האתגר

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

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

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

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

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

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

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

נכתב על ידי:

להמשך הקריאה