Öncelikli inversiyondan kaçınma

Bu makale, Android'in ses sisteminin öncelikli ters çevirmeden nasıl kaçınmaya çalıştığını açıklar ve sizin de kullanabileceğiniz teknikleri vurgular.

Bu teknikler, yüksek performanslı ses uygulamaları geliştiricileri, OEM'ler ve bir ses HAL'ı uygulayan SoC sağlayıcıları için yararlı olabilir. Lütfen bu tekniklerin uygulanmasının, özellikle ses bağlamı dışında kullanılıyorsa, aksaklıkları veya diğer arızaları önleme garantisi olmadığını unutmayın. Sonuçlarınız değişebilir ve kendi değerlendirmenizi ve testinizi kendiniz yapmalısınız.

Arka fon

Android AudioFlinger ses sunucusu ve AudioTrack/AudioRecord istemci uygulaması, gecikmeyi azaltmak için yeniden tasarlanıyor. Bu çalışma Android 4.1'de başladı ve 4.2, 4.3, 4.4 ve 5.0'daki geliştirmelerle devam etti.

Bu daha düşük gecikmeyi elde etmek için sistem genelinde birçok değişiklik yapılması gerekiyordu. Önemli bir değişiklik, CPU kaynaklarını daha öngörülebilir bir zamanlama ilkesiyle kritik zaman iş parçacıklarına atamaktır. Güvenilir zamanlama, ses arabellek boyutlarının ve sayımlarının azaltılmasına izin verirken, yine de yetersiz ve aşımlardan kaçınılır.

Öncelik inversiyonu

Önceliği tersine çevirme , gerçek zamanlı sistemlerin klasik bir başarısızlık modudur; burada daha yüksek öncelikli bir görev sınırsız bir süre boyunca engellenir ve daha düşük öncelikli bir görevin bir mutex (ortak durum tarafından korunan) gibi bir kaynağı serbest bırakmasını bekler.

Bir ses sisteminde, öncelikli ters çevirme tipik olarak bir aksaklık (tıklama, açma, bırakma), dairesel arabellekler kullanıldığında tekrarlanan ses veya bir komuta yanıt vermede gecikme olarak kendini gösterir.

Öncelikli tersine çevirme için yaygın bir geçici çözüm, ses arabellek boyutlarını artırmaktır. Ancak bu yöntem gecikmeyi artırır ve sorunu çözmek yerine yalnızca gizler. Aşağıda görüldüğü gibi öncelikli ters çevirmeyi anlamak ve önlemek daha iyidir.

Android ses uygulamasında, öncelikli tersine çevirmenin bu yerlerde meydana gelmesi daha olasıdır. Ve böylece dikkatinizi buraya odaklamalısınız:

  • AudioFlinger'da normal mikser ipliği ve hızlı mikser ipliği arasında
  • hızlı bir AudioTrack için uygulama geri arama dizisi ile hızlı mikser dizisi arasında (ikisinin de yüksek önceliği vardır, ancak öncelikleri biraz farklıdır)
  • hızlı bir AudioRecord için uygulama geri arama dizisi ile hızlı yakalama dizisi arasında (öncesine benzer)
  • ses Donanım Soyutlama Katmanı (HAL) uygulaması içinde, örneğin telefon veya yankı iptali için
  • çekirdekteki ses sürücüsü içinde
  • AudioTrack veya AudioRecord geri arama dizisi ile diğer uygulama dizileri arasında (bu bizim kontrolümüz dışındadır)

Ortak çözümler

Tipik çözümler şunları içerir:

  • kesintileri devre dışı bırakma
  • öncelikli kalıtım muteksleri

Kesintileri devre dışı bırakmak Linux kullanıcı alanında mümkün değildir ve Simetrik Çoklu İşlemciler (SMP) için çalışmaz.

Öncelikli kalıtım futeksleri (hızlı kullanıcı alanı muteksleri), nispeten ağır oldukları ve güvenilir bir istemciye güvendikleri için ses sisteminde kullanılmaz.

Android tarafından kullanılan teknikler

Deneyler "kilitlemeyi dene" ile başladı ve zaman aşımı ile kilitlendi. Bunlar, muteks kilitleme işleminin bloke olmayan ve sınırlı bloke eden çeşitleridir. Zaman aşımı ile kilitlemeyi ve kilitlemeyi deneyin oldukça iyi çalıştı ancak birkaç belirsiz hata moduna açıktı: istemci meşgulse sunucunun paylaşılan duruma erişebileceği garanti edilmedi ve eğer kümülatif zaman aşımı çok uzun olabilir: hepsi zaman aşımına uğrayan uzun bir ilgisiz kilit dizisi vardı.

Ayrıca aşağıdakiler gibi atomik işlemleri de kullanırız:

  • artış
  • bitsel "veya"
  • bitsel "ve"

