Gestión térmica en notebook clamshell con RAPL y tuned

Tapa cerrada, monitor portátil apoyado encima, notebook como CPU box debajo de todo: lo que se llama modo clamshell —la notebook cerrada como una almeja, usada solo como unidad de cómputo con monitor externo—. El objetivo: evitar que suba la temperatura dañando el hardware.

El problema, brevemente

Los notebooks toman aire por abajo y/o expulsan calor por arriba del teclado. Un monitor portátil apoyado en clamshell rompe ese flujo. Como no se puede recuperar la disipación sin tocar hardware, lo que queda es bajar voluntariamente el techo de potencia para que el CPU jamás llegue a temperaturas de throttling.

Mejor 12W tibios sostenidos que un loop entre 28W ardiendo y 5W throttleado.

Eso es todo. El resto del post es la pelea para implementarlo en Fedora 43 (el setup no cambió en Fedora 44).

Las tres palancas

Linux expone tres puntos donde tocar, y cada uno opera en un plano distinto del sistema:

RAPL (Running Average Power Limit). El CPU Intel se autoimpone límites de potencia: PL1 sostenido, PL2 boost. Están en /sys/class/powercap/intel-rapl/. Si los bajás, el CPU físicamente no puede consumir más. Es el techo duro, aplicado por el hardware del procesador (el PCU, Power Control Unit): no depende ni del scheduler ni del usuario.

tuned. Daemon de gestión de perfiles de energía. Desde Fedora 41 es el default del sistema (vía tuned-ppd), reemplazando a power-profiles-daemon. Maneja governor, EPP, runtime PM, sysctls, sysfs. No baja literalmente el consumo: configura los subsistemas del kernel para que ellos lo hagan. Opera en el plano de las políticas, no del hardware — por eso no se solapa con RAPL.

thermald. Reactivo: lee zonas térmicas y aplica medidas correctivas cuando se calienta. En este equipo nunca funcionó, y de eso también va el post.

RAPL, primer round

Bajar PL1 a 12W y PL2 a 20W es un echo a un archivo en /sys/:

echo 12000000 | sudo tee /sys/class/powercap/intel-rapl:0/constraint_0_power_limit_uw

Tres segundos, listo. Después de verificar que el valor quedó aplicado y que las temperaturas en stress test caían a una zona razonable, vino la primera trampa con la que choco cada tanto y siempre me tomo unos minutos para acordarme:

/sys no persiste. Lo que escribís ahí desaparece al reboot.

Solución: un service unit propio (rapl-limits.service) que reaplica los valores al boot. Heredoc, daemon-reload, enable --now. Hecho.

thermald, el daemon zombi

Acá viene la parte que me costó descubrir.

Habilito thermald, escribo un /etc/thermald/thermal-conf.xml custom, lo arranco. systemctl status lo reporta activo. ps -ef | grep thermald muestra el proceso vivo. Todo bien.

Solo que no estaba haciendo absolutamente nada.

Días después, ya con el sistema funcionando bien y con thermald deshabilitado por sospechoso, abro journalctl -u thermald para confirmar la sospecha. Encuentro esto, mezclado entre los logs:

thermald[1010]: Thermal DTS: No coretemp sysfs found
thermald[1010]: Thermal DTS or hwmon: No Zones present Need to configure manually
thermald[1010]: XML zone: invalid sensor type x86_pkg_temp
thermald[1010]: Zone update failed: unable to bind

Una sola causa raíz, dos síntomas en el log:

  1. No había un sensor térmico del CPU que descubrir. El módulo que expone la temperatura de paquete no estaba cargado (No coretemp sysfs found), así que thermald arrancó sin ninguna zona del CPU a la vista. Lo venía diciendo desde el primer boot del histórico, mucho antes de que yo empezara a tocar nada.
  2. El invalid sensor type x86_pkg_temp no significa lo que parece. x86_pkg_temp es el nombre correcto del sensor de paquete; thermald no lo rechaza por schema. Resuelve el tipo en runtime contra los sensores que efectivamente descubrió, y como no había ninguno, la búsqueda volvió vacía y el bind falló. El mensaje dice "invalid type" pero quiere decir "no encontré un sensor de ese tipo en este sistema".

Resultado: el daemon arrancaba, intentaba bindear las zonas definidas en el XML, no encontraba el sensor, y se quedaba corriendo sin nada que monitorear. Vivo, ocupando memoria, sin función.

systemctl status te dice si systemd cree que el servicio está bien. No te dice si el servicio está haciendo lo que tiene que hacer. Para eso está journalctl.

Validación empírica

Antes de tomar la decisión final de desactivar thermald, corrí un baseline de 6 minutos midiendo Package temp y frecuencia, después un stress test de 6 minutos exactos midiendo lo mismo, y los comparé. Lo que vi fue lo que esperaba: con RAPL fijo en 12W y tuned manejando el resto en su profile balanced, las temperaturas se mantenían en una zona estable y la frecuencia se sostenía sin las caídas abruptas del clamshell sin tunear.

La pregunta que la medición respondía no era "¿thermald aporta?" — eso ya estaba contestado de antemano por los logs. Era la otra: "¿con solo RAPL+tuned alcanza para clamshell?". La respuesta fue sí, y eso permitió cerrar el setup con tranquilidad.

Estado final

tuned                 → active (profile balanced)
RAPL PL1=12W PL2=20W  → fijo vía rapl-limits.service
thermald              → disabled (no podía operar en este hardware)

Filosofía: un techo duro de potencia (RAPL), un orquestador de estado (tuned), nada reactivo encima. Tres piezas, ninguna pelea con la otra, todas debuggeables.

Una nota sobre cómo empecé

Originalmente armé el setup con tlp + RAPL, siguiendo una sugerencia de Claude (vía claude.ai) que asumía power-profiles-daemon como el daemon por defecto en Fedora. No contrasté la premisa. Cuando fui a verificarla, descubrí que desde Fedora 41 el default pasó a tuned (vía tuned-ppd), no PPD. Y para este escenario — clamshell estático, siempre AC, sin diferenciar AC/BAT, sin que tlp-rdw aporte nada — tlp no resolvía nada que tuned no resuelva. Migré. El post documenta el setup resultante, no el camino original.

La lección no es "no preguntarle a una IA". Es verificar la premisa que la IA está usando, no solo la recomendación que te entrega. Un asistente puede recomendar una herramienta correctamente condicional a un default que ya no es el actual; sin contrastar esa premisa, terminás con un setup más complicado del necesario.

Lo que me llevo

  • Un daemon puede estar "running" y no estar haciendo nada. La verdad está en los logs de aplicación, no en systemctl status.
  • Un unit file propio de pocas líneas a veces es la decisión correcta y que no requiere demasiado esfuerzo.
  • El consejo técnico de una IA puede ser internamente coherente y aún así basarse en premisas obsoletas (defaults, versiones, comandos). El costo de chequear la premisa antes de implementar es bajo; el costo de no hacerlo se paga cada vez que volvés a tocar el equipo.

Comentarios

Comments powered by Disqus