Menulis Microbenchmark

Untuk mempelajari cara menggunakan library Microbenchmark dengan menambahkan perubahan pada kode aplikasi Anda, lihat bagian Panduan Memulai. Untuk mempelajari cara menyelesaikan penyiapan lengkap dengan perubahan yang lebih rumit pada codebase Anda, lihat bagian Penyiapan project lengkap.

Panduan memulai

Bagian ini menunjukkan cara mencoba benchmark dan menjalankan pengukuran satu kali tanpa perlu memindahkan kode ke dalam modul. Untuk mendapatkan hasil performa yang akurat, maka langkah-langkah ini akan melibatkan penonaktifan proses debug di aplikasi Anda. Jadi, simpan tindakan ini dalam salinan yang berfungsi secara lokal tanpa melakukan perubahan pada sistem kontrol sumber Anda.

Untuk menjalankan benchmark satu kali, lakukan hal berikut:

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

    Kotlin

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

    Groovy

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

    Gunakan dependensi implementation, bukan dependensi androidTestImplementation. Jika Anda menggunakan androidTestImplementation, benchmark gagal berjalan karena manifes library tidak digabungkan ke dalam manifes aplikasi.

  2. Perbarui jenis build debug agar tidak dapat di-debug:

    Kotlin

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

    Groovy

    android {
        ...
        buildTypes {
            debug {
                debuggable false
            }
        }
    }
  3. Ubah testInstrumentationRunner menjadi AndroidBenchmarkRunner:

    Kotlin

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

    Groovy

    android {
        ...
        defaultConfig {
            testInstrumentationRunner "androidx.benchmark.junit4.AndroidBenchmarkRunner"
        }
    }
  4. Tambahkan instance BenchmarkRule dalam file pengujian di direktori androidTest untuk menambahkan benchmark. Untuk informasi selengkapnya tentang penulisan benchmark, lihat Membuat class Microbenchmark.

    Cuplikan kode berikut menunjukkan cara menambahkan benchmark ke Pengujian berinstrumen:

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

Untuk mempelajari cara menulis benchmark, lanjutkan ke Membuat class Microbenchmark.

Penyiapan project lengkap

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

Karena Microbenchmark menjalankan kode Anda secara langsung, tempatkan kode yang ingin Anda ukur ke dalam modul Gradle terpisah lalu tetapkan dependensi pada modul tersebut seperti ditunjukkan dalam gambar 1.

struktur aplikasi
Gambar 1. Struktur aplikasi dengan modul Gradle :app, :microbenchmark, dan :benchmarkable, yang memungkinkan kode benchmark Microbenchmark dalam modul :benchmarkable.

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

  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 jenis modul Benchmark.

  4. Ketik "microbenchmark" untuk nama modul.

  5. Klik Finish.

Mengonfigurasi modul library baru
Gambar 2. Tambahkan modul Gradle baru di Android Studio Bumblebee.

Setelah modul dibuat, ubah file build.gradle atau build.gradle.kts lalu tambahkan androidTestImplementation ke modul yang berisi kode untuk diukur:

Kotlin

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

Groovy

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

Membuat class Microbenchmark

Benchmark adalah uji instrumentasi standar. Untuk membuat benchmark, gunakan class BenchmarkRule yang disediakan oleh library. Untuk menjalankan benchmark aktivitas, gunakan ActivityScenario 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() {
    // 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));
}
    

Cobalah untuk meminimalkan jumlah pekerjaan yang dilakukan di dalam blok measureRepeated dan 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 yang Anda lakukan dengan @Test apa pun menggunakan tindakan gutter di samping class atau metode pengujian, seperti ditunjukkan pada gambar 3.

Menjalankan Microbenchmark
Gambar 3. Menjalankan pengujian Microbenchmark menggunakan tindakan gutter di samping class pengujian.

Atau, dari command line, jalankan connectedCheck 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.

Hasil Microbenchmark
Gambar 4. Hasil Microbenchmark.

Laporan JSON dan setiap rekaman aktivitas pembuatan profil juga otomatis disalin dari perangkat ke host. Laporan tersebut ditulis pada mesin host di lokasi berikut:

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

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.

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.
  • Level baterai pada perangkat memadai, 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.

Anda dapat menetapkannya dari skrip Gradle, seperti yang ditunjukkan pada contoh berikut:

Kotlin

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

Groovy

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

Anda juga dapat menyembunyikan error dari command line:

$ ./gradlew :benchmark:connectedCheck -P andoidtestInstrumentationRunnerArguments.androidx.benchmark.supperssErrors=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.