Scripts para regular la frecuencia del procesador en función de la temperatura

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. :stuck_out_tongue_winking_eye:

¡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. :neutral_face:

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.

5 Me gusta

Levo una noche de insomnio y ya hay novedades: ahora se pueden establecer las variables en modo gráfico, con cuadros de diálogo. La prioridad la tienen los argumentos pasados por consola; si se ha pasado alguno, el modo gráfico no preguntará por él. En los diálogos, el valor por defecto será el que esté establecido en las variables del script.
La congifuración por cuadros de diálogo se puede desactivar desde la variable $gui en el script.
Además, si no se detecta la variable $XDG_CURRENT_DESKTOP, se asume que está sin modo gráfico o no interactivo, por lo que ni muestra notificaciones ni utiliza diálogos.

La idea es adaptarse lo mejor posible a estas situaciones:

  • Usuario ejecuta el script directamente, sin parámetros y sin tocar las variables: El script le pregunta si quiere establezerlas de forma gráfica. Si quiere, se pregunta todo, tomando por defecto los valores escritos en el script. Si no quiere, toma dichos valores como válidos.
  • Usuario ejecuta el script desde una consola no interactiva (P.E.: Una distro sin escritorio, sólo terminal): No hay notificaciones ni cuadros de diálogo. Puede usar parámetros; de lo contrario, se toman los valores por defecto.
  • Se configura el script para autoarranque: o bien se establecen todos los valores por parámetros o se edita el script con la variable $gui = false. En este último caso, el script dará prioridad a los parámetros y tomará el resto de valores por defecto. Si no se cambia el valor de $gui, el script preguntará mediante diálogos todo lo que no se haya especificado por parámetros.
    He intentado que sea lo más polivalente posible, y lo más cómodo dependiendo de la situación. No se me ocurren más casos de uso.

En fin, aquí os presento:

temperaturas.sh (versión 7)

temperaturas.sh
#!/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

# Default variables. You can change it to run the script easily.
delay=0
seconds=0
t_limit=85
t_normal=75
logfile="/dev/null" # <- File used as log. Caution: the size is incremental.
################################# To do: Limit the size of the logfile.
notif="yes"
gui=true

# Internal variables. Please, do not change.
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 | no> \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 yes"
		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

# Reading arguments. Add "####" for priority over GUI diaglogs; it will be removed after that.
	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> -n <yes | no>\nUse -h for help."
			exit;;
		esac
	done
fi

# Active or disable notifications.
# Maximum priority are:
# 1º Must exist a desktop.
# 2º Argument from console ( -n <yes | no> ).
# 3º Default variable at the beggining of the script ( notif= ).
# 4º If not disabled yet, show a dialog to acivate or not.

if [ -v $XDG_CURRENT_DESKTOP ]; then
 	# There are no desktop.
	notif="no"
	gui=false
elif [ gui == true ]; then
	# There are desktop, no arguments passed, and default gui variable is true
	zenity --question --text "¿Configuración gráfica?" --no-wrap --ok-label "Vale" --cancel-label "No" 2>/dev/null
	if [ $? = 0 ]; then
		gui=true
	else
		gui=false
	fi
fi

# GUI: Setting variables not stablished by parameters:
if [ $gui == true ]; then
	if [[ $delay != *"####"* ]]; then
		delay=$(zenity --entry --title "Delay (s): " --text "Time waiting for start the srcipt: " --entry-text="$delay") 2>/dev/null
	fi

	if [[ $seconds != *"####"* ]]; then
		seconds=$(zenity --entry --title "Time (s): " --text "Time running the srcipt: " --entry-text="$seconds") 2>/dev/null
	fi

	if [[ $t_limit != *"####"* ]]; then
		t_limit=$(zenity --entry --title "Max temperature (ºC): " --text "Temperature to start reducing frequency: " --entry-text="$t_limit") 2>/dev/null
	fi

	if [[ $t_normal != *"####"* ]]; then
		t_normal=$(zenity --entry --title "Normal temperature (ºC): " --text "Temperature to start increasing frequency: " --entry-text="$t_normal") 2>/dev/null
	fi
	
	if [[ $notif != *"####"* ]]; then
		zenity --question  --title "Notifiactions" --text "Do tou want desktop notifications?" --no-wrap --ok-label "Yes" --cancel-label "No" 2>/dev/null
		if [ $? = 0 ]; then
			notif="yes"
		else
			notif="no"
		fi
	fi

	if [[ $logfile != *"####"* ]]; then
		wlf=$(zenity --question  --title "Log file" --text "Select a file or create a new one?" --switch --extra-button "Select" --extra-button "Create" --extra-button "None") 2>/dev/null
		if [ $wlf = "Select" ]; then
			logfile_gui=$(zenity --file-selection --text "Location of new file: " --filename "${HOME}/") 2>/dev/null
			if [ $? == 0 ]; then
				logfile=$logfile_gui
			fi
		elif [ $wlf = "Create" ]; then
			logfile_gui=$(zenity --entry --title "Log file" --text "Write the route: " --entry-text="${HOME}/temp_log.txt") 2>/dev/null
			if [ $? == 0 ]; then
				logfile=$logfile_gui
			fi
		else
			logfile=/dev/null
		fi
	fi

fi


# Cleaning variables:
		notif=${notif%"####"}
		delay=${delay%"####"}
		seconds=${seconds%"####"}
		t_limit=${t_limit%"####"}
		t_normal=${t_normal%"####"}
		logfile=${logfile%"####"}
# If used character ~ to use the /home/user folder, change it to ${HOME} to use in redirections:
logfile=${logfile//\~/"${HOME}"}

# For unlimited execution:
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

FALTA:

  • Simplificar la instalación inicial del script de superusuario. Tengo varias ideas, pero ninguna me convence…
  • Agregar idiomas, como en el otro.
  • Controlar el tamaño máximo del archivo de log. No sería el primer sistema que falla porque tiene un log de chopocientos GB. :sweat_smile:
  • Probarlo en distintas distros y equipos con procesadores diferentes (AMD, ARM, mononúcleo…).
  • Ehm… No sé. ¿Que baile flamenco? Este script empezó algo sencillo, para medir temperaturas mientras juego, y está evolucionando a bloatware del chulo. :rofl:
2 Me gusta

Nueva versión 8

  • Con o sin GUI. Activado por defecto, se puede desactivar mediante una variable en el script, mediante el parámetro -g o pulsando “No” en el primer diálogo. Se desactiva automáticamente si no detecta ningún escritorio, leyendo la variable $XDG_CURRENT_DESKTOP.
  • Autoinstalación. Si no detecta el script secundario, inicia el script en modo de instalación. Pide permisos mediante pkexec si el GUI está activado o mediante sudo por terminal si no lo está. Crea el script secundario en /usr/bin/setfreq.sh, le asigna propietario root:root y permisos 755, y añade a /etc/sudoers una línea para que deba ejecutarse con sudo pero no pida contraseña. Ya no hace falta usar dos scripts: el script secundario está contenido en el principal, como una cadena de texto.
  • El tamaño del archivo de log se ha limitado a 250 líneas. Se comprueba al final de cada bucle. Cuando se rebasa ese límite, se eliminan las líneas más antiguas.
  • Pequeñas correcciones y optimizaciones.

Falta:

  • Añadir idiomas.
  • El tamaño del log debería ser configurable. En fin, eso es secundario, ya lo haré.
  • Mejorar el formato del log. Ahora mismo no es todo lo legible que me gustaría.

He aquí el monstruo:

temperatura.sh
#!/bin/bash
# -*- ENCODING: UTF-8 -*-

# Default variables. You can change it to run the script easily.
delay=0
seconds=0
t_limit=85
t_normal=75
logfile="/dev/null" # <- File used as log.
notif="yes"
gui=true

# Special argument: if /usr/bin/setfreq.sh is not present, it creates them and stablishes permissions:
if [ "$1" == "install" ]; then
	echo -e '#!/bin/bash\n# -*- ENCODING: UTF-8 -*-\n\n# This script MUST be launched by root\n\n# Setting the governor to "userspace":\nif [ "$1" == "userspace" ]; then\n	echo userspace | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor &> /dev/null\n	test -n "`grep -v "userspace" /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor`" && echo "Failed swithing to the userspace governor! Might not be supported or compiled in." && exit 1\n	exit 0\nfi\n\n# Changing the max speed:\necho "$1" | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_setspeed > /dev/null\nexit 0' > /usr/bin/setfreq.sh
	chown root:root /usr/bin/setfreq.sh
	chmod 755 /usr/bin/setfreq.sh
	# This test if sudoers is configured, and configure it if not:
	if [ $(grep -c 'ALL ALL=(ALL) NOPASSWD: /usr/bin/setfreq.sh' /etc/sudoers) -eq 0 ]; then
		echo -e '\n# Users cat execude this with sudo without password:\nALL ALL=(ALL) NOPASSWD: /usr/bin/setfreq.sh' >> /etc/sudoers
	fi
	exit
fi

# Internal variables. Please, do not change.
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 | no> \t Enable or disable desktop notifiacions."
		echo -e "-g \t Disable GUI dialogs."
		echo -e "\nExample: Limit frequency when the temperature is 85ºC, restore it when temperature is below 75ºC and show desktop notifications:\n\n ./temperature.sh -l 85 -r 75 -n yes"
		echo -e "\nExample: 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), disable GUI dialogs and log the changes in <HOME>/temper.txt:\n\n ./tepmerature.sh -l 70 -r 50 -d 30 -t 300 -g -f ~/temper.txt"
		exit
	fi

# Reading arguments. Add "####" for priority over GUI diaglogs; it will be removed after that.
	while getopts d:t:l:r:f:n:g 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}"####";;
		    g) gui=false;;
			*) echo -e "Valid arguments: -d <seconds> -t <seconds> -l <Cº> -n <Cº> -f <file> -n <yes | no>\nUse -h for help."
			exit;;
		esac
	done
fi

# Active or disable notifications.
# Maximum priority are:
# 1º Must exist a desktop.
# 2º Argument from console ( -g ).
# 3º Default variable at the beggining of the script ( notif= ).
# 4º If not disabled yet, show a dialog to acivate or not.

if [ -z "$XDG_CURRENT_DESKTOP" ]; then
 	# There are no desktop.
	notif="no"
	gui=false
elif [ $gui == true ]; then
	# There are desktop and default gui variable is true
	zenity --question --text "¿Configuración gráfica?" --no-wrap --ok-label "Vale" --cancel-label "No" 2>/dev/null
	if [ $? == 0 ]; then
		gui=true
	else
		gui=false
	fi
fi

# AUTOINSTALL
# Test if the superuser part of this script is installed. If not, it launches the script on installation mode.
if ! [ -f /usr/bin/setfreq.sh ]; then
	if [ -z "$XDG_CURRENT_DESKTOP" ] || [ $gui == false ]; then
 		# There are no desktop, or GUI disabled.
		read -r -p "Script /usr/bin/setfreq not found. ¿Install? (y/n)" a
		if [ "$a" == "y" ]; then
			sudo ./temperatura.sh install
		else
			echo "Exiting..."
			exit
		fi
	else
		# GUI enabled.
		zenity --question --text "/usr/bin/setfreq not found. ¿Install?\nIt needs root access." --no-wrap --ok-label "Install" --cancel-label "Cancel" 2>/dev/null
		if [ $? == 0 ]; then
			pkexec ./temperatura.sh install
		else
			exit
		fi
	fi
fi

# GUI: Setting variables not stablished by parameters:
if [ $gui == true ]; then
	if [[ $delay != *"####"* ]]; then
		delay=$(zenity --entry --title "Delay (s): " --text "Time waiting for start the srcipt: " --entry-text="$delay") 2>/dev/null
	fi

	if [[ $seconds != *"####"* ]]; then
		seconds=$(zenity --entry --title "Time (s): " --text "Time running the srcipt: " --entry-text="$seconds") 2>/dev/null
	fi

	if [[ $t_limit != *"####"* ]]; then
		t_limit=$(zenity --entry --title "Max temperature (ºC): " --text "Temperature to start reducing frequency: " --entry-text="$t_limit") 2>/dev/null
	fi

	if [[ $t_normal != *"####"* ]]; then
		t_normal=$(zenity --entry --title "Normal temperature (ºC): " --text "Temperature to start increasing frequency: " --entry-text="$t_normal") 2>/dev/null
	fi
	
	if [[ $notif != *"####"* ]]; then
		zenity --question  --title "Notifiactions" --text "Do tou want desktop notifications?" --no-wrap --ok-label "Yes" --cancel-label "No" 2>/dev/null
		if [ $? == 0 ]; then
			notif="yes"
		else
			notif="no"
		fi
	fi

	if [[ $logfile != *"####"* ]]; then
		wlf=$(zenity --question  --title "Log file" --text "Select a file or create a new one?" --switch --extra-button "Select" --extra-button "Create" --extra-button "None") 2>/dev/null
		if [ $wlf = "Select" ]; then
			logfile_gui=$(zenity --file-selection --text "Location of new file: " --filename "${HOME}/") 2>/dev/null
			if [ $? == 0 ]; then
				logfile=$logfile_gui
			fi
		elif [ $wlf = "Create" ]; then
			logfile_gui=$(zenity --entry --title "Log file" --text "Write the route: " --entry-text="${HOME}/temp_log.txt") 2>/dev/null
			if [ $? == 0 ]; then
				logfile=$logfile_gui
			fi
		else
			logfile=/dev/null
		fi
	fi

fi


# Cleaning variables:
		notif=${notif%"####"}
		delay=${delay%"####"}
		seconds=${seconds%"####"}
		t_limit=${t_limit%"####"}
		t_normal=${t_normal%"####"}
		logfile=${logfile%"####"}
