Benchmark dalam Continuous Integration

Anda dapat menjalankan benchmark dalam Continuous Integration (CI) untuk melacak performa seiring waktu, dan mengenali regresi—atau peningkatan—performa bahkan sebelum aplikasi dirilis. Halaman ini memberikan informasi dasar tentang benchmark dalam CI.

Sebelum mulai menggunakan benchmark di CI, pertimbangkan perbedaan antara merekam dan mengevaluasi hasil dengan pengujian reguler.

Hasil fuzzy

Meskipun benchmark adalah pengujian berinstrumen, hasilnya bukan hanya lulus atau gagal. Benchmark memberikan pengukuran waktu untuk perangkat tertentu yang digunakan untuk menjalankannya. Dengan grafik hasil seiring waktu, Anda dapat memantau perubahan dan mengamati derau dalam sistem pengukuran.

Menggunakan perangkat sebenarnya

Menjalankan benchmark di perangkat Android fisik. Meskipun benchmark dapat berjalan di emulator, hal ini sangat tidak disarankan karena tidak mewakili pengalaman pengguna yang realistis dan sebagai gantinya menyediakan angka yang terikat dengan kemampuan OS dan hardware host. Sebaiknya gunakan perangkat sebenarnya atau layanan yang memungkinkan Anda menjalankan pengujian di perangkat sebenarnya, seperti Firebase Test Lab.

Menjalankan benchmark

Menjalankan benchmark sebagai bagian dari pipeline CI mungkin berbeda dengan menjalankannya secara lokal dari Android Studio. Secara lokal, Anda biasanya menjalankan pengujian integrasi Android dengan satu tugas connectedCheck Gradle. Tugas ini secara otomatis mem-build APK dan menguji APK Anda serta menjalankan pengujian pada perangkat yang terhubung ke server CI. Saat berjalan di CI, alur ini biasanya perlu dibagi menjadi fase terpisah.

Build

Untuk library Microbenchmark, jalankan tugas Gradle assemble[VariantName]AndroidTest, yang membuat APK pengujian berisi kode aplikasi serta kode yang diuji.

Atau, library Macrobenchmark mengharuskan Anda membuat APK target dan APK pengujian secara terpisah. Oleh karena itu, jalankan tugas Gradle :app:assemble[VariantName] dan :macrobenchmark:assemble[VariantName].

Instal dan jalankan

Langkah-langkah ini biasanya dilakukan tanpa perlu menjalankan tugas Gradle. Perhatikan bahwa pengujian tersebut mungkin diabstrakkan, bergantung pada apakah Anda menggunakan layanan yang memungkinkan Anda menjalankan pengujian pada perangkat sebenarnya.

Untuk penginstalan, gunakan perintah adb install dan tentukan APK pengujian atau APK target.

Jalankan perintah instrumen adb shell am untuk menjalankan semua benchmark:

adb shell am instrument -w com.example.benchmark/androidx.benchmark.junit4.AndroidBenchmarkRunner

Saat menggunakan library Macrobenchmark, gunakan androidx.test.runner.AndroidJUnitRunner reguler sebagai runner instrumentasi.

Anda dapat meneruskan argumen instrumentasi yang sama seperti dalam konfigurasi Gradle menggunakan argumen -e. Untuk semua opsi argumen instrumentasi, lihat Argumen Instrumentasi Microbenchmark atau Tambahkan argumen instrumentasi untuk Macrobenchmark.

Misalnya, Anda dapat menetapkan argumen dryRunMode untuk menjalankan microbenchmark sebagai bagian dari proses verifikasi permintaan pull. Dengan mengaktifkan flag ini, microbenchmark hanya berjalan dalam satu loop, yang memverifikasi bahwa proses tersebut berjalan dengan benar, tetapi tidak membutuhkan waktu yang terlalu lama untuk dijalankan.

adb shell am instrument -w -e "androidx.benchmark.dryRunMode.enable" "true" com.example.benchmark/androidx.benchmark.junit4.AndroidBenchmarkRunner

Untuk mengetahui informasi selengkapnya tentang cara menjalankan uji instrumentasi dari command line, lihat Menjalankan pengujian dengan ADB.

Mengunci frekuensi CPU

Plugin Gradle Microbenchmark memberikan perintah ./gradlew lockClocks untuk mengunci frekuensi CPU perangkat yang telah di-root. Hal ini berguna untuk memastikan stabilitas saat Anda memiliki akses ke perangkat yang telah di-root, seperti build "userdebug". Anda dapat mereplika ini menggunakan skrip shell lockClocks.sh, yang tersedia di sumber library.

Anda dapat menjalankan skrip tersebut secara langsung dari host Linux atau Mac, atau mengirimnya ke perangkat dengan beberapa perintah adb:

