Partager via


Problèmes de performances pour un pilote WavePci Miniport

L’impact d’un pilote audio sur les performances du système peut être considérablement réduit en suivant ces principes généraux :

  • Réduisez le code qui est exécuté pendant une opération normale.

  • Exécutez du code uniquement si nécessaire.

  • Considérez la consommation totale des ressources système (pas seulement le chargement du processeur).

  • Optimisez le code pour la vitesse et la taille.

En outre, les pilotes de miniport WavePci doivent résoudre plusieurs problèmes de performances spécifiques aux périphériques audio. La discussion suivante traite principalement des problèmes de rendu audio, même si certaines des techniques suggérées s’appliquent également à la capture audio.

Mécanismes de maintenance de flux

Avant de discuter des optimisations des performances, un peu d’arrière-plan est nécessaire pour comprendre les mécanismes WavePci pour les flux de maintenance.

Lors du traitement d’un flux de rendu ou de capture d’ondes, un périphérique audio nécessite une maintenance à intervalles réguliers par le pilote miniport. Lorsque de nouveaux mappages sont disponibles pour un flux, le pilote ajoute ces mappages à la file d’attente DMA du flux. Le pilote supprime également de la file d’attente tous les mappages qui ont déjà été traités. Pour plus d’informations sur les mappages, consultez Latence WavePci.

Pour effectuer la maintenance, le pilote miniport fournit un appel de procédure différée (DPC) ou une routine de service d’interruption (ISR), selon que l’intervalle est défini par un minuteur système ou par des interruptions pilotées par DMA. Dans ce dernier cas, le matériel DMA déclenche généralement une interruption à chaque fois si le transfert termine le transfert d’une certaine quantité de données de flux.

Chaque fois que le DPC ou l’ISR s’exécute, il détermine quels flux nécessitent une maintenance. La DPC ou l’ISR dessert un flux en appelant la méthode IPortWavePci::Notify . Cette méthode prend comme paramètre d’appel le groupe de services du flux, qui est un objet de type IServiceGroup. La méthode Notify appelle la méthode RequestService du groupe de services (voir IServiceSink::RequestService).

Un objet service-group contient un groupe de récepteurs de service, qui sont des objets de type IServiceSink. IServiceGroup est dérivé d’IServiceSink, et les deux interfaces ont des méthodes RequestService . Lorsque la méthode Notify appelle la méthode RequestService du groupe de services, le groupe de services répond en appelant la méthode RequestService sur chaque récepteur de service du groupe.

Le groupe de services d’un flux contient au moins un récepteur de service, que le pilote de port ajoute au groupe de services immédiatement après la création du flux. Le pilote de port appelle la méthode IMiniportWavePci::NewStream du pilote miniport pour obtenir un pointeur vers le groupe de services. La méthode RequestService du récepteur de service est la routine de service spécifique au flux du pilote de port. Cette routine effectue les opérations suivantes :

  • Appelle la méthode IMiniportWavePciStream::Service du pilote miniport.

  • Déclenche tout nouvel événement de position ou d’horloge en attente sur le flux depuis la dernière exécution de la routine de service.

Comme indiqué dans KS Events, les clients peuvent s’inscrire pour être avertis lorsqu’un flux atteint une position particulière ou lorsqu’une horloge atteint un horodatage particulier. La méthode NewStream a la possibilité de ne pas fournir de groupe de services, auquel cas le pilote de port configure son propre minuteur pour marquer les intervalles entre les appels à sa routine de service.

Comme la méthode NewStream , la méthode IMiniportWavePci::Init du pilote miniport génère également un pointeur vers un groupe de services. Après l’appel Init , le pilote de port ajoute son récepteur de service au groupe de services. Ce récepteur de service particulier contient la routine de service pour le filtre dans son ensemble. (Le paragraphe précédent décrit le récepteur de service pour le flux associé à une broche sur le filtre.) Cette routine de service appelle la méthode IMiniportWavePci::Service du pilote miniport . La routine de service s’exécute chaque fois que le DPC ou l’ISR appelle Notify avec le groupe de services pour le filtre. La méthode Init a la possibilité de ne pas fournir de groupe de services, auquel cas le pilote de port n’appelle jamais sa routine de service de filtre.