# If used character ~ to use the /home/user folder, change it to ${HOME} to use in redirections:
logfile=${logfile//\~/"${HOME}"}



 echo -e "Delay: $delay\nseconds: $seconds\nt_limit: $t_limit\nt_normal: $t_normal\nlogfile: $logfile\nnotif: $notif\ngui: $gui" ############### FOR DEBUGGIN ############


# For unlimited execution:
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

# Limits log file size
if [ $(wc -l < $logfile) -gt 250 ]; then
	templog=$(tail -n 250 $logfile)
	cat <<<$templog > $logfile
fi

done
1 me gusta

Nueva versión:

  • Ahora comprueba que “sensors” existe y está configurado; básicamente, lanza el comando y si hay error termina el script inmediatamente.
    Me di cuenta probando en una máquina virtual (Devuan; quería probarlo con un init distinto). Como no tiene sensores, los valores de temperatura eran raros: eran una cadena con el error “Not sensors found etc…”. Podría pasar en ordenadores muy antiguos o un poco raritos, o en sistemas que no usen sensors.
  • Creada la función cutlog(). Se encarga de comprobar que el log no es demasiado largo. Se ejecuta cada vez que se añade una línea al log. Antes formaba parte del bucle principal y se ejecutaba cada segundo, innecesariamente.
  • Nueva variable “rows”: establece el máximo número de líneas que puede tener el archivo de log. Se puede cambiar en el script (por defecto, 250), con el argumento -s <líneas> o mediante GUI.
  • Ahora muestra el log en tiempo real en la terminal, si se está usando desde ahí. En modo gráfico (doble click en el ejecutable) o en no interactivo no hay salida estádar, así que sólo sale por archivo. Si además se establece la salida en /dev/null (por defecto), el script hace su trabajo pero no dice ni pío.
  • El log está mucho más limpio, resumido y legible. Los valores están separados por columnas, en una tabla. La cabecera de la tabla con el significado de los valores se agrega al inicio y cada 10 líneas nuevas (no sé si vale la pena preguntar al usuario por esto… pero se puede añadir). Ahora mismo, el valor está en la línea 288 ( if [ $lines -ge 10 ]; then ).

Sin más preámbulos, versión 9:

temperatura.sh
#!/bin/bash
# -*- ENCODING: UTF-8 -*-

# Default variables. You can change it to run the script easily.
delay=0
seconds=0
t_limit=85
t_normal=75
logfile="/dev/null" # <- File used as log.
rows=250
notif="yes"
gui=true

# Testing for needed tools:
sensors 2> /dev/stdout > /dev/null
if [ $? == 1 ]; then
	echo "Exiting."
	exit
fi



# Special argument: if /usr/bin/setfreq.sh is not present, it creates them and stablishes permissions:
if [ "$1" == "install" ]; then
	echo -e '#!/bin/bash\n# -*- ENCODING: UTF-8 -*-\n\n# This script MUST be launched by root\n\n# Setting the governor to "userspace":\nif [ "$1" == "userspace" ]; then\n	echo userspace | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor &> /dev/null\n	test -n "`grep -v "userspace" /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor`" && echo "Failed swithing to the userspace governor! Might not be supported or compiled in." && exit 1\n	exit 0\nfi\n\n# Changing the max speed:\necho "$1" | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_setspeed > /dev/null\nexit 0' > /usr/bin/setfreq.sh
	chown root:root /usr/bin/setfreq.sh
	chmod 755 /usr/bin/setfreq.sh
	# This test if sudoers is configured, and configure it if not:
	if [ $(grep -c 'ALL ALL=(ALL) NOPASSWD: /usr/bin/setfreq.sh' /etc/sudoers) -eq 0 ]; then
		echo -e '\n# Users cat execude this with sudo without password:\nALL ALL=(ALL) NOPASSWD: /usr/bin/setfreq.sh' >> /etc/sudoers
	fi
	exit
fi

cutlog () {
if [ $(wc -l < $logfile) -gt $rows ]; then
	templog=$(tail -n $rows $logfile)
	cat <<<$templog > $logfile
fi
}


# Internal variables. Please, do not change.
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 "-s <size> \t Maximum size, in rows, for the log file."
		echo -e "-n <yes | no> \t Enable or disable desktop notifiacions."
		echo -e "-g \t Disable GUI dialogs."
		echo -e "\nExample: Limit frequency when the temperature is 85ºC, restore it when temperature is below 75ºC and show desktop notifications:\n\n ./temperature.sh -l 85 -r 75 -n yes"
		echo -e "\nExample: 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), disable GUI dialogs and log the changes in <HOME>/temper.txt:\n\n ./tepmerature.sh -l 70 -r 50 -d 30 -t 300 -g -f ~/temper.txt"
		exit
	fi

# Reading arguments. Add "####" for priority over GUI diaglogs; it will be removed after that.
	while getopts d:t:l:r:f:s:n:g flag
	do
		case "${flag}" in
		    d) delay=${OPTARG}"####";;
		    t) seconds=${OPTARG}"####";;
		    l) t_limit=${OPTARG}"####";;
		    r) t_normal=${OPTARG}"####";;
		    f) logfile=${OPTARG}"####";;
		    s) rows=${OPTARG}"####";;
		    n) notif=${OPTARG}"####";;
		    g) gui=false;;
			*) echo -e "Valid arguments: -d <seconds> -t <seconds> -l <Cº> -n <Cº> -f <file> -n <yes | no>\nUse -h for help."
			exit;;
		esac
	done
fi

# Active or disable notifications.
# Maximum priority are:
# 1º Must exist a desktop.
# 2º Argument from console ( -g ).
# 3º Default variable at the beggining of the script ( notif= ).
# 4º If not disabled yet, show a dialog to acivate or not.

if [ -z "$XDG_CURRENT_DESKTOP" ]; then
 	# There are no desktop.
	notif="no"
	gui=false
elif [ $gui == true ]; then
	# There are desktop and default gui variable is true
	zenity --question --text "¿Configuración gráfica?" --no-wrap --ok-label "Vale" --cancel-label "No" 2>/dev/null
	if [ $? == 0 ]; then
		gui=true
	else
		gui=false
	fi
fi


# AUTOINSTALLATION
# Test if the superuser part of this script is installed. If not, it launches the script on installation mode.
if ! [ -f /usr/bin/setfreq.sh ]; then
	if [ -z "$XDG_CURRENT_DESKTOP" ] || [ $gui == false ]; then
 		# There are no desktop, or GUI disabled.
		read -r -p "Script /usr/bin/setfreq not found. ¿Install? (y/n)" a
		if [ "$a" == "y" ]; then
			sudo ./temperatura.sh install
		else
			echo "Exiting..."
			exit
		fi
	else
		# GUI enabled.
		zenity --question --text "/usr/bin/setfreq not found. ¿Install?\nIt needs root access." --no-wrap --ok-label "Install" --cancel-label "Cancel" 2>/dev/null
		if [ $? == 0 ]; then
			pkexec ./temperatura8.sh install
		else
			exit
		fi
	fi
fi

# GUI: Setting variables not stablished by parameters:
if [ $gui == true ]; then
	if [[ $delay != *"####"* ]]; then
		delay=$(zenity --entry --title "Delay (s): " --text "Time waiting for start the srcipt: " --entry-text="$delay") 2>/dev/null
	fi

	if [[ $seconds != *"####"* ]]; then
		seconds=$(zenity --entry --title "Time (s): " --text "Time running the srcipt: " --entry-text="$seconds") 2>/dev/null
	fi

	if [[ $t_limit != *"####"* ]]; then
		t_limit=$(zenity --entry --title "Max temperature (ºC): " --text "Temperature to start reducing frequency: " --entry-text="$t_limit") 2>/dev/null
	fi

	if [[ $t_normal != *"####"* ]]; then
		t_normal=$(zenity --entry --title "Normal temperature (ºC): " --text "Temperature to start increasing frequency: " --entry-text="$t_normal") 2>/dev/null
	fi
	
	if [[ $notif != *"####"* ]]; then
		zenity --question  --title "Notifiactions" --text "Do tou want desktop notifications?" --no-wrap --ok-label "Yes" --cancel-label "No" 2>/dev/null
		if [ $? == 0 ]; then
			notif="yes"
		else
			notif="no"
		fi
	fi

	if [[ $logfile != *"####"* ]]; then
		wlf=$(zenity --question  --title "Log file" --text "Select a file or create a new one?" --switch --extra-button "Select" --extra-button "Create" --extra-button "None") 2>/dev/null
		if [ $wlf = "Select" ]; then
			logfile_gui=$(zenity --file-selection --text "Location of new file: " --filename "${HOME}/") 2>/dev/null
			if [ $? == 0 ]; then
				logfile=$logfile_gui
			fi
		elif [ $wlf = "Create" ]; then
			logfile_gui=$(zenity --entry --title "Log file" --text "Write the route: " --entry-text="${HOME}/temp_log.txt") 2>/dev/null
			if [ $? == 0 ]; then
				logfile=$logfile_gui
			fi
		else
			logfile=/dev/null
		fi
	fi


	if [[ $rows != *"####"* ]]; then
		rows=$(zenity --entry --title "Size (rows): " --text "Maximum size, in rows, for the log file: " --entry-text="$rows") 2>/dev/null
	fi


fi


# Cleaning variables:
		notif=${notif%"####"}
		delay=${delay%"####"}
		seconds=${seconds%"####"}
		t_limit=${t_limit%"####"}
		t_normal=${t_normal%"####"}
		logfile=${logfile%"####"}
		rows=${rows%"####"}
