Pengujian performa

Android 8.0 menyertakan pengujian performa binder dan hwbinder untuk throughput dan latensi. Meskipun terdapat banyak skenario untuk mendeteksi masalah kinerja yang nyata, menjalankan skenario seperti itu dapat memakan waktu dan sering kali hasilnya baru dapat diperoleh setelah sistem terintegrasi. Menggunakan tes kinerja yang disediakan memudahkan pengujian selama pengembangan, mendeteksi masalah serius lebih awal, dan meningkatkan pengalaman pengguna.

Tes kinerja mencakup empat kategori berikut:

  • throughput pengikat (tersedia di system/libhwbinder/vts/performance/Benchmark_binder.cpp )
  • latensi pengikat (tersedia di frameworks/native/libs/binder/tests/schd-dbg.cpp )
  • throughput hwbinder (tersedia di system/libhwbinder/vts/performance/Benchmark.cpp )
  • latensi hwbinder (tersedia di system/libhwbinder/vts/performance/Latency.cpp )

Tentang pengikat dan hwbinder

Binder dan hwbinder adalah infrastruktur komunikasi antar-proses (IPC) Android yang menggunakan driver Linux yang sama namun memiliki perbedaan kualitatif berikut:

Aspek bahan pengikat pengikat hw
Tujuan Menyediakan skema IPC tujuan umum untuk kerangka kerja Berkomunikasi dengan perangkat keras
Properti Dioptimalkan untuk penggunaan kerangka Android Latensi rendah overhead minimum
Ubah kebijakan penjadwalan untuk latar depan/latar belakang Ya TIDAK
Argumen berlalu Menggunakan serialisasi yang didukung oleh objek Parcel Menggunakan buffer pencar dan menghindari overhead untuk menyalin data yang diperlukan untuk serialisasi Parcel
Warisan prioritas TIDAK Ya

Proses pengikat dan hwbinder

Visualisator systrace menampilkan transaksi sebagai berikut:

Gambar 1. Visualisasi Systrace dari proses pengikatan.

Dalam contoh di atas:

  • Empat (4) proses schd-dbg adalah proses klien.
  • Empat (4) proses pengikat adalah proses server (nama dimulai dengan Binder dan diakhiri dengan nomor urut).
  • Proses klien selalu dipasangkan dengan proses server, yang didedikasikan untuk kliennya.
  • Semua pasangan proses klien-server dijadwalkan secara independen oleh kernel secara bersamaan.

Di CPU 1, kernel OS mengeksekusi klien untuk mengeluarkan permintaan. Kemudian menggunakan CPU yang sama bila memungkinkan untuk membangunkan proses server, menangani permintaan, dan mengalihkan konteks kembali setelah permintaan selesai.

Throughput vs. latensi

Dalam transaksi yang sempurna, di mana proses klien dan server beralih secara mulus, pengujian throughput dan latensi tidak menghasilkan pesan yang jauh berbeda. Namun, ketika kernel OS menangani permintaan interupsi (IRQ) dari perangkat keras, menunggu kunci, atau sekadar memilih untuk tidak segera menangani pesan, gelembung latensi dapat terbentuk.

Gambar 2. Gelembung latensi akibat perbedaan throughput dan latensi.

Uji throughput menghasilkan sejumlah besar transaksi dengan ukuran payload berbeda, memberikan perkiraan yang baik untuk waktu transaksi reguler (dalam skenario terbaik) dan throughput maksimum yang dapat dicapai pengikat.

Sebaliknya, pengujian latensi tidak melakukan tindakan apa pun pada payload untuk meminimalkan waktu transaksi reguler. Kita dapat menggunakan waktu transaksi untuk memperkirakan overhead pengikat, membuat statistik untuk kasus terburuk, dan menghitung rasio transaksi yang latensinya memenuhi tenggat waktu yang ditentukan.

Tangani inversi prioritas

Inversi prioritas terjadi ketika thread dengan prioritas lebih tinggi secara logis menunggu thread dengan prioritas lebih rendah. Aplikasi real-time (RT) memiliki masalah inversi prioritas:

Gambar 3. Inversi prioritas dalam aplikasi real-time.

Saat menggunakan penjadwalan Linux Completely Fair Scheduler (CFS), sebuah thread selalu memiliki peluang untuk berjalan meskipun thread lain memiliki prioritas lebih tinggi. Hasilnya, aplikasi dengan penjadwalan CFS menangani inversi prioritas sesuai perilaku yang diharapkan dan bukan sebagai masalah. Namun, jika framework Android memerlukan penjadwalan RT untuk menjamin hak istimewa thread berprioritas tinggi, inversi prioritas harus diselesaikan.