Interruptions matérielles

Certains pilotes miniport génèrent trop ou pas assez d’interruptions matérielles. Dans certains appareils de rendu WavePci avec accélération matérielle DirectSound, une interruption matérielle se produit uniquement lorsque l’approvisionnement en mappages est presque épuisé et que le moteur de rendu risque d’être affamé. Dans d’autres appareils WavePci accélérés par le matériel, une interruption matérielle se produit à chaque fin de mappage ou à un autre intervalle relativement faible. Dans ce cas, l’ISR constate souvent qu’il a peu à faire, mais chaque interruption consomme toujours des ressources système avec des échanges d’inscription et des rechargements de cache. La première étape de l’amélioration des performances du pilote consiste à réduire autant que possible le nombre d’interruptions sans risquer de s’affamer. Après avoir éliminé les interruptions inutiles, des gains de performances supplémentaires peuvent être obtenus en concevant l’ISR pour qu’il s’exécute plus efficacement.

Dans certains pilotes, les ISR gaspillent du temps en appelant la méthode Notify d’un flux chaque fois qu’une interruption matérielle se produit, que le flux soit en cours d’exécution ou non. Si aucun flux n’est à l’état RUN, DMA est inactif et le temps passé à essayer d’acquérir des mappages, des mappages de mise en production ou des case activée pour de nouveaux événements dans tous les flux est gaspillé. Dans un pilote efficace, l’ISR vérifie qu’un flux est en cours d’exécution avant d’appeler la méthode Notify du flux.

Toutefois, un pilote avec ce type d’ISR doit s’assurer que tous les événements en attente sur un flux sont déclenchés lorsque le flux quitte l’état RUN. Sinon, les événements peuvent être retardés ou perdus. Ce problème se produit uniquement pendant les transitions RUN-to-PAUSE dans les systèmes d’exploitation antérieurs à Microsoft Windows XP. Dans Windows XP et versions ultérieures, le pilote de port signale automatiquement les événements de position en attente immédiatement lorsqu’un flux passe de l’état RUN à PAUSE. Dans les anciens systèmes d’exploitation, toutefois, le pilote miniport est chargé de déclencher tous les événements en suspens en effectuant un appel final à Notifier immédiatement après la suspension du flux. Pour plus d’informations, consultez PAUSE/ACQUIRE Optimizations ci-dessous.

Un pilote de miniport WavePci classique gère un seul flux de lecture à partir du pilote système KMixer. L’implémentation actuelle de KMixer utilise au moins trois IIP de mappage pour mettre en mémoire tampon un flux de lecture. Chaque IRP contient suffisamment de stockage tampon pour environ 10 millisecondes d’audio. Si le pilote miniport déclenche une interruption matérielle chaque fois que le contrôleur DMA termine le mappage final dans un IRP, les interruptions doivent se produire à intervalles assez réguliers de 10 millisecondes, ce qui est assez fréquent pour empêcher la file d’attente DMA de s’affamer.

Contrôleurs DPC du minuteur

Si un pilote gère des flux DirectSound accélérés par le matériel, il doit utiliser un DPC du minuteur (voir Timer Objects and DCS) au lieu des interruptions matérielles pilotées par DMA. De manière équivalente, un appareil WavePci sur un carte PCI avec un minuteur intégré peut utiliser une interruption matérielle pilotée par le minuteur au lieu d’un DPC.

