Kasus penggunaan benchmark dengan Jetpack Macrobenchmark

Macrobenchmark memungkinkan Anda menulis pengujian performa startup dan runtime secara langsung pada aplikasi di perangkat yang menjalankan Android M (API 23) atau yang lebih baru.

Sebaiknya Anda menggunakan Macrobenchmark dengan versi terbaru Android Studio (2020.3.1 Beta 4 atau yang lebih baru), karena ada fitur baru dalam versi IDE tersebut yang terintegrasi dengan Macrobenchmark. Pengguna Android Studio versi sebelumnya dapat menggunakan petunjuk tambahan nanti dalam topik ini untuk menangani file rekaman aktivitas.

Pengujian benchmarking disediakan melalui API aturan JUnit4 MacrobenchmarkRule di library Macrobenchmark:

Kotlin

    @get:Rule
    val benchmarkRule = MacrobenchmarkRule()

    @Test
    fun startup() = benchmarkRule.measureRepeated(
        packageName = "mypackage.myapp",
        metrics = listOf(StartupTimingMetric()),
        iterations = 5,
        startupMode = StartupMode.COLD
    ) { // this = MacrobenchmarkScope
        pressHome()
        val intent = Intent()
        intent.setPackage("mypackage.myapp")
        intent.setAction("mypackage.myapp.myaction")
        startActivityAndWait(intent)
    }
  

Java

    @Rule
    MacrobenchmarkRule benchmarkRule = MacrobenchmarkRule()

    @Test
    void startup() = benchmarkRule.measureRepeated(
        "mypackage.myapp", // packageName
        listOf(StartupTimingMetric()), // metrics
        5, // iterations
        StartupMode.COLD // startupMode
    ) { scope ->
        scope.pressHome()
        Intent intent = Intent()
        intent.setPackage("mypackage.myapp")
        intent.setAction("mypackage.myapp.myaction")
        scope.startActivityAndWait(intent)
    }
  

Metrik ditampilkan langsung di Android Studio dan juga merupakan output untuk Penggunaan CI dalam file JSON.

Contoh Hasil Studio

Penyiapan modul

Macro benchmark memerlukan modul com.android.test terpisah dari kode aplikasi yang bertanggung jawab untuk menjalankan pengujian yang mengukur aplikasi Anda.

Arctic Fox

Di Arctic Fox, Anda akan membuat modul library, dan mengonversinya menjadi modul pengujian.

Menambahkan modul baru

Tambahkan modul baru ke project Anda. Modul ini menyimpan pengujian Macrobenchmark Anda.

  1. Klik kanan project atau modul di panel Project di Android Studio, lalu klik New > Module.
  2. Pilih Android Library di panel Templates.
  3. Ketik macrobenchmark untuk nama modul.
  4. Setel Minimum SDK ke API 23: Android M
  5. Klik Finish.

Mengonfigurasi modul library baru

Mengubah file Gradle

Sesuaikan build.gradle modul Macrobenchmark sebagai berikut:

  1. Ubah plugin dari com.android.library menjadi com.android.test.
  2. Tambahkan properti modul pengujian tambahan yang diperlukan dalam blok android {}:
  3.    targetProjectPath = ":app" // Note that your module name may be different
    
       // Enable the benchmark to run separately from the app process
       experimentalProperties["android.experimental.self-instrumenting"] = true
       buildTypes {
           // Declare a build type (release) to match the target app's build type
           release {
               debuggable = true
           }
       }
  4. Ubah semua dependensi dengan nama testImplementation atau androidTestImplementation menjadi implementation.
  5. Tambahkan dependensi pada library Macrobenchmark:
    • implementation 'androidx.benchmark:benchmark-macro-junit4:1.1.0-alpha13'
  6. Setelah blok android {}, tetapi sebelum blok dependencies {}, tambahkan:
  7.    androidComponents {
          beforeVariants(selector().all()) {
              // Enable only the benchmark buildType, since we only want to measure
              // release-like build performance (should match app buildType)
              enabled = buildType == 'benchmark'
          }
       }

Menyederhanakan struktur direktori

Dalam modul com.android.test, hanya ada satu direktori sumber, untuk semua pengujian. Hapus direktori sumber lain, termasuk src/test dan src/androidTest, karena keduanya tidak digunakan.

Lihat contoh modul Macrobenchmark untuk referensi.

Membuat macro benchmark

Tentukan class pengujian baru dalam modul tersebut, dengan mengisi nama paket aplikasi Anda:

@RunWith(AndroidJUnit4::class)
class SampleStartupBenchmark {
    @get:Rule
    val benchmarkRule = MacrobenchmarkRule()

