Google berkomitmen untuk mendorong terwujudnya keadilan ras bagi komunitas Kulit Hitam. Lihat caranya.
Halaman ini diterjemahkan oleh Cloud Translation API.
Switch to English

Menghindari Pembalikan Prioritas

Artikel ini menjelaskan cara sistem audio Android mencoba menghindari inversi prioritas, dan menyoroti teknik yang dapat Anda gunakan juga.

Teknik ini mungkin berguna untuk pengembang aplikasi audio berkinerja tinggi, OEM, dan penyedia SoC yang mengimplementasikan audio HAL. Harap diperhatikan bahwa menerapkan teknik ini tidak dijamin untuk mencegah gangguan atau kegagalan lain, terutama jika digunakan di luar konteks audio. Hasil Anda mungkin berbeda, dan Anda harus melakukan evaluasi dan pengujian Anda sendiri.

Latar Belakang

Server audio Android AudioFlinger dan implementasi klien AudioTrack / AudioRecord sedang dirancang ulang untuk mengurangi latensi. Pekerjaan ini dimulai di Android 4.1, dan dilanjutkan dengan penyempurnaan lebih lanjut di 4.2, 4.3, 4.4, dan 5.0.

Untuk mencapai latensi yang lebih rendah ini, banyak perubahan diperlukan di seluruh sistem. Satu perubahan penting adalah menetapkan sumber daya CPU ke utas waktu kritis dengan kebijakan penjadwalan yang lebih dapat diprediksi. Penjadwalan yang andal memungkinkan ukuran dan jumlah buffer audio dikurangi sambil tetap menghindari underruns dan overruns.

Pembalikan prioritas

Inversi prioritas adalah mode kegagalan klasik sistem real-time, di mana tugas dengan prioritas lebih tinggi diblokir untuk waktu yang tidak terbatas menunggu tugas dengan prioritas lebih rendah untuk merilis sumber daya seperti (status bersama dilindungi oleh) mutex .

Dalam sistem audio, inversi prioritas biasanya bermanifestasi sebagai kesalahan (klik, pop, putus), audio berulang saat buffer melingkar digunakan, atau penundaan dalam merespons perintah.

Solusi umum untuk inversi prioritas adalah dengan meningkatkan ukuran buffer audio. Namun, metode ini meningkatkan latensi dan hanya menyembunyikan masalah alih-alih menyelesaikannya. Lebih baik untuk memahami dan mencegah pembalikan prioritas, seperti yang terlihat di bawah ini.

Dalam implementasi audio Android, inversi prioritas kemungkinan besar terjadi di tempat-tempat ini. Jadi Anda harus memusatkan perhatian Anda di sini:

  • antara ulir mixer normal dan ulir mixer cepat di AudioFlinger
  • antara utas panggilan balik aplikasi untuk AudioTrack cepat dan utas mixer cepat (keduanya memiliki prioritas yang lebih tinggi, tetapi prioritas yang sedikit berbeda)
  • antara utas panggilan balik aplikasi untuk AudioRecord cepat dan utas tangkapan cepat (mirip dengan sebelumnya)
  • dalam implementasi Audio Hardware Abstraction Layer (HAL), misalnya untuk telepon atau pembatalan gema
  • dalam driver audio di kernel
  • antara utas panggilan balik AudioTrack atau AudioRecord dan utas aplikasi lain (ini di luar kendali kami)

Solusi umum

Solusi tipikal meliputi:

  • menonaktifkan interupsi
  • mutex warisan prioritas

Menonaktifkan interupsi tidak dapat dilakukan di ruang pengguna Linux, dan tidak berfungsi untuk Symmetric Multi-Processors (SMP).

Futex warisan prioritas ( mutex ruang pengguna cepat) tersedia di kernel Linux, tetapi saat ini tidak diekspos oleh pustaka waktu proses Android C Bionic . Mereka tidak digunakan dalam sistem audio karena relatif kelas berat, dan karena mengandalkan klien tepercaya.

Teknik yang digunakan oleh Android

Eksperimen dimulai dengan "coba kunci" dan kunci dengan batas waktu. Ini adalah varian pemblokiran non-pemblokiran dan terikat dari operasi kunci mutex. Coba kunci dan kunci dengan waktu tunggu bekerja cukup baik tetapi rentan terhadap beberapa mode kegagalan yang tidak jelas: server tidak dijamin dapat mengakses status bersama jika klien kebetulan sibuk, dan batas waktu kumulatif bisa jadi terlalu lama jika ada urutan panjang kunci yang tidak terkait yang habis waktunya.