Dans le cas d’une mémoire tampon DirectSound, la mémoire tampon entière peut être attachée à un seul IRP. Si la mémoire tampon est volumineuse et que le pilote miniport planifie une interruption matérielle uniquement lorsqu’il atteint la fin de la mémoire tampon, des interruptions successives peuvent se produire si loin que la file d’attente DMA s’épuise. En outre, si le pilote gère un grand nombre de flux DirectSound accélérés par le matériel et que chaque flux génère ses propres interruptions, l’impact cumulé de toutes les interruptions peut dégrader les performances du système. Dans ces circonstances, le pilote miniport doit éviter d’utiliser des interruptions matérielles pour planifier la maintenance des flux individuels. Au lieu de cela, il doit traiter tous les flux dans un seul DPC qui est planifié pour s’exécuter à intervalles réguliers générés par le minuteur.

En définissant l’intervalle du minuteur sur 10 millisecondes, l’intervalle entre les exécutions DPC successives est similaire à celui décrit précédemment pour l’interruption matérielle dans le cas d’un seul flux de lecture KMixer. Ainsi, le DPC peut gérer le flux de lecture KMixer en plus des flux DirectSound à accélération matérielle.

Lorsque le dernier flux quitte l’état RUN, le pilote miniport doit désactiver le DPC du minuteur pour éviter de gaspiller les cycles du processeur système. Immédiatement après avoir désactivé le DPC, le pilote doit s’assurer que tous les événements d’horloge ou de position en attente sur les flux en cours d’exécution sont vidés. Dans Windows 98/Me et Windows 2000, le pilote doit appeler Notify pour déclencher les événements en attente sur les flux en pause. Dans Windows XP et versions ultérieures, le système d’exploitation déclenche automatiquement tous les événements en attente lorsqu’un flux quitte l’état RUN, sans nécessiter l’intervention du pilote miniport.

PAUSE/ACQUISITION Des optimisations

Dans Windows 98/Me et Windows 2000, la routine de service de flux du pilote de port WavePci (la méthode RequestService ) génère toujours un appel à la méthode IMiniportWavePciStream::Service du pilote miniport, que le flux soit à l’état RUN ou non. Dans ces systèmes d’exploitation, la méthode Service doit case activée si le flux est en cours d’exécution avant de passer du temps à effectuer le travail réel. (Toutefois, si le DPC ou l’ISR du pilote miniport a déjà été optimisé pour appeler Notify uniquement pour les flux en cours d’exécution, l’ajout de cette case activée à la méthode Service peut être redondant.)

Dans Windows XP et versions ultérieures, cette optimisation n’est pas nécessaire, car la méthode Notify appelle la méthode Service uniquement sur les flux en cours d’exécution.

Utilisation de l’interface IPreFetchOffset

Les utilisateurs DirectSound sont familiarisés avec le double concept du curseur de lecture et du curseur d’écriture. Le curseur de lecture indique la position dans le flux des données émises par l’appareil (meilleure estimation de l’échantillon actuellement à la DAC par le pilote). La position d’écriture est la position dans le flux de l’emplacement sécurisé suivant pour que le client écrive des données supplémentaires. Pour WavePci, l’hypothèse par défaut est que le curseur d’écriture est positionné à la fin du dernier mappage demandé. Si le pilote miniport a acquis un grand nombre de mappages exceptionnels, le décalage entre le curseur de lecture et le curseur d’écriture peut être très important, ce qui peut être assez important pour échouer à certains tests de position audio WHQL. Dans Windows XP et versions ultérieures, l’interface IPreFetchOffset résout ces problèmes.

Le pilote miniport utilise IPreFetchOffset pour spécifier les caractéristiques de pré-utilisation du matériel master bus, qui sont en grande partie déterminées par la taille du matériel FIFO. Le sous-système audio utilise ces données pour définir un décalage constant entre le curseur de lecture et le curseur d’écriture. Ce décalage constant, qui peut être beaucoup plus petit que le décalage par défaut, tire parti du fait que les données peuvent être écrites dans un mappage même après que le mappage a été remis au matériel, tant que le curseur de lecture est suffisamment éloigné de l’emplacement dans lequel les données sont écrites. (Cette instruction suppose que le pilote ne copie pas ou ne manipule pas les données dans les mappages.) Un décalage classique peut être de l’ordre de 64 exemples, selon la conception du moteur. Avec un décalage aussi petit, un pilote WavePci peut être entièrement réactif et fonctionnel tout en demandant un grand nombre de mappages.

