Unikanie odwrócenia priorytetów

Z tego artykułu dowiesz się, w jaki sposób system audio Androida stara się unikać odwrócenie priorytetów, i wyróżniamy techniki, które również możesz wykorzystać.

Techniki te mogą być przydatne dla programistów o wysokiej wydajności aplikacji audio, producentów OEM i dostawców układów SOC, którzy implementują ścieżki audio HAL. Pamiętaj, że wdrażanie tych technik nie jest w celu uniknięcia usterek i innych awarii, zwłaszcza w przypadku, poza kontekstem audio. Uzyskane wyniki mogą się różnić, dlatego należy przeprowadzić własną analizę jego weryfikacji i testowania.

Tło

serwer audio Android AudioFlinger i ścieżka audio/nagrywanie audio. wdrożenie klienta zmienia architekturę, aby zmniejszyć czas oczekiwania. Zaczęliśmy z niej korzystać w Androidzie 4.1 i kontynuowaliśmy kolejne usprawnienia. w wersjach 4.2, 4.3, 4.4 i 5.0.

Aby osiągnąć krótszy czas oczekiwania, konieczne było wprowadzenie wielu zmian w całym systemie. Jedna ważna zmiana polega na przypisaniu zasobów procesora do zasobów o kluczowym znaczeniu w wątkach z bardziej przewidywalną zasadą planowania. Niezawodne planowanie umożliwia zmniejszenie rozmiaru i liczby buforów dźwięku przy jednoczesnym zachowaniu i unikaniu przestojów.

Odwrócenie priorytetów

Odwrócenie priorytetów to klasyczny tryb awarii systemów działających w czasie rzeczywistym, w którym zadanie o wyższym priorytecie jest blokowane na nieograniczony czas oczekiwania w przypadku zadania o niższym priorytecie, które pozwala zwolnić zasób, taki jak (współdzielony państwa chronione przez) mutex.

W systemie audio odwrócenie priorytetów zwykle ma postać zakłócenie (kliknij, wyskocz, zrzuć) powtarzający się dźwięk podczas buforowania cyklicznego lub opóźnienia w odpowiedzi na polecenie.

Częstym obejściem odwrócenia priorytetu jest zwiększenie rozmiaru bufora audio. Ta metoda wydłuża jednak czas oczekiwania i tylko ukrywa problem. zamiast rozwiązywać zagadkę. lepiej poznać priorytety kampanii i im zapobiegać, jak widać poniżej.

W implementacji audio w Androidzie odwrócenie priorytetów jest najbardziej mogą wystąpić w tych miejscach. Dlatego warto skupić się na tym obszarze:

  • między zwykłym mikserem a wątkiem szybkiego miksera w AudioFlinger
  • między wątkiem wywołania zwrotnego aplikacji, który zapewnia szybką funkcję AudioTrack, szybki mikser (obie mają wyższy priorytet, ale nieco różne priorytety)
  • między wątkiem wywołania zwrotnego aplikacji, który zapewnia szybki nagrywanie dźwięku wątek z szybkim przechwytywaniem (podobny do poprzedniego)
  • w ramach implementacji sprzętowej warstwy abstrakcji (HAL) audio, np. w celu usunięcia połączeń telefonicznych lub echa
  • w ramach sterownika audio w jądrze
  • między wątkiem wywołania zwrotnego AudioTrack lub AudioRecord a innymi wątkami aplikacji (nie mamy na to wpływu)

Typowe rozwiązania

Typowe rozwiązania to:

  • wyłączanie funkcji przerwania
  • muteksy dziedziczenia priorytetu

Wyłączenie przerw w działaniu jest niewykonalne w przestrzeni użytkowników Linuksa, nie działa w przypadku symetrycznych procesorów wieloprocesorowych (SMP).

Dziedziczenie priorytetów futeksy (szybkie muteksy w przestrzeni użytkownika) nie są stosowane w systemie audio, ponieważ są one stosunkowo ciężkie, i korzystają z usług zaufanego klienta.

Techniki używane przez Androida

Eksperymenty rozpoczęte od opcji „wypróbuj blokadę” i zablokować je po pewnym czasie. Są to nieblokujące i ograniczone warianty blokady muteksu . Funkcja blokowania i blokowania ze względu na limit czasu działała dość dobrze, ale nie narażony na kilka mało znanych trybów awarii: serwer nie będzie mieć dostępu do udostępnionego stanu, jeśli klient był zajęty, a łączny czas oczekiwania mógł być zbyt długie, jeśli następowała długa sekwencja niepowiązanych ze sobą blokad, przekroczono limit czasu.

