Prioritätsumkehr vermeiden

In diesem Artikel wird erläutert, wie das Audiosystem von Android Prioritätsumkehrung und zeigt Techniken auf, die Sie anwenden können.

Diese Techniken können für Entwickler nützlich sein, die Audio-Apps, OEMs und SoC-Anbieter, die eine Audio- HAL. Die Implementierung dieser Techniken ist Ausfälle garantiert werden, insbesondere wenn die außerhalb des Audiokontexts verwendet werden. Ihre Ergebnisse können variieren und Sie sollten Ihre eigenen für die Auswertung und das Testen.

Hintergrund

Der AudioFlinger-Audioserver von Android und AudioTrack/AudioRecord Clientimplementierung wird umgestaltet, um die Latenz zu reduzieren. Diese Arbeit begann mit Android 4.1 und wurde mit weiteren Verbesserungen fortgeführt. in 4.2, 4.3, 4.4 und 5.0.

Um diese niedrigere Latenz zu erreichen, waren im gesamten System viele Änderungen erforderlich. Eins ist die Zuweisung von CPU-Ressourcen zu zeitkritischen Threads mit einer besser vorhersehbaren Planungsrichtlinie. Zuverlässige Planung können die Größe und Anzahl der Audiopuffer reduziert werden, während und Überschreitungen vermeiden.

Prioritätsumkehr

Prioritätsumkehr ist ein klassischer Fehlermodus von Echtzeitsystemen, Eine Aufgabe mit höherer Priorität wird für unbegrenzte Wartezeiten blockiert. für eine Aufgabe mit niedrigerer Priorität, um eine Ressource wie z. B. (freigegeben durch) ein mutex an.

In einem Audiosystem zeigt sich die Prioritätsumkehr in der Regel Störung (klicken, knacken, Dropout) wiederholtes Audio wenn die Zwischenspeicher kreisförmig ist oder Verzögerung bei der Antwort auf einen Befehl.

Eine häufige Behelfslösung für die Prioritätsumkehr besteht darin, die Größe der Audiopuffer zu erhöhen. Diese Methode erhöht jedoch die Latenz und verdeckt lediglich das Problem. anstatt sie zu lösen. Es ist besser, die Priorität zu verstehen und zu verhindern, wie unten dargestellt.

In der Android-Audioimplementierung ist die Prioritätsumkehr die wahrscheinlich dort auftreten. Konzentrieren Sie sich daher auf Folgendes:

  • zwischen normalem und schnellem Mischerthread in AudioFlinger
  • zwischen App-Callback-Thread für einen schnellen AudioTrack und Schnellmixer-Threads (beide haben eine höhere Priorität, Prioritäten)
  • zwischen Anwendungs-Callback-Thread für einen schnellen AudioRecord und Thread zur schnellen Erfassung (ähnlich der vorherigen)
  • innerhalb der HAL-Implementierung (Hardware Extraction Layer), z.B. für Telefonie oder Echounterdrückung
  • im Audiotreiber im Kernel
  • zwischen AudioTrack oder AudioRecord Callback-Thread und anderen App-Threads (dies liegt außerhalb unserer Kontrolle)

Gängige Lösungen

Typische Lösungen:

  • Deaktivieren von Unterbrechungen
  • Prioritätsübernahme-Mutexe

Das Deaktivieren von Unterbrechungen ist im Linux-User-Bereich nicht möglich, funktionieren nicht bei Symmetric Multi-Processors (SMP).

Prioritätsübernahme Futexes (schnelle User-Space-Stummschaltung) werden im Audiosystem nicht verwendet, da sie relativ schwer, und weil sie auf einen vertrauenswürdigen Kunden angewiesen sind.

Android-Techniken

Experimente, die mit „try lock“ gestartet wurden und mit Timeout sperren. Dies sind nicht blockierende und begrenzt blockierende Varianten der Mutex-Sperre . Sperren und Sperren mit Zeitüberschreitung hat zwar gut funktioniert, anfällig für einige unklare Fehlermodi: dass der Server nicht auf den gemeinsamen Status zugreifen konnte, war der Client überlastet und die kumulative Zeitüberschreitung zu lang sein, wenn es eine lange Abfolge nicht zusammenhängender Zeitüberschreitung.

Außerdem verwenden wir atomare Vorgänge Beispiele:

  • Erhöhen
  • Bitweises "oder"
  • Bitweises "und"

Bei all diesen Elementen wird der vorherige Wert zurückgegeben und die erforderlichen Hindernisse für soziale Netzwerke Der Nachteil ist, dass sie unbegrenzte Wiederholungen erfordern können. In der Praxis hat sich gezeigt, dass Wiederholungsversuche kein Problem sind.

