Ringkasan pengukuran performa aplikasi

Topik ini membantu Anda mengidentifikasi dan mengatasi masalah performa utama di aplikasi Anda.

Masalah performa utama

Ada banyak masalah yang dapat menyebabkan performa yang buruk dalam aplikasi, tetapi berikut adalah beberapa situasi umum yang harus diperhatikan di aplikasi Anda:

  • Jank Scroll
    • "Jank" adalah istilah yang digunakan untuk menggambarkan gangguan visual yang terjadi saat sistem tidak dapat membuat dan menyediakan frame pada waktunya untuk ditarik ke layar pada ritme yang diminta (60 hz, atau lebih tinggi). Jank paling terlihat saat aktivitas men-scroll, saat alur animasi yang seharusnya lancar mengalami gangguan. Gerakannya juga terjeda untuk satu atau beberapa frame karena aplikasi memerlukan waktu yang lebih lama untuk merender konten daripada durasi frame pada sistem.
    • Aplikasi harus menargetkan rasio pembaruan 90 Hz. Kecepatan rendering tradisional telah mencapai 60 Hz, tetapi banyak perangkat baru yang beroperasi dalam mode 90 Hz selama interaksi pengguna seperti men-scroll, dan perangkat tertentu mendukung kecepatan yang lebih tinggi, hingga 120 Hz.
      • Untuk melihat kecepatan refresh yang digunakan perangkat pada waktu tertentu, aktifkan overlay menggunakan Developer Options > Show refresh rate di bagian Debugging.
  • Latensi pengaktifan

    • Latensi pengaktifan adalah jumlah waktu yang dibutuhkan antara mengetuk ikon aplikasi, notifikasi, atau titik entri lainnya dan data pengguna yang ditampilkan di layar.
    • Anda harus menargetkan dua sasaran pengaktifan ini di aplikasi Anda:

      • Start cold < 500 md: "Start cold" terjadi saat aplikasi yang diluncurkan tidak ada dalam memori sistem. Hal ini terjadi saat aplikasi diluncurkan pertama kali sejak dimulai ulang atau sejak proses aplikasi dihentikan oleh pengguna atau sistem.

        Sebaliknya, "start warm" terjadi saat aplikasi sudah berjalan di latar belakang. Start cold memerlukan paling banyak upaya dari sistem karena harus memuat semuanya dari penyimpanan dan menginisialisasi aplikasi. Usahakan untuk mencapai sasaran start cold dengan waktu 500 md atau kurang.

      • Latensi P95/P99 sangat dekat dengan latensi median. Jika aplikasi terkadang membutuhkan waktu yang sangat lama untuk memulai, kepercayaan pengguna akan terkikis. IPC dan I/O yang tidak perlu selama jalur penting pengaktifan aplikasi dapat mengalami pertentangan kunci dan menimbulkan inkonsistensi ini.

  • Transisi yang tidak lancar

    • Masalah ini timbul selama interaksi seperti beralih antar-tab atau memuat aktivitas baru. Jenis transisi ini harus memiliki animasi yang lancar dan tidak mencakup keterlambatan atau kedipan visual.
  • Ketidakefisienan daya

    • Melakukan tugas akan menghabiskan baterai, dan melakukan tugas yang tidak perlu akan mengurangi masa pakai baterai.
    • Alokasi memori, yang berasal dari pembuatan objek baru dalam kode, dapat menjadi penyebab tugas yang signifikan dalam sistem. Ini karena tidak hanya alokasi tersebut memerlukan upaya dari Android Runtime, tetapi membebaskan objek tersebut nanti ("pembersihan sampah memori") juga memerlukan waktu dan upaya. Alokasi dan pengumpulan jauh lebih cepat dan efisien daripada sebelumnya, terutama untuk objek sementara. Jadi, jika panduan sebelumnya adalah untuk menghindari pengalokasian objek kapan pun memungkinkan, rekomendasinya sekarang adalah melakukan hal yang paling masuk akal bagi aplikasi dan arsitektur Anda; menghemat alokasi dengan risiko kode tidak dapat dipertahankan bukanlah pilihan yang tepat mengingat hal yang mampu dilakukan oleh ART.

      Namun, masih ada upaya yang perlu dilakukan, sehingga perlu diingat apakah Anda mengalokasikan banyak objek di loop dalam, yang dapat menyebabkan masalah performa.

