מדדים הם סוג המידע העיקרי שמופק מהשוואות לשוק. הם מועברים לפונקציה measureRepeated כ-List, וכך אפשר לציין כמה מדדים נמדדים בבת אחת. כדי להריץ את ההשוואה לשוק, צריך לבחור לפחות סוג אחד של מדד.
קטע הקוד הבא מתעד את התזמון של הפריימים ואת מדדי הקטע המותאם אישית של מעקב אחר פריסת Jetpack Compose עצלה:
@OptIn(ExperimentalMetricApi::class)
@Test
fun scrollComposeList() {
benchmarkRule.measureRepeated(
// [START_EXCLUDE]
packageName = TARGET_PACKAGE,
metrics = listOf(
FrameTimingMetric(),
// Measure power usage. This is supported on Pixel 6 and later.
PowerMetric(PowerMetric.Type.Power(
mapOf(
PowerCategory.CPU to PowerCategoryDisplayLevel.TOTAL,
PowerCategory.DISPLAY to PowerCategoryDisplayLevel.TOTAL,
PowerCategory.GPU to PowerCategoryDisplayLevel.TOTAL,
PowerCategory.NETWORK to PowerCategoryDisplayLevel.TOTAL,
)
)),
// Measure custom trace sections by name EntryRow (which is added to the EntryRow composable).
// Mode.Sum measures combined duration and also how many times it occurred in the trace.
// This way, you can estimate whether a composable recomposes more than it should.
TraceSectionMetric("EntryRowCustomTrace", TraceSectionMetric.Mode.Sum),
// This trace section takes into account the SQL wildcard character %,
// which can find trace sections without the full name.
// This way, you can measure composables produced by the composition tracing
// and measure how long they took and how many times they recomposed.
// WARNING: This metric only shows results when running with composition tracing, otherwise it won't be visible in the outputs.
TraceSectionMetric("%EntryRow%", TraceSectionMetric.Mode.Sum),
),
// Try switching to different compilation modes to see the effect
// it has on frame timing metrics.
compilationMode = CompilationMode.None(),
startupMode = StartupMode.WARM, // restarts activity each iteration
iterations = DEFAULT_ITERATIONS,
// [END_EXCLUDE]
setupBlock = {
uiAutomator {
// Before starting to measure, navigate to the UI to be measured.
startIntent(Intent("$packageName.COMPOSE_ACTIVITY"))
}
}
) {
uiAutomator {
onElement { isScrollable }.fling(Direction.DOWN)
}
}
}
בדוגמה הבאה, EntryRowCustomTrace מייצג קטע של מעקב בהתאמה אישית שהוגדר בתוך השכבות של הפריט שניתן להרכבה באמצעות עטיפת הבלוק trace(sectionName) { ... } הרגילה של Kotlin. כדי לספק נתונים עבור TraceSectionMetric, צריך להוסיף את רכיבי ממשק המשתמש הרלוונטיים בתוך קוד הבסיס של האפליקציה, באמצעות עטיפת בלוק זמן הריצה הרגיל של Jetpack trace:
@Composable
private fun EntryRow(entry: Entry, modifier: Modifier = Modifier) = trace("EntryRowCustomTrace") {
Card(modifier = modifier) {
Row(verticalAlignment = Alignment.CenterVertically) {
Text(
text = entry.contents,
modifier = Modifier
.padding(16.dp)
.wrapContentSize()
)
Spacer(modifier = Modifier.weight(1f))
Checkbox(
checked = false,
onCheckedChange = {},
modifier = Modifier.padding(16.dp)
)
}
}
}
תוצאות ההשוואה מוצגות ישירות בכרטיסיית המסוף Benchmark ב-Android Studio, כמו שמוצג באיור 1. אם מוגדרים כמה מדדים, כל נקודות הנתונים המחושבות שלהם משולבות בחלון הסיכום.
TraceSectionMetric ו-FrameTimingMetric עבור פריסת כתיבה מודרנית.התכונות StartupTimingMetric, FrameTimingMetric, TraceSectionMetric ו-PowerMetric מוסברות בפירוט בהמשך. רשימה מלאה של מדדי השוואה זמינה במחלקות המשנה של Metric במאמרי העזרה בנושא API.
StartupTimingMetric
StartupTimingMetric מתעד מדדים של תזמון הפעלת האפליקציה עם הערכים הבאים:
timeToInitialDisplayMs: משך הזמן שחולף מהרגע שבו המערכת מקבלת כוונת הפעלה ועד שהיא מעבדת את הפריימים הראשונים של מסך היעד.-
timeToFullDisplayMs: משך הזמן מרגע שהמערכת מקבלת כוונה להפעיל את האפליקציה ועד שהאפליקציה מדווחת על ציור מלא באמצעות מנגנוני הדיווח הפנימיים של הפלטפורמה. המדידה מסתיימת כשהרינדור של הפריים הראשון מסתיים אחרי או כולל את האות המלא של הציור.
StartupTimingMetric מחזירה את ערכי המינימום, החציון והמקסימום מהאיטרציות של ההפעלה. כדי להעריך את השיפור בהפעלה, תמיד צריך להתמקד בערכי החציון, כי הם מספקים את האומדן הטוב ביותר של זמני ההפעלה האופייניים של המשתמשים.
בארכיטקטורה של Compose-first, אל תנסו להפעיל את activity.reportFullyDrawn באופן ידני. במקום זאת, אפשר להשתמש בכלי השירות האסינכרוניים ReportDrawn, ReportDrawnWhen או ReportDrawnAfter בתוך רכיבי ה-Composable של המסך כדי לסמן אוטומטית ל-Macrobenchmark מתי נתוני הרשת האסינכרוניים או מצבי ממשק המשתמש המורכבים סיימו את הרינדור.
מידע נוסף על ניתוח ואופטימיזציה של ביצועי ההפעלה זמין במאמר זמן ההפעלה של האפליקציה.
FrameTimingMetric
FrameTimingMetric מתעד מידע מדויק על התזמון מתוך פריימים שנוצרו על ידי תהליך השוואה, כמו גלילה ברשימה או פריסת ממשק משתמש מורכב, ומפיק את ערכי האבחון הבאים:
-
frameOverrunMs: משך הזמן שבו פריים מסוים לא עמד בדדליין. מספרים חיוביים מציינים פריים שהושמט, בליווי תנועה קופצנית או מגמגמת שניתן לראות. מספרים שליליים מציינים כמה מהר יותר הושלם פריים ביחס למועד האחרון של חומרת מערכת המשנה. הערה: המדד הזה זמין רק ב-Android 12 (רמת API 31) ובגרסאות מתקדמות יותר. -
frameDurationCpuMs: משך הזמן שבו הפריימים נוצרו באופן פעיל ב-CPU, גם בשרשור ה-UI הראשי של האפליקציה וגם ב-ComposeRenderThread.
הנתונים האלה נאספים בהתפלגות של אחוזונים: 50, 90, 95 ו-99:
frameDurationCpuMs P50 3.5, P90 6.0, P95 6.4, P99 11.0
frameOverrunMs P50 -11.6, P90 -7.2, P95 -7.1, P99 -1.2
כשמבצעים אופטימיזציה להיררכיות של פריסות ב-Jetpack Compose, כדאי לבדוק את המסגרות עם הביצועים הכי גרועים (הגבולות P95 ו-P99). אם הערך של frameOverrunMs עולה בחדות למספרים שלמים חיוביים באחוזונים הגבוהים, זה מצביע על כך שהרכבות מחדש מעכבות את השרשור הראשי במהלך אנימציות גלילה כבדות.
לקבלת תובנות מעמיקות יותר לגבי זיהוי ופתרון של פריימים איטיים, אפשר לעיין במאמר ביצועים של Jetpack Compose.
TraceSectionMetric
TraceSectionMetric מתעד את מספר הפעמים שקטע מסוים של מעקב מתרחש ואת משך הזמן המוחלט שלוקח לו להתבצע. למעקב אחר זמן, הפונקציה מחזירה את הזמנים המינימליים, הממוצעים והמקסימליים באלפיות השנייה. הקטע target trace מוגדר על ידי הקריאה לפונקציה trace(sectionName) או על ידי הגבולות של הבלוק ברמה נמוכה יותר בין Trace.beginSection(sectionName) לבין Trace.endSection() או הגרסאות האסינכרוניות שלהם.
EntryRowCustomTraceCount min 20.0, median 28.0, max 50.0
EntryRowCustomTraceSumMs min 34.9, median 44.4, max 66.6
כברירת מחדל, המדד מפיק רק קטעי מעקב שנאספו ישירות מקובצי הבינאריים של חבילת האפליקציה שלכם. כדי לכלול תהליכים שמקורם מחוץ לגבולות החבילה של האפליקציה, צריך להגדיר את המאפיין targetPackageOnly = false.
כשעובדים על מעקב אחר זמן הריצה של Jetpack Compose, אפשר להציג פונקציות קומפוזביליות נפרדות בתרשימי המעקב של המערכת בלי לכתוב עטיפות מעקב ידניות, על ידי הפעלת מעקב אחר קומפוזיציה.
הוספת התלות androidx.compose.runtime:runtime-tracing לאפליקציית היעד מספיקה למעקב ידני של פרופילר, אבל כדי לתעד את המעקב הזה באופן פרוגרמטי במהלך הפעלה של Macrobenchmark, צריך לבצע הגדרה נוספת במודול ההשוואה.
הוראות מלאות להגדרה מופיעות במאמר בנושא תיעוד של נתוני מעקב באמצעות Jetpack Macrobenchmark.
PowerMetric
PowerMetric מתעד את השינוי בהספק או באנרגיה במהלך ההרצה של בדיקת המאקרו. כל קטגוריה שנבחרה מחולקת לרכיבי החומרה הניתנים למדידה שלה, ואילו קטגוריות שלא נבחרו מקובצות לדלי 'לא נבחר'.
דרישות חומרה: המדדים האלה מודדים את הצריכה בכל המערכת ולא את החישובים בכל אפליקציה. לכן, איסוף הנתונים מוגבל למכשירי Google Pixel 6, Pixel 6 Pro ולמכשירים פיזיים חדשים יותר.
המדד מפיק שני ערכים לכל קטגוריה:
-
power<category>Uw: כמות החשמל שנצרכה במהלך הבדיקה בקטגוריה הזו (נמדדת במיקרוואט). -
energy<category>Uws: כמות האנרגיה הכוללת שהועברה ליחידת זמן במהלך הבדיקה בקטגוריה הזו (נמדדת במיקרוואט-שניות).
הקטגוריות כוללות את האפשרויות הבאות:
CPUDISPLAYGPUGPSMEMORYMACHINE_LEARNINGNETWORKUNCATEGORIZED
בקטגוריות מסוימות, כמו CPU, יכול להיות שיהיה קשה להפריד בין עבודה שמתבצעת על ידי תהליכים אחרים לבין עבודה שמתבצעת על ידי האפליקציה שלכם. כדי לצמצם את ההפרעות, כדאי להסיר או להגביל אפליקציות וחשבונות לא נחוצים.
powerCategoryCpuUw min 300.2, median 346.1, max 519.6
powerCategoryDisplayUw min 319.8, median 325.8, max 329.7
powerCategoryGpuUw min 18.8, median 23.3, max 36.9
powerCategoryNetworkUw min 97.3, median 123.3, max 681.3
powerTotalUw min 1234.8, median 1316.6, max 2112.4
powerUnselectedUw min 483.3, median 512.6, max 561.7
ניתוח של מערכות משנה מרכזיות
PowerMetric מתעד את השינוי בעוצמה או באנרגיה במהלך הבדיקה עבור קטגוריות העוצמה שצוינו. כל קטגוריה שתבחרו תפורט לרכיבי המשנה שלה שאפשר למדוד, וקטגוריות שלא תבחרו יתווספו למדד 'לא נבחר'.
הפלט של הטרמינל ממופה להגדרה שביקשתם:
-
powerCategoryCpuUw: כמות החשמל שנצרכה על ידי ה-CPU במהלך הבדיקה. -
powerCategoryGpuUw: כמות החשמל שנצרכה על ידי ה-GPU במהלך הבדיקה. -
powerUnselectedUw: צריכת החשמל הכוללת של כל קטגוריות החומרה הזמינות שלא נכללו במפורש במפת האתחול.
כדי למנוע קפיצות חדות בנתונים של רכיבי החומרה במהלך ההרצה, צריך לנעול את בהירות המסך לערך קבוע, לשמור על טמפרטורה יציבה של המכשיר ולסגור תהליכי רקע מתחרים לפני שמתחילים את הלולאה של Macrobenchmark.
מקורות מידע נוספים
צפיות בתוכן
מומלץ בשבילכם
- הערה: טקסט הקישור מוצג כש-JavaScript מושבת
- יצירת פרופיל Baseline {:#creating-profile-rules}
- כתיבת Macrobenchmark
- ניתוח ואופטימיזציה של הפעלת אפליקציות {:#app-startup-analysis-optimization}