כתיבה של נקודת מאקרו בנצ'מרק

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

הספרייה מפיקה תוצאות השוואה לביצועים גם במסוף של Android Studio וגם בקובץ JSON עם פרטים נוספים. הוא גם מספק קבצים של נתוני מעקב שאפשר לטעון ולנתח ב-Android Studio.

שימוש בספריית Macrobenchmark בסביבת אינטגרציה רציפה (CI), כמו שמתואר במאמר השוואה בין ביצועים באינטגרציה רציפה.

אפשר להשתמש ב-Macrobenchmark כדי ליצור פרופילים של Baseline. קודם מגדירים את ספריית Macrobenchmark, ואז אפשר ליצור פרופיל Baseline.

הגדרת הפרויקט

מומלץ להשתמש ב-Macrobenchmark עם הגרסה העדכנית של Android Studio כדי ליהנות מתכונות של סביבת הפיתוח המשולבת שמשולבות עם Macrobenchmark.

הגדרת מודול Macrobenchmark

בדיקות מאקרו דורשות מודול com.android.test נפרד מקוד האפליקציה, שאחראי להרצת הבדיקות שמודדות את האפליקציה.

ב-Android Studio יש תבנית שמאפשרת להגדיר מודול Macrobenchmark בקלות. תבנית מודול ההשוואה יוצרת באופן אוטומטי מודול בפרויקט כדי למדוד את האפליקציה שנבנתה על ידי מודול האפליקציה, כולל השוואה לדוגמה של זמן ההפעלה.

כדי להשתמש בתבנית של מודול כדי ליצור מודול חדש:

  1. לוחצים לחיצה ימנית על הפרויקט או המודול בחלונית Project (פרויקט) ב-Android Studio, ובוחרים באפשרות New > Module (חדש > מודול).

  2. בוחרים באפשרות השוואה לשוק בחלונית תבניות. אתם יכולים להתאים אישית את אפליקציית היעד – כלומר, האפליקציה שרוצים להשוות לביצועים של אפליקציות אחרות – וגם את שם החבילה והמודול של מודול Macrobenchmark החדש.

  3. לוחצים על סיום.

תבנית Benchmark Module

איור 1. תבנית של מודול השוואה לשוק.

הגדרת האפליקציה

כדי להשוות אפליקציה – שנקראת יעד של המדד המאקרו – האפליקציה צריכה להיות profileable, מה שמאפשר לקרוא מידע מפורט על המעקב בלי להשפיע על הביצועים. אשף המודולים מוסיף את התג <profileable> באופן אוטומטי לקובץ AndroidManifest.xml של האפליקציה.

מוודאים שאפליקציית היעד כוללת את ProfilerInstaller בגרסה 1.3 ומעלה, שספריית Macrobenchmark צריכה כדי להפעיל את השמירה והאיפוס של הפרופיל ואת ניקוי המטמון של Shader.

כדאי להגדיר את האפליקציה להשוואה כמה שיותר קרוב לגרסת הפרסום או לסביבת הייצור. מומלץ להגדיר אותו כלא ניתן לניפוי באגים, ועדיף להפעיל בו מיניפיקציה כדי לשפר את הביצועים. בדרך כלל עושים את זה על ידי יצירת עותק של גרסת ההפצה, שמבצעת את אותה פעולה, אבל חותמת באופן מקומי באמצעות מפתחות ניפוי באגים. אפשר גם להשתמש בפקודה 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, צריך לבצע את הפעולות הבאות:

  1. מבצעים סנכרון של Gradle.
  2. פותחים את החלונית Build Variants.
  3. בוחרים את וריאציית ההשוואה לשוק של האפליקציה ושל מודול Macrobenchmark.

בחירת וריאציה להשוואה

איור 2. בוחרים את וריאציית ההשוואה.

(אופציונלי) הגדרת אפליקציה מרובת מודולים

