Halo, Habr! Nama saya Artyom Dobrovinsky dan saya adalah seorang pengembang Android di FINCH .
Suatu hari, sambil membungkus diri dalam asap cerutu pagi, saya mempelajari kode sumber satu ORM untuk Android. Melihat ada paket yang disebut benchmarks
segera melihat ke sana, dan terkejut bahwa semua evaluasi dilakukan menggunakan Log.d(System.nanoTime())
. Ini bukan pertama kalinya saya melihat ini. Sejujurnya, saya bahkan melihat benchmark dibuat menggunakan System.currentTimeMillis()
. Kesadaran runtuh bahwa sesuatu perlu diubah memaksa saya untuk mengesampingkan segelas wiski dan duduk di keyboard.
Mengapa artikel ini ditulis?
Situasi dengan memahami bagaimana mengukur kinerja kode di Android menyedihkan.
Jangan berbicara tentang profiler, tetapi pada tahun 2019 seseorang tetap yakin bahwa JVM melakukan semua yang ditulis pengembang dan dalam urutan yang tepat di mana kode ditulis. Pada kenyataannya, tidak ada yang lebih jauh dari kebenaran.
Kenyataannya, mesin virtual yang malang itu berkelahi melawan satu miliar pembaca tombol yang ceroboh yang menulis kode mereka sendiri, tidak perlu khawatir tentang bagaimana prosesor akan bekerja dengan semua ini. Pertempuran ini telah berlangsung selama beberapa tahun, dan dia memiliki sejuta optimisasi rumit di lengan bajunya yang (jika diabaikan) akan mengubah pengukuran kinerja program apa pun menjadi buang-buang waktu.
Artinya, pengembang terkadang tidak menganggap perlu untuk mengukur kinerja kode, dan bahkan lebih sering tidak tahu caranya. Kesulitannya terletak pada kenyataan bahwa untuk melakukan penilaian kinerja, perlu untuk menciptakan kondisi yang paling mirip dan ideal untuk semua kasus - ini adalah satu-satunya cara untuk mendapatkan informasi yang bermanfaat. Kondisi ini diciptakan oleh solusi yang tidak tertulis di lutut.
Jika Anda memerlukan argumen tentang apakah akan menggunakan kerangka kerja pihak ketiga untuk mengukur kinerja, Anda selalu dapat membaca Alexei Shipilev dan mengagumi kedalaman masalahnya. Semuanya ada dalam artikel dengan referensi: mengapa pemanasan diperlukan sebelum melakukan benchmark, mengapa System.currentTimeMillis()
tidak dapat dipercaya sama sekali ketika menghitung waktu yang berlalu, dan lelucon untuk 300. Bacaan yang bagus.
Mengapa saya bisa membicarakan ini?
Faktanya adalah bahwa saya adalah pengembang yang dikembangkan secara komprehensif: Saya tidak hanya memiliki Android SDK seolah-olah itu adalah proyek hewan peliharaan saya, tetapi selama sebulan lagi saya menulis kode untuk backend.
Ketika saya membawa microservice pertama saya ke review, dan tidak ada pembandingan di README
, dia menatap saya dengan kesalahpahaman. Saya ingat ini dan tidak pernah mengulangi kesalahan ini lagi. Karena dia pergi dalam seminggu.
Ayo pergi.
Apa yang kita ukur
Sebagai bagian dari kasus untuk pembandingan basis data untuk Android, saya memutuskan untuk mengukur kecepatan inisialisasi dan kecepatan tulis / baca untuk ORM seperti Paper, Hawk, Realm and Room.
Ya, saya mengukur dalam satu tes NoSQL dan basis data relasional - apa pertanyaan berikutnya?
Daripada kita mengukur
Tampaknya jika kita berbicara tentang JVM, maka pilihannya jelas - ada JMH yang dimuliakan , disempurnakan dan didokumentasikan dengan sempurna . Tapi tidak, itu tidak memulai tes instrumentasi untuk Android.
Google Calipher mengikutinya - dengan hasil yang sama.
Ada garpu Calipher yang disebut Spanner - yang selama bertahun-tahun telah zeppercay dan mendorong penggunaan Androidx Benchmark .
Mari kita fokus pada yang terakhir. Kalau saja karena kita tidak punya pilihan.
Seperti semua yang ditambahkan ke Jetpack dan tidak dipikirkan kembali saat bermigrasi dari Support Library, Androidx Benchmark terlihat dan berperilaku seolah-olah itu ditulis dalam satu setengah minggu sebagai tugas tes, dan tidak ada orang lain yang akan menyentuhnya. Plus, lib ini sedikit lalu - karena, lebih untuk mengevaluasi tes UI. Tetapi karena menginginkan yang terbaik, Anda dapat bekerja dengannya. Ini akan menyelamatkan kita setidaknya dari kesalahan nyata , dan juga membantu pemanasan.
Untuk mengurangi kekonyolan hasil, saya akan menjalankan semua tes 10 kali dan menghitung rata-rata.
Perangkat pengujian - Xiaomi A1. Bukan yang terlemah di pasaran, "bersih" Android.
Menghubungkan perpustakaan ke proyek
Ada instruksi yang sangat baik tentang menghubungkan Andoridx Benchmark ke proyek. Saya sangat menyarankan Anda untuk tidak malas dan menghubungkan modul terpisah untuk melakukan pengukuran.
Kemajuan percobaan
Semua tolok ukur kami akan dieksekusi dalam urutan berikut:
- Pertama, kami menginisiasi database di dalam badan uji.
- Kemudian, di blok
benchmarkRule.scope.runWithTimingDisabled
, kami menghasilkan data yang kami beri makan basis data. Kode yang ditempatkan di sirkuit ini tidak akan diperhitungkan dalam evaluasi. - Dalam penutupan yang sama kami menambahkan logika membersihkan database; pastikan database kosong sebelum menulis.
- Berikut ini adalah logika penulisan dan membaca. Pastikan untuk menginisialisasi variabel dengan hasil membaca sehingga JVM tidak menghapus logika ini dari jumlah eksekusi sebagai tidak terpakai.
- Kami mengukur kinerja inisialisasi basis data dalam fungsi terpisah.
- Kami merasa seperti orang sains.
Kode dapat ditemukan di sini . Jika Anda malas berjalan, fungsi pengukuran untuk PaperDb terlihat seperti ini:
@Test fun paperdbInsertReadTest() = benchmarkRule.measureRepeated {
Benchmark untuk sisa ORM terlihat serupa.
Hasil
Inisialisasi
Pemenangnya adalah Realm, di tempat kedua adalah Kertas. Apa yang dilakukan Room, Anda masih dapat membayangkan bahwa Hawk melakukan jumlah waktu yang hampir sama - benar-benar tidak dapat dipahami.
Menulis dan membaca
Di sini lagi pemenang Realm, tetapi dalam hasil ini bernada kegagalan.
Perbedaan empat kali antara dua database "paling lambat" dan enam belas kali antara "tercepat" dan "paling lambat" sangat mencurigakan. Bahkan dengan mempertimbangkan fakta bahwa perbedaannya stabil.
Kesimpulan
Mengukur kinerja kode Anda setidaknya karena penasaran. Bahkan jika kita berbicara tentang kasus yang paling banyak diluncurkan oleh industri (seperti evaluasi tes instrumental untuk Android).
Ada banyak alasan untuk menggunakan kerangka kerja pihak ketiga untuk bisnis ini (daripada menulis sendiri sesuai waktu dan pemandu sorak).
Situasi dalam basis kode sedemikian rupa sehingga setiap orang berusaha menulis dalam arsitektur yang bersih, karena sebagian besar, modul dengan logika bisnis adalah modul java - menghubungkan modul dengan JMH terdekat dan memeriksa kode untuk kemacetan - ia bekerja selama sehari. Dan manfaatnya - untuk tahun-tahun mendatang.
Selamat coding!
PS: Jika pembaca yang penuh perhatian tahu tentang kerangka kerja untuk melakukan benchmark tes instrumental untuk Android, tidak tercantum dalam artikel - silakan berbagi di komentar.
PPS: Gudang uji terbuka untuk permintaan tarik.