En mi equipo tengo un problema: se calienta mucho. Ya hago todo lo normal: limpieza, cambio de pasta térmica (una de calidad), alterar la velocidad del ventilador… Pero nada: cuando hago algo que requiere potencia, se pone a 90~98ºC. Está diseñado así: este procesador tiene una temperatura de trabajo “normal” de 95ºC y una de temperatura crítica de 105ºC, el “throttling” lo estableció el fabricante en la BIOS y no se puede modificar. Pero no me gusta: puede dañar otros componentes.
Así que… me puse manos a la obra, como cualquier otro linuxero de pro.
¡OJO! ¡PRECAUCIÓN ¡CUIDADÍN!
Es un trabajo en curso, no está terminado, no lo he probado más que en mi equipo y no me hago responsable de los daños que pudiera ocasionar. Recomiendo ejecutarlo en equipos de pruebas, siempre bajo supervisión.
Nota: Que yo sepa, no se puede usar en máquinas virtuales: no tienen sensores.
He escrito un script que mide cada segundo la temperatura de todos los núcleos y toma la más alta de ellas. Si pasa de un valor, baja la frecuencia máxima del núcleo una cantidad de Mhz proporcional entre la temperatura actual y la deseada (para reaccionar rápido ante picos de calor). Si queda por debajo de otro valor, sube un poco la frecuencia. En cada cambo de frecuencia espera 5 segundos para que el disipador reaccione y vuelve a repetir el ciclo. Así, la temperatura se acaba estabilizando al valor deseado en cuestión de segundos (10, 30… depende de la cantidad de “saltos” que deba hacer), y se va adaptando a las necesidades del momento.
Leer las temperaturas es fácil, pero establecer el valor de frecuencia sólo se puede hacer como superusuario. Por este motivo, he dividido el script en dos: uno tiene permisos de usuario normal, y cuando hay que hacer un cambio llama al segundo script con sudo. Para evitar que pida contraseña cada vez (sobre todo, porque está pensado para usarse en una shell no interactiva), es necesario añadir permisos de sudo sin contraseña para el segundo script.
Al ejecutar el script, lo primero que hace es comprobar si el “governor” (el “perfil” de consumo energético del procesador) está establecido como “userspace”, porque es el único que permite cambiar frecuencias. Esto también se hace con el segundo script, con sudo.
El script puede generar un log con los cambios de frecuencia y temperatura en un archivo y/o mostrar notificaciones en el escritorio.
Además, se puede dejar funcionando indefinidamente (ideal para tenerlo como autoejecutable) o establecer un período de tiempo (para tests de estrés y rendimiento), además de establecer un retraso en la ejecución.
Se pueden establecer las variables dentro del script o pasárselas como argumentos. Incluye un argumento -h para recibir ayuda básica. Ah, aparte lo he dejado repletito de comentarios, aunque no sé si serán de mucha ayuda.
El segundo script, el que requiere permisos, debe copiarse en /usr/bin/setfreq.sh, con propietario root:root y permisos 755. En /etc/sudoers debe haber una línea como [youruser ALL=(ALL) NOPASSWD: /usr/bin/setfreq.sh]
Tengo pendiente crear un pequeño instalador que automatice esto, pero de momento hay que hacerlo a mano. Las instrucciones detalladas están en los comentarios del primer script. Sólo debe hacerse una vez, para instalarlo.
He aquí el fruto de mis esfuerzos:
temperaturas.sh (versión 5)
#!/bin/bash
# -*- ENCODING: UTF-8 -*-
## Copy setfreq.sh to /usr/bin
## Change proietary to root
# sudo chown root:root /usr/bin/setfreq.sh
## Set permissions:
# sudo chmod 755 /usr/bin/setfreq.sh
## Add your user to souders:
# sudo visudo
# youruser ALL=(ALL) NOPASSWD: /usr/bin/setfreq.sh
delay=0
seconds=0
t_limit=85
t_normal=75
logfile=/dev/null
notif=no
t_cur=0
t_max_total=0
# Variables assigned by parameters:
if [[ $1 ]]; then
if [ $1 == "-h" ] || [ $1 == "--help" ]; then
echo -e "This script monitorize the temperature of the CPU, decreases the maximum frequency when temp is too high, and increase than when temp is low enough, and can create a log with its actions, temperatures, frequencies and date and time."
echo -e "List of valid parameters:"
echo -e "-d <seconds> \t Delay before executing the sript."
echo -e "-t <seconds> \t Time in seconds for check free memory. If 0, the script never stops."
echo -e "-l <Cº> \t Maximum dessired temperature."
echo -e "-r <Cº> \t Minimum temperature to restore maximum performance."
echo -e "-f <file> \t File used as log."
echo -e "-n yes \t Enable or disable desktop notifiacions."
echo -e "Example: Limit frequency when the temperature is 85ºC, restore it when temperature is below 75ºC and show desktop notifications:\n\t ./tepmerature.sh -l 85 -r 75 -n y"
echo -e "Example: Limit frequency when the temperature is 70ºC, restore it when temperature is below 50ºC, wait 30 seconds, run the script for 5 minutes (300 seconds) and log the changes in <HOME>/temper.txt:\n\t ./tepmerature.sh -l 70 -r 50 -d 30 -t 300 -f '~/temper.txt'"
exit
fi
while getopts d:t:l:r:f:n: flag
do
case "${flag}" in
d) delay=${OPTARG};;
t) seconds=${OPTARG};;
l) t_limit=${OPTARG};;
r) t_normal=${OPTARG};;
f) logfile=${OPTARG};;
n) notif=${OPTARG};;
*) echo -e "Valid arguments: -d <seconds> -t <seconds> -l <Cº> -n <Cº> -f <file> \nUse -h for help."
exit;;
esac
done
fi
if [ $seconds == 0 ]; then
infinite=1
seconds=1000
else
infinite=0
fi
echo -e "\n"$(date)"\n___________________ Nueva sesión ___________________" >> $logfile
sleep $delay
# Setting the governor to "userspace":
sudo /usr/bin/setfreq.sh userspace
# Obtain current, max and min frequency:
f_min0=`cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq 2>/dev/null`
f_max0=`cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq 2>/dev/null`
f_cur0=`cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq 2>/dev/null`
f_newlimit=$f_max0
[ $notif == "yes" ] && zenity --notification --text="-Frecuencia máxima: $f_newlimit" 2>/dev/null
# Setting the current temperature to maximum:
sudo /usr/bin/setfreq.sh $f_newlimit
# Principal loop
until [ $seconds -lt 1 ]; do
# Read the highest temperature from all sensors:
t_cur=$(sensors | grep °C | awk -F '+' '{print $2}' | awk -F '°C' '{print $1}' | awk -F '.' '{print $1}' | sort -nr | head -n1)
# Decrease frequency when temperature is too high
if [ $t_cur -gt $t_limit ] && [ $f_newlimit -gt $f_min0 ]; then
# Decease frequency in proportion to excesive temperature
diff=$((t_cur - t_limit))
step=$((diff * 50000))
step=$(( step > 400000 ? 400000 : step ))
f_newlimit=$((f_newlimit - step))
if [ $f_newlimit -lt $f_min0 ]; then
f_newlimit=$f_min0
fi
sudo /usr/bin/setfreq.sh $f_newlimit
f_cur0=`cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq 2>/dev/null`
echo -e "\n"$(date)"\n-> Bajando frecuencia máxima: "$f_newlimit"\nFrecuencia acual: "$f_cur0"\n Temperatura actual: "$t_cur >> $logfile
[ $notif == "yes" ] && zenity --notification --text="-> Bajando frecuencia máxima: $f_newlimit" 2>/dev/null
sleep 4
((seconds-=4))
# Icrease frequency when temperature is acceptable
elif [ $t_cur -lt $t_normal ] && [ $f_newlimit -lt $f_max0 ]; then
f_newlimit=$((f_newlimit + 200000))
if [ $f_newlimit -gt $f_max0 ]; then
f_newlimit=$f_max0
fi
sudo /usr/bin/setfreq.sh $f_newlimit
echo -e "\n"$(date)"\n-> Subiendo frecuencia máxima: "$f_newlimit"\nFrecuencia acual: "$f_cur0"\n Temperatura actual: "$t_cur >> $logfile
[ $notif == "yes" ] && zenity --notification --text="-> Subiendo frecuencia máxima: $f_newlimit" 2>/dev/null
f_cur0=`cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq 2>/dev/null`
sleep 4
((seconds-=4))
fi
if [ $t_cur -gt $t_max_total ]; then
t_max_total=$t_cur
echo -e "\nTemperatura máxima del intervalo: "$t_max_total >> $logfile
fi
sleep 1
((seconds--))
if [[ $infinite -eq 1 ]]; then
seconds=1000
fi
done
/usr/bin/setfreq.sh (versión 5)
#!/bin/bash
# -*- ENCODING: UTF-8 -*-
# This script MUST be launched by root
# Setting the governor to "userspace":
if [ $1 == "userspace" ]; then
echo userspace | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor &> /dev/null
test -n "`cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor | grep -v "userspace"`" && echo "Failed swithing to the userspace governor! Might not be supported or compiled in."
exit
fi
# Changing the max speed:
echo "$1" | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_setspeed > /dev/null
exit
Por supuesto, este código es completamente libre: cualquiera puede usarlo, copiarlo, modificarlo, distribuirlo o sacarlo a pasear al parque en un día de lluvia. Renuncio a todos los derechos.
Agradecería cualquier corrección o sugerencia.