Mengidentifikasi masalah

Alur kerja yang direkomendasikan untuk mengidentifikasi dan memperbaiki masalah performa adalah sebagai berikut:

  • Identifikasi perjalanan penting pengguna untuk diperiksa. Hal ini dapat mencakup:
    • Alur pengaktifan umum, termasuk dari peluncur dan notifikasi.
    • Layar apa pun tempat pengguna men-scroll data.
    • Transisi antar-layar.
    • Alur yang berjalan lama, seperti navigasi atau pemutaran musik.
  • Periksa peristiwa yang terjadi selama alur tersebut menggunakan alat proses debug:
    • Systrace atau Perfetto: Memungkinkan Anda melihat peristiwa yang sebenarnya terjadi di seluruh perangkat dengan data waktu yang tepat.
    • Memory profiler: Memungkinkan Anda melihat alokasi memori yang terjadi pada heap.
    • Simpleperf: Melihat flamegraph panggilan fungsi yang paling banyak menggunakan CPU selama periode tertentu. Saat Anda mengidentifikasi sesuatu yang memerlukan waktu lama di systrace, tetapi Anda tidak tahu alasannya, simpleperf dapat memberikan informasi tambahan.

Proses debug manual pada setiap pengujian yang dijalankan sangat penting untuk memahami dan mendebug masalah performa ini. Langkah-langkah di atas tidak dapat diganti dengan menganalisis data gabungan. Namun, menyiapkan pengumpulan metrik dalam pengujian otomatis serta di lapangan juga penting untuk memahami apa yang sebenarnya dilihat dan diidentifikasi pengguna saat terjadi regresi:

  • Alur pengaktifan
  • Jank
    • Metrik kolom
      • Konsol Play frame vitals: Perlu diketahui bahwa dalam Konsol Play, Anda tidak dapat mempersempit metrik ke perjalanan pengguna tertentu, karena semua yang dilaporkan adalah keseluruhan jank di seluruh aplikasi.
      • Pengukuran kustom dengan FrameMetricsAggregator: Anda dapat menggunakan FrameMetricsAggregator untuk merekam metrik jank selama alur kerja tertentu.
    • Pengujian lab
      • Jetpack Macrobenchmark: Men-scroll
      • Macrobenchmark mengumpulkan waktu render frame menggunakan perintah dumpsys gfxinfo yang mengelompokkan perjalanan pengguna. Ini adalah cara yang wajar untuk memahami variasi dalam jank selama perjalanan pengguna tertentu. Metrik RenderTime, yang menyoroti lamanya waktu yang diperlukan untuk menggambar frame, lebih penting daripada jumlah frame yang mengalami jank untuk mengidentifikasi regresi atau peningkatan.

Menyiapkan aplikasi untuk analisis performa

Penyiapan yang benar sangat penting untuk mendapatkan tolok ukur yang akurat, dapat diulang, dan dapat ditindaklanjuti dari aplikasi. Uji pada sistem yang semirip mungkin dengan produksinya, sambil menyembunyikan sumber derau. Di bagian berikut, terdapat langkah-langkah khusus APK dan khusus sistem yang dapat Anda ambil untuk mempersiapkan penyiapan pengujian, yang beberapa di antaranya adalah khusus kasus penggunaan.

Tracepoint

Aplikasi dapat menggunakan kodenya dengan peristiwa perekaman aktivitas khusus.

Saat aktivitas direkam, perekaman aktivitas menimbulkan overhead kecil (sekitar 5 μs) per bagian, jadi jangan letakkan di setiap metode. Hanya dengan merekam aktivitas bagian tugas yang lebih besar (>0,1 md) dapat memberikan insight yang signifikan tentang bottleneck.