# If used character ~ to use the /home/user folder, change it to ${HOME} to use in redirections:
logfile=${logfile//\~/"${HOME}"}



# echo -e "Delay: $delay\nseconds: $seconds\nt_limit: $t_limit\nt_normal: $t_normal\nlogfile: $logfile\nnotif: $notif\ngui: $gui" ############### FOR DEBUGGIN ############


# For unlimited execution:
if [ $seconds == 0 ]; then
	infinite=1
	seconds=1000
else
	infinite=0	
fi

echo -e "\n"$(date)"\n___________________ Nueva sesión ___________________" >> "$logfile"
echo -e "Fecha\t\t\t\tAcción\t\tF now\tF max\tT now\tT max" >> /dev/stdout | tee -a "$logfile"
lines=0

cutlog


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`
		f_new_str=$((f_newlimit/1000))
		f_cur_str=$((f_cur0/1000))
		echo -e $(date '+%y/%m/%d %H:%M:%S')"\tDecrease\t"$f_cur_str"Mhz\t"$f_new_str"Mhz\t"$t_cur"ºC\t"$t_max_total"ºC" >> /dev/stdout | tee -a "$logfile"
		cutlog
		((lines++))
		[ $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
		f_new_str=$((f_newlimit/1000))
		f_cur_str=$((f_cur0/1000))
		echo -e $(date '+%y/%m/%d %H:%M:%S')"\tIncrease\t"$f_cur_str"Mhz\t"$f_new_str"Mhz\t"$t_cur"ºC\t"$t_max_total"ºC" >> /dev/stdout | tee -a "$logfile"
		cutlog
		((lines++))
		[ $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
#		f_new_str=$((f_newlimit/1000))
#		f_cur_str=$((f_cur0/1000))
#		echo -e $(date '+%y/%m/%d %H:%M:%S')"\tNew max\t\t"$f_cur_str"Mhz\t"$f_new_str"Mhz\t"----"\t"$t_max_total"ºC" >> "$logfile"
#		echo -e "\nTemperatura máxima del intervalo: "$t_max_total >> $logfile
	fi

	# Limits log file size
#	if [ $(wc -l < $logfile) -gt 25 ]; then
#		templog=$(tail -n 25 $logfile)
#		cat <<<$templog > $logfile
#	fi


	# Update tags each 10 lines
	if [ $lines -ge 10 ]; then
		echo -e "Fecha\t\t\t\tAcción\t\tF now\tF max\tT now\tT max" >> /dev/stdout | tee -a $logfile
		lines=0
		cutlog
	fi
		
	sleep 1
	((seconds--))
	if [[ $infinite -eq 1 ]]; then
		seconds=1000
	fi

done
1 me gusta

Nueva versión 10:

  • Ahora lee temperatura de gráficas nVidia (probado sólo con una GTX 950M, con drivers propietarios). Comprueba si nvidia-smi existe y se ejecuta sin errores; de lo contrario, no intentará leer temperaturas de GPU.
  • Soporte de idiomas. De momento, español e inglés. Todos los textos se encuentran al principio del script. Es fácil editarlos o añadir más idiomas.
  • Al terminar la ejecución (señal SIGINT, por ejemplo con Ctrl+C) muestra un mensaje con la máxima temperatura alcanzada y restaura la frecuencia máxima por defecto.
  • Ahora se usa la variable $DISPLAY en lugar de $XDG_CURRENT_DESKTOP para decidir si existe entorno gráfico.
  • Comprueba si la instalación del script secundario ha sido exitosa. Si no, muestra un error y termina la ejecución.
  • Las notificaciones de escritorio funcionan con notify-send en lugar de con zenity. Consume menos recursos y evita bloqueos.
  • Corregido un error al llamarse a sí mismo para la instalación: antes esperaba estar en ./temperatura.sh; ahora funciona desde cualquier ruta y con cualquier nombre.

Necesito algunos voluntarios para hacer pruebas en hardware distinto. Yo no tengo nada de AMD (ni CPU ni GPU), ni gráficas modernas, ni procesadores con núcleos diferentes (ya los están haciendo con núcleos de distinto rendimiento).
Puedo preparar una versión modificada del script que no haga cambios reales, sólo lecturas de temperatura de distintos tipos de hardware.

En fin, aquí está el bicho.

Versión 10:

temperaturas.sh
#!/bin/bash
# -*- ENCODING: UTF-8 -*-

# Default variables. You can change it to run the script easily.
delay=0
seconds=0
t_limit=85
t_normal=75
logfile="/dev/null" # <- File used as log.
rows=250
notif="yes"
gui=true

# Languages
# locale | grep '^LANGUAGE=' | cut -d= -f2 | cut -d_ -f1
lang=$(locale | grep LANGUAGE= | cut -d= -f2 | cut -d_ -f1)
case $lang in
	es)
	text_exiting="Saliendo..."
	txt_exit_permissions="Error. Compruebe permisos de escritura en /usr/bin. Saliendo..."
	txt_exit_term="Script terminado. Saliendo..."
	txt_tem_max="Temperatura máxima alcanzada: "
	tex_q_gui="¿Configuración gráfica?"
	tex_q_install="No se encontró el script /usr/bin/setfreq.sh Requiere permisos de administrador. ¿Instalar?"
	tex_install="Instalar"
	tex_ok="Vale"
	tex_yes="Sí"
	tex_cancel="Cancelar"
	tex_no="No"
	tex_select="Seleccionar"
	tex_create="Crear"
	tex_none="Ninguno"
	tex_t_delay="Retraso (s)"
	tex_delay="Tiempo antes de ejecutar el script: "
	tex_t_time="Tiempo (s)"
	tex_time="Tiempo ejecutando el script: "
	tex_t_maxt="Temperatura máxima (ºC)"
	tex_temp="Temperatura a la que reducir la frecuencia: "
	tex_t_nort="Temperatura normal (ºC): "
	tex_nort="Temperatura a la que subir la frecuencia: "
	tex_t_notif="Notificaciones"
	tex_notif="¿Desea notificationes de escritorio?"
	tex_t_logfile="Archivo log"
	tex_logfile="¿Seleccionar un archivo o crear uno nuevo?"
	tex_logfile_location="Ubicación del nuevo archivo: "
	tex_logfile_route="Escriba la ruta: "
	tex_t_logfile_size="Tamaño (líneas)"
	tex_logfile_size="Tamaño máximo, en líneas del archivo log: "
	tex_newsession="Nueva sesión"
	tex_titles="Fecha\t\t\tAcción\t\tF ahora\tF max\tT ahora\tT max\tT GPU"

tex_decrease="Bajando "
tex_decreasing="Bajando frecuencia máxima: "
tex_increase="Subiendo "
tex_increasing="Subiendo frecuencia máxima: "


	
	# Ayuda:
#	tex_help="Argumentos válidos: -d <segundos> -t <segundos> -l <Cº> -n <Cº> -f <archivo> -n <yes | no>\nUse -h for help."
	tex_help="
		Este script monitoriza la temperatura de la CPU, reduce la frecuencia máxima cuando es muy alta y la aumenta cuando es suficientemente baja, y puede crear un log con sus acciones, temperaturas, fecuencias y fecha y hora. de cada evento.

		Lista de parámetros válidos:
		\n	-d <segundos> \t Retraso antes de ejecutar el script.
		\n	-t <segundos> \t Tiempo en segundos de ejecución del script. Si es 0, el script no parará.
		\n	-l <ºC> \t Temperatura máxima deseada.
		\n	-r <ºC> \t Temperatura mínima para aumentar la frecuencia.
		\n	-f <file> \t Archivo a usar como log.
		\n	-s <size> \t Tamaño máximo, en filas, del archivo de log.
		\n	-n <yes | no> \t Activar o desactivar notificaciones de escritorio.
		\n	-g \t Deshabilita la configuración gráfica.
		\n\n	Ejemplo: Limita la frecuencia cuando la temperatura llega a 85ºC, la restaura cuando la temperatura es menor de 75ºC y muestra notificaciones de escritorio:
		\n\n	./temperature.sh -l 85 -r 75 -n yes
		\n\n	Ejemplo: Limita la frecuencia cuando la temperatura llega a 70ºC, la restaura cuando la temperatura es menor de 50ºC, espera 30 segundos antes de ejecutar el script, se ejecuta durante 5 minutos (300 segundos), desactiva la confguración gráfica y guarda el log en  <HOME>/temper.txt:
		\n\n	./tepmerature.sh -l 70 -r 50 -d 30 -t 300 -g -f ~/temper.txt
	"
	
	;;

	*)
	text_exiting="Exiting..."
	txt_exit_permissions="Error. Please, test permissions to write in /usr/bin. Exiting..."
	txt_exit_term="Script terminated. Exiting"
	txt_tem_max="Maximum temperature reached: "
	tex_q_gui="Graphical configuration?"
	tex_q_install="Script /usr/bin/setfreq.sh not found. It requires administrator permissions. ¿Install?"
	tex_install="Install"
	tex_ok="O.K."
	tex_yes="Yes"
	tex_cancel="Cancel"
	tex_no="No"
	tex_select="Select"
	tex_create="Create"
	tex_none="None"
	tex_t_delay="Delay (s)"
	tex_delay="Time waiting for start the srcipt: "
	tex_t_time="Time (s)"
	tex_time="Time running the srcipt: "
	tex_t_maxt="Max temperature (ºC)"
	tex_temp="Temperature to start reducing frequency: "
	tex_t_nort="Normal temperature (ºC): "
	tex_nort="Temperature to start increasing frequency: "
	tex_t_notif="Notifications"
	tex_notif="Do tou want desktop notifications?"
	tex_t_logfile="Log file"
	tex_logfile="Select a file or create a new one?"
	tex_logfile_location="Location of new file: "
	tex_logfile_route="Write the route: "
	tex_t_logfile_size="Size (rows)"
	tex_logfile_size="Maximum size, in rows, for the log file: "
	tex_newsession="New session"
	tex_titles="Date\t\t\tAction\t\tF now\tF max\tT now\tT max\tT GPU"
	tex_decrease="Decrease"
	tex_decreasing="Decreassing maximun frequency: "
	tex_increase="Increase"
	tex_increasing="Increassing maximun frequency: "

	# Help:
#	tex_help="Valid arguments: -d <seconds> -t <seconds> -l <Cº> -n <Cº> -f <file> -n <yes | no>\nUse -h for help."
	tex_help="
		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 for each event.

		List of valid parameters:
		\n	-d <seconds> \t Delay before executing the sript.
		\n	-t <seconds> \t Time in seconds running the script. If 0, the script will never stop.
		\n	-l <ºC> \t Maximum dessired temperature.
		\n	-r <ºC> \t Minimum temperature to increase frequency.
		\n	-f <file> \t File used as log.
		\n	-s <size> \t Maximum size, in rows, for the log file.
		\n	-n <yes | no> \t Enable or disable desktop notifiacions.
		\n	-g \t Disable GUI dialogs.
		\n\n	Example: Limit frequency when the temperature is 85ºC, restore it when temperature is below 75ºC and show desktop notifications:
		\n\n	./temperature.sh -l 85 -r 75 -n yes
		\n\n	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), disable GUI dialogs and log the changes in <HOME>/temper.txt:
		\n\n	./tepmerature.sh -l 70 -r 50 -d 30 -t 300 -g -f ~/temper.txt
	"
	
	;;
esac

# Testing for needed tools:
sensors 2> /dev/stdout > /dev/null
if [ $? == 1 ]; then
	echo $text_exiting
	exit
fi

nvidia-smi > /dev/null 2> /dev/null
if [ $? == 0 ]; then
	nv=1
else
	nv=0
	t_gpu="NA"
fi


# Special argument: if /usr/bin/setfreq.sh is not present, it creates them and stablishes permissions:
if [ "$1" == "install" ]; then
	echo -e '#!/bin/bash\n# -*- ENCODING: UTF-8 -*-\n\n# This script MUST be launched by root\n\n# Setting the governor to "userspace":\nif [ "$1" == "userspace" ]; then\n	echo userspace | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor &> /dev/null\n	test -n "`grep -v "userspace" /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor`" && echo "Failed swithing to the userspace governor! Might not be supported or compiled in." && exit 1\n	exit 0\nfi\n\n# Changing the max speed:\necho "$1" | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_setspeed > /dev/null\nexit 0' > /usr/bin/setfreq.sh
	if [ $? == 1 ]; then
		echo $txt_exit_permissions
		exit
	fi
	chown root:root /usr/bin/setfreq.sh
	chmod 755 /usr/bin/setfreq.sh
	# This test if sudoers is configured, and configure it if not:
	if [ $(grep -c 'ALL ALL=(ALL) NOPASSWD: /usr/bin/setfreq.sh' /etc/sudoers) -eq 0 ]; then
		echo -e '\n# Users cat execude this with sudo without password:\nALL ALL=(ALL) NOPASSWD: /usr/bin/setfreq.sh' >> /etc/sudoers
	fi
	exit
fi

########### Functions ###########

# Size limit for logfile:
cutlog () {
	if [ $(wc -l < $logfile) -gt $rows ]; then
		templog=$(tail -n $rows $logfile)
		cat <<<$templog > $logfile
	fi
}

# Exit function. Reset the max frequency.
saliendo () {
	echo
	echo $txt_exit_term
	echo $txt_tem_max$t_max_total >> /dev/stdout | tee -a "$logfile"
	sudo /usr/bin/setfreq.sh $f_max0
	exit
}

# Internal variables. Please, do not change.
t_cur=0
t_max_total=0
# Variables assigned by parameters:
if [[ $1 ]]; then
	if [ $1 == "-h" ] || [ $1 == "--help" ]; then
		echo -e $tex_help
		exit
	fi

# Reading arguments. Add "####" for priority over GUI diaglogs; it will be removed after that.
	while getopts d:t:l:r:f:s:n:g flag
	do
		case "${flag}" in
		    d) delay=${OPTARG}"####";;
		    t) seconds=${OPTARG}"####";;
		    l) t_limit=${OPTARG}"####";;
		    r) t_normal=${OPTARG}"####";;
		    f) logfile=${OPTARG}"####";;
		    s) rows=${OPTARG}"####";;
		    n) notif=${OPTARG}"####";;
		    g) gui=false;;
			*) echo -e $tex_help
			exit;;
		esac
	done
fi

# Active or disable notifications.
# Maximum priority are:
# 1º Must exist a desktop.
# 2º Argument from console ( -g ).
# 3º Default variable at the beggining of the script ( notif= ).
# 4º If not disabled yet, show a dialog to acivate or not.

if [ -z "$DISPLAY" ]; then
 	# There are no desktop.
	notif="no"
	gui=false
elif [ $gui == true ]; then
	# There are desktop and default gui variable is true
	zenity --question --text "$tex_q_gui" --no-wrap --ok-label "Vale" --cancel-label "No" 2>/dev/null
	if [ $? == 0 ]; then
		gui=true
	else
		gui=false
	fi
fi


# AUTOINSTALLATION
# Test if the superuser part of this script is installed. If not, it launches the script on installation mode.
if ! [ -f /usr/bin/setfreq.sh ]; then
	if [ -z "$DISPLAY" ] || [ $gui == false ]; then
 		# There are no desktop, or GUI disabled.
		read -r -p "$tex_q_install  (y/n)" a
		if [ "$a" == "y" ]; then
			sudo $0 install
		else
			echo $text_exiting
			exit
		fi
		unset a
	else
		# GUI enabled.
		zenity --question --text "$tex_q_install" --no-wrap --ok-label "$tex_install" --cancel-label "$tex_cancel" 2>/dev/null
		if [ $? == 0 ]; then
			pkexec $0 install
		else
			exit
		fi
	fi
fi

# GUI: Setting variables not stablished by parameters:
if [ $gui == true ]; then
	if [[ $delay != *"####"* ]]; then
		delay=$(zenity --entry --title "$tex_q_delay" --text "$tex_delay" --entry-text="$delay") 2>/dev/null
	fi

	if [[ $seconds != *"####"* ]]; then
		seconds=$(zenity --entry --title "$tex_t_time" --text "$tex_time" --entry-text="$seconds") 2>/dev/null
	fi

	if [[ $t_limit != *"####"* ]]; then
		t_limit=$(zenity --entry --title "$tex_t_maxt" --text "$tex_temp" --entry-text="$t_limit") 2>/dev/null
	fi

	if [[ $t_normal != *"####"* ]]; then
		t_normal=$(zenity --entry --title "$tex_t_nort" --text "$tex_nort" --entry-text="$t_normal") 2>/dev/null
	fi
	
	if [[ $notif != *"####"* ]]; then
		zenity --question  --title "$tex_t_notif" --text "$tex_notif" --no-wrap --ok-label "$tex_yes" --cancel-label "$tex_no" 2>/dev/null
		if [ $? == 0 ]; then
			notif="yes"
		else
			notif="no"
		fi
	fi

	if [[ $logfile != *"####"* ]]; then
		wlf=$(zenity --question  --title "$tex_t_logfile" --text "$tex_logfile" --switch --extra-button "$tex_select" --extra-button "$tex_create" --extra-button "$tex_none") 2>/dev/null
		if [ $wlf = "$tex_select" ]; then
			logfile_gui=$(zenity --file-selection --text "$tex_logfile_location" --filename "${HOME}/") 2>/dev/null
			if [ $? == 0 ]; then
				logfile=$logfile_gui
			fi
		elif [ $wlf = "$tex_create" ]; then
			logfile_gui=$(zenity --entry --title "$tex_t_logfile" --text "$tex_logfile_route" --entry-text="${HOME}/temp_log.txt") 2>/dev/null
			if [ $? == 0 ]; then
				logfile=$logfile_gui
			fi
		else
			logfile=/dev/null
		fi
	fi

	if [[ $rows != *"####"* ]]; then
		rows=$(zenity --entry --title "$tex_t_logfile_size" --text "$tex_logfile_size" --entry-text="$rows") 2>/dev/null
	fi

fi

# Cleaning variables:
		notif=${notif%"####"}
		delay=${delay%"####"}
		seconds=${seconds%"####"}
		t_limit=${t_limit%"####"}
		t_normal=${t_normal%"####"}
		logfile=${logfile%"####"}
		rows=${rows%"####"}

# If used character ~ to use the /home/user folder, change it to ${HOME} to use in redirections:
logfile=${logfile//\~/"${HOME}"}

# For unlimited execution:
if [ $seconds == 0 ]; then
	infinite=1
	seconds=1000
else
	infinite=0	
fi

echo -e "\n"$(date)"\n___________________ "$tex_newsession" ___________________" >> "$logfile"
echo -e "$tex_titles" >> /dev/stdout | tee -a "$logfile"
lines=0

cutlog


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

# Setting the current temperature to maximum:
sudo /usr/bin/setfreq.sh $f_newlimit

trap saliendo 0

# ----------------------- 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`
		f_new_str=$((f_newlimit/1000))
		f_cur_str=$((f_cur0/1000))
		[ $nv == 1 ] && t_gpu=$(nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader)
		echo -e $(date '+%y/%m/%d %H:%M:%S')"\t$tex_decrease\t"$f_cur_str"Mhz\t"$f_new_str"Mhz\t"$t_cur"ºC\t"$t_max_total"ºC\t"$t_gpu"ºC" >> /dev/stdout | tee -a "$logfile"
		cutlog
		((lines++))
		[ $notif == "yes" ] && notify-send "$tex_decreasing$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
		f_new_str=$((f_newlimit/1000))
		f_cur_str=$((f_cur0/1000))
		[ $nv == 1 ] && t_gpu=$(nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader)
		echo -e $(date '+%y/%m/%d %H:%M:%S')"\t$tex_increase\t"$f_cur_str"Mhz\t"$f_new_str"Mhz\t"$t_cur"ºC\t"$t_max_total"ºC\t"$t_gpu"ºC" >> /dev/stdout | tee -a "$logfile"
		cutlog
		((lines++))
		[ $notif == "yes" ] && notify-send "$tex_increasing$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
#		f_new_str=$((f_newlimit/1000))
#		f_cur_str=$((f_cur0/1000))
#		echo -e $(date '+%y/%m/%d %H:%M:%S')"\tNew max\t\t"$f_cur_str"Mhz\t"$f_new_str"Mhz\t"----"\t"$t_max_total"ºC" >> "$logfile"
#		echo -e "\nTemperatura máxima del intervalo: "$t_max_total >> $logfile
	fi

	# Limits log file size
#	if [ $(wc -l < $logfile) -gt 25 ]; then
#		templog=$(tail -n 25 $logfile)
#		cat <<<$templog > $logfile
#	fi


	# Update tags each 10 lines
	if [ $lines -ge 10 ]; then
		echo -e "$tex_titles" >> /dev/stdout | tee -a $logfile
		lines=0
		cutlog
	fi
		
	sleep 1
	((seconds--))
	if [[ $infinite -eq 1 ]]; then
		seconds=1000
	fi

done
1 me gusta

Hola, acabo de probar tu proyecto en una mac con Apple Silicon, y una PC con AMD.

Apple Silicon

  • Dispositivo : Macbook air m1 A2337
  • OS : Fedora
  • Resultado : Funciona bien.

AMD

  • Dispositivo : Por lo que dice la caja, es un Ryzen 5 3500
  • No tiene GPU, es un CPU con graficos integrados
  • OS : Ubuntu
  • Resultado : No me funciono, me marca errores con CPUFreq.

En unos dias puede que instale Arch en una laptop intel con graficos integrados, si lo hago, lo pruebo y publico los resultados.

1 me gusta

Interesante, lo probare después. Aunque deberías considerar limpiar las
variables que no usas y limitar el código a 80 lineas. Puedes usar shellcheck para ello. También creo que deberías subirlo a tu git.

2 Me gusta

¡Muchas gracias!
Me sorprende que funcione a la primera en un Mac ARM. Es una arquitectura muy diferente.
En cuanto al AMD, mientras voy investigando, ¿podrías darme el resultado de unos comandos? No son peligrosos, es sólo para ver qué archivos virtuales usa para controlar la frecuencia del procesador y qué valores devuelve cpupower:
ls /sys/devices/system/cpu/cpu0/cpufreq
ls /sys/devices/system/cpu/cpufreq
sudo cpupower frequency-info

Ahora mismo estoy probando cpupower en mi Intel y funciona bastante bien. Si AMD es compatible (como se supone que es), será fácil cambiar todo lo relevante en el script y aumentar la compatibilidad.

P.D.: Aunque no tengas una gráfica dedicada, la que hay integrada en el núcleo también es una GPU. En el caso de los AMD, además, suele ser bastante potente, prácticamente como una dedicada de gama baja. Desde el punto de vista del sistema operativo, es prácticamente lo mismo que esté integrada en el encapsulado de la CPU o que esté en una tarjeta separada.
→ Acabo de buscar qué GPU lleva el Ryzen 5 3500 y todos los resultados me dicen que no lleva gráficos integrados. :neutral_face:

1 me gusta

No conocía shellcheck. Lo estoy probando y es una herramienta muy útil. ¡Gracias!

Me ha encontrado un par de errores de despiste (una variable mal escrita), un par de malas prácticas (no cerrar variables entre comillas, usar ‘comando’ en vez de $(comando)…) y algún otro fallo menor. Estoy corrigiéndolos. :grin:

1 me gusta

Lo siento por lo del AMD, me equivoque en el nombre, es un AMD Ryzen 5 5600G con graficos Radeon. llegando a mi casa te mando el resultado de los comandos

1 me gusta

¡Nueva versión 11!

Novedades:

  • Ya no lee ni escribe directamente en /sys/devices/system/cpu/cpu*/cpufreq. Utiliza el servicio cpupower, que es (o debería ser) estándar en cualquier hardware… siempre que la distro lo incluya. Es un programa muy común, así que no debería ser un problema. Por tanto, debería funcionar en procesadores AMD, Intel, Mac, ARM…
  • Ahora establece la velocidad de cada núcleo por separado, para procesadores con núcleos heterogéneos. Ningún núcleo subirá por encima de su frecuencia máxima ni bajará de su mínima. El log muestra las velocidades actuales de cada núcleo.
  • Ahora el log saca tres líneas para cada acción en lugar de una. Eso era necesario para implementar los núcleos por separado.
  • Corregido un error que impedía usar rutas con el carácter espacio.
  • Pequeñas correcciones. No recuerdo cuáles… :sweat_smile:
  • Las operaciones de consulta y cambio de frecuencia se han movido del bucle principa a funciones.

¡Ojo cuidao! El archivo /usr/bin/setfreq.sh ha cambiado. Si alguien probó la versión anterior, debe eliminarlo antes de ejecutar la nueva ( sudo rm /usr/bin/setfreq.sh )

Parece que no, pero han sido unos cambios bastante complicados. Trabajar con bucles en Bash, manteniendo condicionales y variables, es un poco locura.

Versión 11:

temperaturas.sh
#!/bin/bash
# -*- ENCODING: UTF-8 -*-

# Default variables. You can change it to run the script easily.
delay=0
seconds=0
t_limit=85
t_normal=75
logfile="/dev/null" # <- File used as log.
rows=250
notif="yes"
gui=true

# Languages
# locale | grep '^LANGUAGE=' | cut -d= -f2 | cut -d_ -f1
lang=$(locale | grep LANGUAGE= | cut -d= -f2 | cut -d_ -f1)
case $lang in

# SPANISH
	es)
	text_exiting="Saliendo..."
	txt_exit_permissions="Error. Compruebe permisos de escritura en /usr/bin. Saliendo..."
	txt_exit_term="Script terminado. Saliendo..."
	txt_tem_max="Temperatura máxima alcanzada: "
	tex_q_gui="¿Configuración gráfica?"
	tex_q_install="No se encontró el script /usr/bin/setfreq.sh Requiere permisos de administrador. ¿Instalar?"
	tex_install="Instalar"
	tex_ok="Vale"
	tex_yes="Sí"
	tex_cancel="Cancelar"
	tex_no="No"
	tex_select="Seleccionar"
	tex_create="Crear"
	tex_none="Ninguno"
	tex_t_delay="Retraso (s)"
	tex_delay="Tiempo antes de ejecutar el script: "
	tex_t_time="Tiempo (s)"
	tex_time="Tiempo ejecutando el script: "
	tex_t_maxt="Temperatura máxima (ºC)"
	tex_temp="Temperatura a la que reducir la frecuencia: "
	tex_t_nort="Temperatura normal (ºC): "
	tex_nort="Temperatura a la que subir la frecuencia: "
	tex_t_notif="Notificaciones"
	tex_notif="¿Desea notificationes de escritorio?"
	tex_t_logfile="Archivo log"
	tex_logfile="¿Seleccionar un archivo o crear uno nuevo?"
	tex_logfile_location="Ubicación del nuevo archivo: "
	tex_logfile_route="Escriba la ruta: "
	tex_t_logfile_size="Tamaño (líneas)"
	tex_logfile_size="Tamaño máximo, en líneas del archivo log: "
	tex_newsession="Nueva sesión"
	tex_max="Max: "
	tex_now="Ahora: "
	tex_decrease="Acción: Bajando "
	tex_decreasing="Bajando frecuencia máxima: "
	tex_increase="Acción: Subiendo "
	tex_increasing="Subiendo frecuencia máxima: "


	
	# Ayuda:
#	tex_help="Argumentos válidos: -d <segundos> -t <segundos> -l <Cº> -n <Cº> -f <archivo> -n <yes | no>\nUse -h for help."
	tex_help="
		Este script monitoriza la temperatura de la CPU, reduce la frecuencia máxima cuando es muy alta y la aumenta cuando es suficientemente baja, y puede crear un log con sus acciones, temperaturas, fecuencias y fecha y hora. de cada evento.

		Lista de parámetros válidos:
		\n	-d <segundos> \t Retraso antes de ejecutar el script.
		\n	-t <segundos> \t Tiempo en segundos de ejecución del script. Si es 0, el script no parará.
		\n	-l <ºC> \t Temperatura máxima deseada.
		\n	-r <ºC> \t Temperatura mínima para aumentar la frecuencia.
		\n	-f <file> \t Archivo a usar como log.
		\n	-s <size> \t Tamaño máximo, en filas, del archivo de log.
		\n	-n <yes | no> \t Activar o desactivar notificaciones de escritorio.
		\n	-g \t Deshabilita la configuración gráfica.
		\n\n	Ejemplo: Limita la frecuencia cuando la temperatura llega a 85ºC, la restaura cuando la temperatura es menor de 75ºC y muestra notificaciones de escritorio:
		\n\n	./temperature.sh -l 85 -r 75 -n yes
		\n\n	Ejemplo: Limita la frecuencia cuando la temperatura llega a 70ºC, la restaura cuando la temperatura es menor de 50ºC, espera 30 segundos antes de ejecutar el script, se ejecuta durante 5 minutos (300 segundos), desactiva la confguración gráfica y guarda el log en  <HOME>/temper.txt:
		\n\n	./tepmerature.sh -l 70 -r 50 -d 30 -t 300 -g -f ~/temper.txt
	"
	
	;;

# ENGLISH
	*)
	text_exiting="Exiting..."
	txt_exit_permissions="Error. Please, test permissions to write in /usr/bin. Exiting..."
	txt_exit_term="Script terminated. Exiting"
	txt_tem_max="Maximum temperature reached: "
	tex_q_gui="Graphical configuration?"
	tex_q_install="Script /usr/bin/setfreq.sh not found. It requires administrator permissions. ¿Install?"
	tex_install="Install"
	tex_ok="O.K."
	tex_yes="Yes"
	tex_cancel="Cancel"
	tex_no="No"
	tex_select="Select"
	tex_create="Create"
	tex_none="None"
	tex_t_delay="Delay (s)"
	tex_delay="Time waiting for start the srcipt: "
	tex_t_time="Time (s)"
	tex_time="Time running the srcipt: "
	tex_t_maxt="Max temperature (ºC)"
	tex_temp="Temperature to start reducing frequency: "
	tex_t_nort="Normal temperature (ºC): "
	tex_nort="Temperature to start increasing frequency: "
	tex_t_notif="Notifications"
	tex_notif="Do tou want desktop notifications?"
	tex_t_logfile="Log file"
	tex_logfile="Select a file or create a new one?"
	tex_logfile_location="Location of new file: "
	tex_logfile_route="Write the route: "
	tex_t_logfile_size="Size (rows)"
	tex_logfile_size="Maximum size, in rows, for the log file: "
	tex_newsession="New session"
	tex_max="Max: "
	tex_now="Now: "
	tex_decrease="Action: Decrease"
	tex_decreasing="Decreassing maximun frequency: "
	tex_increase="Action: Increase"
	tex_increasing="Increassing maximun frequency: "

	# Help:
#	tex_help="Valid arguments: -d <seconds> -t <seconds> -l <Cº> -n <Cº> -f <file> -n <yes | no>\nUse -h for help."
	tex_help="
		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 for each event.

		List of valid parameters:
		\n	-d <seconds> \t Delay before executing the sript.
		\n	-t <seconds> \t Time in seconds running the script. If 0, the script will never stop.
		\n	-l <ºC> \t Maximum dessired temperature.
		\n	-r <ºC> \t Minimum temperature to increase frequency.
		\n	-f <file> \t File used as log.
		\n	-s <size> \t Maximum size, in rows, for the log file.
		\n	-n <yes | no> \t Enable or disable desktop notifiacions.
		\n	-g \t Disable GUI dialogs.
		\n\n	Example: Limit frequency when the temperature is 85ºC, restore it when temperature is below 75ºC and show desktop notifications:
		\n\n	./temperature.sh -l 85 -r 75 -n yes
		\n\n	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), disable GUI dialogs and log the changes in <HOME>/temper.txt:
		\n\n	./tepmerature.sh -l 70 -r 50 -d 30 -t 300 -g -f ~/temper.txt
	"
	
	;;
esac

# Testing for needed tools:
sensors 2> /dev/stdout > /dev/null
if [ $? == 1 ]; then
	echo $text_exiting
	exit
fi

nvidia-smi > /dev/null 2> /dev/null
if [ $? == 0 ]; then
	nv=1
else
	nv=0
	t_gpu="NA"
fi


# Special argument: if /usr/bin/setfreq.sh is not present, it creates them and stablishes permissions:
if [ "$1" == "install" ]; then
	echo -e '#!/bin/bash\n# -*- ENCODING: UTF-8 -*-\n\n# This script MUST be launched by root\n\n# Setting the governor to "performance":\nif [ "$1" == "performance" ]; then\n	cpupower frequency-set -g performance > /dev/null\n	[[ ! -n "$(cpupower frequency-info | grep -v cpufreq | grep performance)" ]] && echo "The governor has not changed to performance. This script needs that governor to run." && exit 1\n	exit 0\nfi\n\n# Changing the max speed:\ncpupower -c $1 frequency-set -u $2  > /dev/null\nexit 0' > /usr/bin/setfreq.sh
	if [ $? == 1 ]; then
		echo "$txt_exit_permissions"
		exit
	fi
	chown root:root /usr/bin/setfreq.sh
	chmod 755 /usr/bin/setfreq.sh
	# This test if sudoers is configured, and configure it if not:
	if [ $(grep -c 'ALL ALL=(ALL) NOPASSWD: /usr/bin/setfreq.sh' /etc/sudoers) -eq 0 ]; then
		echo -e '\n# Users cat execude this with sudo without password:\nALL ALL=(ALL) NOPASSWD: /usr/bin/setfreq.sh' >> /etc/sudoers
	fi
	exit
fi

########### Functions ###########

# Size limit for logfile:
cutlog () {
	if [ $(wc -l < "$logfile") -gt $rows ]; then
		templog=$(tail -n $rows "$logfile")
		cat <<<"$templog" > "$logfile"
	fi
}

# Exit function. Reset the max frequency.
saliendo () {
	echo
	echo "$txt_exit_term"
	echo "$txt_tem_max$t_max_total"  | tee -a "$logfile"
	cpunum=0
	for cpunum in $(seq 0 $cpus); do
#		echo "Establecer la temperatura de la PCU $cpunum en ${f_max[$cpunum]}"
		sudo /usr/bin/setfreq.sh $cpunum ${f_max[$cpunum]}
	done
	exit
}

# Read maximum frequencies
read_f_max () {
#	echo "Tomando valores de frecuencias máximas en el array f_max:"
	cpunum=0
	f_max=()
	while read line ; do
		f_max+=($line)
		f_newlimit[$cpunum]=${f_max[$cpunum]}
		((cpunum ++))
	done <<< $(cpupower -c all frequency-info -l | grep -v "analyzing" | cut -d\  -f 2)
#	echo "Frecuencias máximas: ${f_max[*]}"
#	echo "New limit: ${f_newlimit[*]}"
}

# Read minimum frequencies
read_f_min () {
#	echo "Tomando valores de frecuencias mínimas en el array f_min:"
	cpunum=0
	f_min=()
	while read line ; do
		f_min+=($line)
		((cpunum ++))
	done <<< $(cpupower -c all frequency-info -l | grep -v "analyzing" | cut -d\  -f 1)
#	echo "Frecuencias mínimas: ${f_min[*]}"
}

# Read current frequencies
read_f_cur () {
#	echo "Tomando valores de frecuencias actuales en el array f_cur:"
	f_cur=()
	while read line ; do
		f_cur+=($line)
	done <<< $(cpupower -c all frequency-info -f | grep -v "analyzing" | cut -d\  -f 6)
#	echo "Frecuencias actuales: ${f_cur[*]}"
}


# Internal variables. Please, do not change.
t_cur=0
t_max_total=0
# Variables assigned by parameters:
if [[ $1 ]]; then
	if [ $1 == "-h" ] || [ $1 == "--help" ]; then
		echo -e "$tex_help"
		exit
	fi

# Reading arguments. Add "####" for priority over GUI diaglogs; it will be removed after that.
	while getopts d:t:l:r:f:s:n:g flag
	do
		case "${flag}" in
		    d) delay=${OPTARG}"####";;
		    t) seconds=${OPTARG}"####";;
		    l) t_limit=${OPTARG}"####";;
		    r) t_normal=${OPTARG}"####";;
		    f) logfile=${OPTARG}"####";;
		    s) rows=${OPTARG}"####";;
		    n) notif=${OPTARG}"####";;
		    g) gui=false;;
			*) echo -e "$tex_help"
			exit;;
		esac
	done
fi

# Active or disable notifications.
# Maximum priority are:
# 1º Must exist a desktop.
# 2º Argument from console ( -g ).
# 3º Default variable at the beggining of the script ( notif= ).
# 4º If not disabled yet, show a dialog to acivate or not.

if [ -z "$DISPLAY" ]; then
 	# There are no desktop.
	notif="no"
	gui=false
elif [ $gui == true ]; then
	# There are desktop and default gui variable is true
	zenity --question --text "$tex_q_gui" --no-wrap --ok-label "$tex_ok" --cancel-label "No" 2>/dev/null
	if [ $? == 0 ]; then
		gui=true
	else
		gui=false
	fi
fi


# AUTOINSTALLATION
# Test if the superuser part of this script is installed. If not, it launches the script on installation mode.
if ! [ -f /usr/bin/setfreq.sh ]; then
	if [ -z "$DISPLAY" ] || [ $gui == false ]; then
 		# There are no desktop, or GUI disabled.
		read -r -p "$tex_q_install  (y/n)" a
		if [ "$a" == "y" ]; then
			sudo "$0" install
		else
			echo "$text_exiting"
			exit
		fi
		unset a
	else
		# GUI enabled.
		zenity --question --text "$tex_q_install" --no-wrap --ok-label "$tex_install" --cancel-label "$tex_cancel" 2>/dev/null
		if [ $? == 0 ]; then
			pkexec $0 install
		else
			exit
		fi
	fi
