Öncelik tersine çevirme

Bu makalede, Android'in ses sisteminin öncelik tersine çevirme sorununu nasıl önlemeye çalıştığı açıklanmakta ve kullanabileceğiniz teknikler vurgulanmaktadır.

Bu teknikler, yüksek performanslı ses uygulamaları geliştiricileri, OEM'ler ve ses HAL'i uygulayan SoC sağlayıcıları için yararlı olabilir. Bu tekniklerin uygulanmasının, özellikle ses bağlamı dışında kullanıldığında aksaklıkları veya diğer hataları önleme garantisi olmadığını lütfen unutmayın. Sonuçlarınız değişiklik gösterebilir. Kendi değerlendirmenizi ve testinizi yapmanız gerekir.

Arka plan

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'de daha da iyileştirilerek devam etti.

Bu düşük gecikmeyi elde etmek için sistem genelinde birçok değişiklik yapılması gerekiyordu. Önemli değişikliklerden biri, daha tahmin edilebilir bir planlama politikasıyla zaman açısından kritik olan iş parçacıklarına CPU kaynakları atamak. Güvenilir planlama, ses arabelleği boyutlarının ve sayılarının azaltılmasına olanak tanır. Bu sayede, eksik ve fazla çalışma önlenir.

Öncelik ters çevirme

Önceliğin ters dönmesi, gerçek zamanlı sistemlerin klasik bir hata modudur. Bu modda, daha yüksek öncelikli bir görev, daha düşük öncelikli bir görevin mutex (ortak durum tarafından korunan) gibi bir kaynağı serbest bırakmasını beklerken sınırsız bir süre boyunca engellenir.

Ses sistemlerinde öncelik ters çevirme genellikle ses arızası (tıklama, patlama, kesinti), dairesel tamponlar kullanıldığında tekrarlanan ses veya bir komuta yanıt vermede gecikme şeklinde kendini gösterir.

Öncelik tersine çevirmeyle ilgili yaygın bir geçici çözüm, ses arabelleği 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 öncelik tersine çevrilmesini anlamak ve önlemek daha iyidir.

Android ses uygulamasında öncelik ters çevirme, büyük olasılıkla bu yerlerde gerçekleşir. Bu nedenle, aşağıdakilere odaklanmanız gerekir:

  • AudioFlinger'da normal karıştırıcı iş parçacığı ile hızlı karıştırıcı iş parçacığı arasında
  • hızlı AudioTrack için uygulama geri çağırma mesajı dizisi ile hızlı karıştırıcı mesaj dizisi arasında (her ikisi de yüksek önceliğe sahiptir ancak biraz farklı önceliklere sahiptir)
  • Hızlı AudioRecord için uygulama geri çağırma iş parçacığı ile hızlı yakalama iş parçacığı arasında (öncekine benzer)
  • Ses donanım soyutlama katmanı (HAL) uygulamasında (ör. telefon veya yankı iptali için)
  • çekirdekteki ses sürücüsü içinde
  • AudioTrack veya AudioRecord geri çağırma mesaj dizisi ile diğer uygulama mesaj dizileri arasında (bu bizim kontrolümüzde değildir)

Yaygın çözümler

Tipik çözümler şunlardır:

  • Kesintileri devre dışı bırakma
  • öncelikli devralma muteksleri

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

Öncelik devralma futex'leri (hızlı kullanıcı alanı mutex'leri), nispeten ağır oldukları ve güvenilir bir istemciye ihtiyaç duydukları için ses sisteminde kullanılmaz.

Android tarafından kullanılan teknikler

"Kilitlemeyi dene" ve zaman aşımı ile kilitle ile başlayan denemeler. Bunlar, mutex kilit işleminin engellenmeyen ve sınırlı engelleme varyantlarıdır. Kilitle ve kilitle (zaman aşımı) denemeleri oldukça iyi çalışıyordu ancak birkaç belirsiz hata moduna açıktı: İstemci meşgulse sunucunun paylaşılan duruma erişebileceği garanti edilmez ve zaman aşımı süresi dolan çok sayıda alakasız kilit varsa kümülatif zaman aşımı çok uzun olabilir.

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

  • artır
  • bit tabanlı "veya"
  • bit "ve"

Bunların tümü önceki değeri döndürür ve gerekli SMP bariyerlerini içerir. Dezavantajı, sınırsız sayıda yeniden deneme gerektirebilmesidir. Uygulamada, yeniden denemelerin sorun oluşturmadığını tespit ettik.