Pertimbangan APK

Perhatian: Jangan ukur performa pada build debug.

Varian debug dapat berguna untuk pemecahan masalah dan melambangkan contoh stack, tetapi variasi tersebut memiliki dampak non-linear yang parah terhadap performa. Perangkat yang menjalankan Android 10 (API Level 29) dan yang lebih tinggi dapat menggunakan profileable android:shell="true" dalam manifesnya untuk mengaktifkan pembuatan profil dalam build rilis.

Gunakan konfigurasi penyingkatan kode berkelas produksi. Bergantung pada resource yang digunakan aplikasi Anda, hal ini dapat berdampak besar terhadap performa. Perlu diketahui bahwa konfigurasi ProGuard tertentu menghapus tracepoint, jadi pertimbangkan untuk menghapus aturan tersebut untuk konfigurasi yang Anda gunakan saat menjalankan pengujian.

Kompilasi

Kompilasikan aplikasi Anda di perangkat ke status yang diketahui (umumnya kecepatan atau profil kecepatan). Aktivitas JIT latar belakang dapat memiliki overhead performa yang signifikan, dan Anda akan sering menemukannya jika menginstal ulang APK di antara pengujian. Perintah yang harus dilakukan adalah:

adb shell cmd package compile -m speed -f com.google.packagename

Mode kompilasi 'kecepatan' akan mengompilasi aplikasi sepenuhnya; mode 'profil kecepatan' akan mengompilasi aplikasi berdasarkan profil jalur kode yang digunakan dan dikumpulkan selama penggunaan aplikasi. Terkadang sulit untuk mengumpulkan profil secara konsisten dan benar, jadi jika Anda memutuskan untuk menggunakannya, pastikan profil tersebut mengumpulkan apa yang Anda harapkan. Profil berada di sini:

/data/misc/profiles/ref/[package-name]/primary.prof

Perlu diketahui bahwa Macrobenchmark memungkinkan Anda langsung menentukan mode kompilasi.

Pertimbangan sistem

Untuk pengukuran level rendah dan fidelitas tinggi, kalibrasikan perangkat Anda. Jalankan perbandingan A/B di perangkat dan versi OS yang sama. Mungkin ada perbedaan yang signifikan dalam performa, bahkan pada jenis perangkat yang sama.

Di perangkat yang telah di-root, pertimbangkan untuk menggunakan skrip lockClocks untuk tolok ukur mikro. Di antara hal lain, skrip ini melakukan hal berikut:

  • Menempatkan CPU pada frekuensi tetap.
  • Menonaktifkan core kecil yang mengonfigurasi GPU.
  • Menonaktifkan throttling termal.

Ini tidak direkomendasikan untuk pengujian yang berfokus pada pengalaman pengguna (seperti peluncuran aplikasi, pengujian DoU, dan pengujian jank), tetapi dapat menjadi penting untuk mengurangi derau dalam pengujian tolok ukur mikro.

Jika memungkinkan, pertimbangkan untuk menggunakan framework pengujian seperti Macrobenchmark, yang dapat mengurangi derau dalam pengukuran dan mencegah ketidakakuratan pengukuran.

Waktu pengaktifan aplikasi lambat: aktivitas trampolin yang tidak perlu

Aktivitas trampolin dapat memperpanjang waktu pengaktifan aplikasi yang tidak perlu, dan penting untuk diketahui jika aplikasi melakukannya. Seperti yang dapat Anda lihat dalam contoh rekaman aktivitas berikut, satu activityStart langsung diikuti oleh activityStart lain tanpa frame yang digambar oleh aktivitas pertama.

alt_text

Hal ini dapat terjadi pada titik entri notifikasi dan titik entri pengaktifan aplikasi biasa, dan sering kali dapat diatasi dengan pemfaktoran ulang. Misalnya, jika Anda menggunakan aktivitas tersebut untuk melakukan penyiapan sebelum aktivitas lain berjalan, faktorkan kode tersebut ke dalam komponen atau library yang dapat digunakan kembali.

