Pengujian performa

Android 8.0 mencakup pengujian performa binder dan hwbinder untuk throughput dan latensi yang rendah. Meskipun ada banyak skenario untuk mendeteksi performa yang dapat terlihat masalah, menjalankan skenario seperti itu dapat memakan waktu dan hasilnya sering tidak tersedia sampai setelah sistem diintegrasikan. Menggunakan performa yang diberikan pengujian mempermudah pengujian selama pengembangan, mendeteksi masalah serius lebih awal, dan meningkatkan pengalaman pengguna.

Pengujian performa mencakup empat kategori berikut:

  • throughput binder (tersedia di system/libhwbinder/vts/performance/Benchmark_binder.cpp)
  • latensi binder (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 binder dan hwbinder

Binder dan hwbinder adalah komunikasi antar-proses (IPC) Android infrastruktur yang menggunakan {i>driver<i} Linux yang sama tetapi memiliki perbedaan kualitatif:

Aspek {i>binder<i} Hwbinder
Tujuan Memberikan skema IPC tujuan umum untuk framework Berkomunikasi dengan hardware
Properti Dioptimalkan untuk penggunaan framework Android Overhead minimum latensi rendah
Mengubah kebijakan penjadwalan untuk latar depan/latar belakang Ya Tidak
Penerusan argumen Menggunakan serialisasi yang didukung oleh objek Parcel Menggunakan {i>buffer <i}pencar dan menghindari {i> overhead<i} untuk menyalin data yang diperlukan Serialisasi paket
Pewarisan prioritas Tidak Ya

Proses binder dan hwbinder

Visualizer systrace menampilkan transaksi sebagai berikut:

Gambar 1. Visualisasi binder Systrace proses-proses tersebut.

Dalam contoh di atas:

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

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

Throughput vs. latensi

Dalam transaksi yang sempurna, di mana proses klien dan server beralih dengan lancar, pengujian throughput dan latensi tidak menghasilkan perbedaan yang signifikan membuat pesan teks. Namun, ketika {i>kernel<i} OS menangani permintaan interupsi (IRQ) dari perangkat keras, menunggu kunci, atau hanya memilih untuk tidak menangani pesan maka balon latensi dapat segera terbentuk.

Gambar 2. Balon latensi karena perbedaan throughput dan latensi yang rendah.

Tes throughput menghasilkan transaksi dalam jumlah besar dengan ukuran {i>payload<i}, yang memberikan perkiraan yang baik untuk waktu transaksi reguler (di skenario kasus terbaik) dan throughput maksimum yang dapat dicapai binder.

Sebaliknya, uji latensi tidak melakukan tindakan apa pun pada payload untuk meminimalkan waktu transaksi reguler. Kita dapat menggunakan waktu transaksi untuk memperkirakan binder {i>overhead<i}, membuat statistik untuk kasus terburuk, dan menghitung rasio transaksi yang latensinya memenuhi batas waktu tertentu.

Menangani inversi prioritas

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

Gambar 3. Inversi prioritas secara real-time aplikasi.

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

Contoh inversi prioritas selama transaksi binder (thread RT adalah secara logis diblokir oleh thread CFS lain saat menunggu thread binder untuk ):

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

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

Untuk menyelesaikan semua kemungkinan inversi prioritas, Anda dapat menggunakan pewarisan untuk {i>binder<i} dan {i>hwbinder<i}. Namun, karena binder banyak digunakan di seluruh sistem, memungkinkan pewarisan prioritas untuk transaksi pengikat mungkin mengirim spam ke sistem dengan thread RT lebih banyak daripada yang bisa dilayaninya.

Menjalankan pengujian throughput

Pengujian throughput dijalankan terhadap throughput transaksi binder/hwbinder. Di beberapa dalam sistem yang tidak kelebihan beban, balon latensi jarang terjadi dan dampaknya dapat dihilangkan selama jumlah iterasinya cukup tinggi.

  • Pengujian throughput binder dilakukan system/libhwbinder/vts/performance/Benchmark_binder.cpp.
  • Uji throughput hwbinder sedang system/libhwbinder/vts/performance/Benchmark.cpp.

Hasil uji

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

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 keterlambatan pulang pergi yang diukur secara real time.
  • CPU menunjukkan akumulasi waktu saat CPU dijadwalkan untuk pengujian.
  • Iterasi menunjukkan frekuensi fungsi pengujian telah dijalankan.

Misalnya, untuk payload 8 byte:

BM_sendVec_binderize/8         69974 ns      32700 ns      21296

... throughput maksimum yang dapat dicapai binder dihitung sebagai:

Throughput MAX dengan payload 8 byte = (8 * 21.296)/69974 ~= 2,423 b/ns ~= 2,268 Gb/dtk

Opsi pengujian

Untuk mendapatkan hasil dalam format .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"
    },
   ….
}

Menjalankan uji latensi

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

  • Uji latensi binder dilakukan frameworks/native/libs/binder/tests/schd-dbg.cpp.
  • Tes latensi {i>hwbinder<i} sudah system/libhwbinder/vts/performance/Latency.cpp.

Hasil uji

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