Contoh inversi prioritas selama transaksi pengikat (thread RT secara logis diblokir oleh thread CFS lainnya ketika menunggu thread pengikat untuk diservis):

Gambar 4. Inversi prioritas, thread real-time yang diblokir.

Untuk menghindari penyumbatan, Anda dapat menggunakan pewarisan prioritas untuk mengeskalasi sementara thread Binder ke thread RT saat melayani permintaan dari klien RT. Ingatlah bahwa penjadwalan RT memiliki sumber daya yang terbatas dan harus digunakan dengan hati-hati. Dalam sistem dengan n CPU, jumlah maksimum thread RT saat ini juga n ; thread RT tambahan mungkin perlu menunggu (dan karenanya melewati tenggat waktu) jika semua CPU digunakan oleh thread RT lainnya.

Untuk mengatasi semua kemungkinan inversi prioritas, Anda dapat menggunakan pewarisan prioritas untuk binder dan hwbinder. Namun, karena pengikat digunakan secara luas di seluruh sistem, mengaktifkan pewarisan prioritas untuk transaksi pengikat mungkin akan mengirim spam ke sistem dengan lebih banyak rangkaian RT daripada yang dapat dilayaninya.

Jalankan tes throughput

Tes throughput dijalankan terhadap throughput transaksi pengikat/hwbinder. Dalam sistem yang tidak kelebihan beban, gelembung latensi jarang terjadi dan dampaknya dapat dihilangkan selama jumlah iterasinya cukup tinggi.

  • Tes throughput pengikat ada di system/libhwbinder/vts/performance/Benchmark_binder.cpp .
  • Tes throughput hwbinder ada di system/libhwbinder/vts/performance/Benchmark.cpp .

Hasil tes

Contoh hasil pengujian throughput untuk transaksi yang menggunakan ukuran payload berbeda:

Benchmark                      Time          CPU           Iterations
---------------------------------------------------------------------
BM_sendVec_binderize/4         70302 ns      32820 ns      21054
BM_sendVec_binderize/8         69974 ns      32700 ns      21296
BM_sendVec_binderize/16        70079 ns      32750 ns      21365
BM_sendVec_binderize/32        69907 ns      32686 ns      21310
BM_sendVec_binderize/64        70338 ns      32810 ns      21398
BM_sendVec_binderize/128       70012 ns      32768 ns      21377
BM_sendVec_binderize/256       69836 ns      32740 ns      21329
BM_sendVec_binderize/512       69986 ns      32830 ns      21296
BM_sendVec_binderize/1024      69714 ns      32757 ns      21319
BM_sendVec_binderize/2k        75002 ns      34520 ns      20305
BM_sendVec_binderize/4k        81955 ns      39116 ns      17895
BM_sendVec_binderize/8k        95316 ns      45710 ns      15350
BM_sendVec_binderize/16k      112751 ns      54417 ns      12679
BM_sendVec_binderize/32k      146642 ns      71339 ns       9901
BM_sendVec_binderize/64k      214796 ns     104665 ns       6495
  • Waktu menunjukkan penundaan perjalanan pulang pergi yang diukur secara real time.
  • CPU menunjukkan akumulasi waktu ketika CPU dijadwalkan untuk pengujian.
  • Iterasi menunjukkan berapa kali fungsi pengujian dijalankan.

Misalnya, untuk payload 8 byte:

BM_sendVec_binderize/8         69974 ns      32700 ns      21296

… throughput maksimum yang dapat dicapai pengikat dihitung sebagai:

Throughput MAKSIMUM dengan payload 8-byte = (8 * 21296)/69974 ~= 2,423 b/ns ~= 2,268 Gb/s

Opsi tes

Untuk mendapatkan hasil dalam .json, jalankan pengujian dengan argumen --benchmark_format=json :

