Ta strona skupia się na czynnikach wpływających na opóźnienie wyjściowe, ale podobne uwagi dotyczą opóźnienia wejściowego.
Zakładając, że obwód analogowy nie ma większego wpływu, główne czynniki wpływające na opóźnienie dźwięku na poziomie powierzchni to:
- Zgłoszenie do programu
- Łączna liczba buforów w potoku
- Rozmiar każdego bufora w klatkach
- Dodatkowy czas oczekiwania po przetworzeniu aplikacji, np. przez DSP
Powyższa lista współtwórców może być prawidłowa, ale jest też myląca. Wynika to z tego, że liczba i rozmiar bufora są raczej skutkiem niż przyczyną. Zwykle implementuje się i testuje dany schemat bufora, ale podczas testowania dźwięk krótszy lub dłuższy niż powinien jest słyszalny jako „kliknięcie” lub „trzasknięcie”. Aby to zrekompensować, projektant systemu zwiększa rozmiary lub liczbę buforów. Daje to pożądany efekt w postaci wyeliminowania niedoborów i nadwyżek, ale ma też niepożądany efekt uboczny w postaci zwiększenia opóźnienia. Więcej informacji o rozmiarach buforów znajdziesz w filmie Opóźnienie dźwięku: rozmiary buforów.
Lepszym podejściem jest poznanie przyczyn niedoborów i nadwyżek oraz ich skorygowanie. Pozwala to wyeliminować słyszalne artefakty i może umożliwić jeszcze mniejsze lub rzadsze buforowanie, co z kolei zmniejsza opóźnienia.
Z naszego doświadczenia wynika, że najczęstsze przyczyny niedoborów i nadwyżek to:
- Linux CFS (Completely Fair Scheduler)
- wątki o wysokim priorytecie z planowaniem SCHED_FIFO
- odwrócenie priorytetów
- długi czas planowania,
- długotrwałe moduły obsługi przerwań;
- Długi czas wyłączenia przerwania
- zarządzanie zasilaniem
- jądra zabezpieczeń
Planowanie CFS i SCHED_FIFO w systemie Linux
System CFS dla systemu Linux został zaprojektowany tak, aby był sprawiedliwy dla konkurencyjnych zadań, które korzystają z wspólnego procesora. Ta obiektywność jest reprezentowana przez parametr nice w poszczególnych wątkach. Wartość nice może przyjmować wartości od -19 (najmniej łagodna, czyli najwięcej czasu procesora) do 20 (najłagodniejsza, czyli najmniej czasu procesora). Ogólnie wszystkie wątki o danej wartości nice otrzymują mniej więcej tyle samo czasu procesora, a wątek o niższej wartości nice powinien otrzymać więcej czasu procesora. Jednak CFS jest „sprawiedliwy” tylko w przypadku stosunkowo długich okresów obserwacji. W krótkich okresach obserwacji usługa CFS może przydzielać zasoby procesora w nieoczekiwany sposób. Na przykład może odłączyć procesor od wątku o niskiej wartości miary łagodności i przekierować go do wątku o wysokiej wartości miary łagodności. W przypadku dźwięku może to skutkować wyświetleniem reklamy poniżej lub powyżej założeń.
Oczywistym rozwiązaniem jest unikanie korzystania z CFS w przypadku wątków audio o wysokiej wydajności. Począwszy od Androida 4.1 takie wątki korzystają z zasady harmonogramu SCHED_FIFO
, a nie z zasady harmonogramu SCHED_NORMAL
(zwanej też SCHED_OTHER
) implementowanej przez CFS.
Priorytety SCHED_FIFO
Chociaż wątki audio o wysokiej wydajności korzystają teraz z poziomu SCHED_FIFO
, są nadal podatne na inne wątki o wyższym priorytecie (SCHED_FIFO
).
Zazwyczaj są to wątki robocze jądra, ale może też być kilka wątków użytkownika bez audio z zasadami SCHED_FIFO
. Dostępne priorytety SCHED_FIFO
mają zakres od 1 do 99. Wątek audio działa z priorytetem 2 lub 3. W rezultacie priorytet 1 jest dostępny dla wątków o niższym priorytecie, a priorytety od 4 do 99 dla wątków o wyższym priorytecie. Zalecamy
używanie priorytetu 1 w miarę możliwości i rezerwowanie priorytetów od 4 do 99 dla wątków, które są gwarantowane do ukończenia w określonym czasie, są wykonywane w okresie krótszym niż czas trwania wątków audio i nie zakłócają harmonogramu wątków audio.
Planowanie z zasadą monotoniczności stawek
Więcej informacji o teorii przypisywania stałych priorytetów znajdziesz w artykule Rate-monotonic scheduling (RMS) w Wikipedii. Kluczową kwestią jest to, że priorytety stałe powinny być przypisywane wyłącznie na podstawie okresu, przy czym wyższe priorytety powinny być przypisywane wątkom o krótszych okresach, a nie na podstawie postrzeganej „ważności”. Nieokresowe wątki można modelować jako wątki okresowe, używając maksymalnej częstotliwości wykonywania i maksymalnego obliczenia na wykonanie. Jeśli wątek nieokresowy nie może być modelowany jako wątek okresowy (np. może być wykonywany z nieograniczoną częstotliwością lub nieograniczoną ilością obliczeń na wykonanie), nie należy mu przypisywać stałego priorytetu, ponieważ byłoby to niezgodne z harmonogramem prawdziwych wątków okresowych.
odwrócenie priorytetów.
Odwrócenie priorytetów to klasyczny sposób działania systemów w czasie rzeczywistym, w którym zadanie o wyższym priorytecie jest blokowane przez nieograniczony czas, oczekując na uwolnienie zasobu przez zadanie o niższym priorytecie, np. muteks. Więcej informacji o metodach zapobiegania odwróceniu priorytetów znajdziesz w artykule Unikanie odwrócenia priorytetów.
Opóźnienie planowania
Opóźnienie planowania to czas od momentu, gdy wątek jest gotowy do uruchomienia, do momentu, gdy nastąpi przełączenie kontekstu, dzięki któremu wątek faktycznie działa na procesorze. Im krótsze opóźnienie, tym lepiej. Warto pamiętać, że wszystko powyżej 2 milisekund powoduje problemy z dźwiękiem. Długi czas planowania opóźnienie występuje najprawdopodobniej podczas przełączania się między trybami, takich jak uruchamianie lub zamykanie procesora, przełączanie się między jądrem zabezpieczeń a normalnym jądrem, przełączanie się z trybu pełnej mocy na tryb niskiego poboru mocy lub dostosowywanie częstotliwości zegara procesora i napięcia.
Przerywanie
W wielu projektach procesor 0 obsługuje wszystkie zewnętrzne przerwania. Dlatego długotrwały przetwarzacz przerwania może opóźniać inne przerwania, w szczególności przerwania dotyczące zakończenia dostępu do pamięci DMA dźwięku. Zaprojektuj przerywniki tak, aby szybko kończyły działanie i odkładały czasochłonne zadania do wątku (najlepiej CFS lub SCHED_FIFO
o priorytecie 1).
Podobnie wyłączenie przerwań na procesorze 0 przez długi czas powoduje opóźnienie obsługi przerwań audio. Długie czasy wyłączenia przerwania występują zwykle podczas oczekiwania na blokadę spinlocka. Sprawdź te blokady obrotu, aby mieć pewność, że są ograniczone.
Zasilanie, wydajność i zarządzanie temperaturą
Zarządzanie zasilaniem to ogólne pojęcie obejmujące działania mające na celu monitorowanie i ograniczanie zużycia energii przy jednoczesnej optymalizacji wydajności. Zarządzanie temperaturą i chłodzenie komputera to podobne funkcje, które mają na celu pomiar i kontrolę temperatury, aby uniknąć uszkodzeń spowodowanych przez nadmierną temperaturę. W jądrze Linuxa sterownik procesora odpowiada za zasady niskiego poziomu, a tryb użytkownika konfiguruje zasady wysokiego poziomu. Wykorzystywane techniki:
- dynamiczne skalowanie napięcia
- dynamiczne skalowanie częstotliwości
- dynamiczne włączanie rdzenia
- przełączanie klastrów
- blokowanie zasilania
- hotplug (hotswap)
- różne tryby uśpienia (zatrzymanie, zatrzymanie, bezczynność, zawieszenie itp.);
- proces migracji
- ustawienia procesora,
Niektóre operacje zarządzania mogą powodować „przerwy w pracy” lub czasy, w których procesor aplikacji nie wykonuje żadnej przydatnej pracy. Takie przerwy w pracy mogą zakłócać dźwięk, dlatego należy zadbać o to, aby przerwy w pracy w najgorszym przypadku nie zakłócały dźwięku. Oczywiście, gdy nieuchronny jest wzrost temperatury, uniknięcie trwałego uszkodzenia jest ważniejsze niż dźwięk.
Rdzenie zabezpieczeń
Jądro zabezpieczeń do zarządzania prawami cyfrowymi (DRM) może działać na tym samym rdzeniu procesora aplikacji co rdzeń głównego systemu operacyjnego i kod aplikacji. Każdy czas, w którym operacja rdzenia zabezpieczeń jest aktywna na rdzeniu, jest w zasadzie przerwą w zwykłej pracy, która normalnie odbywa się na tym rdzeniu. Dotyczy to w szczególności dźwięku. Z wynika tego, że wewnętrzne zachowanie rdzenia zabezpieczeń jest nieczytelne na wyższych poziomach, wszelkie anomalie wydajności spowodowane przez rdzeń zabezpieczeń są szczególnie szkodliwe. Na przykład operacje jądra związane z bezpieczeństwem zwykle nie pojawiają się w śladach przełączania kontekstu. Nazywamy to „ciemnym czasem” – czasem, który upływa, a którego nie można zaobserwować. Rdzenie zabezpieczeń powinny być zaprojektowane tak, aby zapewniać akceptowalne przerwy w działaniu w najgorszym przypadku, gdy dźwięk jest aktywny.