Mitwirkende zur Audiolatenz

Diese Seite konzentriert sich auf die Mitwirkenden an der Ausgabelatenz, eine ähnliche Diskussion gilt jedoch auch für die Eingabelatenz.

Unter der Annahme, dass die analogen Schaltkreise keinen wesentlichen Beitrag leisten, sind die wichtigsten oberflächlichen Faktoren, die zur Audiolatenz beitragen, die folgenden:

  • Anwendung
  • Gesamtzahl der Puffer in der Pipeline
  • Größe jedes Puffers in Frames
  • Zusätzliche Latenz nach dem App-Prozessor, beispielsweise von einem DSP

So zutreffend die obige Liste der Mitwirkenden auch sein mag, so irreführend ist sie auch. Der Grund dafür ist, dass Pufferanzahl und Puffergröße eher eine Auswirkung als eine Ursache sind. Was normalerweise passiert, ist, dass ein bestimmtes Pufferschema implementiert und getestet wird, aber während des Tests ist ein Audio-Unterlauf oder -Überlauf als „Klicken“ oder „Knacken“ zu hören. Zum Ausgleich erhöht der Systementwickler dann die Puffergröße oder Pufferanzahl. Dies hat das gewünschte Ergebnis, nämlich die Eliminierung von Underruns oder Overruns, aber auch den unerwünschten Nebeneffekt, dass die Latenz zunimmt. Weitere Informationen zu Puffergrößen finden Sie im Video Audiolatenz: Puffergrößen .

Ein besserer Ansatz besteht darin, die Ursachen der Unterschreitungen und Überschreitungen zu verstehen und diese dann zu beheben. Dies eliminiert die hörbaren Artefakte und ermöglicht möglicherweise noch kleinere oder weniger Puffer und verringert so die Latenz.

Nach unserer Erfahrung gehören zu den häufigsten Ursachen für Unter- und Überschreitungen:

  • Linux CFS (Completely Fair Scheduler)
  • Threads mit hoher Priorität und SCHED_FIFO-Planung
  • Prioritätsumkehr
  • lange Planungslatenz
  • Interrupt-Handler mit langer Laufzeit
  • lange Interrupt-Deaktivierungszeit
  • Energieverwaltung
  • Sicherheitskernel

Linux CFS- und SCHED_FIFO-Planung

Das Linux CFS ist so konzipiert, dass es konkurrierenden Arbeitslasten gerecht wird, die sich eine gemeinsame CPU-Ressource teilen. Diese Fairness wird durch einen netten Parameter pro Thread dargestellt. Der nette Wert reicht von -19 (am wenigsten nett oder am meisten zugewiesene CPU-Zeit) bis 20 (am besten oder am wenigsten zugewiesene CPU-Zeit). Im Allgemeinen erhalten alle Threads mit einem bestimmten Nice-Wert ungefähr die gleiche CPU-Zeit, und Threads mit einem numerisch niedrigeren Nice-Wert sollten damit rechnen, mehr CPU-Zeit zu erhalten. Allerdings ist CFS nur über relativ lange Beobachtungszeiträume „fair“. Über kurzfristige Beobachtungsfenster kann CFS die CPU-Ressourcen auf unerwartete Weise zuweisen. Es kann beispielsweise dazu führen, dass die CPU von einem Thread mit numerisch niedriger Feinheit auf einen Thread mit numerisch hoher Feinheit verlagert wird. Bei Audio kann dies zu einer Unter- oder Überschreitung führen.

Die offensichtliche Lösung besteht darin, CFS für Hochleistungs-Audio-Threads zu vermeiden. Ab Android 4.1 verwenden solche Threads nun die Planungsrichtlinie SCHED_FIFO anstelle der von CFS implementierten Planungsrichtlinie SCHED_NORMAL (auch SCHED_OTHER genannt).

SCHED_FIFO-Prioritäten

Obwohl die Hochleistungs-Audio-Threads jetzt SCHED_FIFO verwenden, sind sie immer noch anfällig für andere SCHED_FIFO Threads mit höherer Priorität. Dabei handelt es sich in der Regel um Kernel-Worker-Threads, es können jedoch auch einige Nicht-Audio-Benutzer-Threads mit der Richtlinie SCHED_FIFO vorhanden sein. Die verfügbaren SCHED_FIFO Prioritäten reichen von 1 bis 99. Die Audio-Threads werden mit Priorität 2 oder 3 ausgeführt. Dadurch bleibt Priorität 1 für Threads mit niedrigerer Priorität und die Prioritäten 4 bis 99 für Threads mit höherer Priorität verfügbar. Wir empfehlen Ihnen, wann immer möglich, Priorität 1 zu verwenden und die Prioritäten 4 bis 99 für die Threads zu reservieren, die garantiert innerhalb einer begrenzten Zeit abgeschlossen werden, mit einem kürzeren Zeitraum als dem Zeitraum von Audio-Threads ausgeführt werden und bekanntermaßen die Planung nicht beeinträchtigen von Audio-Threads.

Ratenmonotone Planung