Not: Atomik işlemler ve bellek bariyerleriyle etkileşimleri, yanlış anlaşıldığı ve yanlış kullanıldığı bilinen bir konudur. Bu yöntemleri eksiksiz olması için burada paylaşıyoruz ancak daha fazla bilgi için Android için SMP Primer makalesini de okumanızı öneririz.

Yukarıdaki araçların çoğunu hâlâ kullanıyoruz ve kısa süre önce aşağıdaki teknikleri ekledik:

  • Veriler için tek okuyucu tek yazar FIFO sıraları kullanın.
  • Yüksek ve düşük öncelikli modüller arasında durumu paylaşmak yerine kopyalamayı deneyin.
  • Durumun paylaşılması gerektiğinde, durumu tek otobüs işleminde atomik olarak yeniden deneme yapılmadan erişilebilen maksimum boyuttaki kelime ile sınırlayın.
  • Karmaşık, çok kelimeli durum için durum kuyruğu kullanın. Durum kuyruğu, temel olarak veri yerine durum için kullanılan, tek okuyucu ve tek yazarlı, engellenmeyen bir FIFO kuyruğudur. Yazar, bitişik itişleri tek bir itişte birleştirir.
  • SMP'nin doğruluğu için bellek bariyerlerine dikkat edin.
  • Güven, ancak doğrula. İşlemler arasında durum paylaşırken durumun doğru biçimlendirilmiş olduğunu varsaymayın. Örneğin, dizinlerin sınırlar dahilinde olup olmadığını kontrol edin. Bu doğrulama, aynı işlemdeki mesaj dizileri arasında ve karşılıklı güvenen işlemler (genellikle aynı UID'ye sahip) arasında gerekli değildir. Ayrıca, bozulmanın önemsiz olduğu PCM ses gibi paylaşılan veriler için de gereksizdir.

Engellemeyen algoritmalar

Engellemeyen algoritmalar son zamanlarda çokça çalışılmış bir konudur. Ancak tek okuyucu tek yazar FIFO sıraları hariç, bunların karmaşık ve hataya açık olduğunu tespit ettik.

Android 4.2'den itibaren, tek okuyucu/yazar sınıflarımızı şu konumlarda bulabilirsiniz:

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

Bunlar, AudioFlinger için özel olarak tasarlanmıştır ve genel amaçlı değildir. Engellemeyen algoritmaların hata ayıklama işleminin zor olmasıyla tanınırlar. Bu koda model olarak bakabilirsiniz. Ancak sınıflarda hata olabileceğini ve sınıfların başka amaçlar için uygunluğunun garanti edilmediğini unutmayın.

Geliştiriciler, örnek OpenSL ES uygulama kodlarından bazılarını, engellemeyen algoritmalar kullanacak veya Android dışı bir açık kaynak kitaplığına referans verecek şekilde güncellemelidir.

Özellikle uygulama kodu için tasarlanmış, engellenmeyen bir FIFO örneği uygulamasını yayınladık. Platform kaynak dizininde bulunan şu dosyalara bakın: frameworks/av/audio_utils

Araçlar

Bildiğimiz kadarıyla, öncelik tersine çevirme sorununu (özellikle de gerçekleşmeden önce) bulmak için otomatik bir araç yoktur. Bazı statik kod analizi araştırma araçları, kod tabanının tamamına erişebiliyorsa öncelikli ters çevirmeleri bulabilir. Elbette, rastgele kullanıcı kodu varsa (uygulamada olduğu gibi) veya büyük bir kod tabanı varsa (Linux çekirdeği ve cihaz sürücülerinde olduğu gibi) statik analiz uygun olmayabilir. En önemli şey, kodu çok dikkatli bir şekilde okumak ve sistemin tamamı ile etkileşimleri iyice anlamaktır. systrace ve ps -t -p gibi araçlar, öncelik tersine çevrilmesini oluştuktan sonra görmek için kullanışlıdır ancak önceden bilgi vermez.

Son söz

Tüm bu tartışmalardan sonra, mutex'lerden korkmayın. Zaman açısından kritik olmayan normal kullanım alanlarında doğru şekilde kullanıldığında ve uygulandığında MUTEX'ler normal kullanım için iyi bir seçenektir. Ancak yüksek ve düşük öncelikli görevler arasında ve zamana duyarlı sistemlerde mutex'lerin soruna yol açması daha olasıdır.