Esta página se enfoca en los contribuyentes a la latencia de salida, pero una discusión similar se aplica a la latencia de entrada.
Suponiendo que los circuitos analógicos no contribuyan significativamente, los principales contribuyentes a nivel de superficie a la latencia de audio son los siguientes:
- Solicitud
- Número total de búferes en proceso
- Tamaño de cada búfer, en fotogramas
- Latencia adicional después del procesador de aplicaciones, como de un DSP
A pesar de lo precisa que puede ser la lista anterior de contribuyentes, también es engañosa. La razón es que el número de búfer y el tamaño del búfer son más un efecto que una causa . Lo que suele suceder es que se implementa y prueba un esquema de búfer dado, pero durante la prueba, una insuficiencia o saturación de audio se escucha como un "clic" o "pop". Para compensar, el diseñador del sistema aumenta los tamaños de búfer o los recuentos de búfer. Esto tiene el resultado deseado de eliminar los atrasos o los excesos, pero también tiene el efecto secundario no deseado de aumentar la latencia. Para obtener más información sobre los tamaños de búfer, consulte el video Latencia de audio: tamaños de búfer .
Un mejor enfoque es comprender las causas de los atrasos y excesos, y luego corregirlos. Esto elimina los artefactos audibles y puede permitir menos o menos búferes y, por lo tanto, reducir la latencia.
Según nuestra experiencia, las causas más comunes de insuficiencias y excesos incluyen:
- Linux CFS (programador completamente justo)
- subprocesos de alta prioridad con programación SCHED_FIFO
- inversión de prioridad
- larga latencia de programación
- manejadores de interrupciones de ejecución prolongada
- tiempo de desactivación de interrupción largo
- administración de energía
- núcleos de seguridad
Programación de Linux CFS y SCHED_FIFO
Linux CFS está diseñado para ser justo con las cargas de trabajo competidoras que comparten un recurso de CPU común. Esta equidad está representada por un parámetro agradable por subproceso. El valor agradable varía de -19 (menos agradable o mayor tiempo de CPU asignado) a 20 (mejor o menos tiempo de CPU asignado). En general, todos los subprocesos con un valor Niza dado reciben aproximadamente el mismo tiempo de CPU y los subprocesos con un valor Niza numéricamente más bajo deberían recibir más tiempo de CPU. Sin embargo, CFS es "justo" solo durante períodos de observación relativamente largos. Durante las ventanas de observación a corto plazo, CFS puede asignar el recurso de la CPU de formas inesperadas. Por ejemplo, puede quitar la CPU de un subproceso con una amabilidad numéricamente baja a un subproceso con una amabilidad numéricamente alta. En el caso del audio, esto puede dar lugar a una insuficiencia o saturación.
La solución obvia es evitar CFS para subprocesos de audio de alto rendimiento. A partir de Android 4.1, estos subprocesos ahora usan la política de programación SCHED_FIFO
en lugar de la política de programación SCHED_NORMAL
(también llamada SCHED_OTHER
) implementada por CFS.
Prioridades SCHED_FIFO
Aunque los subprocesos de audio de alto rendimiento ahora usan SCHED_FIFO
, aún son susceptibles a otros subprocesos SCHED_FIFO
de mayor prioridad. Por lo general, estos son subprocesos de trabajo del núcleo, pero también puede haber algunos subprocesos de usuario que no sean de audio con la política SCHED_FIFO
. Las prioridades SCHED_FIFO
disponibles van de 1 a 99. Los subprocesos de audio se ejecutan con prioridad 2 o 3. Esto deja la prioridad 1 disponible para subprocesos de menor prioridad y las prioridades 4 a 99 para subprocesos de mayor prioridad. Le recomendamos que use la prioridad 1 siempre que sea posible y reserve las prioridades de la 4 a la 99 para aquellos subprocesos que se garantiza que se completarán en un período de tiempo limitado, se ejecutarán en un período más corto que el período de los subprocesos de audio y se sabe que no interfieren con la programación. de hilos de audio.
Programación de tarifa monotónica
Para obtener más información sobre la teoría de la asignación de prioridades fijas, consulte el artículo de Wikipedia Programación monotónica de frecuencia (RMS). Un punto clave es que las prioridades fijas deben asignarse estrictamente en función del período, con prioridades más altas asignadas a subprocesos de períodos más cortos, no en función de la "importancia" percibida. Los subprocesos no periódicos pueden modelarse como subprocesos periódicos, utilizando la frecuencia máxima de ejecución y el cálculo máximo por ejecución. Si un subproceso no periódico no se puede modelar como un subproceso periódico (por ejemplo, podría ejecutarse con una frecuencia ilimitada o un cálculo ilimitado por ejecución), entonces no se le debe asignar una prioridad fija, ya que eso sería incompatible con la programación de subprocesos periódicos verdaderos. .
inversión de prioridad
La inversión de prioridad es un modo de falla clásico de los sistemas en tiempo real, donde una tarea de mayor prioridad se bloquea durante un tiempo ilimitado a la espera de que una tarea de menor prioridad libere un recurso como (estado compartido protegido por) un mutex . Consulte el artículo " Evitar la inversión de prioridad " para conocer las técnicas para mitigarlo.
Latencia de programación
La latencia de programación es el tiempo que transcurre entre el momento en que un subproceso está listo para ejecutarse y el cambio de contexto resultante se completa para que el subproceso se ejecute realmente en una CPU. Cuanto más corta sea la latencia, mejor, y más de dos milisegundos causa problemas para el audio. La latencia de programación larga es más probable que ocurra durante las transiciones de modo, como encender o apagar una CPU, cambiar entre un kernel de seguridad y el kernel normal, cambiar del modo de máxima potencia al modo de baja potencia o ajustar la frecuencia y el voltaje del reloj de la CPU .
Interrupciones
En muchos diseños, la CPU 0 da servicio a todas las interrupciones externas. Por lo tanto, un controlador de interrupciones de ejecución prolongada puede retrasar otras interrupciones, en particular, las interrupciones de finalización del acceso directo a la memoria (DMA) de audio. Diseñe controladores de interrupción para que finalicen rápidamente y difiera el trabajo extenso a un subproceso (preferiblemente un subproceso CFS o un subproceso SCHED_FIFO
de prioridad 1).
De manera equivalente, deshabilitar las interrupciones en la CPU 0 durante un período prolongado tiene el mismo resultado de retrasar el servicio de las interrupciones de audio. Los tiempos prolongados de inhabilitación de interrupciones suelen ocurrir mientras se espera un bloqueo de giro del núcleo. Revise estos bloqueos giratorios para asegurarse de que estén delimitados.
Energía, rendimiento y administración térmica
La administración de energía es un término amplio que abarca los esfuerzos para monitorear y reducir el consumo de energía mientras se optimiza el rendimiento. La gestión térmica y la refrigeración del ordenador son similares pero buscan medir y controlar el calor para evitar daños por exceso de calor. En el kernel de Linux, el gobernador de la CPU es responsable de la política de bajo nivel, mientras que el modo de usuario configura la política de alto nivel. Las técnicas utilizadas incluyen:
- escalado de voltaje dinámico
- escala de frecuencia dinámica
- habilitación de núcleo dinámico
- conmutación de clúster
- puerta de poder
- conexión en caliente (intercambio en caliente)
- varios modos de suspensión (detener, detener, inactivo, suspender, etc.)
- proceso de migración
- afinidad del procesador
Algunas operaciones de administración pueden resultar en "paros de trabajo" o tiempos durante los cuales el procesador de la aplicación no realiza ningún trabajo útil. Estos paros laborales pueden interferir con el audio, por lo que dicha gestión debe diseñarse para un paro laboral aceptable en el peor de los casos mientras el audio está activo. Por supuesto, cuando la fuga térmica es inminente, ¡evitar daños permanentes es más importante que el audio!
Núcleos de seguridad
Un kernel de seguridad para la gestión de derechos digitales (DRM) puede ejecutarse en los mismos núcleos de procesador de aplicaciones que los utilizados para el kernel del sistema operativo principal y el código de la aplicación. Cualquier momento durante el cual una operación del núcleo de seguridad esté activa en un núcleo es efectivamente una interrupción del trabajo ordinario que normalmente se ejecutaría en ese núcleo. En particular, esto puede incluir trabajos de audio. Por su naturaleza, el comportamiento interno de un kernel de seguridad es inescrutable desde las capas de nivel superior y, por lo tanto, cualquier anomalía de rendimiento causada por un kernel de seguridad es especialmente perniciosa. Por ejemplo, las operaciones del núcleo de seguridad no suelen aparecer en los seguimientos de cambio de contexto. A esto lo llamamos "tiempo oscuro": tiempo que transcurre y aún no se puede observar. Los núcleos de seguridad deben diseñarse para una interrupción del trabajo aceptable en el peor de los casos mientras el audio está activo.