Notez que DirectSound rembourse actuellement le curseur d’écriture d’une broche à accélération matérielle de 10 millisecondes.

Pour plus d’informations, consultez Décalages de prérécupération.

Traitement des données dans les mappages

Évitez que votre pilote matériel touche les données dans les mappages si possible. Tout traitement logiciel des données contenues dans les mappages doit être divisé en un filtre logiciel distinct du pilote matériel. Le fait qu’un pilote matériel effectue un tel traitement réduit son efficacité et crée des problèmes de latence.

Un pilote matériel doit s’efforcer d’être transparent sur ses capacités matérielles réelles. Le pilote ne doit jamais prétendre fournir une prise en charge matérielle d’une transformation de données qui est réellement effectuée dans un logiciel.

Primitives de synchronisation

Un pilote est moins susceptible d’avoir des problèmes d’interblocage ou de performances maintenant et à l’avenir si son code est conçu pour éviter d’être bloqué dans la mesure du possible. Plus précisément, le thread d’exécution d’un pilote doit s’efforcer de s’exécuter jusqu’à l’achèvement sans risquer de se bloquer en attendant un autre thread ou une autre ressource. Par exemple, les threads de pilote peuvent utiliser les fonctionsXxx verrouillées (par exemple, voir InterlockedIncrement) pour coordonner leurs accès à certaines ressources partagées sans risquer d’être bloqués.

Bien qu’il s’agisse de techniques puissantes, il se peut que vous ne puissiez pas supprimer en toute sécurité tous les verrous de rotation, mutex et autres primitives de synchronisation bloquantes du chemin d’exécution. Utilisez judicieusement les fonctionsXxx verrouillées, en sachant qu’une attente indéfinie peut entraîner une insuffisance de données.

Surtout, ne créez pas de primitives de synchronisation personnalisées. Les primitives Windows intégrées (mutex, verrous de rotation, etc.) sont susceptibles d’être modifiées en fonction des besoins pour prendre en charge les nouvelles fonctionnalités du planificateur à l’avenir, et un pilote qui utilise des constructions personnalisées est pratiquement garanti de ne pas fonctionner à l’avenir.

IPinCount, interface

Dans Windows XP et versions ultérieures, l’interface IPinCount permet à un pilote miniport de prendre en compte plus précisément les ressources matérielles consommées par l’allocation d’une broche. En appelant la méthode IPinCount::P inCount du pilote miniport, le pilote de port effectue les opérations suivantes :

  • Expose le nombre actuel de broches du filtre (tel qu’il est géré par le pilote de port) au pilote miniport.

  • Donne au pilote miniport la possibilité de réviser le nombre de broches pour refléter dynamiquement la disponibilité actuelle des ressources matérielles.

Pour certains périphériques audio, les flux d’ondes avec des attributs différents (3D, stéréo/mono, etc.) peuvent également avoir des « poids » différents en termes de nombre de ressources matérielles qu’ils consomment. Lors de l’ouverture ou de la fermeture d’un flux « léger », le pilote incrémente ou décrémente le nombre de broches disponibles d’un. Toutefois, lors de l’ouverture d’un flux « lourd », le pilote miniport peut avoir besoin de décrémenter le nombre de broches disponibles de deux au lieu d’une pour indiquer plus précisément le nombre de broches qui peuvent être créées avec les ressources restantes.

Le processus est inversé lorsqu’un flux lourd est fermé. Le nombre de broches disponibles peut augmenter de plus d’un afin de refléter le fait que deux ou plusieurs flux légers peuvent être créés à partir des ressources nouvellement libérées.