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

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

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

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

כדי לבצע השוואה חד-פעמית:

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

    Kotlin

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

    מגניב

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

    צריך להשתמש בתלות של 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"
        }
    }
    

    מגניב

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

    קטע הקוד הבא מראה איך להוסיף נקודת השוואה לערוץ בדיקה:

    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()
                );
           }
        }
    }
    

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

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

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

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

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

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

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

  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"))
}

מגניב

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.

תוצאות המיקרובנצ&#39;מרק
איור 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_ לפני שמות הבדיקה.