adb push path/lockClocks.sh /data/local/tmp/lockClocks.sh
adb shell /data/local/tmp/lockClocks.sh
adb shell rm /data/local/tmp/lockClocks.sh

Menjalankan skrip shell secara langsung di host akan membuatnya mengirimkan perintah ini ke perangkat terhubung.

Untuk mengetahui informasi selengkapnya tentang alasan pentingnya mengunci frekuensi CPU, lihat cara mendapatkan benchmark yang konsisten.

Mengumpulkan hasil

Library benchmark menghasilkan pengukuran di JSON, beserta rekaman aktivitas pembuatan profil ke direktori di perangkat Android setelah setiap benchmark dijalankan. Library Macrobenchmark menghasilkan beberapa file rekaman aktivitas perfetto: satu file per iterasi pengukuran untuk setiap loop MacrobenchmarkRule.measureRepeated. Namun, Microbenchmark hanya membuat satu file rekaman aktivitas untuk semua iterasi dari setiap BenchmarkRule.measureRepeated. File rekaman aktivitas pembuatan profil juga akan dihasilkan ke direktori yang sama ini.

Menyimpan dan menemukan file

Jika Anda menjalankan benchmark dengan Gradle, file ini akan otomatis disalin ke direktori output komputer host Anda di build/outputs/connected_android_test_additional_output/debugAndroidTest/connected/.

Jika berjalan langsung dengan perintah adb, Anda perlu menarik file secara manual. Secara default, laporan disimpan di perangkat dalam direktori media dari penyimpanan eksternal aplikasi yang diuji. Untuk memudahkan, library mencetak jalur file ke Logcat. Perhatikan bahwa folder output mungkin berbeda, tergantung pada versi Android tempat benchmark dijalankan.

Benchmark: writing results to /storage/emulated/0/Android/media/com.example.macrobenchmark/com.example.macrobenchmark-benchmarkData.json

Anda juga dapat mengonfigurasi lokasi tempat laporan benchmark disimpan pada perangkat menggunakan argumen instrumentasi additionalTestOutputDir. Folder ini harus dapat ditulis oleh aplikasi Anda.

adb shell am instrument -w -e additionalTestOutputDir /sdcard/Download/ com.example.benchmark/androidx.benchmark.junit4.AndroidBenchmarkRunner

Di Android 10 (API level 29) dan yang lebih tinggi, pengujian aplikasi Anda dijalankan di sandbox penyimpanan secara default yang mencegah aplikasi Anda mengakses file di luar direktori khusus aplikasi. Agar dapat menyimpan ke direktori global, seperti /sdcard/Download, teruskan argumen instrumentasi berikut:

-e no-isolated-storage true

Anda juga harus secara eksplisit mengizinkan opsi penyimpanan lama dalam manifes benchmark Anda:

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

Untuk informasi selengkapnya, lihat Memilih tidak menggunakan penyimpanan terbatas untuk sementara.

Mengambil file

Untuk mengambil file yang dihasilkan dari perangkat, gunakan perintah adb pull, yang menarik file yang ditentukan ke direktori saat ini pada host Anda:

adb pull /storage/emulated/0/Android/media/com.example.macrobenchmark/com.example.macrobenchmark-benchmarkData.json

Untuk mengambil semua benchmarkData dari folder yang ditentukan, periksa cuplikan berikut:

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

File rekaman aktivitas (.trace atau .perfetto-trace) disimpan di folder yang sama dengan benchmarkData.json, sehingga Anda dapat mengumpulkannya dengan cara yang sama.

Contoh data benchmark

Library benchmark menghasilkan file JSON yang berisi informasi tentang perangkat tempat benchmark dijalankan dan benchmark sebenarnya yang dijalankannya. Cuplikan berikut mewakili file JSON yang dihasilkan:

{
    "context": {
        "build": {
            "brand": "google",
            "device": "blueline",
            "fingerprint": "google/blueline/blueline:12/SP1A.210812.015/7679548:user/release-keys",
            "model": "Pixel 3",
            "version": {
                "sdk": 31
            }
        },
        "cpuCoreCount": 8,
        "cpuLocked": false,
        "cpuMaxFreqHz": 2803200000,
        "memTotalBytes": 3753299968,
        "sustainedPerformanceModeEnabled": false
    },
    "benchmarks": [
        {
            "name": "startup",
            "params": {},
            "className": "com.example.macrobenchmark.startup.SampleStartupBenchmark",
            "totalRunTimeNs": 4975598256,
            "metrics": {
                "timeToInitialDisplayMs": {
                    "minimum": 347.881076,
                    "maximum": 347.881076,
                    "median": 347.881076,
                    "runs": [
                        347.881076
                    ]
                }
            },
            "sampledMetrics": {},
            "warmupIterations": 0,
            "repeatIterations": 3,
            "thermalThrottleSleepSeconds": 0
        }
    ]
}

Referensi lainnya