כתיבת נתוני מיקרובנצ'מרק

כדי ללמוד איך להשתמש בספריית ה-Microbenchmark על ידי הוספת שינויים את הקוד של האפליקציה, ראו מדריך למתחילים. כדי ללמוד איך להשלים הגדרה מלאה עם שינויים מורכבים יותר ב-codebase. קטע בנושא הגדרת פרויקט מלאה.

מדריך למתחילים

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

כדי לבצע בדיקת ביצועים חד-פעמית:

  1. מוסיפים את הספרייה לקובץ build.gradle או build.gradle.kts של המודול:

    Kotlin

    dependencies {
        implementation("androidx.benchmark:benchmark-junit4:1.2.4")
    }
    

    Groovy

    dependencies {
        implementation 'androidx.benchmark:benchmark-junit4:1.2.4'
    }
    

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

  2. מעדכנים את סוג ה-build של debug כדי שלא יהיה ניתן לניפוי באגים:

    Kotlin

    android {
        ...
        buildTypes {
            debug {
                isDebuggable = false
            }
        }
    }
    

    מגניב

    android {
        ...
        buildTypes {
            debug {
                debuggable false
            }
        }
    }
    
  3. משנים את הערך של testInstrumentationRunner ל-AndroidBenchmarkRunner:

    Kotlin

    android {
        ...
        defaultConfig {
            testInstrumentationRunner = "androidx.benchmark.junit4.AndroidBenchmarkRunner"
        }
    }
    

    Groovy

    android {
        ...
        defaultConfig {
            testInstrumentationRunner "androidx.benchmark.junit4.AndroidBenchmarkRunner"
        }
    }
    
  4. מוסיפים מופע של BenchmarkRule בקובץ בדיקה בתיקייה androidTest כדי להוסיף את מדד הביצועים. מידע נוסף על כתיבת מדדי ביצועים זמין במאמר יצירת כיתה של מדדי ביצועים מיקרו.

    בקטע הקוד הבא מוצג איך מוסיפים בדיקת ביצועים למבחן עם כלי למדידת ביצועים:

    Kotlin

    @RunWith(AndroidJUnit4::class)
    class SampleBenchmark {
        @get:Rule
        val benchmarkRule = BenchmarkRule()
    
        @Test
        fun benchmarkSomeWork() {
            benchmarkRule.measureRepeated {
                doSomeWork()
            }
        }
    }
    

    Java

    @RunWith(AndroidJUnit4.class)
    class SampleBenchmark {
        @Rule
        public BenchmarkRule benchmarkRule = new BenchmarkRule();
    
        @Test
        public void benchmarkSomeWork() {
                BenchmarkRuleKt.measureRepeated(
                    (Function1<BenchmarkRule.Scope, Unit>) scope -> doSomeWork()
                );
           }
        }
    }
    

כדי ללמוד איך לכתוב בדיקת ביצועים, אפשר לדלג לקטע יצירת כיתה של בדיקת ביצועים ברמת המיקרו.

הגדרה מלאה של הפרויקט

כדי להגדיר השוואות ביצועים קבועות במקום השוואות חד-פעמיות, צריך להפריד את ההשוואות למודול משלהם. כך אפשר להבטיח שההגדרות שלהם, כמו הגדרת debuggable ל-false, יהיו נפרדות מהבדיקות הרגילות.

מאחר שמערכת Microbenchmark מריצה את הקוד שלך ישירות, עליך למקם את הקוד הרצוי בנצ'מרק למודול Gradle נפרד, ולהגדיר את התלות במודול הזה בתור שמוצגת באיור 1.

מבנה האפליקציה
איור 1. מבנה האפליקציה עם :app, :microbenchmark ו-:benchmarkable Gradle , שמאפשר ל-Microbenchmarks מודול :benchmarkable.

כדי להוסיף מודול Gradle חדש, תוכלו להשתמש באשף המודולים ב-Android Studio. האשף יוצר מודול שמוגדר מראש לבדיקת ביצועים, עם הוספה של ספריית ביצועים והגדרה של debuggable כ-false.

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

  2. בוחרים את האפשרות השוואה לשוק בחלונית תבניות.

  3. בוחרים באפשרות Microbenchmark בתור סוג המודול של ההשוואה לשוק.

  4. מקלידים microbenchmark בשם המודול.

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

הגדרת מודול ספרייה חדש
איור 2. הוספה של מודול Gradle חדש ב-Android Studio דבורה.

לאחר יצירת המודול, משנים את build.gradle או build.gradle.kts שלו ומוסיפים את androidTestImplementation למודול שמכיל את הקוד בנצ'מרק:

Kotlin

dependencies {
    // The module name might be different.
    androidTestImplementation(project(":benchmarkable"))
}

Groovy

dependencies {
    // The module name might be different.
    androidTestImplementation project(':benchmarkable')
}

יצירת כיתה של Microbenchmark

נקודות השוואה הן בדיקות אינסטרומנטציה רגילות. כדי ליצור מדד ביצועים, משתמשים בכיתה BenchmarkRule שסופקת על ידי הספרייה. כדי ליצור נקודות השוואה לפעילויות, משתמשים ב-ActivityScenario או ב-ActivityScenarioRule. כדי לבדוק את קוד ממשק המשתמש כנקודת השוואה, להשתמש ב-@UiThreadTest.

הקוד הבא מציג נקודת השוואה לדוגמה:

Kotlin