Weitere Informationen zur Theorie der Zuweisung fester Prioritäten finden Sie im Wikipedia-Artikel Rate-monotonisches Scheduling (RMS). Ein wichtiger Punkt besteht darin, dass feste Prioritäten streng auf der Grundlage des Zeitraums zugewiesen werden sollten, wobei Threads mit kürzeren Zeiträumen höhere Prioritäten zugewiesen werden sollten und nicht auf der Grundlage der wahrgenommenen „Wichtigkeit“. Nichtperiodische Threads können als periodische Threads modelliert werden, wobei die maximale Ausführungshäufigkeit und die maximale Berechnung pro Ausführung verwendet werden. Wenn ein nichtperiodischer Thread nicht als periodischer Thread modelliert werden kann (er könnte beispielsweise mit unbegrenzter Häufigkeit oder unbegrenzter Berechnung pro Ausführung ausgeführt werden), sollte ihm keine feste Priorität zugewiesen werden, da dies mit der Planung echter periodischer Threads nicht kompatibel wäre .

Prioritätsumkehr

Die Prioritätsumkehr ist ein klassischer Fehlermodus von Echtzeitsystemen, bei dem eine Aufgabe mit höherer Priorität für eine unbegrenzte Zeit blockiert wird und darauf wartet, dass eine Aufgabe mit niedrigerer Priorität eine Ressource freigibt, z. B. einen Mutex (durch einen gemeinsam genutzten Zustand geschützt). Im Artikel „ Prioritätsumkehr vermeiden “ finden Sie Techniken zur Abschwächung.

Latenz planen

Die Planungslatenz ist die Zeit zwischen der Bereitschaft eines Threads zur Ausführung und dem Abschluss des resultierenden Kontextwechsels, sodass der Thread tatsächlich auf einer CPU ausgeführt wird. Je kürzer die Latenz, desto besser, und alles über zwei Millisekunden führt zu Audioproblemen. Lange Planungslatenz tritt am wahrscheinlichsten bei Modusübergängen auf, z. B. beim Hochfahren oder Herunterfahren einer CPU, beim Umschalten zwischen einem Sicherheitskernel und dem normalen Kernel, beim Umschalten vom Vollleistungsmodus in den Energiesparmodus oder beim Anpassen der CPU-Taktfrequenz und -Spannung .

Unterbricht

In vielen Designs bedient CPU 0 alle externen Interrupts. Daher kann ein Interrupt-Handler mit langer Laufzeit andere Interrupts verzögern, insbesondere DMA-Abschlussinterrupts (Audio Direct Memory Access). Entwerfen Sie Interrupt-Handler so, dass sie schnell fertig werden und langwierige Arbeiten an einen Thread (vorzugsweise einen CFS-Thread oder SCHED_FIFO Thread mit Priorität 1) verlagern.

Entsprechend hat das Deaktivieren von Interrupts auf CPU 0 über einen längeren Zeitraum das gleiche Ergebnis wie eine Verzögerung der Verarbeitung von Audio-Interrupts. Beim Warten auf eine Kernel- Spin-Sperre kommt es normalerweise zu langen Interrupt-Deaktivierungszeiten. Überprüfen Sie diese Spin-Locks, um sicherzustellen, dass sie begrenzt sind.

Leistung, Leistung und Wärmemanagement

Energiemanagement ist ein weit gefasster Begriff, der Maßnahmen zur Überwachung und Reduzierung des Stromverbrauchs bei gleichzeitiger Optimierung der Leistung umfasst. Wärmemanagement und Computerkühlung ähneln sich, zielen jedoch darauf ab, die Wärme zu messen und zu steuern, um Schäden durch übermäßige Wärme zu vermeiden. Im Linux-Kernel ist der CPU- Governor für die Low-Level-Richtlinie verantwortlich, während der Benutzermodus die High-Level-Richtlinie konfiguriert. Zu den verwendeten Techniken gehören:

  • dynamische Spannungsskalierung
  • dynamische Frequenzskalierung
  • dynamische Kernaktivierung
  • Cluster-Switching
  • Power-Gating
  • Hotplug (Hotswap)
  • verschiedene Schlafmodi (Halt, Stop, Idle, Suspend usw.)
  • Prozessmigration
  • Prozessoraffinität

Einige Verwaltungsvorgänge können zu „Arbeitsunterbrechungen“ oder zu Zeiten führen, in denen der Anwendungsprozessor keine sinnvolle Arbeit leistet. Diese Arbeitsunterbrechungen können die Audiowiedergabe beeinträchtigen. Daher sollte eine solche Verwaltung auf akzeptable Worst-Case-Arbeitsunterbrechungen bei aktiver Audiowiedergabe ausgelegt sein. Wenn ein thermisches Durchgehen droht, ist die Vermeidung dauerhafter Schäden natürlich wichtiger als der Klang!

Sicherheitskerne

Ein Sicherheitskernel für die Verwaltung digitaler Rechte (DRM) kann auf denselben Anwendungsprozessorkernen ausgeführt werden, die auch für den Hauptbetriebssystemkernel und den Anwendungscode verwendet werden. Jeder Zeitpunkt, zu dem ein Sicherheitskernelvorgang auf einem Kernel aktiv ist, stellt praktisch eine Unterbrechung der normalen Arbeit dar, die normalerweise auf diesem Kern ausgeführt würde. Hierzu kann es sich insbesondere um Audioarbeiten handeln. Das interne Verhalten eines Sicherheitskernels ist naturgemäß für übergeordnete Schichten nicht durchschaubar, und daher sind alle durch einen Sicherheitskernel verursachten Leistungsanomalien besonders schädlich. Sicherheitskerneloperationen werden beispielsweise normalerweise nicht in Kontextwechselspuren angezeigt. Wir nennen dies „dunkle Zeit“ – Zeit, die vergeht, aber nicht beobachtet werden kann. Sicherheitskerne sollten für eine akzeptable Worst-Case-Arbeitsunterbrechung ausgelegt sein, während Audio aktiv ist.