Configurando la Compatibilidad CPU IRQ: Mejorando el Rendimiento de IRQ en el ODROID-XU4

Recientemente me he topado con una publicación en la subreddit ODROID que muestra un artículo que ofrece consejo para ajustar el ODROID-XU4. El artículo fue escrito originalmente en alemán y luego fue traducido al inglés y publicado en ODROID Magazine. Puesto tengo un ODROID-XU4 desde hace mucho tiempo, la mayoría de los consejos ya los conocía, ya que están publicados en los foros de ODROID desde hace bastante tiempo. Sin embargo, aparece un consejo que desconocía, me llamado bastante la atención y no en el buen sentido.

IRQs

Las IRQs (peticiones de interrupción) permiten que el hardware acceda a la CPU incluso cuando está ocupado haciendo otra cosa. De modo que, nuestros teclados, ratones y redes, por ejemplo, no dejan de funcionar si tenemos nuestra CPU funcionando al máximo.

Cualquiera que lleve usando ordenadores bastante tiempo, le será familiar el fenómeno en el que el ratón y el teclado se bloquean momentáneamente, se retrasan o dejan de responder por algún tiempo cuando la CPU lleva a cabo una tarea muy intensa. Esto era bastante común en los primeros ordenadores y se ha vuelto prácticamente inexistente a medida que han ido apareciendo CPUs más potentes, han evolucionado los sistemas operativos y se ha introducido la arquitectura APIC.

Para lograr el mejor rendimiento en términos absolutos de los periféricos de hardware en un sistema de múltiples núcleos, debemos asegurarnos de que estamos dirigiendo las IRQ al núcleo más inactivo, aumentando las posibilidades de que se ejecuten en el acto. En los sistemas de chips Arm big.LITTLE (como el ODROID-XU4) es más probable que obtengamos una mejor capacidad de respuesta para IRQ con los núcleos "grandes", lo cual tiene bastante sentido.

IRQs en Linux

Para obtener una lista de IRQs y sus compatibilidades de CPU, simplemente debemos mirar dentro de /proc/interrupts. Así es como se aparece en mi ODROID-XU4 con Arch Linux ARM con kernel v4.14.157: Nota: El resultado es bastante largo, así que sólo mostraré la cabeza.

$ cat /proc/interrupts | head
CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7
49: 0 0 0 0 0 0 0 0 COMBINER 187 Edge mct_comp_irq
50: 8344372 0 0 0 0 0 0 0 GICv2 152 Edge mct_tick0
51: 0 5765406 0 0 0 0 0 0 GICv2 153 Edge mct_tick1
52: 0 0 4389485 0 0 0 0 0 GICv2 154 Edge mct_tick2
53: 0 0 0 3384898 0 0 0 0 GICv2 155 Edge mct_tick3
54: 0 0 0 0 55211190 0 0 0 GICv2 160 Edge mct_tick4
55: 0 0 0 0 0 48058391 0 0 GICv2 161 Edge mct_tick5
56: 0 0 0 0 0 0 33449904 0 GICv2 162 Edge mct_tick6
57: 0 0 0 0 0 0 0 20020736 GICv2 163 Edge mct_tick7
En el anterior resultado tenemos IRQs # 49-57 que parecen ser las marcas del reloj del sistema. Uno por cada uno de los 8 núcleos. Básicamente, cada IRQ tiene su propia ID y está vinculado a una única CPU.

La última declaración puede ser un tanto difícil de entender, así que echemos un vistazo a cómo se ven las interrupciones del lector de tarjetas SD y MMC:

Nota: Me doy cuenta que dw-mci son interrupciones para los dispositivos de E/S simplemente mirando el código fuente (https://github.com/hardkernel/linux/blob/odroidxu4-4.14.y/drivers/mmc/host/dw_mmc-exynos.c).

$ cat /proc/interrupts | grep dw-mci
83: 0 0 0 0 0 0 0 0 GICv2 107 Edge dw-mci
84: 103693202 0 0 0 0 0 0 0 GICv2 109 Edge dw-mci
IRQ #83 es para eMMC, que no tengo, y IRQ #84 es para la tarjeta MicroSD que obviamente está instalada.

Por defecto, todos las IRQs que no son de reloj de CPU están vinculados a todos los núcleos, aunque en realidad la CPU0 es la que se usará la mayor parte del tiempo, ya que simplemente es la primera. En mi versión de kernel del ODROID-XU4, la CPU0 es uno de los núcleos "pequeños". La forma más fácil de confirmar esto es observando la frecuencia máxima de CPU de cada núcleo, puesto que los "pequeños" se ejecutan a una velocidad menor:

$ cat /sys/devices/system/cpu/cpu*/cpufreq/cpuinfo_max_freq
1500000
1500000
1500000
1500000
2000000
2000000
2000000
2000000
Las primeras 4 CPU (=núcleos) funcionan a 1.5GHz y los últimos a 2GHz, que coincide con las velocidades de CPU Samsung Exynos5422 del ODROID-XU4, mis núcleos "grandes" funcionan a unos 100MHz más lentos.

Cambiar la compatibilidad CPU IRQ

Es bastante fácil cambiar la compatibilidad CPU de los IRQ. Todos los IRQ están enumerados en /proc/irq/ y la compatibilidad de cada uno se escribe correctamente dentro de smp_affinity y smp_affinity_list con el primero que contiene un valor hexadecimal y el último un valor decimal.

De modo que, para cambiar la compatibilidad de la CPU IRQ de nuestra tarjeta MicroSD, todo lo que tenemos que hacer es cambiar el valor de /proc/irq/84/smp_affinity_list a cualquier número de CPU que deseemos, por ejemplo, 5. Por supuesto, no podemos hacerlo como un usuario normal, así que tendremos que usar sudo. La forma más fácil de hacerlo es la siguiente:

$ sudo sh -c "echo 5 > /proc/irq/84/smp_affinity_list"
Y podemos confirmar que funciona:
$ cat /proc/irq/84/smp_affinity_list
5
$ cat /proc/interrupts | grep dw-mci
83: 0 0 0 0 0 0 0 0 GICv2 107 Edge dw-mci
84: 103699631 0 0 0 152288 0 0 0 GICv2 109 Edge dw-mci
Nota: Este valor no se mantendrá después de reiniciar, pero esta es la idea en general.

Los "ajustes"

Volviendo a donde empezamos, el artículo sugiere hacer exactamente lo que he dicho antes, entonces, ¿por qué no estoy satisfecho con ello? Por el uso del artículo de irqbalance. Dejando de lado la mala elección de usar /etc/rc.local para aplicar este ajuste, el primer paso fue el que más me llamó la atención:

$ systemctl disable irqbalance
¿Existe un programa dedicado cuyo objetivo es equilibrar la IRQ y lo vamos a desactivar? Suena extremadamente sospechoso.

Lo que pensé al instante fue que quizás irqbalance no permitía limitar sus asignaciones especificas a la CPU y, por lo tanto, desactivarlo tendría sentido. Sin embargo, no era el caso. Mirando la página del manual de irqbalance, Existe una variable de entorno:

IRQBALANCE_BANNED_CPUS

que puede indicarle al programa que evite asignar IRQ a esas CPU; que es exactamente lo que queremos.

El valor de esta variable de entorno es una máscara hexadecimal. Simplemente necesitamos decir qué CPU queremos activar y cuáles no. Cada CPU está encendida o apagada (= 1 o 0) y en nuestro caso queremos apagar las primeras cuatro y dejar las últimas encendidas. Eso significa que nuestra máscara en binario sería

00001111
El valor debe ser hexadecimal, que es una conversión bastante fácil de binario en este caso: OF.

Todo lo que tenemos que hacer ahora es ajustar nuestra variable de entorno en 0F (o simplemente F, ya que el 0 inicial no tiene significado). Probemos esto para asegurarnos de que las matemáticas son las correctas:

$ sudo su
$ export IRQBALANCE_BANNED_CPUS="f"
$ irqbalance -d
This machine seems not NUMA capable.
Isolated CPUs: 00000000
Adaptive-ticks CPUs: 00000000
Banned CPUs: 0000000f
...
Package 0: numa_node -1 cpu mask is 000000f0 (load 520000000)
Cache domain 0: numa_node is -1 cpu mask is 00000080 (load 90000000)
CPU number 7 numa_node is -1 (load 90000000)
Cache domain 1: numa_node is -1 cpu mask is 00000020 (load 100000000)
CPU number 5 numa_node is -1 (load 100000000)
Cache domain 2: numa_node is -1 cpu mask is 00000040 (load 130000000)
CPU number 6 numa_node is -1 (load 130000000)
Cache domain 3: numa_node is -1 cpu mask is 00000010 (load 200000000)
CPU number 4 numa_node is -1 (load 200000000)

  • Primero cambiamos el usuario a root para que sea más fácil para nosotros.
  • Luego, exporta la variable de entorno para irqbalance.
  • Ejecutar irqbalance en modo depuración -d.
  • Resultado: La primera parte muestra en CPU prohibidas que aceptaron nuestro valor. Luego, si observamos con detenimiento el resto de los resultados, podemos detectar la asignación a las CPU # 4-7 (5 a 8), que es exactamente lo que queríamos.

Para configurar esta variable de entorno para que la unidad systemd pueda acceder a ella, debemos analizada:

$ systemctl show irqbalance
Buscamos el valor de EnvironmentFile que podría ser cualquier cosa dependiendo del sistema operativo. En Ubuntu 18.04, es /etc/default/irqbalance y en mi sistema Arch es /etc/irqbalance.env. Probablemente ya exista una plantilla en esta ubicación, y todo lo que tenemos que hacer es asegurarnos de que no esté comentado y configurado el valor correcto.

Usar una ID de IRQ fija

El "tip" indica poner cada línea que corresponde a una ID de IRQ de un controlador de hardware diferente. Sin embargo, las ID de IRQ no son consistentes y dependen de la versión del kernel. Por ejemplo, en mi sistema, las ID de IRQ # 103-105 se asignan a algunos pines gpio:

$ cat /proc/interrupts | awk '$1 ~ /103|104|105/'
103: 0 0 0 0 0 0 0 0 GICv2 110 Edge 13410000.pinctrl
104: 0 0 0 0 0 0 0 0 GICv2 78 Edge 14000000.pinctrl
105: 0 0 0 0 0 0 0 0 GICv2 82 Edge 14010000.pinctrl

Vincular cada interrupción a una única CPU

Por último, pero no menos importante, el artículo sugiere vincular cada interrupción a una CPU diferente. La tarjeta de red obtiene CPU4, el adaptador USB3 obtiene CPU5, etc. ¿Por qué molestarse en limitar las CPU puesto que nuestro núcleo puede elegir? ¿Qué sucede si un programa bloquea esa CPU específica durante un largo período de tiempo? El kernel no podría asignar la IRQ a una CPU diferente para evitar ralentizaciones.

Afterword

Aunque me gustan estas compilaciones de ajustes tanto como a ti, siempre tiendo a asegurarme de entender completamente lo que está haciendo cada ajuste y verificar dos veces para ver cómo se aplican a mi sistema y en mi caso en particular. Además, si existe una herramienta dedicada para un determinado propósito (como irqbalance para este asunto), primero deberíamos considerar usarla, de lo contrario, su existencia no estaría justificada.

El propósito de este artículo no es de ninguna manera ofender o condenar a u/blaumedia que escribió el artículo original, está destinado a crear conciencia sobre por qué los usuarios deben considerar su situación y comprender lo que están haciendo. Para más información, consulta el artículo original en https://my-take-on.tech/2020/01/12/setting-irq-cpu-affinities-to-improve-performance-on-the-odroid-xu4/.

Be the first to comment

Leave a Reply