lunes, 26 de julio de 2021

Limitar la CPU de un proceso

Recientemente he empezado a grabar algunos vídeos de demo para el trabajo y me he visto en la necesidad de mostrar por pantalla las pulsaciones del teclado.

Para este propósito he encontrado la herramienta de Screenkey, la cual está muy bien (las cosas como son).

Sin embargo esta herramienta tiene una pega que me molesta mucho, y es que cuando pulsas una tecla, la CPU se dispara al 100% mientras esta permanezca pulsada.
Para mí esto no es aceptable ya que no tiene sentido tal derroche de CPU.

Por suerte es posible solucionarlo limitando la CPU asignada al proceso encargado de correr el programa.
Y es eso lo que explicaré aquí.

Para ello haremos uso de systemd y de los Control Groups v2.
No entraré en detalles de que es cada una de estas cosas porque hay suficiente literatura sobre ello.
Solo decir que systemd es el sistema encargado de arrancar todo el Linux y cgroup es una tecnología perteneciente al kernel de Linux encargada de limitar los recursos.

Es cgroup importante que sea en su versión v2 ya que así podremos correr el screenkey sin privilegios de administrador.

Para poder controlar los límites de la CPU, hay que seguir los pasos aquí mencionados.
Concretamente nos interesa los siguientes.

Determinar si tenemos cgroupv2.

cat /sys/fs/cgroup/user.slice/user-$(id -u).slice/user@$(id -u).service/cgroup.controllers

Si la salida no es un error y es esta memory pids, significa que tenemos cgroupv2 pero no podemos controlar los límites de la CPU.

Para activarlos hace falta hacer:

sudo mkdir -p /etc/systemd/system/user@.service.d
cat <<EOF | sudo tee /etc/systemd/system/user@.service.d/delegate.conf
[Service]
Delegate=cpu cpuset io memory pids
EOF
sudo systemctl daemon-reload

Esto editará el servicio de user@.service añadiendo la línea del Delegate=.
Este servicio es el que luego el sistema usará como plantilla para cargar la configuración de nuestro usuario user@1000.service en el caso de que nuestro usuario tenga el id 1000.

Ahora es necesario reiniciar el sistema.

Una vez iniciado, volvemos a comprobar los controllers:

cat /sys/fs/cgroup/user.slice/user-$(id -u).slice/user@$(id -u).service/cgroup.controllers

Esta vez la salida será algo como: cpuset cpu io memory pids.

Una vez realizado esto, podemos lanzar el screenkey con un límite de CPU del 10%.

systemd-run --user --property="CPUQuota=10%" screenkey

Y para pararlo, simplemente hay que cerrarlo de la barra del sistema.


Añado un alias útil para el .bash_aliases:

alias screenkey='systemd-run --user --property="CPUQuota=5%" --unit=run-screenkey --pty --same-dir --wait --collect --quiet screenkey'

¡Un saludo!