Bunların tümü önceki değeri döndürür ve gerekli SMP engellerini içerir. Dezavantajı, sınırsız yeniden deneme gerektirebilmeleridir. Uygulamada, yeniden denemelerin bir sorun olmadığını gördük.

Not: Atomik işlemler ve bunların bellek engelleriyle etkileşimleri kötü bir şekilde yanlış anlaşılmakta ve yanlış kullanılmaktadır. Bu yöntemleri eksiksiz olması için buraya ekledik, ancak daha fazla bilgi için Android için SMP Primer makalesini de okumanızı öneririz.

Yukarıdaki araçların çoğuna hala sahibiz ve bunları kullanıyoruz ve yakın zamanda şu teknikleri ekledik:

  • Veriler için engellenmeyen tek okuyuculu tek yazarlı FIFO kuyruklarını kullanın.
  • Durumu yüksek ve düşük öncelikli modüller arasında paylaşmak yerine durumu kopyalamaya çalışın.
  • Durumun paylaşılması gerektiğinde, durumu yeniden denemeden tek veri yolu işleminde atomik olarak erişilebilen maksimum boyutlu sözcükle sınırlayın.
  • Karmaşık çok kelimeli durum için bir durum kuyruğu kullanın. Bir durum kuyruğu, temel olarak, yazarın bitişik pushları tek bir push'a daraltması dışında, veri yerine durum için kullanılan, engellemeyen, tek okuyuculu, tek yazarlı bir FIFO kuyruğudur.
  • SMP doğruluğu için bellek engellerine dikkat edin.
  • Güven ama doğrula . İşlemler arasında durum paylaşırken, durumun iyi biçimli olduğunu varsaymayın. Örneğin, endekslerin sınırlar içinde olup olmadığını kontrol edin. Bu doğrulama, aynı işlemdeki iş parçacıkları arasında, karşılıklı güvenilen işlemler arasında (genellikle aynı UID'ye sahip olan) gerekli değildir. Ayrıca, bozulmanın önemsiz olduğu PCM sesi gibi paylaşılan veriler için de gereksizdir.

Engellemeyen algoritmalar

Engellemeyen algoritmalar çok yakın zamanda yapılan bir çalışmanın konusu olmuştur. Ancak tek okuyuculu tek yazarlı FIFO kuyrukları dışında, bunların karmaşık ve hataya açık olduğunu gördük.

Android 4.2'den başlayarak, engellemesiz, tek okuyuculu/yazıcı sınıflarımızı şu konumlarda bulabilirsiniz:

  • çerçeveler/av/include/media/nbaio/
  • çerçeveler/av/media/libnbaio/
  • çerçeveler/av/hizmetler/audioflinger/StateQueue*

Bunlar, AudioFlinger için özel olarak tasarlanmıştır ve genel amaçlı değildir. Engellemeyen algoritmalar, hata ayıklamanın zor olmasıyla ünlüdür. Bu koda model olarak bakabilirsiniz. Ancak hatalar olabileceğini ve sınıfların başka amaçlar için uygun olduğunun garanti edilmediğini unutmayın.

Geliştiriciler için, örnek OpenSL ES uygulama kodlarından bazıları, engellemeyen algoritmalar kullanmak veya Android olmayan bir açık kaynak kitaplığına başvurmak için güncellenmelidir.

Uygulama kodu için özel olarak tasarlanmış, engellemeyen bir FIFO uygulaması örneği yayınladık. Platform kaynak dizini frameworks/av/audio_utils içinde bulunan şu dosyalara bakın:

Aletler

Bildiğimiz kadarıyla, öncelikli inversiyonu, özellikle de gerçekleşmeden önce bulmak için otomatik araçlar yoktur. Bazı araştırma statik kod analiz araçları, kod tabanının tamamına erişebiliyorsa, öncelikli inversiyonları bulabilir. Tabii ki, isteğe bağlı kullanıcı kodu söz konusuysa (burada uygulama için olduğu gibi) veya büyük bir kod tabanıysa (Linux çekirdeği ve aygıt sürücüleri için olduğu gibi), statik analiz pratik olmayabilir. En önemli şey, kodu çok dikkatli bir şekilde okumak ve tüm sistemi ve etkileşimleri iyi anlamaktır. systrace ve ps -t -p gibi araçlar, önceliğin tersine çevrilmesini gerçekleştikten sonra görmek için kullanışlıdır, ancak size önceden söylemezler.

son bir söz

Tüm bu tartışmadan sonra mutekslerden korkmayın. Muteksler, sıradan, zaman açısından kritik olmayan kullanım durumlarında doğru kullanıldığında ve uygulandığında, sıradan kullanım için arkadaşınızdır. Ancak yüksek ve düşük öncelikli görevler arasında ve zamana duyarlı sistemlerde mutekslerin sorun yaratması daha olasıdır.