Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Der Einfluss eines Audiotreibers auf die Leistung des Systems kann durch die folgenden allgemeinen Prinzipien deutlich reduziert werden:
Minimieren Sie den Code, der während des normalen Vorgangs ausgeführt wird.
Führen Sie Code nur bei Bedarf aus.
Berücksichtigen Sie den gesamten Systemressourcenverbrauch (nicht nur CPU-Ladevorgang).
Optimieren Sie Code für Geschwindigkeit und Größe.
Darüber hinaus müssen WavePci-Miniporttreiber mehrere Leistungsprobleme beheben, die für Audiogeräte spezifisch sind. Die folgende Diskussion befasst sich in erster Linie mit Audiorenderingproblemen, obwohl einige der vorgeschlagenen Techniken auch für die Audioaufnahme gelten.
Stream-Wartungsmechanismen
Bevor Performance-Optimierungen diskutiert werden, ist etwas Hintergrundwissen erforderlich, um die WavePci-Mechanismen für das Bedienen von Datenströmen zu verstehen.
Bei der Verarbeitung eines Wellenrender- oder Aufnahmedatenstroms erfordert ein Audiogerät regelmäßige Wartungen durch den Miniporttreiber. Wenn neue Zuordnungen für einen Datenstrom verfügbar sind, fügt der Treiber diese Zuordnungen zur DMA-Warteschlange des Datenstroms hinzu. Der Treiber entfernt auch alle Zuordnungen, die bereits verarbeitet wurden, aus der Warteschlange. Informationen zu Zuordnungen finden Sie unter WavePci Latency.
Um die Wartung durchzuführen, stellt der Miniporttreiber entweder einen Verzögerten Prozeduraufruf (DPC) oder eine Unterbrechungsdienstroutine (Interrupt Service Routine, ISR) bereit, je nachdem, ob das Intervall von einem Systemtimer oder von DMA-gesteuerten Unterbrechungen festgelegt wird. In letzterem Fall löst die DMA-Hardware in der Regel jedes Mal eine Unterbrechung aus, wenn die Übertragung einer Datenmenge beendet ist.
Jedes Mal, wenn der DPC oder ISR ausgeführt wird, bestimmt er, welche Datenströme wartung erfordern. Der DPC oder ISR dient einem Datenstrom, indem sie die IPortWavePci::Notify-Methode aufruft. Diese Methode verwendet als Aufrufparameter die Dienstgruppe des Datenstroms, bei der es sich um ein Objekt vom Typ "IServiceGroup" handelt. Die Notify-Methode ruft die RequestService-Methode der Dienstgruppe auf (siehe IServiceSink::RequestService).
Ein Dienstgruppenobjekt enthält eine Gruppe von Dienstsenken, die Objekte vom Typ "IServiceSink" sind. IServiceGroup wird von IServiceSink abgeleitet, und beide Schnittstellen weisen RequestService-Methoden auf. Wenn die Notify-Methode die RequestService-Methode der Dienstgruppe aufruft, antwortet die Dienstgruppe, indem die RequestService-Methode für jede Dienstsenke in der Gruppe aufgerufen wird.
Die Dienstgruppe eines Datenstroms enthält mindestens eine Dienstsenke, die der Porttreiber der Dienstgruppe unmittelbar nach der Erstellung des Datenstroms hinzufügt. Der Porttreiber ruft die IMiniportWavePci::NewStream-Methode des Miniporttreibers auf, um einen Zeiger auf die Dienstgruppe abzurufen. Die RequestService-Methode des Service-Sinks ist die streamspezifische Dienstroutine des Porttreibers. Diese Routine führt folgende Aktionen aus:
Ruft die IMiniportWavePciStream::Service-Methode des Miniporttreibers auf.
Löst alle neu ausstehenden Positions- oder Zeitevents im Stream aus, seitdem die Dienstroutine zuletzt ausgeführt wurde.
Wie in KS-Ereignissen beschrieben, können Clients registrieren, um benachrichtigt zu werden, wenn ein Datenstrom eine bestimmte Position erreicht oder wenn eine Uhr einen bestimmten Zeitstempel erreicht. Die NewStream-Methode hat die Möglichkeit, keine Dienstgruppe zu liefern. In diesem Fall richtet der Porttreiber einen eigenen Timer ein, um die Intervalle zwischen Aufrufen der Dienstroutine zu markieren.
Wie bei der NewStream-Methode gibt die IMiniportWavePci::Init-Methode des Miniporttreibers auch einen Zeiger auf eine Dienstgruppe aus. Nach dem Init-Aufruf fügt der Porttreiber seiner Servicegruppe die Dienstsenke hinzu. Diese spezielle Dienstsenke enthält die Dienstroutine für den Filter als Ganzes. (Im vorherigen Absatz wird die Dienstsenke für den Datenstrom beschrieben, der einem Pin auf dem Filter zugeordnet ist.) Diese Dienstroutine ruft die IMiniportWavePci::Service-Methode des Miniporttreibers auf. Die Dienstroutine wird jedes Mal ausgeführt, wenn der DPC oder ISR Notify mit der Dienstgruppe für den Filter aufruft. Die Init-Methode hat die Möglichkeit, keine Dienstgruppe zu liefern, in diesem Fall ruft der Porttreiber nie seine Filterdienstroutine auf.
Hardwareunterbrechungen
Einige Miniporttreiber generieren entweder zu viele oder nicht genügend Hardwareunterbrechungen. Bei einigen WavePci-Renderinggeräten mit DirectSound-Hardwarebeschleunigung tritt eine Hardwareunterbrechung nur auf, wenn die Bereitstellung von Zuordnungen fast erschöpft ist und das Renderingmodul das Risiko einer Verhungerung darstellt. Bei anderen hardwarebeschleunigten WavePci-Geräten tritt bei jedem einzelnen Zuordnungsabschluss oder einem anderen relativ kleinen Intervall ein Hardwareunterbruch auf. In diesem Fall findet der ISR häufig, dass er wenig zu tun hat, aber jeder Interrupt verbraucht weiterhin Systemressourcen mit Registertauschs und Cache-Neuladen. Der erste Schritt bei der Verbesserung der Treiberleistung besteht darin, die Anzahl der Unterbrechungen so weit wie möglich zu reduzieren, ohne das Risiko einer Blockierung einzugehen. Nachdem unnötige Unterbrechungen beseitigt wurden, können zusätzliche Leistungsgewinne erzielt werden, indem der ISR effizienter ausgeführt wird.
In einigen Treibern verschwenden ISRs Zeit, indem die Notify-Methode eines Datenstroms jedes Mal aufgerufen wird, wenn ein Hardwareunterbrechung auftritt – unabhängig davon, ob der Datenstrom tatsächlich ausgeführt wird. Wenn sich keine Datenströme im RUN-Zustand befinden, ist DMA inaktiv. Jeglicher Zeitaufwand, der auf das Erwerben oder Freigeben von Zuordnungen sowie das Überprüfen neuer Ereignisse in allen Datenströmen verwendet wird, ist somit verschwendet. In einem effizienten Treiber überprüft der ISR, ob ein Datenstrom ausgeführt wird, bevor die Notify-Methode des Datenstroms aufgerufen wird.
Ein Treiber mit diesem ISR-Typ muss jedoch sicherstellen, dass alle ausstehenden Ereignisse in einem Datenstrom ausgelöst werden, wenn der Datenstrom den RUN-Zustand verlässt. Andernfalls können die Ereignisse verzögert oder verloren gegangen sein. Dieses Problem tritt nur bei RUN-to-PAUSE-Übergängen in Betriebssystemen auf, die älter als Microsoft Windows XP sind. In Windows XP und höher signalisiert der Porttreiber automatisch alle ausstehenden Positionsereignisse sofort, wenn ein Datenstrom den Zustand von RUN in PAUSE ändert. In den älteren Betriebssystemen ist der Miniporttreiber jedoch dafür verantwortlich, alle ausstehenden Ereignisse auszulösen, indem er sofort nach dem Anhalten des Datenstroms einen abschließenden Aufruf von Notify vornimmt. Weitere Informationen finden Sie unter PAUSE/ACQUIRE Optimizations unten.
Ein typischer WavePci Miniport-Treiber verwaltet einen einzelnen Wiedergabedatenstrom vom KMixer-Systemtreiber. Die aktuelle Implementierung von KMixer verwendet mindestens drei Zuordnungs-IRPs, um einen Wiedergabestream zu puffern. Jedes IRP enthält genügend Pufferspeicher für ca. 10 Millisekunden Audio. Wenn der Miniporttreiber jedes Mal eine Hardwareunterbrechung auslöst, wenn der DMA-Controller mit der endgültigen Zuordnung in einem IRP beendet ist, sollten Unterbrechungen in relativ regelmäßigen 10-Millisekunden-Intervallen auftreten, was häufig genug ist, um die DMA-Warteschlange nicht abreißen zu lassen.
Timer-DPCs
Wenn ein Treiber hardwarebeschleunigte DirectSound-Streams verwaltet, sollte ein Timer-DPC (siehe Timer Objects und DPCs) anstelle von DMA-gesteuerten Hardwareunterbrechungen verwendet werden. Entsprechend kann ein WavePci-Gerät auf einer PCI-Karte mit einem On-Board-Timer einen timergesteuerten Hardware-Interrupt anstelle eines DPC verwenden.
Bei einem DirectSound-Puffer kann der gesamte Puffer an einen einzelnen IRP angefügt werden. Wenn der Puffer groß ist und der Miniporttreiber einen Hardware-Interrupt nur plant, wenn er das Ende des Puffers erreicht, können aufeinanderfolgende Unterbrechungen so weit auseinander liegen, dass die DMA-Warteschlange verhungert. Wenn der Treiber eine große Anzahl von hardwarebeschleunigten DirectSound-Streams verwaltet und jeder Datenstrom eigene Unterbrechungen generiert, kann die kumulierte Auswirkung aller Unterbrechungen die Systemleistung beeinträchtigen. Unter diesen Umständen sollte der Miniporttreiber die Verwendung von Hardwareunterbrechungen vermeiden, um die Wartung einzelner Datenströme zu planen. Stattdessen sollten alle Datenströme in einem einzelnen DPC gewartet werden, der für die Ausführung in regelmäßigen, durch Timer erzeugten Intervallen geplant ist.
Durch Festlegen des Zeitgeberintervalls auf 10 Millisekunden ähnelt das Intervall zwischen aufeinanderfolgenden Ausführungen von DPC dem, das zuvor für die Hardwareunterbrechung beschrieben wurde, im Falle eines einzelnen KMixer-Wiedergabedatenstroms. So kann der DPC zusätzlich zu hardwarebeschleunigten DirectSound-Streams den KMixer-Wiedergabedatenstrom verarbeiten.
Wenn der letzte Datenstrom den RUN-Zustand beendet, sollte der Miniporttreiber den Timer-DPC deaktivieren, um zu vermeiden, dass System-CPU-Zyklen verschwendet werden. Unmittelbar nach dem Abschalten des DPC sollte der Treiber sicherstellen, dass alle ausstehenden Uhr- oder Positionsereignisse bei zuvor laufenden Streams (Datenströmen) geleert werden. In Windows 98/Me und Windows 2000 sollte der Treiber "Notify" aufrufen, um ausstehende Ereignisse in den Datenströmen auszulösen, die angehalten werden. In Windows XP und höher löst das Betriebssystem alle ausstehenden Ereignisse automatisch aus, wenn ein Datenstrom den RUN-Zustand verlässt, ohne dass der Miniporttreiber eingreifen muss.
PAUSE/ACQUIRE Optimierungen
In Windows 98/Me und Windows 2000 generiert die Streamdienstroutine des WavePci-Porttreibers ( die RequestService-Methode ) immer einen Aufruf der IMiniportWavePciStream::Service-Methode des Miniporttreibers , unabhängig davon, ob sich der Stream im RUN-Zustand befindet. In diesen Betriebssystemen sollte die Dienstmethode überprüfen, ob der Datenstrom ausgeführt wird, bevor sie Zeit für die eigentliche Arbeit aufwendet. (Wenn der DPC oder ISR des Miniporttreibers jedoch bereits zum Aufrufen von Notify nur für datenströme optimiert wurde, die ausgeführt werden, ist das Hinzufügen dieser Überprüfung zur Dienstmethode möglicherweise redundant.)
In Windows XP und höher ist diese Optimierung nicht erforderlich, da die Notify-Methode die Dienstmethode nur für Datenströme aufruft, die ausgeführt werden.
Verwenden der IPreFetchOffset-Schnittstelle
DirectSound-Benutzer sind mit den dualen Konzepten des Wiedergabecursors und dem Schreibcursor vertraut. Der Wiedergabecursor gibt die Position im Datenstrom an, die vom Gerät ausgegeben wird (die beste Schätzung des Treibers für das Signal, das sich derzeit am DAC befindet). Die Schreibposition ist die Position im Datenstrom des nächsten sicheren Orts, an dem der Client zusätzliche Daten schreiben kann. Bei WavePci ist die Standardannahme, dass der Schreibcursor am Ende der letzten angeforderten Zuordnung positioniert ist. Wenn beim Miniporttreiber eine große Anzahl an ausstehenden Zuordnungen vorhanden ist, kann der Abstand zwischen dem Wiedergabecursor und dem Schreibcursor sehr groß sein – groß genug, um bestimmte WHQL-Audiopositionstests zu fehlschlagen. In Windows XP und höher behebt die IPreFetchOffset-Schnittstelle diese Probleme.
Der Miniporttreiber verwendet IPreFetchOffset , um die Prefetch-Eigenschaften der Busmasterhardware anzugeben, die größtenteils durch die Hardware-FIFO-Größe bestimmt werden. Das Audiosubsystem verwendet diese Daten, um einen konstanten Offset zwischen dem Wiedergabecursor und dem Schreibcursor festzulegen. Dieser konstante Offset, der wesentlich kleiner als der Standardoffset sein kann, nutzt die Tatsache, dass Daten auch dann noch in eine Zuordnung geschrieben werden können, nachdem diese an die Hardware übergeben wurde, solange der Wiedergabecursor weit genug von der Position entfernt ist, an die Daten geschrieben werden. (Diese Anweisung geht davon aus, dass der Treiber die Daten in Zuordnungen nicht kopiert oder anderweitig bearbeitet.) Ein typischer Offset kann je nach Engine-Design in der Größenordnung von 64 Samples vorliegen. Mit einem so kleinen Offset kann ein WavePci-Treiber vollständig reaktionsfähig und funktionsfähig sein, während er gleichzeitig eine große Anzahl von Zuordnungen anfordert.
Beachten Sie, dass DirectSound derzeit den Schreibcursor eines hardwarebeschleunigten Pins um 10 Millisekunden auffüllt.
Weitere Informationen finden Sie unter Prefetch Offsets.
Verarbeiten von Daten in Zuordnungen
Vermeiden Sie, dass Ihr Hardwaretreiber die Daten in den Zuordnungen berührt, sofern möglich. Jede Softwareverarbeitung von Daten, die in Zuordnungen enthalten sind, sollte getrennt vom Hardwaretreiber in einen Softwarefilter aufgeteilt werden. Wenn ein Hardwaretreiber eine solche Verarbeitung ausführt, verringert sich seine Effizienz und verursacht Latenzprobleme.
Ein Hardwaretreiber sollte sich bemühen, transparent über seine tatsächlichen Hardwarefunktionen zu sein. Der Treiber sollte niemals behaupten, Hardwareunterstützung für eine Datentransformation bereitzustellen, die tatsächlich in der Software ausgeführt wird.
Synchronisierungsgrundtypen
Ein Treiber hat jetzt und in Zukunft weniger wahrscheinlich Probleme mit Deadlocks oder der Leistung, wenn sein Code darauf ausgelegt ist, Blockierungen so weit wie möglich zu vermeiden. Insbesondere sollte der Thread der Ausführung eines Treibers darauf abzielen, bis zur Fertigstellung zu laufen, ohne das Risiko eines Stillstands beim Warten auf einen anderen Thread oder eine Ressource. Beispielsweise können Treiberthreads die InterlockedXxx-Funktionen (z. B. InterlockedIncrement) verwenden, um den Zugriff auf bestimmte freigegebene Ressourcen zu koordinieren, ohne dass das Risiko einer Blockierung besteht.
Obwohl es sich hierbei um leistungsstarke Techniken handelt, können Sie möglicherweise nicht alle Drehungssperren, Mutexes und andere blockierende Synchronisierungsgrundtypen aus dem Ausführungspfad sicher entfernen. Verwenden Sie die InterlockedXxx-Funktionen sorgfältig, mit dem Wissen, dass eine unbestimmte Wartezeit zu Datenverknappung führen kann.
Erstellen Sie vor allem keine benutzerdefinierten Synchronisierungsgrundtypen. Die integrierten Windows-Grundtypen (Mutexes, Spinlocks usw.) werden wahrscheinlich bei Bedarf geändert, um neue Scheduler-Features in Zukunft zu unterstützen, und ein Treiber, der benutzerdefinierte Konstrukte verwendet, funktioniert in Zukunft mit großer Wahrscheinlichkeit nicht mehr.
IPinCount-Schnittstelle
In Windows XP und höher bietet die IPinCount-Schnittstelle eine Möglichkeit für einen Miniporttreiber, um die Hardwareressourcen, die von der Zuordnung eines Pins verbraucht werden, genauer zu berücksichtigen. Durch Aufrufen der IPinCount::PinCount-Methode des Miniporttreibers führt der Porttreiber folgende Aktionen aus:
Macht die aktuelle Anzahl der Filter-Pins (wie vom Porttreiber verwaltet) für den Miniporttreiber zugänglich.
Bietet dem Miniporttreiber die Möglichkeit, die Pinanzahl zu überarbeiten, um die aktuelle Verfügbarkeit von Hardwareressourcen dynamisch widerzuspiegeln.
Bei einigen Audiogeräten können Wellenströme mit unterschiedlichen Attributen (3D, Stereo/Mono usw.) auch unterschiedliche "Gewichtungen" aufweisen, was die Anzahl der von ihnen verbrauchten Hardwareressourcen angeht. Beim Öffnen oder Schließen eines "lightweight"-Streams erhöht oder verringert der Treiber die Anzahl der verfügbaren Pins um eins. Beim Öffnen eines "Schwergewichts"-Datenstroms muss der Miniporttreiber die Anzahl der verfügbaren Pins möglicherweise um zwei statt um eins verringern, um die Anzahl der Pins genauer anzugeben, die mit den verbleibenden Ressourcen erstellt werden können.
Der Prozess wird umgekehrt, wenn ein Schwergewichtsstrom geschlossen wird. Die verfügbare Pinanzahl kann um mehr als eins erhöht werden, um die Tatsache widerzuspiegeln, dass zwei oder mehr einfache Datenströme aus den neu freigegebenen Ressourcen erstellt werden können.