Hinweis:Atomare Vorgänge und ihre Interaktionen mit Gedächtnisbarrieren missverstanden und falsch verwendet werden. Wir berücksichtigen diese Methoden, der Vollständigkeit halber an, aber wir empfehlen Ihnen auch, <ph type="x-smartling-placeholder"></ph> SMP-Primer für Android finden Sie weitere Informationen.

Die meisten der oben genannten Tools werden auch weiterhin eingesetzt und verwendet. haben diese Techniken hinzugefügt:

  • Verwenden Sie einen einzelnen Autor, der das Buch nicht blockiert FIFO-Warteschlangen nach Daten.
  • Versuchen Sie, kopieren Bundesstaat und nicht Teilen zwischen hohen und Module mit niedriger Priorität.
  • Wenn ein Status geteilt werden muss, beschränken Sie ihn auf die maximale Größe Wort auf die in einem Ein-Bus-Betrieb unteilbar zugegriffen werden kann. ohne Wiederholungsversuche.
  • Verwenden Sie für komplexe Statusangaben aus mehreren Wörtern eine Statuswarteschlange. Eine Statuswarteschlange ist im Grunde ein nicht blockierender FIFO mit einem einzelnen Leser, Warteschlange für den Status statt für Daten, mit der Ausnahme, dass der Autor minimiert wird benachbarten Drücke in einem einzigen Stoß.
  • Achten Sie auf Gedächtnisbarrieren um die Richtigkeit der sozialen Netzwerke zu überprüfen.
  • Vertrauen, aber bestätigen: Beim Teilen state zwischen Prozessen zu verstehen, dass der Bundesstaat gut geformt ist. Prüfen Sie beispielsweise, ob Indizes innerhalb der Grenzen liegen. Diese Bestätigung ist zwischen Threads nicht erforderlich im selben Prozess, zwischen gegenseitigen vertrauensvollen Prozessen (die haben in der Regel dieselbe UID. Sie ist auch nicht notwendig, Daten wie PCM-Audio, wo Beschädigungen unerheblich sind.

Nicht blockierende Algorithmen

Nicht blockierende Algorithmen vielfach erforscht wurden. Aber mit Ausnahme von FIFO-Warteschlangen mit einem einzelnen Leser haben wir festgestellt, dass sie komplex und fehleranfällig sind.

Ab Android 4.2 finden Sie unsere nicht blockierenden, Kurse für einzelne Leser/Autoren an folgenden Orten:

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

Sie wurden speziell für AudioFlinger entwickelt und sind für allgemeine Zwecke. Nicht-blockierende Algorithmen sind dafür bekannt, schwierig zu beheben. Sie können sich diesen Code als Modell ansehen. Aber seien Sie wissen, dass es Fehler gibt, und die Klassen sind nicht zwangsläufig auch für andere Zwecke geeignet sind.

Für Entwickler sollte ein Teil des OpenSL ES-Beispielanwendungscodes so aktualisiert werden, dass nicht blockierende Algorithmen verwenden oder auf eine Open-Source-Bibliothek außerhalb von Android verweisen.

Wir haben ein Beispiel für eine nicht blockierende FIFO-Implementierung veröffentlicht, die speziell für Anwendungscode. Diese Dateien befinden sich im Quellverzeichnis der Plattform frameworks/av/audio_utils:

Tools

Unserer Erfahrung nach gibt es keine automatischen Tools für um die Prioritätsumkehrung zu finden, vor allem bevor sie eintritt. Einige Statische Code-Analysetools für die Forschung können Priorität wenn auf die gesamte Codebasis zugegriffen werden kann. Natürlich sollten Sie Beliebiger Nutzercode ist beteiligt (wie hier für die Anwendung) oder eine große Codebasis hat (wie der Linux-Kernel und die Gerätetreiber), kann eine statische Analyse unpraktisch sein. Am wichtigsten ist, den Code sorgfältig durchlesen und den gesamten Inhalt System und den Interaktionen. Tools wie Systrace und ps -t -p sind nützlich, um die Prioritätsumkehr im Anschluss zu sehen. nicht im Voraus wissen.

Ein letztes Wort

Haben Sie nach der ganzen Diskussion keine Angst vor Mutexen. Stumme die für den normalen Gebrauch geeignet sind, wenn sie richtig eingesetzt und implementiert werden. für gewöhnliche, nicht zeitkritische Anwendungsfälle. Aber zwischen hohen und Aufgaben mit niedriger Priorität und in zeitkritischen Systemen die wahrscheinlich Probleme verursachen.