domingo, 9 de mayo de 2010

Configuración del script rtirq para muy baja latencia

###################################
Notas de revisiones:
Revisión 0: 8 mayo 2010. Publicado.
Revisión 1: 15 mayo 2010. Retocado.
Revisión 2: 26 mayo 2010. Añadida nota sobre los sirq-timers y la prioridad de jackd
Revisión 3: 28 mayo 2010. Actualizada la explicación sobre los sirq-timers, reordenado y modificado título
Revisión 4: 26 noviembre 2010. Añadida advertencia "sólo funciona con kernel rt"
Revisión 5: 8 enero 2011. Actualizado: Funciona con cualquier kernel >= 2.6.39 con threadirqs habilitado.
###################################


El script rtirq-init está empaquetado y disponible en la mayoría de las distros. En Debian/ubuntu el paquete se llama "rtirq-init".

A partir de la versión del kernel 2.6.39, el script funciona en kernels precompilados como "generic" o "low-latency", siempre y cuando tengan habilitada la opción de arranque "threadirqs". Es decir, ya no es necesario un kernel modificado con el parche realtime para que este script funcione.

Si usamos grub2 como gestor de arranque, una forma de habilitar "threadirqs" es editar el archivo /etc/default/grub.

$ sudo gedit /etc/default/grub

Buscamos la línea

GRUB_CMDLINE_LINUX=""

y la modificamos a:

GRUB_CMDLINE_LINUX="threadirqs"

Para que el cambio tenga efecto, debemos actualizar grub:

$ sudo update-grub

Y reiniciar



Este script levanta las prioridades de los "kernel threads" más importantes para el trabajo con audio y MIDI en tiempo real y a baja latencia, automáticamente al arrancar el ordenador. Este script no es necesario en todos los casos, pero a veces ayuda.

Si escribimos en la terminal:

$ sudo updatedb
$ locate rtirq

Entre otros debería dar:
/etc/default/rtirq
/etc/init.d/rtirq

/etc/init.d/rtirq es el script, que lee el archivo de configuración /etc/default/rtirq.
Es este el archivo que debemos editar para conseguir el objetivo.

El objetivo depende de cada caso, pero normalmente será levantar las prioridades de:

1º El reloj y los temporizadores del sistema (para precisión con MIDI)
2º La tarjeta de audio (para baja latencia de audio)

Todo lo indicado en esta entrada lo vamos a hacer en línea de comandos y vamos a usar htop como monitor del sistema. Propongo terminator como emulador de terminal.

$ sudo apt-get install terminator htop

Ahora vamos a lanzar terminator y lo vamos a maximizar. Botón derecho sobre la pantalla y dividimos verticalmente. En la ventana de la derecha, botón derecho y dividimos horizontalmente. Tenemos 3 terminales.

En la de la izquierda lanzamos:

$ htop

htop nos da un montón de información sobre los procesos y el consumo de recursos de nuestra máquina. Hacemos:

F2 --> Display options --> Desmarcar "hide kernel threads" --> F10
F6 --> Sort by: PRI

Así vemos los procesos, incluidos los "kernel threads", ordenados por prioridad. Al menos en mi caso, los kernel threads cuya prioridad no ha sido levantada automáticamente al iniciar el ordenador por rtirq, toman la prioridad (omitiendo el signo) 51 ó 50. Los que están por encima es que han sido levantados por rtirq.

En una terminal de la derecha vamos a ver los "interrupts" con el comando:

$ cat /proc/interrupts

En la columna de la derecha tendremos que adivinar cuál es nuestra tarjeta de audio. Con una m-audio Audiophile 2496 veo que ICE1712 está en el número 22. Esto será diferente para cada sistema hardware-software, pero lo pongo como ejemplo. Si tu tarjeta es usb, debes fijarte en el número de bus, por ejemplo ehci_hcd:usbx o uhci_hcd:usbx. Con el comando lsusb puedes ver el número de bus usb en la primera columna. Si nos fijamos ahora en htop, vemos en la columna "Command" el número de irq seguido por su identificación. En mi caso, en la prioridad 51 veo irq/22-ICE1712, y también el irq/8-rtc0. Precisamente los dos kernel threads que se pretendían levantar se han quedado en 51, mientras que los ehci_hcd y uhci_ehcd, así como el i8042 (para el ratón y teclado PS/2, en mi caso inexistente) tienen las prioridades levantadas. Esto no es lo que quería conseguir.