    @Test
    fun startup() = benchmarkRule.measureRepeated(
        packageName = "mypackage.myapp",
        metrics = listOf(StartupTimingMetric()),
        iterations = 5,
        startupMode = StartupMode.COLD
    ) { // this = MacrobenchmarkScope
        pressHome()
        val intent = Intent()
        intent.setPackage("mypackage.myapp")
        intent.setAction("mypackage.myapp.myaction")
        startActivityAndWait(intent)
    }
}
   

Bumblebee

Di Android Studio Bumblebee Canary 3, tersedia template untuk menyederhanakan penyiapan modul Macrobenchmark.

Menambahkan modul baru

Template modul benchmark otomatis membuat modul dalam project Anda untuk mengukur aplikasi yang dibuat oleh modul aplikasi, termasuk benchmark contoh startup.

Untuk menggunakan template modul guna membuat modul baru, lakukan hal berikut:

  1. Klik kanan project atau modul di panel Project di Android Studio, lalu klik New > Module.

  2. Pilih Benchmark Module.

    Template Modul Benchmark

  3. Anda dapat menyesuaikan aplikasi target (aplikasi yang akan diukur), serta nama paket dan modul untuk modul macrobenchmark baru.

  4. Klik Finish.

Menyiapkan aplikasi

Untuk mengukur aplikasi (disebut target macro benchmark), aplikasi tersebut harus dapat dibuat profil, yang memungkinkan pembacaan informasi rekaman aktivitas mendetail. Anda dapat mengaktifkannya dalam tag <application> AndroidManifest.xml aplikasi:

<application ... >
    <!-- Profileable to enable Macrobenchmark profiling -->
    <!-- Suppress AndroidElementNotAllowed -->
    <profileable android:shell="true"/>
    ...
</application>

Konfigurasikan aplikasi benchmark seidentik mungkin dengan pengalaman pengguna. Siapkan sebagai tidak dapat di-debug dan sebaiknya dengan minifikasi aktif, yang akan meningkatkan performa. Hal ini biasanya dilakukan dengan membuat salinan benchmark varian release, yang akan memiliki performa yang sama, tetapi ditandatangani secara lokal dengan kunci debug:

buildTypes {
    benchmark {
        // duplicate any release build type settings for measurement accuracy,
        // such as "minifyEnabled" and "proguardFiles" in this block

        debuggable false
        signingConfig signingConfigs.debug
    }
}

Lakukan sinkronisasi Gradle, buka panel Build Variants di sebelah kiri, lalu pilih varian benchmark aplikasi dan modul Macrobenchmark. Hal ini memastikan bahwa menjalankan benchmark akan mem-build dan menguji varian yang benar dari aplikasi Anda:

Pilih varian benchmark

Menjalankan Macrobenchmark pada aktivitas internal memerlukan langkah tambahan. Untuk mengukur aktivitas internal exported=false, teruskan setupBlock ke MacrobenchmarkRule.measureRepeated() guna memilih kode agar dapat menjalankan pengukuran, lalu gunakan measureBlock untuk memanggil tindakan peluncuran atau scroll aktivitas yang sebenarnya untuk diukur.

Menyesuaikan macro benchmark

CompilationMode

Macro benchmark dapat menentukan CompilationMode, yang menetapkan jumlah aplikasi yang harus dikompilasi sebelumnya dari bytecode DEX (format bytecode dalam APK) ke kode mesin (mirip dengan C++ yang telah dikompilasi sebelumnya).

Secara default, macro benchmark dijalankan dengan CompilationMode.DEFAULT, yang pada Android Nougat (API 24) dan yang lebih tinggi, menginstal Profil Dasar Pengukuran (jika tersedia), serta di Android Marshmallow (API 23) dan yang lebih rendah, sepenuhnya mengompilasi APK (yang merupakan perilaku sistem default).

Anda dapat menginstal Profil Dasar Pengukuran jika aplikasi target berisi Profil Dasar Pengukuran dan library ProfileInstaller.

Di Android Nougat (API 24) dan yang lebih tinggi, Anda dapat menyesuaikan CompilationMode untuk memengaruhi jumlah prakompilasi di perangkat guna meniru berbagai level kompilasi Ahead Of Time (AOT) atau cache JIT. Lihat CompilationMode.Full, CompilationMode.Partial, dan CompilationMode.None.

Fungsi ini dibuat berdasarkan perintah kompilasi ART. Setiap benchmark akan menghapus data profil sebelum dimulai, untuk memastikan tidak adanya gangguan di antara benchmark.

Startup

Untuk memulai aktivitas, Anda dapat meneruskan mode startup yang telah ditentukan (salah satu dari COLD, WARM, atau HOT) ke fungsi measureRepeated(). Parameter ini mengubah cara aktivitas diluncurkan, dan status proses pada awal pengujian.

Untuk mempelajari lebih lanjut jenis startup, lihat dokumentasi startup Android Vitals.

Scroll dan animasi