@RunWith(AndroidJUnit4::class)
class SampleBenchmark {
    @get:Rule
    val benchmarkRule = BenchmarkRule()

    @Test
    fun benchmarkSomeWork() {
        benchmarkRule.measureRepeated {
            doSomeWork()
        }
    }
}
    

Java

@RunWith(AndroidJUnit4.class)
class SampleBenchmark {
    @Rule
    public BenchmarkRule benchmarkRule = new BenchmarkRule();

    @Test
    public void benchmarkSomeWork() {
        final BenchmarkState state = benchmarkRule.getState();
        while (state.keepRunning()) {
            doSomeWork();
        }
    }
}
    

השבתת התזמון להגדרה

אפשר להשבית את התזמון של קטעי קוד שאתם לא רוצים למדוד באמצעות runWithTimingDisabled{}. בדרך כלל הקטעים האלה מייצגים שצריך להריץ בכל איטרציה של נקודת ההשוואה.

Kotlin

// using random with the same seed, so that it generates the same data every run
private val random = Random(0)

// create the array once and just copy it in benchmarks
private val unsorted = IntArray(10_000) { random.nextInt() }

@Test
fun benchmark_quickSort() {
    // ...
    benchmarkRule.measureRepeated {
        // copy the array with timing disabled to measure only the algorithm itself
        listToSort = runWithTimingDisabled { unsorted.copyOf() }

        // sort the array in place and measure how long it takes
        SortingAlgorithms.quickSort(listToSort)
    }

    // assert only once not to add overhead to the benchmarks
    assertTrue(listToSort.isSorted)
}
    

Java

private final int[] unsorted = new int[10000];

public SampleBenchmark() {
    // Use random with the same seed, so that it generates the same data every
    // run.
    Random random = new Random(0);

    // Create the array once and copy it in benchmarks.
    Arrays.setAll(unsorted, (index) -> random.nextInt());
}

@Test
public void benchmark_quickSort() {
    final BenchmarkState state = benchmarkRule.getState();

    int[] listToSort = new int[0];

    while (state.keepRunning()) {
        
        // Copy the array with timing disabled to measure only the algorithm
        // itself.
        state.pauseTiming();
        listToSort = Arrays.copyOf(unsorted, 10000);
        state.resumeTiming();
        
        // Sort the array in place and measure how long it takes.
        SortingAlgorithms.quickSort(listToSort);
    }

    // Assert only once, not to add overhead to the benchmarks.
    assertTrue(SortingAlgorithmsKt.isSorted(listToSort));
}
    

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

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

ב-Android Studio, אפשר להריץ את ההשוואה לשוק כמו בכל מכשיר @Test באמצעות מעל כיתת הבדיקה או שיטת הבדיקה, כפי שמוצג באיור 3.

הפעלת Microbench
איור 3. הרצת בדיקת המיקרובנצ'מרק באמצעות פעולת המרזב שליד כיתת מבחן.

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

./gradlew benchmark:connectedCheck

או בדיקה אחת:

./gradlew benchmark:connectedCheck -P android.testInstrumentationRunnerArguments.class=com.example.benchmark.SampleBenchmark#benchmarkSomeWork

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

אחרי הרצת Microbenchmark מוצלחת, המדדים מוצגים ישירות ב-Android Studio, ודוח מלא של מדדי ביצועים עם מדדים נוספים ומידע על המכשיר זמין בפורמט JSON.

תוצאות של מיקרו-בדיקות
איור 4. תוצאות של בדיקות מיקרו-ביצועים.

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

project_root/module/build/outputs/connected_android_test_additional_output/debugAndroidTest/connected/device_id/

כברירת מחדל, דוח ה-JSON נכתב בדיסק במכשיר בתיקיית המדיה המשותפת החיצונית של קובץ ה-APK לבדיקה, שנמצאת בדרך כלל ב-/storage/emulated/0/Android/media/**app_id**/**app_id**-benchmarkData.json.

שגיאות בהגדרות

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

  • האפשרות 'ניפוי באגים' מוגדרת לfalse.
  • נעשה שימוש במכשיר פיזי. אין תמיכה באמולטורים.
  • השעונים ננעלים אם המכשיר עבר תהליך רוט (Root).
  • רמת טעינה מספקת של הסוללה במכשיר של 25% לפחות.

אם אחת מהבדיקות הקודמות נכשלה, נקודת ההשוואה תדווח שגיאה ל- למנוע מדידות לא מדויקות.

כדי להסתיר סוגים מסוימים של שגיאות כאזהרות ולמנוע מהם לעצור את בנצ'מרק, מעבירים את סוג השגיאה ברשימה מופרדת בפסיקים ארגומנט androidx.benchmark.suppressErrors.

אפשר להגדיר את זה בסקריפט של Gradle, כמו בדוגמה הבאה:

Kotlin

android {
    defaultConfig {
       …
      testInstrumentationRunnerArguments["androidx.benchmark.suppressErrors"] = "DEBUGGABLE,LOW-BATTERY"
    }
}

מגניב

android {
    defaultConfig {
       …
      testInstrumentationRunnerArguments["androidx.benchmark.suppressErrors"] = "DEBUGGABLE,LOW-BATTERY"
    }
}

אפשר גם לדכא שגיאות משורת הפקודה:

$ ./gradlew :benchmark:connectedCheck -P andoidtestInstrumentationRunnerArguments.androidx.benchmark.supperssErrors=DEBUGGABLE,LOW-BATTERY

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