כדאי להשתמש בספריית Macrobenchmark כדי לבדוק תרחישי שימוש גדולים יותר באפליקציה, כולל הפעלת האפליקציה ושינויים מורכבים בממשק המשתמש, כמו גלילה ב-LazyColumn או הפעלת אנימציות. אם אתם רוצים לבדוק אזורים קטנים יותר בקוד, עיינו במאמר Microbenchmark. בדף הזה מוסבר איך להגדיר את ספריית Macrobenchmark.
הספרייה מפיקה תוצאות של בדיקות ביצועים למסוף Android Studio ולקובץ JSON עם פרטים נוספים. הוא גם מספק קובצי מעקב שאפשר לטעון ולנתח ב-Android Studio.
משתמשים בספריית Macrobenchmark בסביבת אינטגרציה רציפה (CI), כמו שמתואר במאמר בדיקת ביצועים באינטגרציה רציפה.
אתם יכולים להשתמש ב-Macrobenchmark כדי ליצור פרופילי Baseline. קודם מגדירים את ספריית Macrobenchmark, ואז אפשר ליצור פרופיל Baseline.
Macrobenchmark הוא הכלי המומלץ לבדיקת ממשקי משתמש שנוצרו באמצעות Jetpack פיתוח נייטיב. כדי ללמוד איך לכתוב בדיקות של UI Automator שמקיימות אינטראקציה עם צומתי פיתוח נייטיב, אפשר לעיין במאמר בנושא יכולת פעולה הדדית.
הגדרת הפרויקט
מומלץ להשתמש ב-Macrobenchmark עם הגרסה העדכנית של Android Studio.
הגדרת המודול Macrobenchmark
כדי להשתמש ב-Macrobenchmark, צריך מודול com.android.test – נפרד מקוד האפליקציה – שאחראי על הרצת הבדיקות שמודדות את האפליקציה.
ב-Android Studio יש תבנית שמאפשרת לפשט את ההגדרה של מודול Macrobenchmark. תבנית המודול להשוואה יוצרת באופן אוטומטי מודול בפרויקט כדי למדוד את האפליקציה שנוצרה על ידי מודול האפליקציה, כולל השוואה לדוגמה של זמן ההפעלה.
כדי להשתמש בתבנית המודול ליצירת מודול חדש:
לוחצים לחיצה ימנית על הפרויקט או המודול בחלונית Project ב-Android Studio, ובוחרים באפשרות New > Module.
בחלונית תבניות, בוחרים באפשרות נקודת השוואה. אתם יכולים להתאים אישית את אפליקציית היעד – כלומר האפליקציה שרוצים לבדוק – וגם את שם החבילה והמודול של המודול החדש של Macrobenchmark.
לוחצים על סיום.
הגדרת האפליקציה
כדי לבצע השוואה של אפליקציה – שנקראת יעד של Macrobenchmark – האפליקציה צריכה להיות profileable, שמאפשרת לקרוא מידע מפורט על המעקב בלי להשפיע על הביצועים. אשף המודולים מוסיף את התג <profileable> באופן אוטומטי לקובץ AndroidManifest.xml של האפליקציה.
מוודאים שאפליקציית היעד כוללת את ProfilerInstaller בגרסה 1.3 ואילך, שנדרשת לספריית Macrobenchmark כדי להפעיל את תיעוד הפרופיל, לאפס אותו ולנקות את המטמון של ה-shader.
הגדירו את האפליקציה להשוואה כמה שיותר קרוב לגרסת ההפצה או לסביבת הייצור. מגדירים אותו כלא ניתן לניפוי באגים, ורצוי להפעיל את ההקטנה (minify) כדי לשפר את הביצועים. בדרך כלל עושים את זה על ידי יצירת עותק של גרסת ה-release, שפועלת באותו אופן אבל חתומה באופן מקומי באמצעות מפתחות ניפוי באגים.
אפשר גם להשתמש ב-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.
- בוחרים את גרסת ההשוואה לשוק של האפליקציה ושל מודול 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.
...
כשבוחרים את וריאנט ה-build בפרויקט, בוחרים באפשרות 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 משתמשת בקבוצת הגרסאות כחלופה. ציינו באילו מאפיינים להשתמש אם אתם לא מוצאים אותם במודול.
בדוגמה הבאה, המאפיין 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
בדיקות השוואה מסופקות דרך ה-API של הכלל MacrobenchmarkRule JUnit4 בספריית 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 Compose, למשל כדי למדוד את 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. כל איטרציה שנמדדת מתעדת עקבות מערכת נפרדים. כדי לפתוח את תוצאות המעקב, לוחצים על הקישורים בחלונית Test Results, כמו שמוצג באיור 6:
כשהמעקב נטען, Android Studio מבקש לבחור את התהליך לניתוח. הבחירה מאוכלסת מראש בתהליך של אפליקציית היעד, כפי שמוצג באיור 7:
אחרי שקובץ המעקב נטען, ב-Studio מוצגות התוצאות בכלי CPU Profiler:
דוחות JSON וכל עקבות הפרופילים מועתקים גם הם באופן אוטומטי מהמכשיר למארח. הם נכתבים במכונה המארחת במיקום הבא:
project_root/module/build/outputs/connected_android_test_additional_output/debugAndroidTest/connected/device_id/
גישה ידנית לקובצי מעקב
אם אתם רוצים להשתמש בכלי Perfetto כדי לנתח קובץ מעקב, יש שלבים נוספים שצריך לבצע. בעזרת Perfetto אפשר לבדוק את כל התהליכים שמתרחשים במכשיר במהלך המעקב, ואילו ב-CPU Profiler ב-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 מקבלת פרמטרים שונים שמשפיעים על המדדים שהספרייה אוספת, על האופן שבו האפליקציה מופעלת ומקומפלת, או על מספר האיטרציות שהבנצ'מרק מריץ.
תיעוד המדדים
המדדים הם סוג המידע העיקרי שמופק מההשוואות לשוק. המדדים הבאים זמינים:
מידע נוסף על מדדים זמין במאמר תיעוד מדדי Macrobenchmark.
שיפור נתוני המעקב באמצעות אירועים בהתאמה אישית
כדאי להוסיף לאפליקציה אירועי מעקב מותאמים אישית, שמופיעים עם שאר דוח המעקב ויכולים לעזור לכם לזהות בעיות ספציפיות לאפליקציה. מידע נוסף על יצירת אירועי מעקב מותאמים אישית זמין במאמר הגדרת אירועים מותאמים אישית.
CompilationMode
ב-Macrobenchmarks אפשר לציין CompilationMode, שמגדיר כמה מהאפליקציה צריך לעבור הידור מראש מקוד בייט של DEX (פורמט קוד הבייט ב-APK) לשפת מכונה (בדומה ל-C++ שעבר הידור מראש).
כברירת מחדל, Macrobenchmarks פועלים עם 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.
- בנקודות ההשוואה של Hero מופיע מקרה אמיתי לדוגמה שבו משתמשים ב-Macrobenchmark כדי למדוד את ביצועי ההפעלה והגלילה ב-Jetpack Compose ובתצוגות.
שליחת משוב
כדי לדווח על בעיות או להגיש בקשות להוספת תכונות ל-Jetpack Macrobenchmark, אפשר להשתמש בכלי הציבורי למעקב אחר בעיות.