1. Sebelum memulai
Dalam codelab ini, Anda akan mempelajari cara membuat Profil Dasar Pengukuran untuk mengoptimalkan performa aplikasi dan cara memverifikasi manfaat performa menggunakan Profil Dasar Pengukuran.
Prasyarat
Codelab ini dibuat berdasarkan codelab Memeriksa performa aplikasi dengan Macrobenchmark yang menunjukkan cara mengukur performa aplikasi dengan library Macrobenchmark.
Yang akan Anda butuhkan
- Android Studio Dolphin (2021.3.1) atau yang lebih baru
- Pengetahuan tentang Kotlin
- Pemahaman dasar tentang Jetpack Macrobenchmark
- Perangkat Android fisik dengan Android 6 (API level 23) atau yang lebih baru
- Emulator Android tanpa Google Play dengan Android 9 (API level 28) atau yang lebih baru
Yang akan Anda lakukan
- Membuat Profil Dasar Pengukuran untuk mengoptimalkan performa
- Memverifikasi peningkatan performa dengan library Macrobenchmark
Yang akan Anda pelajari
- Membuat profil dasar pengukuran
- Memahami peningkatan performa Profil Dasar Pengukuran
2. Mempersiapkan
Untuk memulai, clone repositori GitHub dari command line dengan menggunakan perintah berikut:
$ git clone --branch baselineprofiles-main https://github.com/googlecodelabs/android-performance.git
Atau, Anda dapat mendownload dua file ZIP:
Membuka Project ke Android Studio
- Di jendela Welcome to Android Studio, pilih
Open an Existing Project
- Pilih folder
[Download Location]/android-performance/benchmarking
(tips: pastikan Anda memilih direktoribenchmarking
yang berisibuild.gradle
) - Setelah Android Studio mengimpor project, pastikan Anda dapat menjalankan modul
app
untuk mem-build aplikasi contoh yang akan diukur dengan benchmark.
3. Apa itu Profil Dasar Pengukuran
Profil Dasar Pengukuran meningkatkan kecepatan eksekusi kode sekitar 30% sejak peluncuran pertama dengan menghindari langkah interpretasi dan kompilasi tepat waktu (JIT) untuk jalur kode yang disertakan. Dengan mengirimkan Profil Dasar Pengukuran dalam aplikasi atau library, Android Runtime (ART) dapat mengoptimalkan jalur kode yang disertakan melalui kompilasi Ahead of Time (AOT), yang memberikan peningkatan performa untuk setiap pengguna baru dan setiap update aplikasi. Pengoptimalan yang dipandu profil (PGO) ini memungkinkan aplikasi mengoptimalkan startup, mengurangi jank interaksi, dan meningkatkan performa runtime secara keseluruhan untuk pengguna akhir sejak peluncuran pertama.
Manfaat Profil Dasar Pengukuran
Dengan Profil Dasar Pengukuran, semua interaksi pengguna (seperti memulai aplikasi, menavigasi antar-layar, atau men-scroll konten) lebih lancar sejak pertama dijalankan. Peningkatan kecepatan dan responsivitas aplikasi akan meningkatkan jumlah pengguna aktif harian dan rata-rata rasio pengunjung yang kembali yang lebih tinggi.
Profil Dasar Pengukuran membantu memandu pengoptimalan di luar startup aplikasi dengan menyediakan interaksi pengguna umum yang meningkatkan runtime aplikasi sejak peluncuran pertama. Kompilasi AOT yang dipandu tidak mengandalkan perangkat pengguna dan dapat dilakukan sekali per rilis pada mesin pengembangan, bukan perangkat seluler. Dengan mengirimkan rilis menggunakan Profil Dasar Pengukuran, pengoptimalan aplikasi akan tersedia jauh lebih cepat daripada hanya mengandalkan Profil Cloud.
Jika tidak menggunakan Profil Dasar Pengukuran, semua kode aplikasi dikompilasi secara JIT dalam memori setelah diinterpretasikan, atau menjadi file odex di latar belakang saat perangkat tidak ada aktivitas. Pengguna akan mendapatkan pengalaman yang kurang optimal saat pertama kali menjalankan aplikasi setelah menginstal atau mengupdatenya, hingga jalur baru dioptimalkan. Peningkatan performa ini telah diukur sekitar 30% untuk banyak aplikasi.
4. Menyiapkan modul benchmark
Sebagai developer aplikasi, Anda dapat membuat Profil Dasar Pengukuran secara otomatis menggunakan library Jetpack Macrobenchmark. Untuk menghasilkan Profil Dasar Pengukuran, Anda dapat menggunakan modul yang sama yang dibuat untuk menjalankan benchmark pada aplikasi Anda dengan beberapa perubahan tambahan.
Menonaktifkan obfuscation untuk Profil Dasar Pengukuran
Jika aplikasi Anda telah mengaktifkan obfuscation, Anda perlu menonaktifkannya untuk benchmark.
Anda dapat melakukannya dengan menambahkan file proguard tambahan ke modul :app
dan menonaktifkan obfuscation di sana, lalu menambahkan file proguard ke buildType benchmark
.
Buat file baru bernama benchmark-rules.pro
dalam modul :app
. File harus ditempatkan di folder /app/
di samping file build.gradle
khusus modul.
Dalam file ini, nonaktifkan obfuscation dengan menambahkan -dontobfuscate
seperti dalam cuplikan berikut:
# Disables obfuscation for benchmark builds.
-dontobfuscate
Selanjutnya, ubah buildType benchmark
dalam build.gradle
khusus modul :app
, lalu tambahkan file yang Anda buat. Karena kita menggunakan buildType rilis initWith
, baris ini akan menambahkan file proguard benchmark-rules.pro
ke file proguard rilis.
buildTypes {
release {
// ...
}
benchmark {
initWith buildTypes.release
// ...
proguardFiles('benchmark-rules.pro')
}
}
Sekarang, mari kita tulis class generator Profil Dasar Pengukuran.
5. Menulis generator Profil Dasar Pengukuran
Biasanya, Anda akan membuat Profil Dasar Pengukuran untuk perjalanan pengguna biasa pada aplikasi Anda.
Pada contoh kami, Anda dapat mengidentifikasi tiga perjalanan ini:
- Memulai aplikasi (ini akan sangat penting untuk sebagian besar aplikasi)
- Men-scroll daftar camilan
- Membuka detail camilan
Untuk membuat Profil Dasar Pengukuran, kita akan menambahkan class pengujian baru BaselineProfileGenerator
dalam modul :macrobenchmark
. Class ini akan menggunakan aturan pengujian BaselineProfileRule
dan akan berisi satu metode pengujian untuk membuat profil. Titik entri untuk membuat profil adalah fungsi collectBaselineProfile
. Pengujian ini hanya memerlukan dua parameter:
packageName
, yang merupakan paket aplikasi AndaprofileBlock
(parameter lambda terakhir)
@RunWith(AndroidJUnit4::class)
class BaselineProfileGenerator {
@get:Rule
val rule = BaselineProfileRule()
@Test
fun generate() {
rule.collectBaselineProfile("com.example.macrobenchmark_codelab") {
// TODO Add interactions for the typical user journeys
}
}
}
Di lambda profileBlock
, Anda menentukan interaksi yang mencakup perjalanan pengguna biasa pada aplikasi Anda. Library akan menjalankan profileBlock
beberapa kali dan akan mengumpulkan class dan fungsi yang dipanggil untuk dioptimalkan dan membuat Profil Dasar Pengukuran di perangkat.
Anda dapat memeriksa garis besar generator Profil Dasar Pengukuran kami yang mencakup perjalanan biasa dalam cuplikan berikut:
@RunWith(AndroidJUnit4::class)
class BaselineProfileGenerator {
@get:Rule
val rule = BaselineProfileRule()
@Test
fun generate() {
rule.collectBaselineProfile("com.example.macrobenchmark_codelab") {
startApplicationJourney() // TODO Implement
scrollSnackListJourney() // TODO Implement
goToSnackDetailJourney() // TODO Implement
}
}
}
Sekarang, mari kita tulis interaksi untuk setiap perjalanan yang disebutkan. Anda dapat menulisnya sebagai fungsi ekstensi MacrobenchmarkScope
sehingga Anda memiliki akses ke parameter dan fungsi yang disediakannya. Menulis seperti ini memungkinkan Anda menggunakan kembali interaksi dengan benchmark untuk memverifikasi peningkatan performa.
Memulai perjalanan aplikasi
Untuk perjalanan startup aplikasi (startApplicationJourney
), Anda perlu mengikutsertakan interaksi berikut:
- Menekan tombol layar utama untuk memastikan status aplikasi dimulai ulang
- Memulai Aktivitas default dan menunggu hingga frame pertama dirender
- Menunggu hingga konten dimuat dan dirender, dan pengguna dapat berinteraksi dengannya
fun MacrobenchmarkScope.startApplicationJourney() {
pressHome()
startActivityAndWait()
val contentList = device.findObject(By.res("snack_list"))
// Wait until a snack collection item within the list is rendered
contentList.wait(Until.hasObject(By.res("snack_collection")), 5_000)
}
Perjalanan daftar scroll
Untuk scroll perjalanan daftar camilan (scrollSnackListJourney
), Anda dapat mengikuti interaksi berikut:
- Menemukan elemen UI daftar camilan
- Menetapkan margin gestur agar tidak memicu navigasi sistem
- Men-scroll daftar dan menunggu hingga UI selesai
fun MacrobenchmarkScope.scrollSnackListJourney() {
val snackList = device.findObject(By.res("snack_list"))
// Set gesture margin to avoid triggering gesture navigation
snackList.setGestureMargin(device.displayWidth / 5)
snackList.fling(Direction.DOWN)
device.waitForIdle()
}
Membuka perjalanan detail
Perjalanan terakhir (goToSnackDetailJourney
) menerapkan interaksi ini:
- Menemukan daftar camilan dan menemukan semua item camilan yang dapat Anda gunakan
- Memilih item dari daftar
- Mengklik item tersebut dan menunggu hingga layar detail dimuat. Anda dapat memanfaatkan fakta bahwa daftar camilan tidak akan muncul lagi di layar
fun MacrobenchmarkScope.goToSnackDetailJourney() {
val snackList = device.findObject(By.res("snack_list"))
val snacks = snackList.findObjects(By.res("snack_item"))
// Select random snack from the list
snacks[Random.nextInt(snacks.size)].click()
// Wait until the screen is gone = the detail is shown
device.wait(Until.gone(By.res("snack_list")), 5_000)
}
Sekarang Anda telah menentukan semua interaksi yang diperlukan agar generator Profil Dasar Pengukuran siap dijalankan, tetapi Anda harus menentukan perangkat yang akan digunakan terlebih dahulu untuk menjalankannya.
6. Menyiapkan Perangkat yang Dikelola Gradle
Untuk membuat Profil Dasar Pengukuran, Anda harus menyiapkan emulator userdebug
terlebih dahulu. Untuk mengotomatiskan proses pembuatan Profil Dasar Pengukuran, Anda dapat menggunakan Perangkat yang Dikelola Gradle. Anda dapat mempelajari lebih lanjut Perangkat yang Dikelola Gradle dalam dokumentasi kami.
Pertama, tentukan Perangkat yang Dikelola Gradle dalam file build.gradle
modul :macrobenchmark
seperti dalam cuplikan berikut:
testOptions {
managedDevices {
devices {
pixel2Api31(com.android.build.api.dsl.ManagedVirtualDevice) {
device = "Pixel 2"
apiLevel = 31
systemImageSource = "aosp"
}
}
}
}
Untuk membuat Profil Dasar Pengukuran, Anda harus menggunakan Android 9 (API 28) yang telah di-root atau yang lebih tinggi.
Dalam hal ini, kita akan menggunakan Android 11 (API level 31) dan image sistem aosp
dapat mengakses root.
Perangkat yang Dikelola Gradle memungkinkan Anda menjalankan pengujian pada emulator Android tanpa perlu meluncurkannya secara manual dan membongkarnya. Setelah menambahkan definisi ke build.gradle
, tugas pixel2Api31[BuildVariant]AndroidTest
baru akan dapat dijalankan. Kita akan menggunakan tugas tersebut di langkah berikutnya untuk membuat Profil Dasar Pengukuran.
7. Membuat Profil Dasar Pengukuran
Setelah Perangkat yang Dikelola Gradle siap, Anda dapat memulai pengujian generator.
Menjalankan generator dari konfigurasi run
Perangkat yang Dikelola Gradle memerlukan pengujian yang dijalankan sebagai tugas Gradle. Untuk memulai dengan cepat, kami telah membuat konfigurasi run yang menentukan tugas dengan semua parameter yang diperlukan untuk dijalankan.
Untuk menjalankannya, cari konfigurasi run generateBaselineProfile
dan klik tombol Run .
Pengujian akan membuat image emulator yang ditentukan sebelumnya, menjalankan interaksi beberapa kali, lalu membongkar emulator dan memberikan output ke Android Studio.
(Opsional) Menjalankan generator dari command line
Untuk menjalankan generator dari command line, Anda dapat memanfaatkan tugas yang dibuat oleh Perangkat yang Dikelola Gradle – :macrobenchmark:pixel2Api31BenchmarkAndroidTest
.
Perintah ini menjalankan semua pengujian dalam project, yang akan gagal, karena modul juga berisi Benchmark untuk verifikasi peningkatan performa di lain waktu.
Untuk itu, Anda dapat memfilter class yang ingin dijalankan dengan parameter -P android.testInstrumentationRunnerArguments.class
dan menentukan com.example.macrobenchmark.BaselineProfileGenerator
yang Anda tulis sebelumnya.
Seluruh perintah terlihat seperti berikut:
./gradlew :macrobenchmark:pixel2Api31BenchmarkAndroidTest -P android.testInstrumentationRunnerArguments.class=com.example.macrobenchmark.BaselineProfileGenerator
8. Menerapkan Profil Dasar Pengukuran yang dihasilkan
Setelah generator berhasil diselesaikan, Anda perlu melakukan beberapa hal agar Profil Dasar Pengukuran berfungsi dengan aplikasi Anda.
Anda perlu menempatkan file Profil Dasar Pengukuran yang dihasilkan ke dalam folder src/main
(di sebelah AndroidManifest.xml
). Untuk mengambil file tersebut, Anda dapat menyalinnya dari folder managed_device_android_test_additional_output/
yang terletak di /macrobenchmark/build/outputs/
, seperti yang ditunjukkan pada screenshot berikut.
Atau, Anda dapat mengklik link results
di output Android Studio dan menyimpan konten, atau gunakan perintah adb pull
yang dicetak di output.
Selanjutnya, ganti nama file menjadi baseline-prof.txt
.
Kemudian, tambahkan dependensi profileinstaller
ke modul :app
Anda.
dependencies {
implementation("androidx.profileinstaller:profileinstaller:1.2.0")
}
Menambahkan dependensi ini memungkinkan Anda untuk:
- Menjalankan benchmark secara lokal pada Profil Dasar Pengukuran.
- Menggunakan Profil Dasar Pengukuran di Android 7 (API level 24) dan Android 8 (API level 26), yang tidak mendukung profil Cloud.
- Menggunakan Profil Dasar Pengukuran di perangkat yang tidak memiliki Layanan Google Play.
Terakhir, sinkronkan project dengan File Gradle dengan mengklik ikon .
Pada langkah berikutnya, kita akan melihat cara memverifikasi seberapa baik performa aplikasi dengan Profil Dasar Pengukuran.
9. Memverifikasi peningkatan performa startup
Sekarang, kita telah membuat Profil Dasar Pengukuran dan menambahkannya ke aplikasi. Mari kita verifikasi bahwa Profil Dasar Pengukuran ini memiliki efek yang diinginkan pada performa aplikasi.
Mari kita kembali ke class ExampleStartupBenchmark
yang berisi benchmark untuk mengukur startup aplikasi. Anda perlu sedikit mengubah pengujian startup()
agar dapat digunakan kembali dengan berbagai mode kompilasi. Ini akan memungkinkan Anda membandingkan perbedaan saat menggunakan Profil Dasar Pengukuran.
CompilationMode
Parameter CompilationMode
menentukan cara aplikasi dikompilasi sebelumnya ke dalam kode mesin. Parameter ini memiliki opsi berikut:
DEFAULT
– Mengompilasi sebagian aplikasi terlebih dahulu menggunakan Profil Dasar Pengukuran jika tersedia (ini digunakan jika tidak ada parametercompilationMode
yang diterapkan)None()
– Mereset status kompilasi aplikasi dan tidak mengompilasi aplikasi terlebih dahulu. Kompilasi tepat waktu (JIT) masih diaktifkan selama eksekusi aplikasi.Partial()
– Mengompilasi aplikasi terlebih dahulu dengan Profil Dasar Pengukuran dan/atau menjalankan pemanasan.Full()
– Mengompilasi seluruh kode aplikasi terlebih dahulu. Ini adalah satu-satunya opsi di Android 6 (API 23) dan yang lebih rendah.
Jika Anda ingin mulai mengoptimalkan performa aplikasi, Anda dapat memilih mode kompilasi DEFAULT
, karena performanya akan mirip dengan saat aplikasi diinstal dari Google Play. Jika ingin membandingkan manfaat performa yang diberikan Profil Dasar Pengukuran, Anda dapat melakukannya dengan membandingkan hasil mode kompilasi None
dan Partial
.
Mengubah pengujian startup dengan CompilationMode yang berbeda
Pertama, hapus anotasi @Test
dari metode startup
(karena pengujian JUnit tidak dapat memiliki parameter) dan tambahkan parameter compilationMode
serta gunakan dalam fungsi measureRepeated
:
// Remove @Test annotation and add the compilationMode parameter.
fun startup(compilationMode: CompilationMode) = benchmarkRule.measureRepeated(
packageName = "com.google.samples.apps.sunflower",
metrics = listOf(StartupTimingMetric()),
iterations = 5,
compilationMode = compilationMode, // Set the compilation mode
startupMode = StartupMode.COLD
) {
pressHome()
startActivityAndWait()
}
Sekarang setelah Anda memilikinya, tambahkan dua fungsi pengujian dengan CompilationMode
yang berbeda. Yang pertama akan menggunakan CompilationMode.None
, yang berarti bahwa sebelum setiap benchmark, status aplikasi akan direset dan aplikasi tidak akan memiliki kode yang telah dikompilasi sebelumnya.
@Test
fun startupCompilationNone() = startup(CompilationMode.None())
Pengujian kedua akan memanfaatkan CompilationMode.Partial
, yang memuat Profil Dasar Pengukuran dan mengompilasi terlebih dahulu class serta fungsi yang ditentukan dari profil sebelum menjalankan benchmark.
@Test
fun startupCompilationPartial() = startup(CompilationMode.Partial())
Secara opsional, Anda dapat menambahkan metode ketiga yang akan mengompilasi seluruh aplikasi terlebih dahulu menggunakan CompilationMode.Full
. Ini adalah satu-satunya opsi di Android 6 (API 23) atau yang lebih rendah, karena sistem hanya menjalankan aplikasi yang telah sepenuhnya dikompilasi sebelumnya.
@Test
fun startupCompilationFull() = startup(CompilationMode.Full())
Selanjutnya, jalankan benchmark seperti yang Anda lakukan sebelumnya (pada perangkat fisik) dan tunggu Macrobenchmark untuk mengukur waktu startup dengan mode kompilasi yang berbeda.
Setelah benchmark selesai, Anda dapat melihat pengaturan waktu di output Android Studio seperti di screenshot berikut:
Dari screenshot, Anda dapat melihat bahwa waktu startup aplikasi berbeda untuk setiap CompilationMode
. Nilai median ditampilkan dalam tabel berikut:
timeToInitialDisplay [ms] | timeToFullDisplay [ms] | |
Tidak ada | 396,8 | 818,1 |
Penuh | 373,9 | 755,0 |
Parsial | 352,9 | 720,9 |
Secara intuitif, kompilasi None
memiliki performa terburuk karena perangkat harus melakukan kompilasi JIT paling banyak selama startup aplikasi. Hal yang mungkin berlawanan dengan harapan adalah kompilasi Full
tidak berperforma terbaik. Karena semuanya dikompilasi dalam kasus ini, file odex aplikasi sangat besar, dan oleh karena itu, sistem biasanya harus melakukan IO secara signifikan selama startup aplikasi. Performa terbaik ditunjukkan oleh kasus Partial
yang menggunakan Profil Dasar Pengukuran. Hal ini karena kompilasi parsial mencapai keseimbangan antara mengompilasi kode yang kemungkinan besar akan digunakan pengguna, tetapi menyebabkan kode yang tidak begitu penting tidak dikompilasi sebelumnya sehingga tidak perlu dimuat seketika.
10. Memverifikasi peningkatan performa scroll
Demikian pula dengan apa yang Anda lakukan di langkah sebelumnya, Anda dapat mengukur dan memverifikasi benchmark scroll. Mari kita ubah class ScrollBenchmarks
seperti sebelumnya – menambahkan parameter ke pengujian scroll
dan menambahkan pengujian lainnya dengan parameter mode kompilasi yang berbeda.
Buka file ScrollBenchmarks.kt
, ubah fungsi scroll()
untuk menambahkan parameter compilationMode
:
fun scroll(compilationMode: CompilationMode) {
benchmarkRule.measureRepeated(
compilationMode = compilationMode, // Set the compilation mode
// ...
Sekarang, tentukan beberapa pengujian yang menggunakan parameter berbeda:
@Test
fun scrollCompilationNone() = scroll(CompilationMode.None())
@Test
fun scrollCompilationPartial() = scroll(CompilationMode.Partial())
Dan jalankan benchmark seperti sebelumnya untuk mendapatkan hasil seperti dalam screenshot berikut:
Dari hasil tersebut, Anda dapat melihat bahwa CompilationMode.Partial
memiliki waktu render frame yang rata-rata lebih pendek sebesar 0,4 md, yang mungkin tidak terlihat oleh pengguna, tetapi untuk persentil lainnya, hasilnya lebih jelas. Untuk P99, perbedaannya adalah 36,9 md, yang berarti lebih dari 3 frame yang dilewati (Pixel 7 menjalankan 90 FPS, jadi ~11 md).
11. Selamat
Selamat, Anda berhasil menyelesaikan codelab ini dan meningkatkan performa aplikasi Anda dengan menggunakan Profil Dasar Pengukuran.
Apa selanjutnya?
Lihat repositori GitHub contoh performa kami yang berisi Macrobenchmark dan contoh performa lainnya. Selain itu, periksa aplikasi contoh Now In Android – aplikasi dunia nyata yang menggunakan benchmark dan Profil Dasar Pengukuran untuk meningkatkan performa.