Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
El impacto en el rendimiento de un controlador de audio en el sistema se puede reducir considerablemente siguiendo estos principios generales:
Minimice el código que se ejecuta durante la operación normal.
Ejecute código solo cuando sea necesario.
Tenga en cuenta el consumo total de recursos del sistema (no solo la carga de CPU).
Optimice el código para la velocidad y el tamaño.
Además, los controladores de miniport de WavePci deben abordar varios problemas de rendimiento específicos de los dispositivos de audio. En la siguiente explicación se tratan principalmente los problemas de representación de audio, aunque algunas de las técnicas sugeridas también se aplican a la captura de audio.
Mecanismos de mantenimiento de flujos
Antes de analizar las optimizaciones de rendimiento, es necesario conocer algunos aspectos básicos para comprender los mecanismos wavePci para los flujos de mantenimiento.
Al procesar una representación de onda o una secuencia de captura, un dispositivo de audio requiere mantenimiento a intervalos regulares por el controlador de miniport. Cuando hay nuevas asignaciones disponibles para una secuencia, el controlador agrega esas asignaciones a la cola DMA de la secuencia. El controlador también quita de la cola los mapeos que ya se han procesado. Para obtener información sobre las asignaciones, consulte Latencia de WavePci.
Para realizar el mantenimiento, el controlador de miniporte proporciona una llamada a procedimiento diferido (DPC) o una rutina de servicio de interrupción (ISR), dependiendo de si el intervalo está establecido por un temporizador del sistema o por interrupciones controladas por DMA. En este último caso, el hardware DMA normalmente desencadena una interrupción cada vez que finaliza la transferencia de cierta cantidad de datos de flujo.
Cada vez que se ejecuta DPC o ISR, determina qué flujos requieren mantenimiento. El DPC o ISR atiende una secuencia llamando al método IPortWavePci::Notify. Este método toma como parámetro de llamada el grupo de servicios de la secuencia, que es un objeto de tipo IServiceGroup. El método Notify llama al método RequestService del grupo de servicio (consulte IServiceSink::RequestService).
Un objeto de grupo de servicios contiene un grupo de receptores de servicio, que son objetos de tipo IServiceSink. IServiceGroup se deriva de IServiceSink y ambas interfaces tienen métodos RequestService . Cuando el método Notify llama al método RequestService del grupo de servicio, el grupo de servicios responde llamando al método RequestService en cada receptor de servicio del grupo.
El grupo de servicios de una secuencia contiene al menos un sumidero de servicio, que el controlador del puerto agrega al grupo de servicios inmediatamente después de la creación de la secuencia. El controlador de puerto llama al método IMiniportWavePci::NewStream del controlador de miniport para obtener un puntero al grupo de servicios. El método RequestService del sumidero de servicio es la rutina de servicio específica para el flujo del controlador de puerto. Esta rutina hace lo siguiente:
Llama al método IMiniportWavePciStream::Service del controlador de miniport.
Activa cualquier evento de posición o reloj que hayan quedado pendientes recientemente en el flujo desde la última vez que se ejecutó la rutina de servicio.
Como se describe en Eventos KS, los clientes pueden registrarse para recibir notificaciones cuando una secuencia alcanza una posición determinada o cuando un reloj alcanza una marca de tiempo determinada. El método NewStream tiene la opción de no proporcionar un grupo de servicios, en cuyo caso el controlador de puerto configura su propio temporizador para marcar los intervalos entre las llamadas a su rutina de servicio.
Al igual que el método NewStream , el método IMiniportWavePci::Init del controlador de miniport también genera un puntero a un grupo de servicios. Después de la llamada Init, el controlador de puerto agrega su receptor de servicio al grupo de servicios. Este receptor de servicio concreto contiene la rutina de servicio para el filtro en su conjunto. (En el párrafo anterior se describe el sumidero de servicio para la secuencia asociada a un pin en el filtro). Esta rutina de servicio llama al método IMiniportWavePci::Service del controlador de miniport. La rutina de servicio se ejecuta cada vez que el DPC o ISR llama a Notify con el grupo de servicio para el filtro. El método Init tiene la opción de no proporcionar un grupo de servicios, en cuyo caso el controlador de puerto nunca llama a su rutina de servicio de filtro.
Interrupciones de hardware
Algunos controladores de miniporte generan demasiadas interrupciones de hardware o no suficientes. En algunos dispositivos de representación WavePci con aceleración de hardware DirectSound, una interrupción de hardware solo se produce cuando el suministro de asignaciones está casi agotado y el motor de representación está en riesgo de quedarse sin datos. En otros dispositivos WavePci acelerados por hardware, se produce una interrupción de hardware en cada única finalización de asignación o en algún otro intervalo relativamente pequeño. En este caso, el ISR encuentra con frecuencia que tiene poco que hacer, pero cada interrupción sigue consume recursos del sistema con cambios de registro y recargas de caché. El primer paso para mejorar el rendimiento del controlador es reducir el número de interrupciones tanto como sea posible sin riesgo de hambre. Después de eliminar interrupciones innecesarias, se pueden lograr mejoras de rendimiento adicionales mediante el diseño del ISR para que se ejecute de forma más eficaz.
En algunos controladores, los ISR pierden tiempo llamando al método Notify de una secuencia cada vez que se produce una interrupción de hardware, independientemente de si la secuencia se está ejecutando realmente. Si no hay flujos en el estado RUN, entonces DMA está inactivo, y se desperdicia cualquier tiempo dedicado a adquirir asignaciones, liberar asignaciones o comprobar si hay nuevos eventos en los flujos. En un controlador eficaz, el ISR comprueba que se está ejecutando un flujo antes de llamar al método Notify del flujo.
Sin embargo, un controlador con este tipo de ISR debe asegurarse de que los eventos pendientes en una secuencia se desencadenan cuando la secuencia sale del estado RUN. De lo contrario, los eventos pueden retrasarse o perderse. Este problema solo surge durante las transiciones de EJECUCIÓN a PAUSA en sistemas operativos anteriores a Microsoft Windows XP. En Windows XP y versiones posteriores, el controlador de puerto indica automáticamente los eventos de posición pendientes inmediatamente cuando una secuencia cambia el estado de RUN a PAUSE. Sin embargo, en los sistemas operativos más antiguos, el controlador de minipuerto es responsable de desencadenar los eventos pendientes mediante la realización de una llamada final a Notify inmediatamente después de pausar la secuencia. Para obtener más información, consulte PAUSE/ACQUIRE Optimizations a continuación.
Un controlador de miniport de WavePci típico administra una única secuencia de reproducción desde el controlador del sistema KMixer. La implementación actual de KMixer usa un mínimo de tres IRPs de mapeo para almacenar en búfer un flujo de reproducción. Cada IRP contiene suficiente almacenamiento en búfer para aproximadamente 10 milisegundos de audio. Si el controlador de miniporte desencadena una interrupción de hardware cada vez que el controlador DMA finaliza con la asignación final en un IRP, las interrupciones deben producirse en intervalos bastante regulares de 10 milisegundos, lo cual es lo suficientemente frecuente como para evitar que la cola DMA se quede sin datos.
DPC del temporizador
Si un controlador administra secuencias de DirectSound aceleradas por hardware, debe usar un DPC de temporizador (consulte Objetos de temporizador y DPC) en lugar de interrupciones de hardware controladas por DMA. De forma equivalente, un dispositivo WavePci en una tarjeta PCI con un temporizador incorporado puede usar una interrupción de hardware controlada por temporizador en lugar de un DPC.
En el caso de un búfer de DirectSound, todo el búfer se puede conectar a un único IRP. Si el búfer es grande y el controlador de minipuerto programa una interrupción de hardware solo cuando llega al final del búfer, las interrupciones sucesivas pueden ocurrir tan separadas que la cola DMA se quede sin datos. Además, si el controlador administra un gran número de flujos directSound acelerados por hardware y cada secuencia genera sus propias interrupciones, el impacto acumulativo de todas las interrupciones puede degradar el rendimiento del sistema. En estas circunstancias, el controlador de miniporte debe evitar el uso de interrupciones de hardware para programar el mantenimiento de secuencias individuales. En su lugar, debe atender todos los flujos en un único DPC que está programado para ejecutarse en intervalos generados por el temporizador normal.
Al establecer el intervalo del temporizador en 10 milisegundos, el intervalo entre ejecuciones sucesivas de DPC es similar al descrito anteriormente para la interrupción de hardware en el caso de una única secuencia de reproducción de KMixer. Por lo tanto, el DPC puede manejar la secuencia de reproducción de KMixer además de las secuencias de DirectSound aceleradas por hardware.
Cuando el último flujo sale del estado de ejecución (RUN), el controlador miniport debe deshabilitar el DPC del temporizador para evitar el desperdicio de ciclos de CPU del sistema. Inmediatamente después de deshabilitar el DPC, el controlador debe asegurarse de que los eventos de reloj o posición pendientes de las secuencias que estaban en ejecución se vacíen. En Windows 98/Me y Windows 2000, el controlador debe llamar a Notify para desencadenar los eventos pendientes en las secuencias que se están pausando. En Windows XP y versiones posteriores, el sistema operativo desencadena automáticamente los eventos pendientes cuando una secuencia sale del estado RUN, sin necesidad de intervención del controlador de miniport.
Optimizaciones PAUSE/ACQUIRE
En Windows 98/Me y Windows 2000, la rutina del servicio de transmisión del controlador de puerto WavePci (el método RequestService ) siempre genera una llamada al método IMiniportWavePciStream::Service del controlador de miniport, independientemente de si la secuencia está en estado RUN. En estos sistemas operativos, el método Service debe comprobar si la secuencia se está ejecutando antes de invertir tiempo en realizar el trabajo propiamente dicho. (Sin embargo, si el DPC o ISR del controlador de miniporte ya se ha optimizado para llamar a Notify solo para las secuencias que se ejecutan, agregar esta comprobación al método Service podría ser redundante).
En Windows XP y versiones posteriores, esta optimización no es necesaria porque el método Notify llama al método Service solo en secuencias que se ejecutan.
Uso de la interfaz IPreFetchOffset
Los usuarios de DirectSound están familiarizados con los conceptos duales del cursor de reproducción y el cursor de escritura. El cursor de reproducción indica la posición en el flujo de los datos que se emiten desde el dispositivo (la mejor estimación del controlador de la muestra actualmente en la DAC). La posición de escritura es la posición en el flujo del siguiente lugar seguro para que el cliente escriba datos adicionales. Para WavePci, la suposición predeterminada es que el cursor de escritura se coloca al final de la última asignación solicitada. Si el controlador de miniporte ha adquirido un gran número de asignaciones pendientes, el desplazamiento entre el cursor de reproducción y el cursor de escritura puede ser muy grande, lo suficientemente grande como para producir errores en determinadas pruebas de posición de audio WHQL. En Windows XP y versiones posteriores, la interfaz IPreFetchOffset soluciona estos problemas.
El controlador de miniporte usa IPreFetchOffset para especificar las características de prefetch del hardware del bus-master, que dependen en gran medida del tamaño FIFO del hardware. El subsistema de audio usa estos datos para establecer un desplazamiento constante entre el cursor de reproducción y el cursor de escritura. Este desplazamiento constante, que puede ser significativamente menor que el desplazamiento predeterminado, aprovecha el hecho de que los datos se pueden escribir en un mapeo incluso después de que se haya asignado al hardware, siempre que el cursor de reproducción esté lo suficientemente alejado de la ubicación en la que se escriben los datos. (En esta instrucción se supone que el controlador no copia ni manipula los datos en mapeos). Un desplazamiento típico puede ser del orden de 64 muestras, dependiendo del diseño del motor. Con un desplazamiento tan pequeño, un controlador WavePci puede ser totalmente sensible y funcional mientras se solicita un gran número de mapeos.
Tenga en cuenta que DirectSound actualmente rellena el cursor de escritura de un pin acelerado por hardware en 10 milisegundos.
Para obtener más información, consulte Desplazamientos de captura previa.
Procesamiento de datos en mapeos
Evite que el controlador de hardware toque los datos en las asignaciones si es posible. Cualquier procesamiento de software de los datos contenidos en asignaciones debe dividirse en un filtro de software independiente del controlador de hardware. El hecho de que un controlador de hardware realice este procesamiento reduce su eficacia y crea problemas de latencia.
Un controlador de hardware debe esforzarse por ser transparente sobre sus funcionalidades de hardware reales. El controlador nunca debe reclamar proporcionar compatibilidad de hardware para una transformación de datos que se realiza realmente en el software.
Primitivos de sincronización
Es menos probable que un controlador tenga problemas de interbloqueo o rendimiento ahora y, en el futuro, si su código está diseñado para evitar que se bloquee siempre que sea posible. En concreto, el subproceso de ejecución de un controlador debe esforzarse por ejecutarse hasta completarse sin el riesgo de detenerse mientras espera otro subproceso o recurso. Por ejemplo, los subprocesos del controlador pueden usar las funcionesXxx interbloqueadas (por ejemplo, vea InterlockedIncrement) para coordinar sus accesos a determinados recursos compartidos sin el riesgo de bloquearse.
Aunque estas son técnicas eficaces, es posible que no pueda quitar de forma segura todos los bloqueos de giro, las exclusiones mutuas y otros primitivos de sincronización bloqueantes del camino de ejecución. Utiliza las funciones Xxx Interlocked con criterio, con el conocimiento de que una espera indefinida podría provocar un desabastecimiento de datos.
Por encima de todo, no cree primitivos de sincronización personalizados. Es probable que los primitivos integrados de Windows (exclusión mutua, bloqueos de espera activa, etc.) se modifiquen según sea necesario para admitir nuevas características del planificador en el futuro, por lo cual se garantiza que un controlador que utilice constructos personalizados no funcionará en el futuro.
IPinCount (interfaz)
En Windows XP y versiones posteriores, la interfaz IPinCount proporciona una manera de que un controlador de miniporte tenga en cuenta con mayor precisión los recursos de hardware que se consumen asignando un pin. Al invocar el método IPinCount::PinCount del controlador de puerto, el controlador de puerto realiza lo siguiente:
Expone los recuentos actuales de pines del filtro (tal como los mantiene el controlador de puerto) al controlador de miniport.
Proporciona al controlador miniport la oportunidad de revisar los recuentos de pines y reflejar dinámicamente la disponibilidad actual de los recursos de hardware.
Para algunos dispositivos de audio, las secuencias de onda con atributos diferentes (3D, estéreo/mono, etc.) también pueden tener diferentes "pesos" en términos de cuántos recursos de hardware consumen. Al abrir o cerrar una secuencia "ligera", el controlador incrementa o disminuye el recuento de conectores disponibles en uno. Al abrir un flujo de "peso pesado", el controlador de miniport podría necesitar disminuir el número de patillas disponibles en dos en lugar de uno, para indicar con más precisión la cantidad de patillas que se pueden crear con los recursos restantes.
El proceso se invierte cuando se cierra un flujo pesado. El número de pines disponibles puede aumentar en más de uno para reflejar el hecho de que se pueden crear dos o más secuencias ligeras a partir de los recursos recién liberados.