fi

# GUI: Setting variables not stablished by parameters:
if [ $gui == true ]; then
	if [[ $delay != *"####"* ]]; then
		delay=$(zenity --entry --title "$tex_t_delay" --text "$tex_delay" --entry-text="$delay") 2>/dev/null
	fi

	if [[ $seconds != *"####"* ]]; then
		seconds=$(zenity --entry --title "$tex_t_time" --text "$tex_time" --entry-text="$seconds") 2>/dev/null
	fi

	if [[ $t_limit != *"####"* ]]; then
		t_limit=$(zenity --entry --title "$tex_t_maxt" --text "$tex_temp" --entry-text="$t_limit") 2>/dev/null
	fi

	if [[ $t_normal != *"####"* ]]; then
		t_normal=$(zenity --entry --title "$tex_t_nort" --text "$tex_nort" --entry-text="$t_normal") 2>/dev/null
	fi
	
	if [[ $notif != *"####"* ]]; then
		zenity --question  --title "$tex_t_notif" --text "$tex_notif" --no-wrap --ok-label "$tex_yes" --cancel-label "$tex_no" 2>/dev/null
		if [ $? == 0 ]; then
			notif="yes"
		else
			notif="no"
		fi
	fi

	if [[ "$logfile" != *"####"* ]]; then
		wlf=$(zenity --question  --title "$tex_t_logfile" --text "$tex_logfile" --switch --extra-button "$tex_select" --extra-button "$tex_create" --extra-button "$tex_none") 2>/dev/null
		if [ "$wlf" = "$tex_select" ]; then
			logfile_gui=$(zenity --file-selection --text "$tex_logfile_location" --filename "${HOME}/") 2>/dev/null
			if [ $? == 0 ]; then
				logfile="$logfile_gui"
			fi
		elif [ "$wlf" = "$tex_create" ]; then
			logfile_gui=$(zenity --entry --title "$tex_t_logfile" --text "$tex_logfile_route" --entry-text="${HOME}/temp_log.txt") 2>/dev/null
			if [ $? == 0 ]; then
				logfile="$logfile_gui"
			fi
		else
			logfile=/dev/null
		fi
		unset wlf
	fi
	
	logfile=${logfile%"####"}
echo "RUTA: $logfile"
	if [[ $rows != *"####"* ]] && [[ "$logfile" != "/dev/null" ]]; then
		rows=$(zenity --entry --title "$tex_t_logfile_size" --text "$tex_logfile_size" --entry-text="$rows") 2>/dev/null
	fi

fi

# Cleaning variables:
		notif=${notif%"####"}
		delay=${delay%"####"}
		seconds=${seconds%"####"}
		t_limit=${t_limit%"####"}
		t_normal=${t_normal%"####"}
		logfile=${logfile%"####"}
		rows=${rows%"####"}

