Menulis Microbenchmark

Anda dapat dengan cepat mulai menggunakan library Microbenchmark dengan menambahkan perubahan pada kode aplikasi. Untuk penyiapan project yang tepat, ikuti bagian Penyiapan lengkap, yang memerlukan perubahan yang lebih rumit pada codebase Anda.

Panduan memulai

Bagian ini memberikan panduan singkat untuk mencoba benchmark dan menjalankan pengukuran satu kali tanpa mengharuskan Anda untuk memindahkan kode ke dalam modul. Untuk hasil performa yang akurat, langkah-langkah ini melibatkan penonaktifan proses debug dalam aplikasi, sehingga Anda harus menyimpannya dalam direktori file pribadi tanpa melakukan perubahan pada sistem kontrol sumber.

Untuk menjalankan benchmark satu kali dengan cepat, lakukan hal berikut:

  1. Tambahkan library ke file build.gradle modul Anda:

    project_root/module_dir/build.gradle

    Groovy

    dependencies {
        androidTestImplementation 'androidx.benchmark:benchmark-junit4:1.1.0-beta03'
    }
    

    Kotlin

    dependencies {
        androidTestImplementation("androidx.benchmark:benchmark-junit4:1.1.0-beta03")
    }
    
  2. Untuk menonaktifkan proses debug di manifes pengujian, update elemen <application> untuk menonaktifkan paksa proses debug sementara:

    project_root/module_dir/src/androidTest/AndroidManifest.xml

    <!-- Important: disable debuggable for accurate performance results -->
    <application
        android:debuggable="false"
        tools:ignore="HardcodedDebugMode"
        tools:replace="android:debuggable"/>
    
  3. Untuk menambahkan benchmark, tambahkan instance dari BenchmarkRule dalam file pengujian di direktori androidTest. Untuk informasi selengkapnya tentang penulisan benchmark, lihat Membuat class Microbenchmark.

    Cuplikan kode berikut ini menunjukkan cara menambahkan benchmark ke pengujian JUnit:

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

Untuk melihat cara menulis benchmark, buka bagian Membuat class Microbenchmark.

Penyiapan project lengkap

Untuk menyiapkan benchmark reguler, bukan benchmark satu kali, isolasi benchmark ke dalam modulnya sendiri. Tindakan ini memastikan konfigurasi modul, seperti menyetel debuggable ke false, terpisah dari pengujian reguler.

Karena Microbenchmark menjalankan kode Anda secara langsung, Anda harus menempatkan kode yang ingin diukur dalam modul Gradle terpisah dan menetapkan dependensi pada modul tersebut seperti yang ditunjukkan pada gambar berikut.

Struktur aplikasi dengan modul Gradle :app, :microbenchmark dan :benchmarkable
yang memungkinkan Microbenchmark mengukur kode dalam modul
:benchmarkable.

Untuk menambahkan modul Gradle baru, Anda dapat menggunakan wizard modul di Android Studio. Wizard membuat modul yang telah dikonfigurasi sebelumnya untuk benchmark, dengan menambahkan direktori benchmark serta menyetel debuggable ke false.

Bumblebee (atau yang lebih baru)

  1. Klik kanan project atau modul di panel Project di Android Studio, lalu klik New > Module.
  2. Pilih Benchmark di panel Templates.
  3. Pilih Microbenchmark sebagai Benchmark module type (jenis modul Benchmark).
  4. Ketik microbenchmark sebagai nama modul.
  5. Klik Finish.
  6. Mengonfigurasi modul library baru

Arctic Fox

  1. Klik kanan project atau modul di panel Project di Android Studio, lalu klik New > Module.
  2. Pilih Benchmark di panel Templates.
  3. Ketik microbenchmark sebagai nama modul.
  4. Klik Finish.
  5. Mengonfigurasi modul library baru

Setelah modul dibuat, ubah file build.gradle dan tambahkan testImplementation ke modul yang berisi kode untuk diukur:

Groovy

dependencies {
    // Note, that the module name may be different
    androidTestImplementation project(':benchmarkable')
}

Kotlin