Tidak seperti kebanyakan pengujian UI Android, pengujian Macrobenchmark dijalankan dalam proses terpisah dari aplikasi itu sendiri. Hal ini diperlukan untuk mengaktifkan tindakan seperti menutup proses aplikasi dan mengompilasinya menggunakan perintah shell.

Anda dapat mendorong aplikasi menggunakan library UI Automator atau mekanisme lain yang dapat mengontrol aplikasi target dari proses pengujian. Pendekatan seperti Espresso atau ActivityScenario tidak akan berhasil karena diharapkan untuk berjalan dalam proses bersama aplikasi.

Contoh berikut menemukan RecyclerView menggunakan ID resource-nya, dan men-scroll ke bawah beberapa kali:

@Test
fun measureScroll() {
    benchmarkRule.measureRepeated(
        packageName = "mypackage.myapp",
        metrics = listOf(FrameTimingMetric()),
        iterations = 5,
        setupBlock = {
            // before starting to measure, navigate to the UI to be measured
            val intent = Intent()
            intent.action = ACTION
            startActivityAndWait(intent)
        }
    ) {
        val recycler = device.findObject(By.res("mypackage.myapp", "recycler_id"))
        // Set gesture margin to avoid triggering gesture nav
        // with input events from automation.
        recycler.setGestureMargin(device.displayWidth / 5)

        // Scroll down several times
        for (i in 1..10) {
            recycler.scroll(Direction.DOWN, 2f)
            device.waitForIdle()
        }
    }
}

Saat pengujian menentukan FrameTimingMetric, pengaturan waktu render frame dicatat dan dilaporkan sebagai ringkasan tingkat tinggi distribusi pengaturan waktu render frame: persentil ke-50, ke-90, ke-95, dan ke-99.

Benchmark Anda tidak perlu men-scroll UI. Sebagai gantinya, misalnya, aplikasi dapat menjalankan animasi. Ini juga tidak perlu menggunakan UI automator secara khusus; selama bingkai dihasilkan oleh sistem tampilan, yang mencakup bingkai yang dihasilkan oleh Compose, metrik performa dikumpulkan. Perlu diketahui bahwa mekanisme dalam proses seperti Espresso tidak akan berfungsi karena aplikasi harus diarahkan dari proses aplikasi pengujian.

Menjalankan macro benchmark

Jalankan pengujian dari dalam Android Studio untuk mengukur performa aplikasi di perangkat Anda. Perlu diketahui bahwa Anda harus menjalankan pengujian pada perangkat fisik, dan bukan emulator, karena emulator tidak menghasilkan angka performa yang mewakili pengalaman pengguna akhir.

Lihat bagian Benchmark dalam CI untuk mendapatkan informasi tentang cara menjalankan dan memantau benchmark dalam integrasi berkelanjutan.

Anda juga dapat menjalankan semua benchmark dari command line dengan menjalankan perintah connectedCheck:

$ ./gradlew :macrobenchmark:connectedCheck

Error konfigurasi

Jika aplikasi salah dikonfigurasi (dapat di-debug, atau tidak dapat dibuat profil), Macrobenchmark menampilkan error, bukan melaporkan pengukuran yang salah atau tidak lengkap. Anda dapat menyembunyikan error ini dengan argumen androidx.benchmark.suppressErrors.

Error juga ditampilkan saat mencoba mengukur emulator, atau pada perangkat dengan daya baterai lemah, karena hal ini dapat membahayakan ketersediaan inti dan kecepatan clock.

Memeriksa rekaman aktivitas

Setiap iterasi pengukuran menangkap rekaman aktivitas sistem yang terpisah. Anda dapat membuka rekaman aktivitas hasil ini dengan mengklik salah satu link di panel Test Results, seperti yang ditunjukkan pada gambar di bagian Jetpack Macrobenchmark dalam topik ini. Setelah rekaman aktivitas dimuat, Android Studio akan meminta Anda untuk memilih proses yang akan dianalisis. Pemilihan sudah diisi sebelumnya dengan proses aplikasi target:

Pemilihan proses rekaman aktivitas Studio

Setelah file rekaman aktivitas dimuat, Studio akan menampilkan hasilnya di alat CPU profiler:

Rekaman Aktivitas Studio

Mengakses file rekaman aktivitas secara manual

Jika Anda menggunakan Android Studio versi lama (sebelum 2020.3.1), atau menggunakan alat Perfetto untuk menganalisis file rekaman aktivitas, Anda perlu melakukan langkah-langkah tambahan.

Pertama-tama, ambil file rekaman aktivitas dari perangkat:

# The following command pulls all files ending in .perfetto-trace from the directory
# hierarchy starting at the root /storage/emulated/0/Android.
$ adb shell find /storage/emulated/0/Android/ -name "*.perfetto-trace" \
    | tr -d '\r' | xargs -n1 adb pull