Stosujemy też operacje niepodzielne Na przykład:

  • zwiększ
  • bitowe „lub”
  • bitowe „i”

Wszystkie te elementy zwracają poprzednią wartość i zawierają niezbędne Bariery SMP. Wadą jest to, że mogą wymagać nieograniczonych ponownych prób. W praktyce odkryliśmy, że ponowna próba nie stanowi problemu.

Uwaga: operacje atomowe i ich interakcje z barierami pamięci są często źle zrozumiane i używane. Metody te obejmują tutaj, ale zalecamy też zapoznanie się SMP Primer na Androida .

Nadal mamy i wykorzystujemy większość z powyższych narzędzi, dodał(a) te techniki:

  • Używaj nieblokującej funkcji zapisującego tylko z jednym czytnikiem Kolejki FIFO danych.
  • Spróbuj kopiuj stanu, a nie udostępnij między wysokimi a wysokimi modułami o niskim priorytecie.
  • Gdy trzeba udostępnić stan, ogranicz go do maksymalny rozmiar słowo do którego można uzyskać dostęp atomowo w ramach jednej magistrali bez ponownych prób.
  • W przypadku złożonych stanów wielowyrazowych użyj kolejki stanu. Kolejka stanu to w zasadzie po prostu nieblokująca, jednoautorska FIFO kolejka używana na potrzeby stanu, a nie danych, z wyjątkiem zwijania zapisującego wypychanie sąsiadującej opcji.
  • Zwróć uwagę na bariery pamięci pod kątem poprawności SMP.
  • Zaufaj, ale zweryfikuj. Podczas udostępniania stan między procesami, zakładają, że państwo jest dobrze sformułowane. Na przykład sprawdź, czy indeksy mieści się w zakresie. Ta weryfikacja nie jest wymagana między wątkami w ramach tego samego procesu między wzajemnymi procesami zaufania (którymi zwykle mają taki sam identyfikator UID). Jest to też niepotrzebne w przypadku udostępniania. dane np. w PCM audio, gdy uszkodzenie jest nieistotne.

Algorytmy nieblokujące

Algorytmy nieblokujące były przedmiotem wielu ostatnich badań. Jednak z wyjątkiem kolejek FIFO dla pojedynczego odczytujących, są złożone i podatne na błędy.

Począwszy od Androida 4.2, znajdziesz nasze nieblokujące, zajęcia dla pojedynczego czytania/zapisującego w tych lokalizacjach:

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

Zostały one opracowane specjalnie na potrzeby AudioFlinger i nie są do ogólnego przeznaczenia. Algorytmy nieblokujące są znane z tego, są trudne do debugowania. Możesz przyjrzeć się temu kodowi jako modelowi. lecz bądź że mogą występować błędy i nie ma gwarancji, że zajęcia odpowiednie do innych celów.

Programiści powinni zaktualizować część przykładowego kodu aplikacji OpenSL ES do używać nieblokujących algorytmów ani korzystać z biblioteki open source innej niż Android.

Opublikowaliśmy przykładową nieblokującą implementację FIFO przeznaczoną specjalnie dla: kodu aplikacji. Zobacz te pliki w katalogu źródłowym platformy frameworks/av/audio_utils:

Narzędzia

Według naszej wiedzy nie ma automatycznych narzędzi do na znalezienie odwrócenia priorytetów, zwłaszcza zanim to nastąpi. Niektóre narzędzia do badań statycznej analizy kodu są w stanie określić priorytety czy użytkownik może uzyskać dostęp do całej bazy kodu. Oczywiście, jeśli dowolny kod użytkownika (jako kod dla aplikacji) lub stanowi dużą bazę kodu (jak w przypadku jądra systemu Linux i sterowników urządzeń), analiza statyczna może być niepraktyczna. Najważniejsze jest to, dokładnie przeczytaj kod, aby dobrze poznać cały kod i interakcji. Narzędzia takie jak systrace oraz ps -t -p są przydatne do obserwacji odwrócenia priorytetów po wystąpieniu, ale nie ujawnimy Ci z wyprzedzeniem.

Ostatnie słowo

Po całej dyskusji nie bój się muteksów. Wyciszenie przydają się w zwykłym zastosowaniu, pod warunkiem, że są prawidłowo zaimplementowane w zwykłych, niekrytycznych czasowo przypadkach użycia. Ale pomiędzy wysokimi w zadaniach o niskim priorytecie i w systemach pilnych może sprawiać problemy.