¿Cómo arreglarlo? Modificando el archivo de configuración de rtirq.
En la terminal libre de la derecha escribimos:

$ sudo cp /etc/default/rtirq /etc/default/rtirq.copia (copia por si acaso)
$ sudo nano /etc/default/rtirq

Hay una serie de variables escritas en mayúsculas que son las que debemos tener en cuenta. El resto son comentarios. En nano guardamos los cambios con [Control-O] y salimos con [Control-X]. Bueno, usar el editor que os parezca mejor.

La variable más importante es RTIRQ_NAME_LIST. La encontramos así:

RTIRQ_NAME_LIST="rtc snd usb i8042"

Esta me está fastidiando. Cambio a:

RTIRQ_NAME_LIST="rtc0 ICE1712"

Que es lo que leo en la columna derecha de cat /proc/interrupts. Creo que lo que Rui quiere dar a entender es: "1º reloj, 2º tarjeta PCI, 3º tarjeta usb, 4º teclado/ratón PS2". Las distribuciones tienen algunas diferencias, por eso es genérico.

(Me parece que en lucid funciona a la primera con las designaciones genéricas, pero habría que comprobarlo).

He dejado fuera de RTIRQ_NAME_LIST "usb" e "i8042" pues no tengo tarjetas usb ni teclado/ratón PS2.

Si tenemos una tarjeta firewire, habrá que levantar la prioridad de ohci1394 en lugar de la de la tarjeta PCI y posiblemente también la del controlador firewire. Comprobar con htop. Más información en el enlace de ffado de abajo.

Hay otra variable:

RTIRQ_NON_THREADED=

Habría que cambiarla de todas maneras (otra vez, rtc y snd que al menos en mi caso no significan nada) pero creo que la puedo deshabilitar tranquilamente, "comentándola" con una almohadilla delante.

Por probar, voy a dar 98 a RTIRQ_PRIO_HIGH y pongo un paso de 10
en RTIRQ_PRIO_DECR.

Por otro lado, en el lowlatency howto de alsa y en el blog de SounDebian hablan de levantar las prioridades de los soft irq timers. Esto es mucho más fácil con rtirq. Sólo tenemos que descomentar la línea:

# RTIRQ_HIGH_LIST="timer"
Es decir, dejarla en:
RTIRQ_HIGH_LIST="timer"
Y tendremos los sirq-timers con la máxima prioridad.

Los temporizadores no afectan a la tarjeta de audio, que tiene su propio reloj. Sin embargo, son importantes para la reproducción de MIDI.

Una vez modificado el archivo de configuración, vamos a lanzarlo manualmente sin tener que reiniciar. Desde otra terminal:

$ sudo /etc/init.d/rtirq start

Florian (tercer enlace, entrada "Linux Audio/MIDI System") y Soundebian explican cómo hacer todo esto de forma manual (con el comando chrt). Florian propone levantar las prioridades de los secuenciadores y sintetizadores de software por encima de la de la tarjeta de audio y jackd. Por eso elijo un paso grande entre rtc0 y la tarjeta, para tener sitio entre medias, por si acaso, aunque sinceramente nunca me preocupo de levantar manualmente prioridades de otros procesos.

Cuando arrancamos manualmente el script vemos que se levantan las prioridades de los "kernel threads" que hemos configurado pero las que estaban levantadas no "bajan". (A veces tengo que terminar htop con F10 y volver a lanzarlo para asegurarme, pues el efecto no se ve de inmediato). Cuando reiniciemos el ordenador volvemos a comprobar con htop si rtirq ha hecho su función. Los kernels threads no levantados los dejará con prioridad 51 ó 50.

Con esto se consiguen latencias bajísimas sin xruns, como vemos en la siguiente entrada, donde además realizamos algunas mediciones.

Créditos y para saber más, además de nuestro buscador favorito:

http://subversion.ffado.org/wiki/IrqPriorities
http://www.rncbc.org/drupal/node/107
http://tapas.affenbande.org/wordpress/ (linux audio pages)
http://bugtrack.alsa-project.org/main/index.php/Low_latency_howto
http://www.soundebian.com.ar/2009/10/configurando-verdaderamente-el-real-time-para-audio/