אם לאפליקציה יש יותר ממודול Gradle אחד, צריך לוודא שסקריפטים ה-build יודעים איזו וריאציה של build לקמפל. מוסיפים את המאפיין matchingFallbacks לסוג ה-build של מודולי :macrobenchmark ו-:app.benchmark שאר מודולי 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 להפצה ולהשוואה שנבחרו

איור 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:

וריאציות להשוואה לפרויקט עם טעמים של מוצרים שמוצגים
productionBenchmark ו-release
נבחרו

איור 4. השוואה בין וריאציות של המוצר בפרויקט עם טעמי מוצר שמוצגים, כשהאפשרויות 'productionBenchmark' ו-'release' מסומנות.

מידע נוסף זמין במאמר פתרון שגיאות ב-build שקשורות להתאמת וריאנטים.

יצירת מחלקה של בדיקת ביצועים

בדיקות השוואה זמינות דרך כלל 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) }
    }
}

Java

@LargeTest
@RunWith(AndroidJUnit4.class)
public class SampleStartupBenchmark {
    @Rule
    public MacrobenchmarkRule benchmarkRule = new MacrobenchmarkRule();

    @Test
    public void startup() {
        benchmarkRule.measureRepeated(
            /* packageName */ TARGET_PACKAGE,
            /* metrics */ Arrays.asList(new StartupTimingMetric()),
            /* iterations */ 5,
            /* measureBlock */ scope -> {
                // starts default launch activity
                scope.startActivityAndWait();
                return Unit.INSTANCE;
            }
        );
    }
}

כל האפשרויות להתאמה אישית של ההשוואה זמינות בקטע התאמה אישית של ההשוואות.

הפעלת ההשוואה לשוק

מריצים את הבדיקה מתוך Android Studio כדי למדוד את הביצועים של האפליקציה במכשיר. אפשר להריץ את המדדים המשווים באותה דרך שבה מריצים כל @Test אחר. לשם כך, משתמשים בפעולת השוליים שליד מחלקת הבדיקה או המתודה, כמו שמוצג באיור 5.

הרצת Macrobenchmark עם פעולת שוליים לצד מחלקת הבדיקה

איור 5. מריצים את Macrobenchmark באמצעות הפעולה שמופיעה בשולי עורך הקוד לצד מחלקת הבדיקה.

אפשר גם להריץ את כל בדיקות ההשוואה במודול Gradle משורת הפקודה באמצעות הפקודה connectedCheck:

./gradlew :macrobenchmark:connectedCheck

כדי להריץ בדיקה אחת, מריצים את הפקודה הבאה:

./gradlew :macrobenchmark:connectedCheck -P android.testInstrumentationRunnerArguments.class=com.example.macrobenchmark.startup.SampleStartupBenchmark#startup

במאמר השוואה ב-Continuous Integration מוסבר איך להריץ ולעקוב אחרי נקודות השוואה ב-Continuous Integration.

תוצאות ההשוואה לשוק

אחרי הפעלת בדיקת ביצועים מוצלחת, המדדים מוצגים ישירות ב-Android Studio ומופקים לשימוש ב-CI בקובץ JSON. כל איטרציה שנמדדת מתעדת מעקב נפרד של המערכת. כדי לפתוח את תוצאות ה-trace, לוחצים על הקישורים בחלונית Test Results, כמו שמוצג באיור 6:

תוצאות של הפעלה של Macrobenchmark

איור 6. תוצאות ההפעלה של Macrobenchmark.

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

תהליך המעקב ב-Studio
בחירה

איור 7. בחירת תהליך המעקב ב-Studio.

אחרי שהקובץ של ה-trace נטען, התוצאות מוצגות ב-Studio בכלי CPU profiler:

Studio
Trace

איור 8. תיעוד עקבות ב-Studio.

דוחות 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, אפשר להיעזר בכלי הציבורי למעקב אחר בעיות.