Perlu diketahui bahwa jalur file output mungkin berbeda jika Anda menyesuaikannya dengan argumen additionalTestOutputDir. Anda dapat mencari log jalur rekaman aktivitas di logcat untuk melihat tempat log tersebut ditulis. Contoh:

I PerfettoCapture: Writing to /storage/emulated/0/Android/data/androidx.benchmark.integration.macrobenchmark.test/cache/TrivialStartupBenchmark_startup[mode=COLD]_iter002.perfetto-trace.

Jika memanggil pengujian menggunakan command line Gradle (seperti ./gradlew macrobenchmark:connectedCheck), Anda dapat menyalin file hasil pengujian ke direktori output pengujian pada sistem host. Untuk melakukannya, tambahkan baris ini ke file gradle.properties project:

android.enableAdditionalTestOutput=true

File hasil dari pengujian akan ditampilkan di direktori build project seperti ini:

build/outputs/connected_android_test_additional_output/debugAndroidTest/connected/<device-name>/TrivialStartupBenchmark_startup[mode=COLD]_iter002.perfetto-trace

Setelah memiliki file rekaman aktivitas di sistem host, Anda dapat membukanya di Android Studio dengan File > Open di menu. Ini menunjukkan tampilan alat profiler yang ditampilkan di bagian sebelumnya.

Sebagai gantinya, Anda dapat memilih untuk menggunakan alat Perfetto. Perfetto memungkinkan Anda memeriksa semua proses yang terjadi di seluruh perangkat selama pelacakan, sementara CPU profiler Android Studio membatasi pemeriksaan pada satu proses.

Meningkatkan data rekaman aktivitas dengan peristiwa kustom

Ada baiknya Anda menginstrumentasikan aplikasi dengan peristiwa rekaman aktivitas kustom, yang ditampilkan bersama laporan rekaman aktivitas lainnya dan dapat membantu menunjukkan masalah khusus untuk aplikasi Anda. Untuk mempelajari cara membuat peristiwa rekaman aktivitas kustom lebih lanjut, lihat panduan Menentukan peristiwa kustom.

Benchmark dalam CI

Sangat umum untuk menjalankan pengujian di CI tanpa Gradle, atau secara lokal jika Anda menggunakan sistem build yang berbeda. Bagian ini menjelaskan cara mengonfigurasi Macrobenchmark untuk penggunaan CI pada runtime.

File hasil: JSON dan rekaman aktivitas

Macrobenchmark menghasilkan file JSON dan beberapa file rekaman aktivitas: satu per iterasi terukur untuk setiap loop MacrobenchmarkRule.measureRepeated.

Anda dapat menentukan tempat file ini ditulis dengan meneruskan argumen instrumentasi berikut pada runtime:

-e additionalTestOutputDir "device_path_you_can_write_to"

Perlu diketahui bahwa agar lebih mudah Anda dapat menentukan lokasi di /sdcard/, tetapi Anda harus memilih untuk tidak menggunakan penyimpanan dengan cakupan tertentu dengan menyetel requestLegacyExternalStorage ke true di modul Macrobenchmark:

<manifest ... >
  <application android:requestLegacyExternalStorage="true" ... >
    ...
  </application>
</manifest>

Atau, teruskan argumen instrumentasi guna melewati penyimpanan terbatas untuk pengujian:

-e no-isolated-storage 1

Contoh JSON

Berikut ini contoh output JSON untuk benchmark startup tunggal:

{
    "context": {
        "build": {
            "device": "walleye",
            "fingerprint": "google/walleye/walleye:10/QQ3A.200805.001/6578210:userdebug/dev-keys",
            "model": "Pixel 2",
            "version": {
                "sdk": 29
            }
        },
        "cpuCoreCount": 8,
        "cpuLocked": false,
        "cpuMaxFreqHz": 2457600000,
        "memTotalBytes": 3834605568,
        "sustainedPerformanceModeEnabled": false
    },
    "benchmarks": [
        {
            "name": "startup",
            "params": {},
            "className": "androidx.benchmark.integration.macrobenchmark.SampleStartupBenchmark",
            "totalRunTimeNs": 77969052767,
            "metrics": {
                "startupMs": {
                    "minimum": 228,
                    "maximum": 283,
                    "median": 242,
                    "runs": [
                        238,
                        283,
                        256,
                        228,
                        242
                    ]
                }
            },
            "warmupIterations": 3,
            "repeatIterations": 5,
            "thermalThrottleSleepSeconds": 0
        }
    ]
}

Referensi lainnya

Contoh project tersedia sebagai bagian dari repositori contoh performa/Android di GitHub.

Untuk panduan cara mendeteksi regresi performa, lihat Mengatasi Regresi dengan Benchmark dalam CI.

Masukan

Untuk melaporkan masalah atau mengirimkan permintaan fitur untuk Jetpack Macrobenchmark, lihat issue tracker publik.