8 comentarios:

  1. Gracias como siempre, amigo Pablo.

    ResponderEliminar
  2. Wow este blog es genial!

    Yo llevo uno (musicalwars.blogspot) y creo que dentro de poco voy a tener que incluir parte de tu talento en el. Te mantendré informado de lo que haga.

    Un saludo y enhorabuena.

    Una cosa, había visitado el post hace tiempo pero no me acorde de el, ahora me arrepiento. Esta muy wapo - de contenido -.

    ResponderEliminar
  3. Gracias Negro! Será un honor para mí. Te he agregado al blog roll.

    ResponderEliminar
  4. "Florian propone levantar las prioridades de los secuenciadores y sintetizadores de software por encima de la de la tarjeta de audio y jackd."

    Hola, Pablo. Si Florian propone esto se equivoca gravemente, ya que le está dando prioridad alta a partes intrascendentes del sintetizador, como el GUI o threads de disco, por encima de la parte de audio. La parte de código del sintetizador que importa la ejecuta jackd mediante un mecanismo de callback.

    ResponderEliminar
  5. Hola Luis!
    Seguro que lo he interpretado mal. A ver qué te parece:

    http://tapas.affenbande.org/wordpress/?page_id=40

    Se refiere sólo los MIDI threads
    "Midi threads of softsynths/midi sequencers"
    pero no sé cómo el usuario puede identificar estos procesos.

    Gracias por comentar!

    ResponderEliminar
  6. Hola soy Gabriel Ferreira, soy autor junto a Esteban Segreto de el sitio-blog Soundebian, ambos estudiamos Administración en Sistema GNU/Linux en la Facultad de Ingeniería de nuestra ciudad Mar del Plata, Argentina. Tu artículo me parece genial, claro y exacto, voy agregar un enlace a este en nuestra página. Buscando material para un congreso encontré tu blog, si no te molesta voy a citarte en ese trabajo. Estamos en contacto, muchas gracias por hacer música con software libre, cordiales saludos!

    ResponderEliminar
  7. Ajá. Tú hablas de levantar la prioridad de procesos, no de threads. No es lo mismo, ojo al detalle. En sistemas multithread un proceso puede generar varios threads con distintas funciones, cada uno con sus necesidades de recursos.

    Como dice Chris Cannam (el desarrollador principal de Rosegarden o Sonic Visualiser) en los comentarios a ese post, si el secuenciador o el softsynth usan alsa-seq (o jack-midi sobre alsa-seq) la recogida de eventos midi, marcaje de tiempos y su incorporación a la cola se realiza en la rutina de atención a la interrupción de la tarjeta de sonido, que normalmente ya tendrá prioridad más alta que jackd. Lo lógico es que de ahí los recojan en cada periodo de buffer las rutinas de callback de jackd de los distintos clientes para procesarlos.

    En el caso de clientes jack-midi sobre alsa-raw me imagino que es jackd quien pone los timestamps, no sé si cuantizados al periodo de buffer de audio, tendría que mirarlo. En cualquier caso la prioridad relevante es la de jackd, no la de sus clientes.

    Así que a menos que se me esté escapando algo, lo cual puede ser porque no tengo mucha experiencia trabajando tan cerca del driver alsa, los únicos threads que podría ser necesario subir de prioridad serían aquellos que se encargaran de gestionar directamente un dispositivo hardware alsa-raw.

    Sin embargo en general es complicado separar y controlar los threads individuales de una aplicación desde fuera sin conocerla muy a fondo. No es raro además que estos threads aparezcan y desaparezcan bajo demanda.

    El tema de la latencia de eventos midi en tiempo real es bastante complejo, hay muchos pasos que influyen desde que se pulsa una tecla en un controlador hasta que el sonido correspondiente llega a los altavoces.

    ResponderEliminar
  8. Gabriel,
    Gracias por citar este blog en tu trabajo y gracias por la recomendación en el tuyo :)

    Luis,gracias por las aclaraciones.
    Esto no es fácil de entender para un simple usuario pero se intenta. Concluyo que el usuario no tiene que complicarse más de lo estrictamente necesario. Configurar la variable RTIRQ_NAME_LIST adecuadamente es lo más importante y, en caso de trabajar con MIDI, descomentar la línea RTIRQ_HIGH_LIST="timer".
    Del resto se deberían encargar las propias aplicaciones y jackd.
    Saludos, Pablo

    ResponderEliminar