Kami juga menggunakan operasi atom seperti:

  • kenaikan
  • bitwise "atau"
  • bitwise "dan"

Semua ini mengembalikan nilai sebelumnya dan mencakup hambatan SMP yang diperlukan. Kerugiannya adalah mereka dapat memerlukan percobaan ulang tanpa batas. Dalam praktiknya, kami menemukan bahwa percobaan ulang tidak menjadi masalah.

Catatan: Operasi atom dan interaksinya dengan hambatan memori sangat disalahpahami dan digunakan secara tidak benar. Kami menyertakan metode ini di sini untuk kelengkapan tetapi merekomendasikan Anda juga membaca artikel SMP Primer untuk Android untuk informasi lebih lanjut.

Kami masih memiliki dan menggunakan sebagian besar alat di atas, dan baru-baru ini menambahkan teknik berikut:

  • Gunakan antrian FIFO pembaca tunggal non-pemblokiran untuk data.
  • Cobalah untuk menyalin status daripada berbagi status antara modul prioritas tinggi dan rendah.
  • Jika status memang perlu dibagikan, batasi status ke kata berukuran maksimum yang dapat diakses secara atomis dalam operasi satu bus tanpa mencoba lagi.
  • Untuk status multi-kata yang kompleks, gunakan antrian negara. Antrean status pada dasarnya hanyalah antrean FIFO pembaca tunggal non-pemblokiran yang digunakan untuk status, bukan data, kecuali penulis menciutkan dorongan yang berdekatan ke dalam satu dorongan.
  • Perhatikan hambatan memori untuk ketepatan SMP.
  • Percaya, tapi verifikasi . Saat berbagi status antar proses, jangan berasumsi bahwa status terbentuk dengan baik. Misalnya, periksa apakah indeks berada dalam batas-batas. Verifikasi ini tidak diperlukan di antara utas dalam proses yang sama, antara proses yang saling percaya (yang biasanya memiliki UID yang sama). Ini juga tidak perlu untuk data bersama seperti audio PCM di mana korupsi tidak penting.

Algoritme non-pemblokiran

Algoritme non-pemblokiran telah menjadi subjek dari banyak penelitian terbaru. Tetapi dengan pengecualian antrean FIFO pembaca tunggal satu penulis, kami menganggapnya rumit dan rawan kesalahan.

Mulai Android 4.2, Anda dapat menemukan kelas non-blocking, single-reader / writer kami di lokasi berikut:

  • frameworks / av / include / media / nbaio /
  • frameworks / av / media / libnbaio /
  • framework / av / services / audioflinger / StateQueue *

Ini dirancang khusus untuk AudioFlinger dan bukan untuk tujuan umum. Algoritme non-pemblokiran terkenal sulit untuk di-debug. Anda dapat melihat kode ini sebagai model. Namun perlu diketahui bahwa mungkin ada bug, dan kelas tidak dijamin cocok untuk tujuan lain.

Untuk pengembang, beberapa contoh kode aplikasi OpenSL ES harus diperbarui untuk menggunakan algoritme non-pemblokiran atau merujuk pustaka sumber terbuka non-Android.

Kami telah menerbitkan contoh implementasi FIFO non-pemblokiran yang dirancang khusus untuk kode aplikasi. Lihat file-file ini yang terletak di frameworks/av/audio_utils direktori sumber platform frameworks/av/audio_utils :

Alat

Sejauh pengetahuan kami, tidak ada alat otomatis untuk menemukan pembalikan prioritas, terutama sebelum itu terjadi. Beberapa alat analisis kode statis penelitian mampu menemukan inversi prioritas jika dapat mengakses seluruh basis kode. Tentu saja, jika kode pengguna arbitrer terlibat (seperti yang ada di sini untuk aplikasi) atau basis kode yang besar (seperti untuk kernel Linux dan driver perangkat), analisis statis mungkin tidak praktis. Yang paling penting adalah membaca kode dengan sangat hati-hati dan memahami dengan baik seluruh sistem dan interaksinya. Alat seperti systrace dan ps -t -p berguna untuk melihat inversi prioritas setelah terjadi, tetapi tidak memberi tahu Anda sebelumnya.

Kata terakhir

Setelah semua diskusi ini, jangan takut dengan mutex. Mutex adalah teman Anda untuk penggunaan biasa, jika digunakan dan diterapkan dengan benar dalam kasus penggunaan biasa yang tidak membutuhkan waktu kritis. Tetapi antara tugas dengan prioritas tinggi dan rendah dan dalam sistem yang sensitif terhadap waktu, mutex lebih cenderung menyebabkan masalah.