Dokumen ini menunjukkan praktik terbaik untuk membantu mendiagnosis masalah dan memastikan Profil Dasar Pengukuran Anda berfungsi dengan benar agar dapat memberikan manfaat maksimal.
Masalah build
Jika telah menyalin contoh Profil Dasar Pengukuran dalam aplikasi contoh Now in Android, Anda mungkin mengalami kegagalan pengujian selama tugas Profil Dasar Pengukuran yang menyatakan bahwa pengujian tidak dapat dijalankan di emulator:
./gradlew assembleDemoRelease
Starting a Gradle Daemon (subsequent builds will be faster)
Calculating task graph as no configuration cache is available for tasks: assembleDemoRelease
Type-safe project accessors is an incubating feature.
> Task :benchmarks:pixel6Api33DemoNonMinifiedReleaseAndroidTest
Starting 14 tests on pixel6Api33
com.google.samples.apps.nowinandroid.foryou.ScrollForYouFeedBenchmark > scrollFeedCompilationNone[pixel6Api33] FAILED
java.lang.AssertionError: ERRORS (not suppressed): EMULATOR
WARNINGS (suppressed):
...
Kegagalan terjadi karena Now in Android menggunakan perangkat yang dikelola Gradle untuk pembuatan Profil Dasar Pengukuran. Kegagalan sudah diperkirakan karena Anda pada umumnya tidak boleh menjalankan benchmark performa di emulator. Namun, karena Anda tidak mengumpulkan metrik performa saat membuat Profil Dasar Pengukuran, Anda dapat menjalankan pengumpulan Profil Dasar Pengukuran di emulator untuk memudahkan. Untuk menggunakan Profil Dasar Pengukuran dengan emulator, lakukan build dan penginstalan dari command line, serta tetapkan argumen untuk mengaktifkan aturan Profil Dasar Pengukuran:
installDemoRelease -Pandroid.testInstrumentationRunnerArguments.androidx.benchmark.enabledRules=BaselineProfile
Bisa juga dengan membuat konfigurasi run kustom di Android Studio untuk mengaktifkan Profil Dasar Pengukuran pada emulator dengan memilih Jalankan > Edit Konfigurasi:
Masalah penginstalan
Pastikan APK atau AAB yang Anda bangun berasal dari varian build yang menyertakan
Profil Dasar Pengukuran. Cara termudah untuk memeriksanya adalah dengan membuka APK di
Android Studio dengan memilihBuild > Analisis APK, membuka
APK, dan mencari profil di file
/assets/dexopt/baseline.prof
:
Profil Dasar Pengukuran harus dikompilasi di perangkat yang menjalankan aplikasi. Untuk
penginstalan app store dan aplikasi yang diinstal menggunakan
PackageInstaller
, kompilasi di perangkat dilakukan sebagai bagian dari proses
penginstalan aplikasi. Namun, saat aplikasi di-sideload dari Android Studio, atau
menggunakan alat command line, library Jetpack ProfileInstaller
bertanggung jawab untuk mengantrekan profil untuk kompilasi selama
proses pengoptimalan DEX latar belakang berikutnya. Dalam kasus tersebut, jika ingin memastikan
Profil Dasar Pengukuran digunakan, Anda mungkin perlu
memaksa kompilasi Profil Dasar Pengukuran. ProfileVerifier
memungkinkan
Anda membuat kueri status penginstalan dan kompilasi profil, seperti yang ditunjukkan pada
contoh berikut:
Kotlin
private const val TAG = "MainActivity" class MainActivity : ComponentActivity() { ... override fun onResume() { super.onResume() lifecycleScope.launch { logCompilationStatus() } } private suspend fun logCompilationStatus() { withContext(Dispatchers.IO) { val status = ProfileVerifier.getCompilationStatusAsync().await() when (status.profileInstallResultCode) { RESULT_CODE_NO_PROFILE -> Log.d(TAG, "ProfileInstaller: Baseline Profile not found") RESULT_CODE_COMPILED_WITH_PROFILE -> Log.d(TAG, "ProfileInstaller: Compiled with profile") RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION -> Log.d(TAG, "ProfileInstaller: Enqueued for compilation") RESULT_CODE_COMPILED_WITH_PROFILE_NON_MATCHING -> Log.d(TAG, "ProfileInstaller: App was installed through Play store") RESULT_CODE_ERROR_PACKAGE_NAME_DOES_NOT_EXIST -> Log.d(TAG, "ProfileInstaller: PackageName not found") RESULT_CODE_ERROR_CACHE_FILE_EXISTS_BUT_CANNOT_BE_READ -> Log.d(TAG, "ProfileInstaller: Cache file exists but cannot be read") RESULT_CODE_ERROR_CANT_WRITE_PROFILE_VERIFICATION_RESULT_CACHE_FILE -> Log.d(TAG, "ProfileInstaller: Can't write cache file") RESULT_CODE_ERROR_UNSUPPORTED_API_VERSION -> Log.d(TAG, "ProfileInstaller: Enqueued for compilation") else -> Log.d(TAG, "ProfileInstaller: Profile not compiled or enqueued") } } }
Java
public class MainActivity extends ComponentActivity { private static final String TAG = "MainActivity"; @Override protected void onResume() { super.onResume(); logCompilationStatus(); } private void logCompilationStatus() { ListeningExecutorService service = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor()); ListenableFuture<ProfileVerifier.CompilationStatus> future = ProfileVerifier.getCompilationStatusAsync(); Futures.addCallback(future, new FutureCallback<>() { @Override public void onSuccess(CompilationStatus result) { int resultCode = result.getProfileInstallResultCode(); if (resultCode == RESULT_CODE_NO_PROFILE) { Log.d(TAG, "ProfileInstaller: Baseline Profile not found"); } else if (resultCode == RESULT_CODE_COMPILED_WITH_PROFILE) { Log.d(TAG, "ProfileInstaller: Compiled with profile"); } else if (resultCode == RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION) { Log.d(TAG, "ProfileInstaller: Enqueued for compilation"); } else if (resultCode == RESULT_CODE_COMPILED_WITH_PROFILE_NON_MATCHING) { Log.d(TAG, "ProfileInstaller: App was installed through Play store"); } else if (resultCode == RESULT_CODE_ERROR_PACKAGE_NAME_DOES_NOT_EXIST) { Log.d(TAG, "ProfileInstaller: PackageName not found"); } else if (resultCode == RESULT_CODE_ERROR_CACHE_FILE_EXISTS_BUT_CANNOT_BE_READ) { Log.d(TAG, "ProfileInstaller: Cache file exists but cannot be read"); } else if (resultCode == RESULT_CODE_ERROR_CANT_WRITE_PROFILE_VERIFICATION_RESULT_CACHE_FILE) { Log.d(TAG, "ProfileInstaller: Can't write cache file"); } else if (resultCode == RESULT_CODE_ERROR_UNSUPPORTED_API_VERSION) { Log.d(TAG, "ProfileInstaller: Enqueued for compilation"); } else { Log.d(TAG, "ProfileInstaller: Profile not compiled or enqueued"); } } @Override public void onFailure(Throwable t) { Log.d(TAG, "ProfileInstaller: Error getting installation status: " + t.getMessage()); } }, service); } }
Kode hasil berikut memberikan petunjuk penyebab beberapa masalah:
RESULT_CODE_COMPILED_WITH_PROFILE
- Profil diinstal, dikompilasi, dan digunakan setiap kali aplikasi dijalankan. Code ini merupakan hasil yang ingin Anda lihat.
RESULT_CODE_ERROR_NO_PROFILE_EMBEDDED
- Tidak ada profil yang ditemukan dalam APK atau AAB yang dijalankan. Pastikan Anda menggunakan varian build yang menyertakan Profil Dasar Pengukuran jika Anda melihat error ini, dan APK berisi profil.
RESULT_CODE_NO_PROFILE
- Tidak ada profil yang diinstal untuk aplikasi ini saat menginstal aplikasi melalui app
store atau pengelola paket. Alasan utama terjadinya kode error ini adalah penginstal
profil tidak berjalan karena
ProfileInstallerInitializer
dinonaktifkan. Perlu diperhatikan bahwa saat error ini dilaporkan, profil tersemat masih ditemukan dalam APK aplikasi. Jika profil tersemat tidak ditemukan, kode error yang ditampilkan adalahRESULT_CODE_ERROR_NO_PROFILE_EMBEDDED
. RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION
- Profil ditemukan di APK atau AAB lalu diantrekan untuk kompilasi. Jika
diinstal oleh
ProfileInstaller
, profil tersebut akan diantrekan untuk kompilasi saat pengoptimalan DEX latar belakang berikutnya akan dijalankan oleh sistem. Profil tidak akan aktif hingga kompilasi selesai. Jangan mencoba menjalankan benchmark Profil Dasar Pengukuran Anda hingga kompilasi selesai. Anda mungkin perlu memaksa kompilasi Profil Dasar Pengukuran. Error ini tidak akan terjadi jika aplikasi diinstal dari app store atau pengelola paket di perangkat yang menjalankan Android 9 (API 28) dan yang lebih baru karena kompilasi dilakukan selama penginstalan. RESULT_CODE_COMPILED_WITH_PROFILE_NON_MATCHING
- Profil yang tidak cocok akan diinstal dan aplikasi telah dikompilasi menggunakan profil tersebut.
Kode ini merupakan hasil penginstalan melalui Google Play Store atau pengelola paket.
Perhatikan bahwa hasil ini berbeda dengan
RESULT_CODE_COMPILED_WITH_PROFILE
karena profil yang tidak cocok hanya akan mengompilasi metode yang masih dibagikan antara profil dan aplikasi. Profil ini sebenarnya lebih kecil dari yang diharapkan, dan lebih sedikit metode yang akan dikompilasi dibandingkan metode yang disertakan dalam Profil Dasar Pengukuran. RESULT_CODE_ERROR_CANT_WRITE_PROFILE_VERIFICATION_RESULT_CACHE_FILE
ProfileVerifier
tidak dapat menulis file cache hasil verifikasi. Hal ini dapat terjadi karena ada masalah dengan izin folder aplikasi atau jika kapasitas disk kosong di perangkat tidak cukup.RESULT_CODE_ERROR_UNSUPPORTED_API_VERSION
- ProfileVerifier
is running on an unsupported API version of Android. ProfileVerifier
hanya mendukung Android 9 (level API 28) dan yang lebih tinggi. RESULT_CODE_ERROR_PACKAGE_NAME_DOES_NOT_EXIST
PackageManager.NameNotFoundException
ditampilkan saat membuat kueriPackageManager
untuk paket aplikasi. Hal ini biasanya jarang terjadi. Coba uninstal aplikasi lalu instal ulang semuanya.RESULT_CODE_ERROR_CACHE_FILE_EXISTS_BUT_CANNOT_BE_READ
- File cache hasil verifikasi sebelumnya ada, tetapi tidak dapat dibaca. Hal ini biasanya jarang terjadi. Coba uninstal aplikasi lalu instal ulang semuanya.
Menggunakan ProfileVerifier dalam produksi
Dalam produksi, Anda dapat menggunakan ProfileVerifier
bersama dengan
library pelaporan analisis, seperti Google Analytics for Firebase, untuk
menghasilkan peristiwa analisis yang menunjukkan status profil. Misalnya, pemberitahuan ini
akan segera dikirimkan kepada Anda jika versi aplikasi baru yang tidak berisi
Profil Dasar Pengukuran dirilis.
Memaksa kompilasi Profil Dasar Pengukuran
Jika status kompilasi Profil Dasar Pengukuran Anda adalah
RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION
, Anda dapat memaksa kompilasi
langsung menggunakan adb
:
adb shell cmd package compile -r bg-dexopt PACKAGE_NAME
Memeriksa status kompilasi tanpa ProfileVerifier
Jika tidak menggunakan ProfileVerifier
, Anda dapat memeriksa status kompilasi menggunakan
adb
meskipun tidak memberikan insight sedalam ProfileVerifier
:
adb shell dumpsys package dexopt | grep -A 2 PACKAGE_NAME
Penggunaan adb
akan menghasilkan sesuatu yang mirip dengan berikut ini:
[com.google.samples.apps.nowinandroid.demo]
path: /data/app/~~dzJiGMKvp22vi2SsvfjkrQ==/com.google.samples.apps.nowinandroid.demo-7FR1sdJ8ZTy7eCLwAnn0Vg==/base.apk
arm64: [status=speed-profile] [reason=bg-dexopt] [primary-abi]
[location is /data/app/~~dzJiGMKvp22vi2SsvfjkrQ==/com.google.samples.apps.nowinandroid.demo-7FR1sdJ8ZTy7eCLwAnn0Vg==/oat/arm64/base.odex]
Nilai status menunjukkan status kompilasi profil dan merupakan salah satu nilai berikut:
Status kompilasi | Arti |
---|---|
speed‑profile |
Profil yang dikompilasi ada dan sedang digunakan. |
verify |
Tidak ada profil yang dikompilasi. |
Status verify
tidak berarti bahwa APK atau AAB tidak berisi profil,
karena dapat diantrekan untuk kompilasi oleh tugas pengoptimalan DEX latar belakang
berikutnya.
Nilai alasan menunjukkan faktor pemicu kompilasi profil dan merupakan salah satu dari nilai berikut:
Alasan | Arti |
---|---|
install‑dm
|
Profil Dasar Pengukuran dikompilasi secara manual atau oleh Google Play saat aplikasi diinstal. |
bg‑dexopt
|
Profil dikompilasi saat perangkat Anda tidak ada aktivitas. Profil ini mungkin Profil Dasar Pengukuran, atau mungkin profil yang dikumpulkan selama penggunaan aplikasi. |
cmdline
|
Kompilasi dipicu menggunakan adb. Profil ini mungkin Profil Dasar Pengukuran, atau mungkin profil yang dikumpulkan selama penggunaan aplikasi. |
Masalah performa
Bagian ini menunjukkan beberapa praktik terbaik untuk menentukan dan menjalankan benchmark Profil Dasar Pengukuran Anda dengan benar agar dapat memperoleh manfaat maksimal.
Melakukan benchmark metrik startup dengan benar
Profil Dasar Pengukuran Anda akan lebih efektif jika metrik startup ditentukan dengan baik. Dua metrik utama adalah waktu hingga tampilan awal (TTID) dan waktu hingga tampilan penuh (TTFD).
TTID adalah saat aplikasi menggambar frame pertamanya. Penting untuk membuatnya sesingkat mungkin karena menampilkan sesuatu akan menunjukkan kepada pengguna bahwa aplikasi sedang berjalan. Anda bahkan dapat menampilkan indikator progres yang tidak tentu untuk menunjukkan bahwa aplikasi responsif.
TTFD adalah saat aplikasi benar-benar dapat berinteraksi. Sangat penting untuk menjaganya sesingkat mungkin agar pengguna tidak frustrasi. Jika Anda memberikan sinyal TTFD dengan benar, berarti Anda memberi tahu sistem bahwa kode yang dijalankan dalam proses ke TTFD adalah bagian dari startup aplikasi. Akibatnya, sistem kemungkinan besar akan menempatkan kode ini di dalam profil.
Pastikan TTID dan TTFD serendah mungkin agar aplikasi Anda terasa responsif.
Sistem dapat mendeteksi TTID, menampilkannya di Logcat, serta melaporkannya sebagai bagian
dari benchmark startup. Namun, sistem tidak dapat menentukan TTFD, dan
aplikasi bertanggung jawab untuk melaporkan saat aplikasi mencapai status interaktif
yang sepenuhnya digambar. Anda dapat melakukannya dengan memanggil reportFullyDrawn()
, atau
ReportDrawn
jika menggunakan Jetpack Compose. Jika Anda memiliki beberapa
tugas latar belakang yang semuanya harus diselesaikan sebelum aplikasi dianggap telah sepenuhnya
digambar, Anda dapat menggunakan FullyDrawnReporter
seperti dijelaskan di Meningkatkan
akurasi pengaturan waktu startup.
Profil library dan profil kustom
Saat menjalankan benchmark terhadap dampak profil, mungkin sulit untuk memisahkan manfaat profil aplikasi Anda dari profil yang dikontribusikan oleh library, seperti library Jetpack. Saat Anda membangun APK, plugin Android Gradle akan menambahkan dalam dependensi library serta profil kustom Anda. Bagus untuk mengoptimalkan performa keseluruhan, dan direkomendasikan untuk build rilis Anda. Namun, sulit untuk mengukur berapa banyak peningkatan performa tambahan yang dari profil kustom Anda.
Cara cepat untuk melihat secara manual pengoptimalan tambahan yang disediakan oleh adalah menghapusnya, dan menjalankan benchmark Anda. Kemudian ganti dan jalankan {i>benchmarks <i}lagi. Membandingkan keduanya akan menunjukkan pengoptimalan yang diberikan oleh profil library saja, dan profil library plus profil kustom Anda.
Cara yang dapat diotomatisasi untuk membandingkan profil adalah dengan membuat varian build baru yang
hanya berisi profil library dan bukan profil kustom Anda. Bandingkan
benchmark dari varian ini ke varian rilis yang berisi
profil library dan profil kustom Anda. Contoh berikut menunjukkan bagaimana
untuk menyiapkan varian yang hanya menyertakan profil library. Tambahkan varian baru
bernama releaseWithoutCustomProfile
ke modul konsumen profil Anda, yaitu
biasanya modul aplikasi Anda:
Kotlin
android { ... buildTypes { ... // Release build with only library profiles. create("releaseWithoutCustomProfile") { initWith(release) } ... } ... } ... dependencies { ... // Remove the baselineProfile dependency. // baselineProfile(project(":baselineprofile")) } baselineProfile { variants { create("release") { from(project(":baselineprofile")) } } }
Groovy
android { ... buildTypes { ... // Release build with only library profiles. releaseWithoutCustomProfile { initWith(release) } ... } ... } ... dependencies { ... // Remove the baselineProfile dependency. // baselineProfile ':baselineprofile"' } baselineProfile { variants { release { from(project(":baselineprofile")) } } }
Contoh kode sebelumnya menghapus dependensi baselineProfile
dari semua
varian dan menerapkannya secara selektif hanya ke varian release
. Mungkin terlihat
kontra-intuitif bahwa profil perpustakaan
masih ditambahkan ketika
pada modul pembuat profil akan dihapus. Namun, modul ini
hanya bertanggung jawab untuk membuat profil khusus Anda. Android Gradle
plugin masih berjalan untuk semua varian, dan bertanggung jawab untuk menyertakan
profil library.
Anda juga perlu menambahkan varian baru ke modul generator profil. Di sini
contoh, modul produser diberi nama :baselineprofile
.
Kotlin
android { ... buildTypes { ... // Release build with only library profiles. create("releaseWithoutCustomProfile") {} ... } ... }
Groovy
android { ... buildTypes { ... // Release build with only library profiles. releaseWithoutCustomProfile {} ... } ... }
Saat Anda menjalankan benchmark dari Android Studio, pilih
Varian releaseWithoutCustomProfile
untuk mengukur performa dengan library saja
profil, atau pilih varian release
untuk mengukur performa dengan library
dan profil kustom.
Menghindari startup aplikasi yang terikat I/O
Jika aplikasi Anda melakukan banyak panggilan I/O atau panggilan jaringan selama startup, hal ini dapat berdampak negatif pada waktu startup aplikasi dan akurasi benchmark startup Anda. Panggilan level tinggi ini dapat memerlukan waktu yang tidak tentu yang dapat bervariasi dari waktu ke waktu, bahkan di antara iterasi dari benchmark yang sama. Panggilan I/O umumnya lebih baik daripada panggilan jaringan karena panggilan jaringan dapat dipengaruhi oleh faktor-faktor eksternal dan internal perangkat. Hindari panggilan jaringan selama startup. Jika salah satunya tidak dapat dihindari, gunakan I/O.
Sebaiknya buat arsitektur aplikasi Anda mendukung startup aplikasi tanpa panggilan jaringan atau I/O meskipun hanya untuk menggunakannya saat menjalankan benchmark. Hal ini membantu memastikan variabilitas serendah mungkin antara berbagai iterasi benchmark Anda.
Jika aplikasi Anda menggunakan Hilt, Anda dapat memberikan terikat I/O palsu implementasi saat menjalankan benchmark di Microbenchmark dan Hilt.
Membahas semua perjalanan penting pengguna
Penting untuk mencakup semua perjalanan pengguna yang penting secara akurat dalam pembuatan Profil Dasar Pengukuran Anda. Setiap perjalanan pengguna yang tidak tercakup tidak akan ditingkatkan oleh Profil Dasar Pengukuran. Profil dasar pengukuran yang paling efektif mencakup semua perjalanan pengguna startup umum serta perjalanan pengguna dalam aplikasi yang sensitif terhadap performa seperti daftar scroll.