dependencies {
    // Note, that the module name may be different
    androidTestImplementation(project(":benchmarkable"))
}

Membuat class Microbenchmark

Benchmark adalah pengujian instrumentasi standar. Untuk membuat benchmark, gunakan class BenchmarkRule yang disediakan oleh library. Untuk menjalankan benchmark aktivitas, gunakan ActivityTestRule atau ActivityScenarioRule. Untuk menjalankan benchmark kode UI, gunakan @UiThreadTest.

Kode berikut menunjukkan benchmark contoh:

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

Menonaktifkan pengaturan waktu untuk penyiapan

Anda dapat menonaktifkan pengaturan waktu untuk bagian kode yang tidak ingin diukur dengan blok runWithTimingDisabled{}. Bagian ini biasanya mewakili beberapa kode yang harus Anda jalankan pada setiap iterasi benchmark.

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() {
    // using random with the same seed, so that it generates the same data every run
    Random random = new Random(0);

    // create the array once and just 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));
}
    

Cobalah untuk meminimalkan jumlah pekerjaan yang dilakukan di dalam blok measureRepeated, serta di dalam runWithTimingDisabled. Blok measureRepeated dijalankan beberapa kali dan dapat memengaruhi keseluruhan waktu yang diperlukan untuk menjalankan benchmark. Jika Anda perlu memverifikasi beberapa hasil benchmark, Anda dapat menyatakan hasil terakhir, bukan melakukannya pada setiap iterasi benchmark.

Menjalankan benchmark

Di Android Studio, jalankan benchmark seperti halnya @Test dengan menggunakan tindakan gutter di samping class atau metode pengujian, seperti yang ditunjukkan pada gambar berikut.

Menjalankan pengujian Microbenchmark menggunakan tindakan gutter di samping class pengujian

Atau, jalankan connectedCheck dari command line untuk menjalankan semua pengujian dari modul Gradle yang ditentukan:

./gradlew benchmark:connectedCheck

Atau satu pengujian:

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

Hasil benchmark

Setelah Microbenchmark berhasil dijalankan, metrik akan ditampilkan langsung di Android Studio dan laporan benchmark lengkap dengan metrik tambahan serta informasi perangkat tersedia dalam format JSON. Plugin Gradle androidx.benchmark mengaktifkan output JSON secara default.

Hasil Microbenchmark

Secara default, laporan JSON ditulis ke disk di perangkat dalam folder media bersama eksternal APK pengujian, yang biasanya terletak di /storage/emulated/0/Android/media/app_id/app_id-benchmarkData.json.

Laporan JSON juga otomatis disalin dari perangkat ke host. Laporan tersebut ditulis pada mesin host di:

project_root/module/build/outputs/connected_android_test_additional_output/debugAndroidTest/connected/device_id/app_id-benchmarkData.json

Error konfigurasi

Library akan mendeteksi kondisi berikut guna memastikan project dan lingkungan Anda telah disiapkan untuk performa akurat rilis:

  • Debuggable disetel ke false.
  • Perangkat fisik sedang digunakan (emulator tidak didukung).
  • Frekuensi CPU terkunci jika perangkat di-root.
  • Tingkat daya baterai pada perangkat (setidaknya 25%).

Jika salah satu pemeriksaan sebelumnya gagal, benchmark akan melaporkan error untuk mencegah pengukuran yang tidak akurat.

Untuk menyembunyikan jenis error tertentu sebagai peringatan dan mencegahnya menghentikan benchmark, teruskan jenis error dalam daftar yang dipisahkan koma ke argumen instrumentasi androidx.benchmark.suppressErrors.

Ini dapat disetel dari skrip Gradle Anda seperti yang ditunjukkan di bawah ini:

Groovy

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

Kotlin

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

Menyembunyikan error memungkinkan benchmark berjalan dalam keadaan yang tidak dikonfigurasi dengan benar, dan output dari benchmark sengaja diganti namanya dengan menambahkan error tersebut ke nama pengujian. Misalnya, menjalankan benchmark yang dapat di-debug dengan penghentian dalam cuplikan sebelumnya akan menambahkan DEBUGGABLE_ ke nama pengujian.