Opsi pengujian

Pengujian latensi menggunakan opsi berikut:

Perintah Deskripsi
-i value Menentukan jumlah iterasi.
-pair value Tentukan jumlah pasangan proses.
-deadline_us 2500 Tentukan batas waktu di kami.
-v Mendapatkan output panjang (proses debug).
-trace Menghentikan jejak pada tenggat waktu.

Bagian berikut menjelaskan setiap opsi, menjelaskan penggunaan, dan menyediakan contoh hasil.

Menentukan iterasi

Contoh dengan sejumlah besar iterasi dan output panjang 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
Mencakup 5.000 iterasi.
"deadline_us":2500
Batas waktu adalah 2.500 μs (2,5 md); sebagian besar transaksi diharapkan memenuhi dengan sejumlah nilai.
"I": 10000
Satu iterasi pengujian mencakup dua (2) transaksi:
  • Satu transaksi dengan prioritas normal (CFS other)
  • Satu transaksi berdasarkan prioritas real time (RT-fifo)
5000 iterasi sama dengan total 10000 transaksi.
"S": 9352
9352 transaksi disinkronkan di CPU yang sama.
"R": 0.9352
Menunjukkan rasio sinkronisasi klien dan server dalam CPU yang sama.
"other_ms":{ "avg":0.2 , "wst":2.8 , "bst":0.053, "miss":2, "meetR":0.9996}
Rata-rata (avg), terburuk (wst), dan terbaik (bst) untuk semua transaksi yang dikeluarkan oleh pemanggil prioritas normal. Dua transaksi miss memiliki batas waktu, sehingga memenuhi rasio pemenuhan (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 dilakukan oleh klien dengan Prioritas rt_fifo. Kemungkinan (tetapi tidak wajib) bahwa fifo_ms memiliki hasil yang lebih baik daripada other_ms, dengan nilai yang lebih rendah Nilai avg dan wst serta meetR yang lebih tinggi (perbedaannya bisa jauh lebih signifikan dengan beban di latar belakang).

Catatan: Beban latar belakang dapat memengaruhi throughput dan tuple other_ms dalam uji latensi. Hanya fifo_ms dapat menampilkan hasil yang serupa selama pemuatan latar belakang telah prioritas yang lebih rendah dari RT-fifo.

Menentukan 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, CPU migrasi tidak boleh terjadi selama transaksi asalkan tanda SYNC honor.

Pastikan sistem tidak kelebihan beban. Sementara latensi tinggi dalam overload sistem apa yang diharapkan, hasil pengujian untuk sistem yang kelebihan beban tidak memberikan tidak akurat atau tidak sesuai. Untuk menguji sistem dengan tekanan lebih tinggi, gunakan -pair #cpu-1 (atau -pair #cpu dengan hati-hati). Menguji menggunakan -pair n dengan n > #cpu akan membebani sistem dan menghasilkan informasi yang tidak berguna.

Menentukan nilai batas waktu

Setelah pengujian skenario pengguna yang ekstensif (menjalankan uji latensi pada produk memenuhi syarat), kami memutuskan bahwa 2,5 md adalah tenggat waktu. Untuk baru aplikasi dengan persyaratan lebih tinggi (seperti 1.000 foto/detik), nilai batas waktu akan berubah.

Menentukan output panjang

Menggunakan opsi -v akan menampilkan output panjang. 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
  • Thread 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 mengupgrade prioritas server (pid: 8674 tid: 8676) menjadi 99 dan juga menandainya dengan class penjadwalan sementara (dicetak sebagai ???). Penjadwal kemudian menempatkan proses server di CPU:0 untuk dijalankan dan menyinkronkannya dengan CPU yang sama dengan kliennya.
  • Pemanggil transaksi kedua memiliki Prioritas SCHED_OTHER. Server mendowngrade servernya sendiri dan melayani pemanggil dengan prioritas SCHED_OTHER.

Menggunakan rekaman aktivitas untuk proses debug

Anda dapat menentukan opsi -trace untuk men-debug masalah latensi. Kapan digunakan, tes latensi menghentikan perekaman {i>tracelog<i} pada saat terjadi latensi 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 build Android. Mode Eng biasanya lebih lambat dari mode userdebug.
  • Framework. Bagaimana cara layanan kerangka kerja menggunakan ioctl untuk mengonfigurasi ke binder?
  • Driver binding. Apakah pengemudi memberikan dukungan terkunci? Apakah berisi semua patch pembalikan performa?
  • Versi kernel. Kemampuan real-time yang lebih baik pada {i>kernel<i} maka semakin baik hasilnya.
  • Konfigurasi kernel. Apakah konfigurasi {i>kernel<i} berisi Konfigurasi DEBUG seperti DEBUG_PREEMPT dan DEBUG_SPIN_LOCK?
  • Penjadwal kernel. Apakah kernel memiliki opsi Energy-Aware scheduler (EAS) atau Heterogeneous Multi-Processing (HMP) scheduler? Melakukan {i>kernel<i} apa pun pengemudi (driver cpu-freq, pengemudi cpu-idle, cpu-hotplug, dll.) memengaruhi penjadwal?