libhwbinder_benchmark --benchmark_format=json
{
  "context": {
    "date": "2017-05-17 08:32:47",
    "num_cpus": 4,
    "mhz_per_cpu": 19,
    "cpu_scaling_enabled": true,
    "library_build_type": "release"
  },
  "benchmarks": [
    {
      "name": "BM_sendVec_binderize/4",
      "iterations": 32342,
      "real_time": 47809,
      "cpu_time": 21906,
      "time_unit": "ns"
    },
   ….
}

Jalankan tes latensi

Tes latensi mengukur waktu yang diperlukan klien untuk mulai menginisialisasi transaksi, beralih ke proses server untuk penanganan, dan menerima hasilnya. Pengujian ini juga mencari perilaku penjadwal buruk yang diketahui dapat berdampak negatif pada latensi transaksi, seperti penjadwal yang tidak mendukung pewarisan prioritas atau tidak mengikuti tanda sinkronisasi.

  • Tes latensi pengikat ada di frameworks/native/libs/binder/tests/schd-dbg.cpp .
  • Tes latensi hwbinder ada di system/libhwbinder/vts/performance/Latency.cpp .

Hasil tes

Hasil (dalam .json) menunjukkan statistik latensi rata-rata/terbaik/terburuk dan jumlah tenggat waktu yang terlewat.

Opsi tes

Tes latensi mengambil opsi berikut:

Memerintah Keterangan
-i value Tentukan jumlah iterasi.
-pair value Tentukan jumlah pasangan proses.
-deadline_us 2500 Tentukan batas waktu di kami.
-v Dapatkan keluaran verbose (debugging).
-trace Hentikan jejak jika tenggat waktu telah tercapai.

Bagian berikut merinci setiap opsi, menjelaskan penggunaan, dan memberikan contoh hasil.

Tentukan iterasi

Contoh dengan sejumlah besar iterasi dan keluaran verbose dinonaktifkan:

libhwbinder_latency -i 5000 -pair 3
{
"cfg":{"pair":3,"iterations":5000,"deadline_us":2500},
"P0":{"SYNC":"GOOD","S":9352,"I":10000,"R":0.9352,
  "other_ms":{ "avg":0.2 , "wst":2.8 , "bst":0.053, "miss":2, "meetR":0.9996},
  "fifo_ms": { "avg":0.16, "wst":1.5 , "bst":0.067, "miss":0, "meetR":1}
},
"P1":{"SYNC":"GOOD","S":9334,"I":10000,"R":0.9334,
  "other_ms":{ "avg":0.19, "wst":2.9 , "bst":0.055, "miss":2, "meetR":0.9996},
  "fifo_ms": { "avg":0.16, "wst":3.1 , "bst":0.066, "miss":1, "meetR":0.9998}
},
"P2":{"SYNC":"GOOD","S":9369,"I":10000,"R":0.9369,
  "other_ms":{ "avg":0.19, "wst":4.8 , "bst":0.055, "miss":6, "meetR":0.9988},
  "fifo_ms": { "avg":0.15, "wst":1.8 , "bst":0.067, "miss":0, "meetR":1}
},
"inheritance": "PASS"
}

Hasil pengujian ini menunjukkan hal berikut:

"pair":3
Membuat satu pasangan klien dan server.
"iterations": 5000
Termasuk 5000 iterasi.
"deadline_us":2500
Batas waktu adalah 2500us (2,5ms); sebagian besar transaksi diharapkan memenuhi nilai ini.
"I": 10000
Satu iterasi pengujian mencakup dua (2) transaksi:
  • Satu transaksi dengan prioritas normal ( CFS other )
  • Satu transaksi berdasarkan prioritas waktu nyata ( RT-fifo )
5000 iterasi sama dengan total 10.000 transaksi.
"S": 9352
9352 transaksi disinkronkan dalam CPU yang sama.
"R": 0.9352
Menunjukkan rasio di mana klien dan server disinkronkan bersama dalam CPU yang sama.
"other_ms":{ "avg":0.2 , "wst":2.8 , "bst":0.053, "miss":2, "meetR":0.9996}
Kasus rata-rata ( avg ), terburuk ( wst ), dan terbaik ( bst ) untuk semua transaksi yang dikeluarkan oleh penelepon prioritas normal. Dua transaksi miss tenggat waktu sehingga rasio pertemuan ( meetR ) 0,9996.
"fifo_ms": { "avg":0.16, "wst":1.5 , "bst":0.067, "miss":0, "meetR":1}
Mirip dengan other_ms , tetapi untuk transaksi yang dikeluarkan oleh klien dengan prioritas rt_fifo . Kemungkinan besar (tetapi tidak wajib) fifo_ms memiliki hasil yang lebih baik daripada other_ms , dengan nilai avg dan wst yang lebih rendah serta meetR yang lebih tinggi (perbedaannya bisa menjadi lebih signifikan dengan pemuatan di latar belakang).

Catatan: Pemuatan latar belakang dapat memengaruhi hasil throughput dan tupel other_ms dalam pengujian latensi. Hanya fifo_ms yang dapat menampilkan hasil serupa selama pemuatan latar belakang memiliki prioritas lebih rendah daripada RT-fifo .

Tentukan nilai pasangan

Setiap proses klien dipasangkan dengan proses server yang didedikasikan untuk klien, dan setiap pasangan dapat dijadwalkan secara independen ke CPU mana pun. Namun, migrasi CPU tidak boleh terjadi selama transaksi selama flag SYNC-nya adalah honor .

Pastikan sistem tidak kelebihan beban! Meskipun diharapkan terjadi latensi tinggi pada sistem yang kelebihan beban, hasil pengujian untuk sistem yang kelebihan beban tidak memberikan informasi yang berguna. Untuk menguji sistem dengan tekanan lebih tinggi, gunakan -pair #cpu-1 (atau -pair #cpu dengan hati-hati). Pengujian menggunakan -pair n dengan n > #cpu membebani sistem dan menghasilkan informasi yang tidak berguna.

Tentukan nilai tenggat waktu

Setelah pengujian skenario pengguna yang ekstensif (menjalankan pengujian latensi pada produk yang memenuhi syarat), kami menentukan bahwa 2,5 ms adalah batas waktu yang harus dipenuhi. Untuk aplikasi baru dengan persyaratan lebih tinggi (misalnya 1000 foto/detik), nilai tenggat waktu ini akan berubah.

Tentukan keluaran verbose

Menggunakan opsi -v menampilkan keluaran verbose. Contoh:

libhwbinder_latency -i 1 -v

-------------------------------------------------- service pid: 8674 tid: 8674 cpu: 1 SCHED_OTHER 0
-------------------------------------------------- main pid: 8673 tid: 8673 cpu: 1 -------------------------------------------------- client pid: 8677 tid: 8677 cpu: 0 SCHED_OTHER 0
-------------------------------------------------- fifo-caller pid: 8677 tid: 8678 cpu: 0 SCHED_FIFO 99 -------------------------------------------------- hwbinder pid: 8674 tid: 8676 cpu: 0 ??? 99
-------------------------------------------------- other-caller pid: 8677 tid: 8677 cpu: 0 SCHED_OTHER 0 -------------------------------------------------- hwbinder pid: 8674 tid: 8676 cpu: 0 SCHED_OTHER 0
  • Utas layanan dibuat dengan prioritas SCHED_OTHER dan dijalankan di CPU:1 dengan pid 8674 .
  • Transaksi pertama kemudian dimulai oleh fifo-caller . Untuk melayani transaksi ini, hwbinder meningkatkan prioritas server ( pid: 8674 tid: 8676 ) menjadi 99 dan juga menandainya dengan kelas penjadwalan sementara (dicetak sebagai ??? ). Penjadwal kemudian menempatkan proses server di CPU:0 untuk dijalankan dan menyinkronkannya dengan CPU yang sama dengan kliennya.
  • Penelepon transaksi kedua memiliki prioritas SCHED_OTHER . Server menurunkan versinya sendiri dan melayani penelepon dengan prioritas SCHED_OTHER .

Gunakan jejak untuk debugging

Anda dapat menentukan opsi -trace untuk men-debug masalah latensi. Saat digunakan, pengujian latensi menghentikan perekaman tracelog pada saat latensi buruk terdeteksi. Contoh:

atrace --async_start -b 8000 -c sched idle workq binder_driver sync freq
libhwbinder_latency -deadline_us 50000 -trace -i 50000 -pair 3
deadline triggered: halt ∓ stop trace
log:/sys/kernel/debug/tracing/trace

Komponen berikut dapat memengaruhi latensi:

  • Mode pembuatan Android . Mode Eng biasanya lebih lambat dibandingkan mode userdebug.
  • Kerangka . Bagaimana layanan kerangka kerja menggunakan ioctl untuk mengonfigurasi ke pengikat?
  • Penggerak pengikat . Apakah pengemudi mendukung penguncian yang halus? Apakah ini berisi semua patch yang mengubah kinerja?
  • Versi kernel . Semakin baik kemampuan real time yang dimiliki kernel, semakin baik pula hasilnya.
  • Konfigurasi kernel . Apakah konfigurasi kernel berisi konfigurasi DEBUG seperti DEBUG_PREEMPT dan DEBUG_SPIN_LOCK ?
  • Penjadwal kernel . Apakah kernel mempunyai penjadwal Energy-Aware (EAS) atau penjadwal Multi-Pemrosesan Heterogen (HMP)? Apakah ada driver kernel ( cpu-freq driver, cpu-idle driver, cpu-hotplug , dll.) yang memengaruhi penjadwal?