משתמשים בספריית Macrobenchmark כדי לבדוק תרחישי שימוש גדולים יותר באפליקציה, כולל הפעלת האפליקציה ומניפולציות מורכבות בממשק המשתמש, כמו גלילה בLazyColumn או הפעלת אנימציות. אם רוצים לבדוק אזורים קטנים יותר בקוד, אפשר לעיין במאמר בנושא מיקרו-בנצ'מרק. בדף הזה מוסבר איך להגדיר את ספריית Macrobenchmark.
הספרייה מפיקה תוצאות של השוואה לשוק ומציגה אותן במסוף של Android Studio ובקובץ JSON עם פרטים נוספים. הכלי גם מספק קובצי מעקב שאפשר לטעון ולנתח ב-Android Studio.
שימוש בספריית Macrobenchmark בסביבת אינטגרציה רציפה (CI), כמו שמתואר במאמר השוואה בין ביצועים באינטגרציה רציפה.
אפשר להשתמש ב-Macrobenchmark כדי ליצור פרופילים של Baseline. קודם מגדירים את ספריית Macrobenchmark, ואז אפשר ליצור פרופיל Baseline.
Macrobenchmark הוא הכלי המומלץ לבדיקת ממשקי משתמש שנוצרו באמצעות Jetpack פיתוח נייטיב. במאמר בנושא יכולת פעולה הדדית מוסבר איך לכתוב בדיקות של UI Automator שיוצרות אינטראקציה עם צמתי Compose.
הגדרת הפרויקט
מומלץ להשתמש ב-Macrobenchmark עם הגרסה העדכנית של Android Studio.
הגדרת המודול Macrobenchmark
בדיקות מאקרו דורשות מודול com.android.test – מודול נפרד מקוד האפליקציה שאחראי להרצת הבדיקות שמודדות את האפליקציה.
ב-Android Studio יש תבנית שמאפשרת להגדיר מודול Macrobenchmark בקלות. תבנית המודול להשוואה יוצרת באופן אוטומטי מודול בפרויקט כדי למדוד את האפליקציה שנבנתה על ידי מודול האפליקציה, כולל השוואה לדוגמה של זמן ההפעלה.
כדי להשתמש בתבנית של מודול כדי ליצור מודול חדש:
לוחצים לחיצה ימנית על הפרויקט או המודול בחלונית Project (פרויקט) ב-Android Studio ובוחרים באפשרות New > Module (חדש > מודול).
בחלונית תבניות, בוחרים באפשרות השוואה לשוק. אפשר להתאים אישית את אפליקציית היעד – כלומר האפליקציה שרוצים להשוות לביצועים של אפליקציות אחרות – וגם את שם החבילה ושם המודול של מודול ה-Macrobenchmark החדש.
לוחצים על סיום.
הגדרת האפליקציה
כדי להשוות בין אפליקציה מסוימת – שנקראת יעד של Macrobenchmark – לבין אפליקציות אחרות, האפליקציה צריכה להיות profileable, מה שמאפשר לקרוא מידע מפורט על מעקב בלי להשפיע על הביצועים. אשף המודולים מוסיף את התג <profileable> באופן אוטומטי לקובץ AndroidManifest.xml של האפליקציה.
מוודאים שאפליקציית היעד כוללת את ProfilerInstaller 1.3 ואילך, שספריית Macrobenchmark צריכה כדי להפעיל את לכידת הפרופיל, האיפוס והניקוי של מטמון השיידרים.
כדאי להגדיר את האפליקציה להשוואה כמה שיותר קרוב לגרסת הפרסום או לגרסת הייצור. מומלץ להגדיר אותו כלא ניתן לניפוי באגים, ועדיף להפעיל בו מיניפיקציה כדי לשפר את הביצועים. בדרך כלל עושים את זה על ידי יצירת עותק של גרסת הפרסום, שמבצעת את אותה פעולה אבל חתומה באופן מקומי באמצעות מפתחות ניפוי באגים.
אפשר גם להשתמש ב-initWith כדי להנחות את Gradle לעשות זאת בשבילכם:
Kotlin
buildTypes { getByName("release") { isMinifyEnabled = true isShrinkResources = true proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt")) } create("benchmark") { initWith(getByName("release")) signingConfig = signingConfigs.getByName("debug") } }
מגניב
buildTypes { release { isMinifyEnabled = true isShrinkResources = true proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "keep-rules.pro" ) // In real app, this would use its own release keystore signingConfig = signingConfigs.getByName("debug") baselineProfile.automaticGenerationDuringBuild = true } }
כדי לוודא שהפעלת ההשוואה לשוק בונה ובודקת את הגרסה הנכונה של האפליקציה, כמו שמוצג באיור 2, צריך לבצע את הפעולות הבאות:
- מבצעים סנכרון של Gradle.
- פותחים את החלונית Build Variants (וריאציות של גרסאות Build).
- בוחרים את וריאציית ההשוואה לשוק של האפליקציה ושל מודול Macrobenchmark.
(אופציונלי) הגדרת אפליקציה עם כמה מודולים
אם לאפליקציה יש יותר ממודול Gradle אחד, צריך לוודא שסקריפטים ה-build יודעים איזו וריאציה של build לקמפל. מוסיפים את המאפיין matchingFallbacks לסוג ה-build benchmark של מודולי :macrobenchmark ו-:app. שאר מודולי Gradle יכולים להיות עם אותה הגדרה כמו קודם.
Kotlin
create("benchmark") { initWith(getByName("release")) signingConfig = signingConfigs.getByName("debug") matchingFallbacks += listOf("release") }
מגניב
benchmark { initWith buildTypes.release signingConfig signingConfigs.debug matchingFallbacks = ['release'] }
בלי זה, סוג ה-build החדש שנוסף benchmark גורם ל-build להיכשל
ומוצגת הודעת השגיאה הבאה:
> Could not resolve project :shared.
Required by:
project :app
> No matching variant of project :shared was found.
...
כשבוחרים את וריאציות הבנייה בפרויקט, בוחרים באפשרות benchmark עבור המודולים :app ו-:macrobenchmark, ובאפשרות release עבור כל מודול אחר שיש באפליקציה, כמו שמוצג באיור 3:
מידע נוסף זמין במאמר פתרון שגיאות ב-build שקשורות להתאמת וריאנטים.
(אופציונלי) הגדרת טעמים של מוצרים
אם הגדרתם באפליקציה כמה טעמים של מוצרים, צריך להגדיר את מודול :macrobenchmark כך שידע איזה טעם של מוצר לבנות ולמדוד.
בדוגמאות שבדף הזה נעשה שימוש בשני טעמי המוצר במודול :app,
demo ו-production, כמו שמוצג בקטע הקוד הבא:
Kotlin
flavorDimensions += "environment" productFlavors { create("demo") { dimension = "environment" // ... } create("production") { dimension = "environment" // ... } }
מגניב
flavorDimensions 'environment' productFlavors { demo { dimension 'environment' // ... } production { dimension 'environment' // ... } }
בלי ההגדרה הזו, יכול להיות שתקבלו שגיאת build דומה לזו שנגרמת על ידי כמה מודולים של Gradle:
Could not determine the dependencies of task ':macrobenchmark:connectedBenchmarkAndroidTest'.
> Could not determine the dependencies of null.
> Could not resolve all task dependencies for configuration ':macrobenchmark:benchmarkTestedApks'.
> Could not resolve project :app.
Required by:
project :macrobenchmark
> The consumer was configured to find a runtime of a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'benchmark', attribute 'com.android.build.api.attributes.AgpVersionAttr' with value '7.3.0'. However we cannot choose between the following variants of project :app:
- demoBenchmarkRuntimeElements
- productionBenchmarkRuntimeElements
All of them match the consumer attributes:
...
בקטעים הבאים מתוארות דרכים להגדרת השוואה עם כמה גרסאות של מוצרים.
שימוש ב-missingDimensionStrategy
אם מציינים missingDimensionStrategy ב-defaultConfig של המודול :macrobenchmark, מערכת ה-build יודעת לחזור ל-flavor dimension. אם לא מוצאים את המאפיינים במודול, צריך לציין באילו מאפיינים להשתמש.
בדוגמה הבאה, הטעם production משמש כמאפיין ברירת המחדל:
Kotlin
defaultConfig { missingDimensionStrategy("environment", "production") }
מגניב
defaultConfig { missingDimensionStrategy "environment", "production" }
כך, מודול :macrobenchmark יכול לבנות ולמדוד רק את טעם המוצר שצוין, וזה שימושי אם אתם יודעים שלטעם מוצר אחד בלבד יש את ההגדרה המתאימה למדידה.
הגדרת טעמי מוצר במודול :macrobenchmark
אם רוצים ליצור טעמים אחרים של מוצרים ולהשוות אותם, צריך להגדיר אותם במודול :macrobenchmark. מציינים אותו באופן דומה כמו במודול :app, אבל מקצים רק את productFlavors ל-dimension. אין צורך בהגדרות נוספות:
Kotlin
flavorDimensions += "environment" productFlavors { create("demo") { dimension = "environment" } create("production") { dimension = "environment" } }
מגניב
flavorDimensions 'environment' productFlavors { demo { dimension 'environment' } production { dimension 'environment' } }
אחרי שמגדירים ומסנכרנים את הפרויקט, בוחרים את וריאציית ה-build הרלוונטית בחלונית Build Variants, כמו שמוצג באיור 4:
מידע נוסף זמין במאמר פתרון שגיאות ב-build שקשורות להתאמת וריאנטים.
יצירת מחלקה של Macrobenchmark
בדיקות השוואה זמינות דרך כלל MacrobenchmarkRule JUnit4 API בספריית Macrobenchmark. הוא מכיל את השיטה measureRepeated שמאפשרת לציין תנאים שונים להפעלה של אפליקציית היעד ולהשוואה שלה לאפליקציות אחרות.
צריך לציין לפחות את packageName של אפליקציית היעד, את metrics שרוצים למדוד וכמה iterations צריך להריץ את ההשוואה לשוק.
Kotlin
@LargeTest @RunWith(AndroidJUnit4::class) class SampleStartupBenchmark { @get:Rule val benchmarkRule = MacrobenchmarkRule() @Test fun startup() = benchmarkRule.measureRepeated( packageName = TARGET_PACKAGE, metrics = listOf(StartupTimingMetric()), iterations = DEFAULT_ITERATIONS, ) { // starts default launch activity uiAutomator { startApp(TARGET_PACKAGE) } } }
כל האפשרויות להתאמה אישית של ההשוואה לשוק מפורטות בקטע התאמה אישית של ההשוואה לשוק.
השוואה לשוק של אינטראקציות עם ממשק המשתמש של Compose
בדוגמה הקודמת נמדד זמן ההפעלה של האפליקציה, אבל לעיתים קרובות תרצו למדוד את הביצועים של ממשק המשתמש, כמו ירידות בקצב הפריימים (jank) בזמן גלילה.
כדי להשוות בין ביצועים של אפליקציית Jetpack פיתוח נייטיב, למשל כדי למדוד את FrameTimingMetric בזמן גלילה ב-LazyColumn, אפשר להשתמש ב-UI Automator כדי ליצור אינטראקציה ישירה עם צמתי ה-Compose, כמו שמוצג בקטע הקוד הבא.
@LargeTest
@RunWith(AndroidJUnit4::class)
class ComposeScrollBenchmark {
@get:Rule
val benchmarkRule = MacrobenchmarkRule()
@Test
fun scrollLazyColumn() = benchmarkRule.measureRepeated(
packageName = "com.example.compose.app",
metrics = listOf(FrameTimingMetric()),
iterations = 5,
startupMode = StartupMode.WARM,
setupBlock = { pressHome() }
) {
startActivityAndWait()
// Find the Compose node using the testTag defined in your app
val lazyColumn = device.findObject(By.res("my_lazy_column"))
// Simulate a scroll gesture to measure FrameTimingMetric
lazyColumn.setGestureMargin(device.displayWidth / 5)
lazyColumn.fling(Direction.DOWN)
}
}
הפעלת ההשוואה לשוק
מריצים את הבדיקה מתוך Android Studio כדי למדוד את הביצועים של האפליקציה במכשיר. אפשר להריץ את המדדים להשוואה לאמות מידה באותה דרך שבה מריצים כל @Test אחר, באמצעות הפעולה בסרגל הצד שליד מחלקת הבדיקה או המתודה, כמו שמוצג באיור 5.
אפשר גם להריץ את כל בדיקות ההשוואה במודול Gradle משורת הפקודה באמצעות הפקודה connectedCheck:
./gradlew :macrobenchmark:connectedCheckכדי להריץ בדיקה אחת, מריצים את הפקודה הבאה:
./gradlew :macrobenchmark:connectedCheck -P android.testInstrumentationRunnerArguments.class=com.example.macrobenchmark.startup.SampleStartupBenchmark#startupבמאמר השוואה ב-CI מוסבר איך להריץ ולעקוב אחרי נקודות השוואה באינטגרציה רציפה.
תוצאות ההשוואה לשוק
אחרי הפעלת בדיקת ביצועים מוצלחת, המדדים מוצגים ישירות ב-Android Studio ומופקים לשימוש ב-CI בקובץ JSON. כל איטרציה שנמדדת מתעדת מעקב נפרד של המערכת. כדי לפתוח את תוצאות ה-trace, לוחצים על הקישורים בחלונית Test Results (תוצאות הבדיקה), כמו שמוצג באיור 6:
כשקובץ הנתונים נטען, מוצגת ב-Android Studio בקשה לבחור את התהליך שרוצים לנתח. הבחירה מאוכלסת מראש בתהליך של אפליקציית היעד, כפי שמוצג באיור 7:
אחרי שהקובץ של ה-trace נטען, התוצאות מוצגות ב-Studio בכלי CPU profiler:
דוחות JSON וכל עקבות התיעוד מועתקים אוטומטית מהמכשיר למארח. הן נכתבות במכונת המארח במיקום הבא:
project_root/module/build/outputs/connected_android_test_additional_output/debugAndroidTest/connected/device_id/
גישה ידנית לקבצים של פרטי ההעברה
אם רוצים להשתמש בכלי Perfetto כדי לנתח קובץ מעקב, צריך לבצע שלבים נוספים. בעזרת Perfetto אפשר לבדוק את כל התהליכים שמתרחשים במכשיר במהלך המעקב, בעוד שפרופיל המעבד (CPU) של Android Studio מגביל את הבדיקה לתהליך יחיד.
אם מפעילים את הבדיקות מ-Android Studio או משורת הפקודה של Gradle, קובצי המעקב מועתקים באופן אוטומטי מהמכשיר למארח. הם נכתבים במכונת המארח במיקום הבא:
project_root/module/build/outputs/connected_android_test_additional_output/debugAndroidTest/connected/device_id/TrivialStartupBenchmark_startup[mode=COLD]_iter002.perfetto-trace
אחרי שקובץ העקבות נמצא במערכת המארחת, אפשר לפתוח אותו ב-Android Studio באמצעות File > Open (קובץ > פתיחה) בתפריט. כאן מוצגת התצוגה של כלי הפרופילר שמופיעה בקטע הקודם.
שגיאות בהגדרות
אם האפליקציה לא מוגדרת בצורה נכונה – כלומר, אפשר לבצע בה ניפוי באגים או שלא ניתן ליצור ממנה פרופיל – הפונקציה Macrobenchmark מחזירה שגיאה במקום לדווח על מדידה שגויה או לא מלאה. אפשר להשבית את השגיאות האלה באמצעות הארגומנט androidx.benchmark.suppressErrors.
בנוסף, Macrobenchmark מחזיר שגיאות כשמנסים למדוד אמולטור או מכשיר עם סוללה חלשה, כי זה עלול לפגוע בזמינות של ליבות ובמהירות השעון.
התאמה אישית של נקודות ההשוואה
הפונקציה measureRepeated מקבלת פרמטרים שונים שמשפיעים על המדדים שהספרייה אוספת, על האופן שבו האפליקציה מופעלת ומקומפלת או על מספר האיטרציות של נקודת ההשוואה.
תיעוד המדדים
מדדים הם סוג המידע העיקרי שמופק מהשוואות לשוק. המדדים הבאים זמינים:
מידע נוסף על מדדים זמין במאמר תיעוד מדדים של בדיקות השוואה מאקרוסקופיות.
שיפור נתוני המעקב באמצעות אירועים בהתאמה אישית
כדאי להטמיע באפליקציה אירועי מעקב מותאמים אישית, שמוצגים עם שאר דוח המעקב ויכולים לעזור לזהות בעיות שספציפיות לאפליקציה. מידע נוסף על יצירת אירועי מעקב מותאמים אישית זמין במאמר הגדרת אירועים מותאמים אישית.
CompilationMode
במדדי ביצועים ברמת המאקרו אפשר לציין CompilationMode, שמגדיר כמה מהאפליקציה צריך לעבור קומפילציה מראש מקוד בייט של DEX (פורמט קוד הבייט ב-APK) לקוד מכונה (בדומה לקומפילציה מראש של C++).
כברירת מחדל, בדיקות Macrobenchmark מופעלות עם CompilationMode.DEFAULT, שמתקין פרופיל Baseline – אם הוא זמין – ב-Android 7 (רמת API 24) ואילך.
אם אתם משתמשים ב-Android 6 (רמת API 23) או בגרסאות קודמות, מצב הקומפילציה מבצע קומפילציה מלאה של ה-APK כהתנהגות ברירת מחדל של המערכת.
אפשר להתקין פרופיל Baseline אם אפליקציית היעד מכילה גם פרופיל Baseline וגם את ספריית ProfileInstaller.
ב-Android 7 ואילך, אפשר להתאים אישית את CompilationMode כדי להשפיע על כמות ההידור מראש במכשיר, וכך לחקות רמות שונות של הידור מראש (AOT) או שמירת נתונים במטמון של JIT. כדאי לצפות בסרטונים של CompilationMode.Full, CompilationMode.Partial, CompilationMode.None וCompilationMode.Ignore.
התכונה הזו מבוססת על פקודות קומפילציה של ART. כל מדד השוואה מנקה את נתוני הפרופיל לפני שהוא מתחיל, כדי למנוע הפרעות בין מדדי ההשוואה.
StartupMode
כדי להפעיל פעילות, אפשר להעביר מצב הפעלה מוגדר מראש: COLD, WARM או HOT. הפרמטר הזה משנה את אופן ההפעלה של הפעילות ואת מצב התהליך בתחילת הבדיקה.
מידע נוסף על סוגי ההפעלה זמין במאמר זמן ההפעלה של האפליקציה.
דוגמאות
פרויקט לדוגמה זמין בMacrobenchmark Sample במאגר ב-GitHub.
שליחת משוב
כדי לדווח על בעיות או לשלוח בקשות לתכונות חדשות ב-Jetpack Macrobenchmark, אפשר להיכנס אל הכלי הציבורי למעקב אחר בעיות.
מומלץ בשבילך
- הערה: טקסט הקישור מוצג כש-JavaScript מושבת
- איסוף מדדים של ספריית Macrobenchmark
- יצירת פרופיל Baseline {:#creating-profile-rules}
- אוטומציה של מדידה באמצעות ספריית Macrobenchmark {:#measuring-optimization}