Alokasi yang tidak diperlukan memicu seringnya GC

Anda dapat mengetahui bahwa Pembersihan Sampah Memori (GC) lebih sering daripada yang diharapkan dalam systrace.

Dalam hal ini, setiap 10 detik selama operasi yang berjalan lama adalah indikator bahwa aplikasi Anda mungkin melakukan alokasi secara tidak perlu tetapi konsisten dari waktu ke waktu:

alt_text

Atau, Anda mungkin mengetahui bahwa callstack tertentu melakukan sebagian besar alokasi saat menggunakan Memory Profiler. Anda tidak perlu menghilangkan semua alokasi secara agresif, karena hal ini dapat membuat kode lebih sulit dipertahankan. Mulai dengan mengerjakan hotspot alokasi.

Frame yang mengalami jank

Pipeline grafis relatif rumit, dan mungkin ada perbedaan kecil yang terlibat dalam menentukan apakah pengguna pada akhirnya mungkin melihat penurunan frame; dalam kasus tertentu, platform dapat "menyelamatkan" frame menggunakan buffering. Namun, Anda dapat mengabaikan sebagian besar perbedaan kecil tersebut untuk mengidentifikasi frame yang bermasalah dengan mudah dari perspektif aplikasi Anda.

Jika frame digambar dengan sedikit tugas yang diperlukan dari aplikasi, tracepoint Choreographer.doFrame() terjadi pada ritme 16,7 md (dengan asumsi perangkat 60 FPS):

alt_text

Jika memperkecil dan menavigasi rekaman aktivitas, terkadang Anda akan melihat frame memerlukan waktu sedikit lebih lama untuk diselesaikan, tetapi itu tidak masalah karena frame tersebut tidak memerlukan waktu lebih dari 16,7 md:

alt_text

Jika Anda benar-benar melihat gangguan pada ritme teratur tersebut, itulah frame yang mengalami jank:

alt_text

Dengan sedikit latihan, Anda akan dapat melihatnya dengan mudah.

alt_text

Dalam kasus tertentu, Anda harus memperbesar tracepoint tersebut untuk mendapatkan informasi selengkapnya tentang tampilan yang sedang di-inflate atau hal yang dilakukan RecyclerView. Dalam kasus lain, Anda mungkin harus memeriksa lebih lanjut.

Untuk informasi selengkapnya tentang cara mengidentifikasi frame yang mengalami jank dan mendebug penyebabnya, lihat Rendering lambat.

Kesalahan umum RecyclerView

  • Pembatalan validasi seluruh data cadangan RecyclerView yang tidak perlu. Hal ini dapat menyebabkan waktu rendering frame yang lama sehingga terjadi jank. Sebagai gantinya, batalkan validasi hanya data yang telah berubah untuk meminimalkan jumlah tampilan yang perlu diperbarui.
    • Lihat Mempresentasikan data dinamis untuk mengetahui cara menghindari panggilan notifyDatasetChanged() yang mahal, yang menyebabkan konten diperbarui, bukan diganti sepenuhnya.
  • Gagal mendukung RecyclerView bertingkat dengan benar, sehingga menyebabkan RecyclerView internal dibuat ulang sepenuhnya setiap saat.
    • Setiap bagian dalam RecyclerView bertingkat harus memiliki kumpulan RecycledViewPool untuk memastikan tampilan dapat didaur ulang di antara bagian dalam RecyclerView.
  • Tidak mengambil data yang memadai, atau tidak mengambil data secara tepat waktu. Mencapai bagian bawah daftar scroll dengan cepat dan perlu menunggu lebih banyak data dari server mungkin menyebalkan. Meskipun secara teknis ini bukan "jank", karena tidak ada tenggat frame yang terlewat, mengubah waktu dan kuantitas pengambilan data agar pengguna tidak perlu menunggu data dapat menjadi peningkatan UX yang signifikan.