# Change "~" to "${HOME}" to use the "/home/user" folder in redirections:
logfile=${logfile//\~/"${HOME}"}

# For unlimited execution:
if [ $seconds == 0 ]; then
	infinite=1
	seconds=1000
else
	infinite=0	
fi

echo -e "\n$(date)\n___________________ $tex_newsession ___________________" | tee -a "$logfile"
lines=0

cutlog


sleep $delay

# Setting the governor to "performance":
sudo /usr/bin/setfreq.sh performance


# Obtain current, max and min frequency:
read_f_max
#echo "F_max es ${f_max[*]}"
read_f_min
#echo "F_min es ${f_min[*]}"
read_f_cur
#echo "F_cur es ${f_cur[*]}"

# Contando núcleos:
cpus=$(cpupower -c all frequency-info -f | grep -v "analyzing" | wc -l)
((cpus --))

# Setting the current temperature to maximum:		####¡CAMBIOS! ####
#sudo /usr/bin/setfreq.sh $f_newlimit

# Provisional, sin llamar a setfreq.sh:
#for cpunum in $(seq 0 $cpus); do
#	sudo cpupower -c $cpunum frequency-set -u ${f_newlimit[$cpunum]}
#done

# Candidato:
for cpunum in $(seq 0 $cpus); do
	sudo /usr/bin/setfreq.sh $cpunum ${f_newlimit[$cpunum]}
done


trap saliendo 0

# ----------------------- 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)
	# Update maximum teperatura for this session
	if [ $t_cur -gt $t_max_total ]; then
		t_max_total=$t_cur
	fi
	
	# Decrease frequency when temperature is too high
	
	cpunum=0
	lim_reached=true
	for cpunum in $(seq 0 $cpus); do
		if [[ ${f_newlimit[$cpunum]} -gt ${f_min[$cpunum]} ]]; then
			lim_reached=false
			break
		fi
	done

	if [ $t_cur -gt $t_limit ] && [[ $lim_reached == false ]]; then
		# Decease frequency in proportion to excesive temperature
		diff=$((t_cur - t_limit))
		step=$((diff * 50000))
		step=$(( step > 400000 ? 400000 : step ))
		echo -e "$(date '+%y/%m/%d %H:%M:%S')\t$tex_decrease\t$tex_now$t_cur ºC\t$tex_max$t_max_total ºC\tGPU: $t_gpu ºC"  | tee -a "$logfile"
		# Provisional, sin llamar a setfreq.sh:
		log_freq1=""
		log_freq2=""
		cpunum=0
		for cpunum in $(seq 0 $cpus); do
			if [ ${f_newlimit[$cpunum]} -gt ${f_min[$cpunum]} ]; then
			
				f_newlimit[$cpunum]=$((f_newlimit[$cpunum] - step))
				if [ ${f_newlimit[$cpunum]} -lt ${f_min[$cpunum]} ]; then
					f_newlimit[$cpunum]=${f_min[$cpunum]}
				fi
				sudo /usr/bin/setfreq.sh $cpunum ${f_newlimit[$cpunum]}
			fi
			read_f_cur
			f_newlimit_cpunum=${f_newlimit[$cpunum]}
			f_cur_cpunum=${f_cur[$cpunum]}
			f_new_str[$cpunum]=$((f_newlimit_cpunum/1000))
			f_cur_str[$cpunum]=$((f_cur_cpunum/1000))
			[ $nv == 1 ] && t_gpu=$(nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader)
			log_freq1="$log_freq1 C$cpunum ${f_new_str[$cpunum]} "
			log_freq2="$log_freq2 C$cpunum ${f_cur_str[$cpunum]} "
#			echo -e "Núcleo $cpunum\t${f_cur_str[$cpunum]} Mhz\t${f_new_str[$cpunum]} Mhz\t$t_cur"  | tee -a "$logfile"
			((cpunum ++))		
		done
		echo -e "$tex_max (Mhz)\t$log_freq1" | tee -a "$logfile"
		echo -e "$tex_now (Mhz)\t$log_freq2" | tee -a "$logfile"
		unset log_freq1 log_freq2
		cutlog
		((lines++))
		[ $notif == "yes" ] && notify-send "$tex_decreasing ${f_newlimit[0]}" 2>/dev/null
		sleep 4
		((seconds-=4))
	fi
	
	# Icrease frequency when temperature is acceptable
	

	cpunum=0
	lim_reached=true
	for cpunum in $(seq 0 $cpus); do
		if [[ ${f_newlimit[$cpunum]} -lt ${f_max[$cpunum]} ]]; then
			lim_reached=false
			break
		fi
	done
		
	if [ $t_cur -lt $t_normal ] && [[ $lim_reached == false ]]; then
		echo -e "$(date '+%y/%m/%d %H:%M:%S')\t$tex_increase\t$tex_now$t_cur ºC\t$tex_max$t_max_total ºC\tGPU: $t_gpu ºC"  | tee -a "$logfile"
		# Provisional, sin llamar a setfreq.sh:
		cpunum=0
		for cpunum in $(seq 0 $cpus); do
			if [ ${f_newlimit[$cpunum]} -gt ${f_min[$cpunum]} ]; then
				f_newlimit[$cpunum]=$((${f_newlimit[$cpunum]} + 200000))
				if [ ${f_newlimit[$cpunum]} -gt ${f_max[$cpunum]} ]; then
					f_newlimit[$cpunum]=${f_max[$cpunum]}
				fi
				sudo /usr/bin/setfreq.sh $cpunum ${f_newlimit[$cpunum]}
			fi
			read_f_cur
			f_newlimit_cpunum=${f_newlimit[$cpunum]}
			f_cur_cpunum=${f_cur[$cpunum]}
			f_new_str[$cpunum]=$((f_newlimit_cpunum/1000))
			f_cur_str[$cpunum]=$((f_cur_cpunum/1000))
			[ $nv == 1 ] && t_gpu=$(nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader)
			log_freq1="$log_freq1 C$cpunum ${f_new_str[$cpunum]} "
			log_freq2="$log_freq2 C$cpunum ${f_cur_str[$cpunum]} "
#			echo -e "Núcleo $cpunum\t${f_cur_str[$cpunum]} Mhz\t${f_new_str[$cpunum]} Mhz\t$t_cur"  | tee -a "$logfile"
			((cpunum ++))		
		done
		echo -e "$tex_max (Mhz)\t$log_freq1" | tee -a "$logfile"
		echo -e "$tex_now (Mhz)\t$log_freq2" | tee -a "$logfile"
		unset log_freq1 log_freq2
		cutlog
		((lines++))
		[ $notif == "yes" ] && notify-send "$tex_increasing${f_newlimit[0]}" 2>/dev/null
		sleep 4
		((seconds-=4))
		
	fi


	sleep 1
	((seconds--))
	if [[ $infinite -eq 1 ]]; then
		seconds=1000
	fi
	
done

# Exiting
echo "$txt_exit_term"
echo "$txt_tem_max$t_max_total"  | tee -a "$logfile"
saliendo

Versión 12:

  • Corrige un problema surgido al usar Cpufreq en lugar de escribir en archivos de sistema: para que escribir directamente funcionara, era necesario que el governor (el parámetro que establece el modo de rendimiento de la CPU) se estableciera en “userspace”. Usando Cpufreq, se puede elegir cualquiera de los disponibles, afectando a cómo se comporta el procesador en diferentes circunstancias. Por ejemplo, en modo “powersave” nunca se supera la frecuencia mínima, y en “performance” siempre está cerca del límite máximo aunque no haya procesos consumiendo recursos. En cualquier caso, siempre se respeta el límite máximo establecido por el script. En consecuencia, ahora el script permite elegir el governor deseado de varias maneras:
    *- Editando la variable en el script. Por defecto, “ondemand” (es el más equilibrado y he comprobado que funciona bastante bien).
    *- Mediante el parámetro -p . Si el argumento es “list”, el script muestra un menú con los valores posibles y permite elegir por número. El valor por defecto es el que se especifique en la variable del script.

    *- Mediante el GUI. Zenity muestra una lista con los valores posibles, incluyendo un elemento para establecerlo a mano de ser necesario. Si se acepta sin elegir ningún valor, se toma por defecto el que esté en el script. Sólo aparece si no se ha establecido mediante argumento (y siempre que el GUI esté activado y disponible).

  • A partir de ahora, el script /usr/bin/setfreq.sh detecta si el instalado tiene la misma versión que el original. Si no es el caso, la sustituye. Ya no es necesario eliminar el antiguo si una actualización requiere cambiar algo. La versión de ambos scripts se declara mediante una variable en el script principal.
  • Sé que he corregido varios pequeños errores, mejorado la eficiencia de algunas tareas y reducido algo del código anterior, pero no recuerdo qué he hecho dónde. :sweat_smile:

Esta versión está cerca de ser la definitiva. Sigo necesitando que alguien lo pruebe en equipos AMD, entre otros. Me vendría bien que me dierais la salida de estos comandos en vuestras máquinas:
cpupower frequency-info
ls /sys/devices/system/cpu
ls /sys/devices/system/cpu/cpu0/cpufreq
cat /sys/devices/system/cpu/cpu0/cpufreq/*
Ninguno de ellos es peligroso, requiere permisos especiales ni expone datos personales de ningún tipo.

Versión 12:

underclocker.sh (nombre provisional)
#!/bin/bash
# -*- ENCODING: UTF-8 -*-

version=12

# Default variables. You can change it to run the script easily.
delay=0
seconds=0
t_limit=85
t_normal=75
logfile="/dev/null" # <- File used as log.
rows=250
notif="yes"
gui=true
governor=ondemand

# Languages
# locale | grep '^LANGUAGE=' | cut -d= -f2 | cut -d_ -f1
lang=$(locale | grep LANGUAGE= | cut -d= -f2 | cut -d_ -f1)
case $lang in

# SPANISH
	es)
	text_exiting="Saliendo..."
	txt_exit_permissions="Error. Compruebe permisos de escritura en /usr/bin. Saliendo..."
	txt_exit_term="Script terminado. Saliendo..."
	txt_tem_max="Temperatura máxima alcanzada: "
	tex_q_gui="¿Configuración gráfica?"
	tex_q_install="No se encontró el script /usr/bin/setfreq.sh Requiere permisos de administrador. ¿Instalar?"
	tex_install="Instalar"
	tex_ok="Vale"
	tex_yes="Sí"
	tex_cancel="Cancelar"
	tex_no="No"
	tex_select="Seleccionar"
	tex_create="Crear"
	tex_none="Ninguno"
	tex_t_delay="Retraso (s)"
	tex_delay="Tiempo antes de ejecutar el script: "
	tex_t_time="Tiempo (s)"
	tex_time="Tiempo ejecutando el script: "
	tex_t_maxt="Temperatura máxima (ºC)"
	tex_temp="Temperatura a la que reducir la frecuencia: "
	tex_t_nort="Temperatura normal (ºC): "
	tex_nort="Temperatura a la que subir la frecuencia: "
	tex_t_notif="Notificaciones"
	tex_notif="¿Desea notificationes de escritorio?"
	tex_t_logfile="Archivo log"
	tex_logfile="¿Seleccionar un archivo o crear uno nuevo?"
	tex_logfile_location="Ubicación del nuevo archivo: "
	tex_logfile_route="Escriba la ruta: "
	tex_t_logfile_size="Tamaño (líneas)"
	tex_logfile_size="Tamaño máximo, en líneas del archivo log: "
	tex_newsession="Nueva sesión"
	tex_max="Max: "
	tex_now="Ahora: "
	tex_decrease="Acción: Bajando "
	tex_decreasing="Bajando frecuencia máxima: "
	tex_increase="Acción: Subiendo "
	tex_increasing="Subiendo frecuencia máxima: "
	tex_gov_avail="Governors disponilbes:"
	tex_q_gov="Elija el governor deseado:"
	tex_cur_gov="El governor actual es"
	tex_new_gov="Escriba el nombre del nuevo governor"

	# Ayuda:
	tex_help="
		Este script monitoriza la temperatura de la CPU, reduce la frecuencia máxima cuando es muy alta y la aumenta cuando es suficientemente baja, y puede crear un log con sus acciones, temperaturas, fecuencias y fecha y hora. de cada evento.

		Lista de parámetros válidos:
		\n	-d <segundos> \t Retraso antes de ejecutar el script.
		\n	-t <segundos> \t Tiempo en segundos de ejecución del script. Si es 0, el script no parará.
		\n	-p <governor> \t Power governor (usar [-p list] para seleccionarlo de una lista)
		\n	-l <ºC> \t Temperatura máxima deseada.
		\n	-r <ºC> \t Temperatura mínima para aumentar la frecuencia.
		\n	-f <file> \t Archivo a usar como log.
		\n	-s <size> \t Tamaño máximo, en filas, del archivo de log.
		\n	-n <yes | no> \t Activar o desactivar notificaciones de escritorio.
		\n	-g \t Deshabilita la configuración gráfica.
		\n\n	Ejemplo: Limita la frecuencia cuando la temperatura llega a 85ºC, la restaura cuando la temperatura es menor de 75ºC y muestra notificaciones de escritorio:
		\n\n	./temperature.sh -l 85 -r 75 -n yes
		\n\n	Ejemplo: Limita la frecuencia cuando la temperatura llega a 70ºC, la restaura cuando la temperatura es menor de 50ºC, espera 30 segundos antes de ejecutar el script, se ejecuta durante 5 minutos (300 segundos), desactiva la confguración gráfica y guarda el log en <HOME>/temper.txt:
		\n\n	./tepmerature.sh -l 70 -r 50 -d 30 -t 300 -g -f ~/temper.txt
	"
	
	;;

# ENGLISH
	*)
	text_exiting="Exiting..."
	txt_exit_permissions="Error. Please, test permissions to write in /usr/bin. Exiting..."
	txt_exit_term="Script terminated. Exiting"
	txt_tem_max="Maximum temperature reached: "
	tex_q_gui="Graphical configuration?"
	tex_q_install="Script /usr/bin/setfreq.sh not found. It requires administrator permissions. ¿Install?"
	tex_install="Install"
	tex_ok="O.K."
	tex_yes="Yes"
	tex_cancel="Cancel"
	tex_no="No"
	tex_select="Select"
	tex_create="Create"
	tex_none="None"
	tex_t_delay="Delay (s)"
	tex_delay="Time waiting for start the srcipt: "
	tex_t_time="Time (s)"
	tex_time="Time running the srcipt: "
	tex_t_maxt="Max temperature (ºC)"
	tex_temp="Temperature to start reducing frequency: "
	tex_t_nort="Normal temperature (ºC): "
	tex_nort="Temperature to start increasing frequency: "
	tex_t_notif="Notifications"
	tex_notif="Do tou want desktop notifications?"
	tex_t_logfile="Log file"
	tex_logfile="Select a file or create a new one?"
	tex_logfile_location="Location of new file: "
	tex_logfile_route="Write the route: "
	tex_t_logfile_size="Size (rows)"
	tex_logfile_size="Maximum size, in rows, for the log file: "
	tex_newsession="New session"
	tex_max="Max: "
	tex_now="Now: "
	tex_decrease="Action: Decrease"
	tex_decreasing="Decreassing maximun frequency: "
	tex_increase="Action: Increase"
	tex_increasing="Increassing maximun frequency: "
	tex_gov_avail="Available governors:"
	tex_q_gov="Chose the dessired governor:"
	tex_cur_gov="Current governor is"
	tex_new_gov="Write the name for the new governor"

	# Help:
	tex_help="
		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 for each event.

		List of valid parameters:
		\n	-d <seconds> \t Delay before executing the sript.
		\n	-t <seconds> \t Time in seconds running the script. If 0, the script will never stop.
		\n	-p <governor> \t Power governor (use [-p list] to select from a list)
		\n	-l <ºC> \t Maximum dessired temperature.
		\n	-r <ºC> \t Minimum temperature to increase frequency.
		\n	-f <file> \t File used as log.
		\n	-s <size> \t Maximum size, in rows, for the log file.
		\n	-n <yes | no> \t Enable or disable desktop notifiacions.
		\n	-g \t Disable GUI dialogs.
		\n\n	Example: Limit frequency when the temperature is 85ºC, restore it when temperature is below 75ºC and show desktop notifications:
		\n\n	./temperature.sh -l 85 -r 75 -n yes
		\n\n	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), disable GUI dialogs and log the changes in <HOME>/temper.txt:
		\n\n	./tepmerature.sh -l 70 -r 50 -d 30 -t 300 -g -f ~/temper.txt
	"
	
	;;
esac

# Testing for needed tools:
sensors 2> /dev/stdout > /dev/null
if [ $? == 1 ]; then
	echo $text_exiting
	exit
fi

nvidia-smi > /dev/null 2> /dev/null
if [ $? == 0 ]; then
	nv=1
else
	nv=0
	t_gpu="NA"
fi


# Special argument: if /usr/bin/setfreq.sh is not present, it creates them and stablishes permissions:
if [ "$1" == "install" ]; then
	echo -e '#!/bin/bash\n# -*- ENCODING: UTF-8 -*-\n\n# Underclocker version '$version';\n# This script MUST be launched by root\n\n# Setting the governor:\nif [ "$1" == "governor" ]; then\n	a=$(cpupower frequency-set -g "$2")\n	[[ $? != 0 ]] && echo -e "Cpupower failed. Error: $a" && exit 1\n	[[ ! "$(cpupower frequency-info | grep -v cpufreq | grep $2 | cut -d\" -f2)" == "$2" ]] && echo "Governor change not setted. This script needs that governor to run." && exit 1\n	exit 0\nfi\n\n# Changing the max speed:\ncpupower -c $1 frequency-set -u $2 > /dev/null\nexit 0' > /usr/bin/setfreq.sh
	if [ $? == 1 ]; then
		echo "$txt_exit_permissions"
		exit
	fi
	chown root:root /usr/bin/setfreq.sh
	chmod 755 /usr/bin/setfreq.sh
	# This test if sudoers is configured, and configure it if not:
	if [ $(grep -c 'ALL ALL=(ALL) NOPASSWD: /usr/bin/setfreq.sh' /etc/sudoers) -eq 0 ]; then
		echo -e '\n# Users cat execude this with sudo without password:\nALL ALL=(ALL) NOPASSWD: /usr/bin/setfreq.sh' >> /etc/sudoers
	fi
	exit
fi

########### Functions ###########

# Size limit for logfile:
cutlog () {
	if [ $(wc -l < "$logfile") -gt $rows ]; then
		templog=$(tail -n $rows "$logfile")
		cat <<<"$templog" > "$logfile"
	fi
}

# Exit function. Reset the max frequency.
saliendo () {
	echo
	echo "$txt_exit_term"
	echo "$txt_tem_max$t_max_total" | tee -a "$logfile"
	cpunum=0
	for cpunum in $(seq 0 $cpus); do
		sudo /usr/bin/setfreq.sh $cpunum ${f_max[$cpunum]}
		[[ $? == 1 ]] && echo "Error on /usr/bin/setfreq.sh." && exit 1
	done
	exit
}

# Read maximum frequencies
read_f_max () {
	cpunum=0
	f_max=()
	while read line ; do
		f_max+=($line)
		f_newlimit[$cpunum]=${f_max[$cpunum]}
		((cpunum ++))
	done <<< $(cpupower -c all frequency-info -l | grep -v "analyzing" | cut -d\  -f 2)
}

# Read minimum frequencies
read_f_min () {
	cpunum=0
	f_min=()
	while read line ; do
		f_min+=($line)
		((cpunum ++))
	done <<< $(cpupower -c all frequency-info -l | grep -v "analyzing" | cut -d\  -f 1)
}

# Read current frequencies
read_f_cur () {
	f_cur=()
	while read line ; do
		f_cur+=($line)
	done <<< $(cpupower -c all frequency-info -f | grep -v "analyzing" | cut -d\  -f 6)
}


# Internal variables. Please, do not change.
t_cur=0
t_max_total=0

# Variables assigned by arguments:
if [[ $1 ]]; then
	if [ $1 == "-h" ] || [ $1 == "--help" ]; then
		echo -e "$tex_help"
		exit
	fi

# Reading arguments. Add "####" for priority over GUI diaglogs; it will be removed after that.
	while getopts d:t:p:l:r:f:s:n:g flag
	do
		case "${flag}" in
			d) delay=${OPTARG}"####";;
			t) seconds=${OPTARG}"####";;
			p) governor_arg=${OPTARG}"####";;
			l) t_limit=${OPTARG}"####";;
			r) t_normal=${OPTARG}"####";;
			f) logfile=${OPTARG}"####";;
			s) rows=${OPTARG}"####";;
			n) notif=${OPTARG}"####";;
			g) gui=false;;
			*) echo -e "$tex_help"
			exit;;
		esac
	done
fi

# Select governor from a list: 
if [[ $governor_arg == "list####" ]]; then
	cur_gov=$(cpupower frequency-info | grep -v cpufreq | grep "The governor" | cut -d \" -f 2)
	echo "$tex_gov_avail"
	gov_num=0
	while read -d" " line ; do
		echo $gov_num $line
		gov_avail+=($line)
		((gov_num++))
	done <<< $(cpupower frequency-info | grep governors | cut -d : -f 2 | cut -c 2-)
	for gov_selected in "${!gov_avail[@]}"; do
		[[ "${gov_avail[$gov_selected]}" = "$governor" ]] && break
	done
	echo "$tex_cur_gov $cur_gov"
	read -r -p "$tex_q_gov (0/$gov_num) (default: $gov_selected)" a
	[[ $a ]] && gov_selected=$a
	echo "$tex_cur_gov $gov_selected ${gov_avail[$gov_selected]}"
	governor="${gov_avail[$gov_selected]}""####"
elif [[ -n "$governor_arg" ]]; then
	governor="$governor_arg"
fi
unset governor_arg

# Active or disable notifications.
# Maximum priority are:
# 1º Must exist a desktop.
# 2º Argument from console ( -g ).
# 3º Default variable at the beggining of the script ( notif= ).
# 4º If not disabled yet, show a dialog to acivate or not.

if [ -z "$DISPLAY" ]; then
 	# There are no desktop.
	notif="no"
	gui=false
elif [ $gui == true ]; then
	# There are desktop and default gui variable is true
	zenity --question --text "$tex_q_gui" --no-wrap --ok-label "$tex_ok" --cancel-label "No" 2>/dev/null
	if [ $? == 0 ]; then
		gui=true
	else
		gui=false
	fi
fi


# AUTOINSTALLATION
# Test if the correct version of the superuser part of this script is installed. If not, it launches the script on installation mode.
if [ -z "$(grep "# Underclocker version $version;" /usr/bin/setfreq.sh)" ]; then
	if [ -z "$DISPLAY" ] || [ $gui == false ]; then
 		# There are no desktop, or GUI disabled.
		read -r -p "$tex_q_install (y/n)" a
		if [ "$a" == "y" ]; then
			sudo "$0" install
		else
			echo "$text_exiting"
			exit
		fi
		unset a
	else
		# GUI enabled.
		zenity --question --text "$tex_q_install" --no-wrap --ok-label "$tex_install" --cancel-label "$tex_cancel" 2>/dev/null
		if [ $? == 0 ]; then
			pkexec $0 install
		else
			exit
		fi
	fi
fi

# GUI: Setting variables not stablished by parameters:
if [ $gui == true ]; then
	if [[ $delay != *"####"* ]]; then
		delay=$(zenity --entry --title "$tex_t_delay" --text "$tex_delay" --entry-text="$delay") 2>/dev/null
	fi

	if [[ $seconds != *"####"* ]]; then
		seconds=$(zenity --entry --title "$tex_t_time" --text "$tex_time" --entry-text="$seconds") 2>/dev/null
	fi

	if [[ $governor != *"####"* ]]; then
		cur_gov=$(cpupower frequency-info | grep -v cpufreq | grep "The governor" | cut -d \" -f 2)
		gov_num=0
		while read -d" " line ; do
			gov_avail+=($line)
			((gov_num++))
		done <<< $(cpupower frequency-info | grep governors | cut -d : -f 2 | cut -c 2-)
		for gov_selected in "${!gov_avail[@]}"; do
			[[ "${gov_avail[$gov_selected]}" = "$governor" ]] && break
		done
		gov_avail+=("Write new governor")
		gov_selected=$(zenity --list --title "Governos" --text "$tex_cur_gov $cur_gov\nDefault: $governor\n$tex_q_gov" --column=Menu "${gov_avail[@]}" --height 370)
		if [[ "$gov_selected" == "Write new governor" ]]; then
			governor=$(zenity --entry --title "Governor" --text "$tex_new_gov" --entry-text="new") 2>/dev/null
		elif  [[ -n "$gov_selected" ]]; then
			governor="$gov_selected"
		fi
		unset gov_selected
	fi

	if [[ $t_limit != *"####"* ]]; then
		t_limit=$(zenity --entry --title "$tex_t_maxt" --text "$tex_temp" --entry-text="$t_limit") 2>/dev/null
	fi

	if [[ $t_normal != *"####"* ]]; then
		t_normal=$(zenity --entry --title "$tex_t_nort" --text "$tex_nort" --entry-text="$t_normal") 2>/dev/null
	fi
	
	if [[ $notif != *"####"* ]]; then
		zenity --question --title "$tex_t_notif" --text "$tex_notif" --no-wrap --ok-label "$tex_yes" --cancel-label "$tex_no" 2>/dev/null
		if [ $? == 0 ]; then
			notif="yes"
		else
			notif="no"
		fi
	fi

	if [[ "$logfile" != *"####"* ]]; then
		wlf=$(zenity --question --title "$tex_t_logfile" --text "$tex_logfile" --switch --extra-button "$tex_select" --extra-button "$tex_create" --extra-button "$tex_none") 2>/dev/null
		if [ "$wlf" = "$tex_select" ]; then
			logfile_gui=$(zenity --file-selection --text "$tex_logfile_location" --filename "${HOME}/") 2>/dev/null
			if [ $? == 0 ]; then
				logfile="$logfile_gui"
			fi
		elif [ "$wlf" = "$tex_create" ]; then
			logfile_gui=$(zenity --entry --title "$tex_t_logfile" --text "$tex_logfile_route" --entry-text="${HOME}/temp_log.txt") 2>/dev/null
			if [ $? == 0 ]; then
				logfile="$logfile_gui"
			fi
		else
			logfile=/dev/null
		fi
		unset wlf
	fi
	
	logfile=${logfile%"####"}
	if [[ $rows != *"####"* ]] && [[ "$logfile" != "/dev/null" ]]; then
		rows=$(zenity --entry --title "$tex_t_logfile_size" --text "$tex_logfile_size" --entry-text="$rows") 2>/dev/null
	fi

fi

# Cleaning variables:
		notif=${notif%"####"}
		delay=${delay%"####"}
		seconds=${seconds%"####"}
		governor=${governor%"####"}
		t_limit=${t_limit%"####"}
		t_normal=${t_normal%"####"}
		logfile=${logfile%"####"}
		rows=${rows%"####"}

# Change "~" to "${HOME}" to use the "/home/user" folder in redirections:
logfile=${logfile//\~/"${HOME}"}

# For unlimited execution:
if [ $seconds == 0 ]; then
	infinite=1
	seconds=1000
else
	infinite=0	
fi

echo -e "\n$(date)\n___________________ $tex_newsession ___________________" | tee -a "$logfile"
lines=0

cutlog


sleep $delay

# Setting the governor:
sudo /usr/bin/setfreq.sh governor $governor
[[ $? == 1 ]] && echo "Error on /usr/bin/setfreq.sh." && exit 1

# Obtain current, max and min frequency:
read_f_max
read_f_min
read_f_cur

# Contando núcleos:
cpus=$(cpupower -c all frequency-info -f | grep -c "analyzing")
((cpus --))

# Setting the current temperature to maximum:
for cpunum in $(seq 0 $cpus); do
	sudo /usr/bin/setfreq.sh $cpunum ${f_max[$cpunum]}
	[[ $? == 1 ]] && echo "Error on /usr/bin/setfreq.sh." && exit 1
done


trap saliendo 0

# ----------------------- 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)
	# Update maximum teperatura for this session
	if [ $t_cur -gt $t_max_total ]; then
		t_max_total=$t_cur
	fi
	
	# Decrease frequency when temperature is too high
	cpunum=0
	lim_reached=true
	for cpunum in $(seq 0 $cpus); do
		if [[ ${f_newlimit[$cpunum]} -gt ${f_min[$cpunum]} ]]; then
			lim_reached=false
			break
		fi
	done

	if [ $t_cur -gt $t_limit ] && [[ $lim_reached == false ]]; then
		# Decease frequency in proportion to excesive temperature
		diff=$((t_cur - t_limit))
		step=$((diff * 50000))
		step=$(( step > 400000 ? 400000 : step ))
		echo -e "$(date '+%y/%m/%d %H:%M:%S')\t$tex_decrease\t$tex_now$t_cur ºC\t$tex_max$t_max_total ºC\tGPU: $t_gpu ºC" | tee -a "$logfile"
		log_freq1=""
		log_freq2=""
		cpunum=0
		for cpunum in $(seq 0 $cpus); do
			if [ ${f_newlimit[$cpunum]} -gt ${f_min[$cpunum]} ]; then
			
				f_newlimit[$cpunum]=$((f_newlimit[$cpunum] - step))
				if [ ${f_newlimit[$cpunum]} -lt ${f_min[$cpunum]} ]; then
					f_newlimit[$cpunum]=${f_min[$cpunum]}
				fi
				sudo /usr/bin/setfreq.sh $cpunum ${f_newlimit[$cpunum]}
				[[ $? == 1 ]] && echo "Error on /usr/bin/setfreq.sh." && exit 1
			fi
			read_f_cur
			f_newlimit_cpunum=${f_newlimit[$cpunum]}
			f_cur_cpunum=${f_cur[$cpunum]}
			f_new_str[$cpunum]=$((f_newlimit_cpunum/1000))
			f_cur_str[$cpunum]=$((f_cur_cpunum/1000))
			[ $nv == 1 ] && t_gpu=$(nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader)
			log_freq1="$log_freq1 C$cpunum ${f_new_str[$cpunum]} "
			log_freq2="$log_freq2 C$cpunum ${f_cur_str[$cpunum]} "
			((cpunum ++))		
		done
		echo -e "$tex_max (Mhz)\t$log_freq1" | tee -a "$logfile"
		echo -e "$tex_now (Mhz)\t$log_freq2" | tee -a "$logfile"
		unset log_freq1 log_freq2
		cutlog
		((lines++))
		[ $notif == "yes" ] && notify-send "$tex_decreasing ${f_newlimit[0]}" 2>/dev/null
		sleep 4
		((seconds-=4))
	fi
	
	# Icrease frequency when temperature is acceptable
	cpunum=0
	lim_reached=true
	for cpunum in $(seq 0 $cpus); do
		if [[ ${f_newlimit[$cpunum]} -lt ${f_max[$cpunum]} ]]; then
			lim_reached=false
			break
		fi
	done
		
	if [ $t_cur -lt $t_normal ] && [[ $lim_reached == false ]]; then
		echo -e "$(date '+%y/%m/%d %H:%M:%S')\t$tex_increase\t$tex_now$t_cur ºC\t$tex_max$t_max_total ºC\tGPU: $t_gpu ºC" | tee -a "$logfile"
		cpunum=0
		for cpunum in $(seq 0 $cpus); do
			if [ ${f_newlimit[$cpunum]} -gt ${f_min[$cpunum]} ]; then
				f_newlimit[$cpunum]=$((${f_newlimit[$cpunum]} + 200000))
				if [ ${f_newlimit[$cpunum]} -gt ${f_max[$cpunum]} ]; then
					f_newlimit[$cpunum]=${f_max[$cpunum]}
				fi
				sudo /usr/bin/setfreq.sh $cpunum ${f_newlimit[$cpunum]}
				[[ $? == 1 ]] && echo "Error on /usr/bin/setfreq.sh." && exit 1
			fi
			read_f_cur
			f_newlimit_cpunum=${f_newlimit[$cpunum]}
			f_cur_cpunum=${f_cur[$cpunum]}
			f_new_str[$cpunum]=$((f_newlimit_cpunum/1000))
			f_cur_str[$cpunum]=$((f_cur_cpunum/1000))
			[ $nv == 1 ] && t_gpu=$(nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader)
			log_freq1="$log_freq1 C$cpunum ${f_new_str[$cpunum]} "
			log_freq2="$log_freq2 C$cpunum ${f_cur_str[$cpunum]} "
			((cpunum ++))		
		done
		echo -e "$tex_max (Mhz)\t$log_freq1" | tee -a "$logfile"
		echo -e "$tex_now (Mhz)\t$log_freq2" | tee -a "$logfile"
		unset log_freq1 log_freq2
		cutlog
		((lines++))
		[ $notif == "yes" ] && notify-send "$tex_increasing${f_newlimit[0]}" 2>/dev/null
		sleep 4
		((seconds-=4))
		
	fi


	sleep 1
	((seconds--))
	if [[ $infinite -eq 1 ]]; then
		seconds=1000
	fi
	
done

# Exiting
echo "$txt_exit_term"
echo "$txt_tem_max$t_max_total" | tee -a "$logfile"
saliendo
2 Me gusta

Nueva versión, con algunas correcciones:

  • Corregido un error que impedía volver a subir la fecuencia una vez ésta había llegado al mínimo. Introducido al empezar a usar cpupower, al comparar con -gt en lugar de con -ge. :man_facepalming:
  • Corregido un error al tomar por defecto un governor no disponible. Ahora, si detecta que el establecido por variable no existe, propone por defecto el que esté en uso.
  • Corregido un error por el que no se mostraba el último governor de los disponibles.

Versión 13:

undercocker.sh
#!/bin/bash
# -*- ENCODING: UTF-8 -*-

version=13

# Default variables. You can change it to run the script easily.
delay=0
seconds=0
t_limit=85
t_normal=75
logfile="/dev/null" # <- File used as log.
rows=250
notif="yes"
gui=true
governor=ondemand

# Test if the default governor is available
cur_gov=$(cpupower frequency-info | grep -v cpufreq | grep "The governor" | cut -d \" -f 2)
gov_num=0
governors_read=$(cpupower frequency-info | grep governors | cut -d : -f 2 | cut -c 2-)
# Make an array with the list of available governors
while read -d" " line ; do
	gov_avail+=($line)
	((gov_num++))
done <<< $(echo "$governors_read ")
	((gov_num--))
# Test each available governors to find a coincidence with de default
for gov_selected in "${!gov_avail[@]}"; do
	[[ "${gov_avail[$gov_selected]}" = "$governor" ]] && gov_exist=1 && break
done
# If the default governor is not available, it takes the current governor as default
if [[ -z $gov_exist ]]; then
	gov_selected=0
	for gov_selected in "${!gov_avail[@]}"; do
		[[ "${gov_avail[$gov_selected]}" = "$cur_gov" ]] && break
	done
	governor="${gov_avail[$gov_selected]}"
fi


# Languages
# locale | grep '^LANGUAGE=' | cut -d= -f2 | cut -d_ -f1
lang=$(locale | grep LANGUAGE= | cut -d= -f2 | cut -d_ -f1)
case $lang in

# SPANISH
	es)
	text_exiting="Saliendo..."
	txt_exit_permissions="Error. Compruebe permisos de escritura en /usr/bin. Saliendo..."
	txt_exit_term="Script terminado. Saliendo..."
	txt_tem_max="Temperatura máxima alcanzada: "
	tex_q_gui="¿Configuración gráfica?"
	tex_q_install="No se encontró el script /usr/bin/setfreq.sh Requiere permisos de administrador. ¿Instalar?"
	tex_install="Instalar"
	tex_ok="Vale"
	tex_yes="Sí"
	tex_cancel="Cancelar"
	tex_no="No"
	tex_select="Seleccionar"
	tex_create="Crear"
	tex_none="Ninguno"
	tex_t_delay="Retraso (s)"
	tex_delay="Tiempo antes de ejecutar el script: "
	tex_t_time="Tiempo (s)"
	tex_time="Tiempo ejecutando el script: "
	tex_t_maxt="Temperatura máxima (ºC)"
	tex_temp="Temperatura a la que reducir la frecuencia: "
	tex_t_nort="Temperatura normal (ºC): "
	tex_nort="Temperatura a la que subir la frecuencia: "
	tex_t_notif="Notificaciones"
	tex_notif="¿Desea notificationes de escritorio?"
	tex_t_logfile="Archivo log"
	tex_logfile="¿Seleccionar un archivo o crear uno nuevo?"
	tex_logfile_location="Ubicación del nuevo archivo: "
	tex_logfile_route="Escriba la ruta: "
	tex_t_logfile_size="Tamaño (líneas)"
	tex_logfile_size="Tamaño máximo, en líneas del archivo log: "
	tex_newsession="Nueva sesión"
	tex_max="Max: "
	tex_now="Ahora: "
	tex_decrease="Acción: Bajando "
	tex_decreasing="Bajando frecuencia máxima: "
	tex_increase="Acción: Subiendo "
	tex_increasing="Subiendo frecuencia máxima: "
	tex_gov_avail="Governors disponilbes:"
	tex_q_gov="Elija el governor deseado:"
	tex_cur_gov="El governor actual es"
	tex_new_gov="Escriba el nombre del nuevo governor"

	# Ayuda:
	tex_help="
		Este script monitoriza la temperatura de la CPU, reduce la frecuencia máxima cuando es muy alta y la aumenta cuando es suficientemente baja, y puede crear un log con sus acciones, temperaturas, fecuencias y fecha y hora. de cada evento.

		Lista de parámetros válidos:
		\n	-d <segundos> \t Retraso antes de ejecutar el script.
		\n	-t <segundos> \t Tiempo en segundos de ejecución del script. Si es 0, el script no parará.
		\n	-p <governor> \t Power governor (usar [-p list] para seleccionarlo de una lista)
		\n	-l <ºC> \t Temperatura máxima deseada.
		\n	-r <ºC> \t Temperatura mínima para aumentar la frecuencia.
		\n	-f <file> \t Archivo a usar como log.
		\n	-s <size> \t Tamaño máximo, en filas, del archivo de log.
		\n	-n <yes | no> \t Activar o desactivar notificaciones de escritorio.
		\n	-g \t Deshabilita la configuración gráfica.
		\n\n	Ejemplo: Limita la frecuencia cuando la temperatura llega a 85ºC, la restaura cuando la temperatura es menor de 75ºC y muestra notificaciones de escritorio:
		\n\n	./temperature.sh -l 85 -r 75 -n yes
		\n\n	Ejemplo: Limita la frecuencia cuando la temperatura llega a 70ºC, la restaura cuando la temperatura es menor de 50ºC, espera 30 segundos antes de ejecutar el script, se ejecuta durante 5 minutos (300 segundos), desactiva la confguración gráfica y guarda el log en <HOME>/temper.txt:
		\n\n	./tepmerature.sh -l 70 -r 50 -d 30 -t 300 -g -f ~/temper.txt
	"
	
	;;

# ENGLISH
	*)
	text_exiting="Exiting..."
	txt_exit_permissions="Error. Please, test permissions to write in /usr/bin. Exiting..."
	txt_exit_term="Script terminated. Exiting"
	txt_tem_max="Maximum temperature reached: "
	tex_q_gui="Graphical configuration?"
	tex_q_install="Script /usr/bin/setfreq.sh not found. It requires administrator permissions. ¿Install?"
	tex_install="Install"
	tex_ok="O.K."
	tex_yes="Yes"
	tex_cancel="Cancel"
	tex_no="No"
	tex_select="Select"
	tex_create="Create"
	tex_none="None"
	tex_t_delay="Delay (s)"
	tex_delay="Time waiting for start the srcipt: "
	tex_t_time="Time (s)"
	tex_time="Time running the srcipt: "
	tex_t_maxt="Max temperature (ºC)"
	tex_temp="Temperature to start reducing frequency: "
	tex_t_nort="Normal temperature (ºC): "
	tex_nort="Temperature to start increasing frequency: "
	tex_t_notif="Notifications"
	tex_notif="Do tou want desktop notifications?"
	tex_t_logfile="Log file"
	tex_logfile="Select a file or create a new one?"
	tex_logfile_location="Location of new file: "
	tex_logfile_route="Write the route: "
	tex_t_logfile_size="Size (rows)"
	tex_logfile_size="Maximum size, in rows, for the log file: "
	tex_newsession="New session"
	tex_max="Max: "
	tex_now="Now: "
	tex_decrease="Action: Decrease"
	tex_decreasing="Decreassing maximun frequency: "
	tex_increase="Action: Increase"
	tex_increasing="Increassing maximun frequency: "
	tex_gov_avail="Available governors:"
	tex_q_gov="Chose the dessired governor:"
	tex_cur_gov="Current governor is"
	tex_new_gov="Write the name for the new governor"

	# Help:
	tex_help="
		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 for each event.

		List of valid parameters:
		\n	-d <seconds> \t Delay before executing the sript.
		\n	-t <seconds> \t Time in seconds running the script. If 0, the script will never stop.
		\n	-p <governor> \t Power governor (use [-p list] to select from a list)
		\n	-l <ºC> \t Maximum dessired temperature.
		\n	-r <ºC> \t Minimum temperature to increase frequency.
		\n	-f <file> \t File used as log.
		\n	-s <size> \t Maximum size, in rows, for the log file.
		\n	-n <yes | no> \t Enable or disable desktop notifiacions.
		\n	-g \t Disable GUI dialogs.
		\n\n	Example: Limit frequency when the temperature is 85ºC, restore it when temperature is below 75ºC and show desktop notifications:
		\n\n	./temperature.sh -l 85 -r 75 -n yes
		\n\n	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), disable GUI dialogs and log the changes in <HOME>/temper.txt:
		\n\n	./tepmerature.sh -l 70 -r 50 -d 30 -t 300 -g -f ~/temper.txt
	"
	
	;;
esac

# Testing for needed tools:
sensors 2> /dev/stdout > /dev/null
if [ $? == 1 ]; then
	echo $text_exiting
	exit
fi

nvidia-smi > /dev/null 2> /dev/null
if [ $? == 0 ]; then
	nv=1
else
	nv=0
	t_gpu="NA"
fi


# Special argument: if /usr/bin/setfreq.sh is not present, it creates them and stablishes permissions:
if [ "$1" == "install" ]; then
	echo -e '#!/bin/bash\n# -*- ENCODING: UTF-8 -*-\n\n# Underclocker version '$version';\n# This script MUST be launched by root\n\n# Setting the governor:\nif [ "$1" == "governor" ]; then\n	a=$(cpupower frequency-set -g "$2")\n	[[ $? != 0 ]] && echo -e "Cpupower failed. Error: $a" && exit 1\n	[[ ! "$(cpupower frequency-info | grep -v cpufreq | grep $2 | cut -d\" -f2)" == "$2" ]] && echo "Governor change not setted. This script needs that governor to run." && exit 1\n	exit 0\nfi\n\n# Changing the max speed:\ncpupower -c $1 frequency-set -u $2 > /dev/null\nexit 0' > /usr/bin/setfreq.sh
	if [ $? == 1 ]; then
		echo "$txt_exit_permissions"
		exit
	fi
	chown root:root /usr/bin/setfreq.sh
	chmod 755 /usr/bin/setfreq.sh
	# This test if sudoers is configured, and configure it if not:
	if [ $(grep -c 'ALL ALL=(ALL) NOPASSWD: /usr/bin/setfreq.sh' /etc/sudoers) -eq 0 ]; then
		echo -e '\n# Users cat execude this with sudo without password:\nALL ALL=(ALL) NOPASSWD: /usr/bin/setfreq.sh' >> /etc/sudoers
	fi
	exit
fi

########### Functions ###########

# Size limit for logfile:
cutlog () {
	if [ $(wc -l < "$logfile") -gt $rows ]; then
		templog=$(tail -n $rows "$logfile")
		cat <<<"$templog" > "$logfile"
	fi
}

# Exit function. Reset the max frequency.
saliendo () {
	echo
	echo "$txt_exit_term"
	echo "$txt_tem_max$t_max_total" | tee -a "$logfile"
	cpunum=0
	for cpunum in $(seq 0 $cpus); do
		sudo /usr/bin/setfreq.sh $cpunum ${f_max[$cpunum]}
		[[ $? == 1 ]] && echo "Error on /usr/bin/setfreq.sh." && exit 1
	done
	exit
}

# Read maximum frequencies
read_f_max () {
	cpunum=0
	f_max=()
	while read line ; do
		f_max+=($line)
		f_newlimit[$cpunum]=${f_max[$cpunum]}
		((cpunum ++))
	done <<< $(cpupower -c all frequency-info -l | grep -v "analyzing" | cut -d\  -f 2)
}

# Read minimum frequencies
read_f_min () {
	cpunum=0
	f_min=()
	while read line ; do
		f_min+=($line)
		((cpunum ++))
	done <<< $(cpupower -c all frequency-info -l | grep -v "analyzing" | cut -d\  -f 1)
}

# Read current frequencies
read_f_cur () {
	f_cur=()
	while read line ; do
		f_cur+=($line)
	done <<< $(cpupower -c all frequency-info -f | grep -v "analyzing" | cut -d\  -f 6)
}


# Internal variables. Please, do not change.
t_cur=0
t_max_total=0

# Variables assigned by arguments:
if [[ $1 ]]; then
	if [ $1 == "-h" ] || [ $1 == "--help" ]; then
		echo -e "$tex_help"
		exit
	fi

# Reading arguments. Add "####" for priority over GUI diaglogs; it will be removed after that.
	while getopts d:t:p:l:r:f:s:n:g flag
	do
		case "${flag}" in
			d) delay=${OPTARG}"####";;
			t) seconds=${OPTARG}"####";;
			p) governor_arg=${OPTARG}"####";;
			l) t_limit=${OPTARG}"####";;
			r) t_normal=${OPTARG}"####";;
			f) logfile=${OPTARG}"####";;
			s) rows=${OPTARG}"####";;
			n) notif=${OPTARG}"####";;
			g) gui=false;;
			*) echo -e "$tex_help"
			exit;;
		esac
	done
fi

# Select governor from a list: 
if [[ $governor_arg == "list####" ]]; then
	# Show a list of available governors
	for line in $(seq 0 $gov_num); do
		echo $line ${gov_avail[$line]}
	done
	# Ask user for the dessired governor
	echo "$tex_cur_gov $cur_gov"
	read -r -p "$tex_q_gov (0/$gov_num) (default: $gov_selected)" a
	[[ $a ]] && gov_selected=$a
	echo "$tex_cur_gov $gov_selected ${gov_avail[$gov_selected]}"
	governor="${gov_avail[$gov_selected]}""####"
elif [[ -n "$governor_arg" ]]; then
	governor="$governor_arg"
fi
unset governor_arg

# Active or disable notifications.
# Maximum priority are:
# 1º Must exist a desktop.
# 2º Argument from console ( -g ).
# 3º Default variable at the beggining of the script ( notif= ).
# 4º If not disabled yet, show a dialog to acivate or not.

if [ -z "$DISPLAY" ]; then
 	# There are no desktop.
	notif="no"
	gui=false
elif [ $gui == true ]; then
	# There are desktop and default gui variable is true
	zenity --question --text "$tex_q_gui" --no-wrap --ok-label "$tex_ok" --cancel-label "No" 2>/dev/null
	if [ $? == 0 ]; then
		gui=true
	else
		gui=false
	fi
fi


# AUTOINSTALLATION
# Test if the correct version of the superuser part of this script is installed. If not, it launches the script on installation mode.
if [ -z "$(grep "# Underclocker version $version;" /usr/bin/setfreq.sh)" ]; then
	if [ -z "$DISPLAY" ] || [ $gui == false ]; then
 		# There are no desktop, or GUI disabled.
		read -r -p "$tex_q_install (y/n)" a
		if [ "$a" == "y" ]; then
			sudo "$0" install
		else
			echo "$text_exiting"
			exit
		fi
		unset a
	else
		# GUI enabled.
		zenity --question --text "$tex_q_install" --no-wrap --ok-label "$tex_install" --cancel-label "$tex_cancel" 2>/dev/null
		if [ $? == 0 ]; then
			pkexec $0 install
		else
			exit
		fi
	fi
fi

# GUI: Setting variables not stablished by parameters:
if [ $gui == true ]; then
	if [[ $delay != *"####"* ]]; then
		delay=$(zenity --entry --title "$tex_t_delay" --text "$tex_delay" --entry-text="$delay") 2>/dev/null
	fi

	if [[ $seconds != *"####"* ]]; then
		seconds=$(zenity --entry --title "$tex_t_time" --text "$tex_time" --entry-text="$seconds") 2>/dev/null
	fi

	# Select governor from a list: 
	if [[ $governor != *"####"* ]]; then
		gov_avail+=("Write new governor")
		# Ask user for the dessired governor
		gov_selected=$(zenity --list --title "Governors" --text "$tex_cur_gov $cur_gov\nDefault: $governor\n$tex_q_gov" --column=Menu "${gov_avail[@]}" --height 370)
		if [[ "$gov_selected" == "Write new governor" ]]; then
			governor=$(zenity --entry --title "Governor" --text "$tex_new_gov" --entry-text="new") 2>/dev/null
		elif  [[ -n "$gov_selected" ]]; then
			governor="$gov_selected"
		fi
		unset gov_selected
	fi

	if [[ $t_limit != *"####"* ]]; then
		t_limit=$(zenity --entry --title "$tex_t_maxt" --text "$tex_temp" --entry-text="$t_limit") 2>/dev/null
	fi

	if [[ $t_normal != *"####"* ]]; then
		t_normal=$(zenity --entry --title "$tex_t_nort" --text "$tex_nort" --entry-text="$t_normal") 2>/dev/null
	fi
	
	if [[ $notif != *"####"* ]]; then
		zenity --question --title "$tex_t_notif" --text "$tex_notif" --no-wrap --ok-label "$tex_yes" --cancel-label "$tex_no" 2>/dev/null
		if [ $? == 0 ]; then
			notif="yes"
		else
			notif="no"
		fi
	fi

	if [[ "$logfile" != *"####"* ]]; then
		wlf=$(zenity --question --title "$tex_t_logfile" --text "$tex_logfile" --switch --extra-button "$tex_select" --extra-button "$tex_create" --extra-button "$tex_none") 2>/dev/null
		if [ "$wlf" = "$tex_select" ]; then
			logfile_gui=$(zenity --file-selection --text "$tex_logfile_location" --filename "${HOME}/") 2>/dev/null
			if [ $? == 0 ]; then
				logfile="$logfile_gui"
			fi
		elif [ "$wlf" = "$tex_create" ]; then
			logfile_gui=$(zenity --entry --title "$tex_t_logfile" --text "$tex_logfile_route" --entry-text="${HOME}/temp_log.txt") 2>/dev/null
			if [ $? == 0 ]; then
				logfile="$logfile_gui"
			fi
		else
			logfile=/dev/null
		fi
		unset wlf
	fi
	
	logfile=${logfile%"####"}
	if [[ $rows != *"####"* ]] && [[ "$logfile" != "/dev/null" ]]; then
		rows=$(zenity --entry --title "$tex_t_logfile_size" --text "$tex_logfile_size" --entry-text="$rows") 2>/dev/null
	fi

fi

# Cleaning variables:
		notif=${notif%"####"}
		delay=${delay%"####"}
		seconds=${seconds%"####"}
		governor=${governor%"####"}
		t_limit=${t_limit%"####"}
		t_normal=${t_normal%"####"}
		logfile=${logfile%"####"}
		rows=${rows%"####"}

# Change "~" to "${HOME}" to use the "/home/user" folder in redirections:
logfile=${logfile//\~/"${HOME}"}

# For unlimited execution:
if [ $seconds == 0 ]; then
	infinite=1
	seconds=1000
else
	infinite=0	
fi

echo -e "\n$(date)\n___________________ $tex_newsession ___________________" | tee -a "$logfile"
lines=0

cutlog

sleep $delay

# Setting the governor:
sudo /usr/bin/setfreq.sh governor $governor
[[ $? == 1 ]] && echo "Error on /usr/bin/setfreq.sh." && exit 1

# Obtain current, max and min frequency:
read_f_max
read_f_min
read_f_cur

# Contando núcleos:
cpus=$(cpupower -c all frequency-info -f | grep -c "analyzing")
((cpus --))

# Setting the current temperature to maximum:
for cpunum in $(seq 0 $cpus); do
	sudo /usr/bin/setfreq.sh $cpunum ${f_max[$cpunum]}
	[[ $? == 1 ]] && echo "Error on /usr/bin/setfreq.sh." && exit 1
done

trap saliendo 0

# ----------------------- 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)
	# Update maximum teperatura for this session
	if [ $t_cur -gt $t_max_total ]; then
		t_max_total=$t_cur
	fi
	
	# Decrease frequency when temperature is too high
	cpunum=0
	lim_reached=true
	for cpunum in $(seq 0 $cpus); do
		if [[ ${f_newlimit[$cpunum]} -gt ${f_min[$cpunum]} ]]; then
			lim_reached=false
			break
		fi
	done

	if [ $t_cur -gt $t_limit ] && [[ $lim_reached == false ]]; then
		# Decease frequency in proportion to excesive temperature
		diff=$((t_cur - t_limit))
		step=$((diff * 50000))
		step=$(( step > 400000 ? 400000 : step ))
		echo -e "$(date '+%y/%m/%d %H:%M:%S')\t$tex_decrease\t$tex_now$t_cur ºC\t$tex_max$t_max_total ºC\tGPU: $t_gpu ºC" | tee -a "$logfile"
		log_freq1=""
		log_freq2=""
		cpunum=0
		for cpunum in $(seq 0 $cpus); do
			if [ ${f_newlimit[$cpunum]} -gt ${f_min[$cpunum]} ]; then
			
				f_newlimit[$cpunum]=$((f_newlimit[$cpunum] - step))
				if [ ${f_newlimit[$cpunum]} -lt ${f_min[$cpunum]} ]; then
					f_newlimit[$cpunum]=${f_min[$cpunum]}
				fi
				sudo /usr/bin/setfreq.sh $cpunum ${f_newlimit[$cpunum]}
				[[ $? == 1 ]] && echo "Error on /usr/bin/setfreq.sh." && exit 1
			fi
			read_f_cur
			f_newlimit_cpunum=${f_newlimit[$cpunum]}
			f_cur_cpunum=${f_cur[$cpunum]}
			f_new_str[$cpunum]=$((f_newlimit_cpunum/1000))
			f_cur_str[$cpunum]=$((f_cur_cpunum/1000))
			[ $nv == 1 ] && t_gpu=$(nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader)
			log_freq1="$log_freq1 C$cpunum ${f_new_str[$cpunum]} "
			log_freq2="$log_freq2 C$cpunum ${f_cur_str[$cpunum]} "
			((cpunum ++))		
		done
		echo -e "$tex_max (Mhz)\t$log_freq1" | tee -a "$logfile"
		echo -e "$tex_now (Mhz)\t$log_freq2" | tee -a "$logfile"
		unset log_freq1 log_freq2
		cutlog
		((lines++))
		[ $notif == "yes" ] && notify-send "$tex_decreasing ${f_newlimit[0]}" 2>/dev/null
		sleep 4
		((seconds-=4))
	fi
	
	# Icrease frequency when temperature is acceptable
	cpunum=0
	lim_reached=true
	for cpunum in $(seq 0 $cpus); do
		if [[ ${f_newlimit[$cpunum]} -lt ${f_max[$cpunum]} ]]; then
			lim_reached=false
			break
		fi
	done
		
	if [ $t_cur -lt $t_normal ] && [[ $lim_reached == false ]]; then
		echo -e "$(date '+%y/%m/%d %H:%M:%S')\t$tex_increase\t$tex_now$t_cur ºC\t$tex_max$t_max_total ºC\tGPU: $t_gpu ºC" | tee -a "$logfile"
		cpunum=0
		for cpunum in $(seq 0 $cpus); do
			if [ ${f_newlimit[$cpunum]} -ge ${f_min[$cpunum]} ]; then
				f_newlimit[$cpunum]=$((${f_newlimit[$cpunum]} + 200000))
				if [ ${f_newlimit[$cpunum]} -gt ${f_max[$cpunum]} ]; then
					f_newlimit[$cpunum]=${f_max[$cpunum]}
				fi
				sudo /usr/bin/setfreq.sh $cpunum ${f_newlimit[$cpunum]}
				[[ $? == 1 ]] && echo "Error on /usr/bin/setfreq.sh." && exit 1
			fi
			read_f_cur
			f_newlimit_cpunum=${f_newlimit[$cpunum]}
			f_cur_cpunum=${f_cur[$cpunum]}
			f_new_str[$cpunum]=$((f_newlimit_cpunum/1000))
			f_cur_str[$cpunum]=$((f_cur_cpunum/1000))
			[ $nv == 1 ] && t_gpu=$(nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader)
			log_freq1="$log_freq1 C$cpunum ${f_new_str[$cpunum]} "
			log_freq2="$log_freq2 C$cpunum ${f_cur_str[$cpunum]} "
			((cpunum ++))		
		done
		echo -e "$tex_max (Mhz)\t$log_freq1" | tee -a "$logfile"
		echo -e "$tex_now (Mhz)\t$log_freq2" | tee -a "$logfile"
		unset log_freq1 log_freq2
		cutlog
		((lines++))
		[ $notif == "yes" ] && notify-send "$tex_increasing${f_newlimit[0]}" 2>/dev/null
		sleep 4
		((seconds-=4))
		
	fi


	sleep 1
	((seconds--))
	if [[ $infinite -eq 1 ]]; then
		seconds=1000
	fi
	
done

# Exiting
echo "$txt_exit_term"
echo "$txt_tem_max$t_max_total" | tee -a "$logfile"
saliendo
2 Me gusta