Как запускать или убивать задачи, когда температура ядра поднимается выше / ниже определенного значения?
Я хотел бы написать короткий скрипт, который запускается вручную один раз, а затем должен:
- запустить команду, если все температуры ниже
x
° С. - приостановить команду, если температура поднимется выше
y
° С. - продолжить команду, как только все температуры упадут ниже
x
° С снова.
Конечно это x°C < y°C
,
Я могу получить значения температуры, например, через sensors
команда:
$ sensors | grep °C
temp1: +68.0°C (crit = +95.0°C)
Core 0: +68.0°C (high = +80.0°C, crit = +90.0°C)
Core 2: +67.0°C (high = +80.0°C, crit = +90.0°C)
Скрипт должен быть постоянно отключен, например, через killall scriptname
, Если это не сработает с вашим решением (например, потому что оно будет регистрировать любые запланированные события для опроса температуры), мне нужна отдельная команда для его выхода.
Как я могу написать этот скрипт?
3 ответа
Этот скрипт будет влиять на все дерево процессов, внедренное в процесс, запущенный в нем.
Вы можете легко проверить это, запустив его в терминале и проверив температуру в другом терминале, используя watch -n 1 'sensors -u | grep -Po "^ temp[0-9]+_input: \K.*"'
,
В этом примере пороговые значения установлены на 50
а также 75
и процесс запуска stress -c 3
: они жестко запрограммированы в сценарии, но сценарий легко изменить, чтобы прочитать их из аргументов.
Как только все температуры будут ниже 50° С stress
начнет; пока все температуры будут оставаться ниже 75°C stress
будет продолжать; как только одна температура станет выше 75°C stress
остановится; как только все температуры снова будут ниже 50°C stress
продолжим снова:
#!/bin/bash
function n_t_exceeding {
sensors -u | awk -v x=0 -v temp=$1 '$1~/^temp[0-9]+_input:/{if($2 > temp){x++}}END{print x}'
}
set -m # Enables job control
mintemp=50 # First threshold
maxtemp=75 # Second threshold
while true; do
if [ $(n_t_exceeding $mintemp) -eq 0 ]; then
stress -c 3 & pid=$! # Starts the process, backgrounds it and stores the process' PID
printf 'Started\n'
break
fi
sleep 1 & wait $!
done
trap 'pkill -g $pid; exit' 2 # Upon SIGINT, sends SIGTERM to the process group and exits
while true; do
if [ $(n_t_exceeding $maxtemp) -gt 0 ]; then
pkill -19 -g $pid # Sends SIGSTOP to the process group
printf 'Stopped\n'
while true; do
if [ $(n_t_exceeding $mintemp) -eq 0 ]; then
pkill -18 -g $pid # Sends SIGCONT to the process group
printf 'Resumed\n'
break
fi
sleep 1 & wait $!
done
fi
sleep 1 & wait $!
done
function n_t_exceeding { sensors -u | awk -v x=0 -v temp=$1 '$1~/^temp[0-9]+_input:/{if($2 > temp){x++}}END{print x}'; }
анализирует выводsensors -u
и печатает количество температур выше$1
(который является первым аргументом, переданным функции):% sensors -u acpitz-virtual-0 Adapter: Virtual device temp1: temp1_input: 45.000 temp1_crit: 108.000 asus-isa-0000 Adapter: ISA adapter cpu_fan: fan1_input: 2200.000 temp1: temp1_input: 45.000 coretemp-isa-0000 Adapter: ISA adapter Physical id 0: temp1_input: 47.000 temp1_max: 87.000 temp1_crit: 105.000 temp1_crit_alarm: 0.000 Core 0: temp2_input: 46.000 temp2_max: 87.000 temp2_crit: 105.000 temp2_crit_alarm: 0.000 Core 1: temp3_input: 47.000 temp3_max: 87.000 temp3_crit: 105.000 temp3_crit_alarm: 0.000 % sensors -u | awk -v x=0 -v temp=46 '$1~/^temp[0-9]+_input:/{if($2 > temp){x++}}END{print x}' 2
set -m
позволяет контролировать работу;mintemp=50; maxtemp=75
наборы$mintemp
а также$maxtemp
в50
а также75
соответственно; это пороги 1), ниже которых процесс должен начинаться в первый раз и продолжаться снова после превышения$maxtemp
2) выше которого процесс должен остановиться;trap 'pkill -g $pid; exit' 2
гарантирует, что сценарий завершит все процессы в группе процессов и завершится после нажатия CTRL+C;Первый
while
петля бездействует до тех пор, пока число температур не превысит$mintemp
является0
; когда число температур превышает$mintemp
является0
запускает процесс, помещает его в фоновый режим и выходит из цикла;Второй
while
петля бездействует до тех пор, пока число температур не превысит$maxtemp
больше чем0
; когда число температур превышает$maxtemp
больше чем0
отправляет SIGSTOP в группу процессов и запускает третийwhile
петля; третийwhile
петля бездействует до тех пор, пока число температур не превысит$mintemp
является0
; когда число температур превышает$mintemp
является0
отправляет SIGCONT в группу процессов и выходит из цикла.
Это может сработать:
#!/bin/bash
targettemp=90
started=1
COMMAND &
trap "kill COMMAND; exit" SIGINT SIGTERM
while true
do
currenttemp=$(sensors -u | awk '/temp1_input/ {print $2; exit}' )
compare=$(echo $currenttemp'>'$targettemp | bc -l)
if [ "$compare" -eq 1 ] && [ "$started" -eq 1 ]
then
started=0
kill -STOP COMMAND
fi
if [ "$compare" -eq 0 ] && [ "$started" -eq 0 ]
then
started=1
kill -CONT COMMAND
fi
sleep 1 & wait $!
done
Это позволит получить текущий результат "temp1" от датчиков, обрезать любые другие символы, которые ему не нужны, чтобы bash мог видеть его как число, а затем сравнить его с любой целевой температурой, которую вы установили.
Мое рассуждение за все добавление "NR+1000", а затем grep 1001
потому что у вас может быть два результата "temp1" в sensors
как я сделал. Это своего рода бред, но это работает.
Затем, когда вы хотите убить его, просто killall script.sh
,
sleep 1
линия заключается в том, чтобы избежать чрезмерного потребления ресурсов процессора из-за ожидания ожидания. Вы можете изменить это на любой sleep duration
Вам нравится, если вы хотите опрашивать только температуру так часто.
Сценарий
#!/usr/bin/env python3
import subprocess
import time
import sys
low = int(sys.argv[1]); high = int(sys.argv[2]); command = sys.argv[3:]; proc = command[0]
def get_temps():
data = subprocess.check_output("sensors").decode("utf-8").splitlines()
return sum([[float(l.split(":")[1].split()[0].replace("+", "").replace("°C", "")) \
for l in data if l.startswith(mark)]for mark in ["temp1", "Core"]], [])
def manage_start():
try:
pid = subprocess.check_output(["pgrep", proc]).decode("utf-8").strip()
subprocess.Popen(["killall", "-s", "CONT", proc])
except subprocess.CalledProcessError:
subprocess.Popen(["/bin/bash", "-c", (" ").join(command)])
run = False
while True:
time.sleep(1)
if run == False:
if all([n < low for n in get_temps()]):
manage_start(); run = True
elif run == True:
if not all([n < high for n in get_temps()]):
subprocess.Popen(["killall", "-s", "STOP", proc]); run = False
Как пользоваться
- Скопируйте скрипт в пустой файл, сохраните его как
temp_run.py
Запустите его, лучше всего до запуска процесса (скрипт запустит процесс), с (впоследствии)
low_temp
,high_temp
,process_name
и возможные аргументы, как аргументы. Я проверил это, например, с:python3 /path/to/temp_run.py 60 80 gedit /path/to/file.txt
(используя другой текстовый редактор для изменения чисел)
Как я это проверял
Поскольку у меня нет разнообразия в реальной температуре, в скрипте я заменил функцию get_temps()
, с помощью функции чтения чисел из текстового файла.
Таким образом, "подпитывая" скрипт виртуальными температурами, он сделал свою работу без ошибок: остановился выше "высокого" во время работы, возобновил ниже "низкого" во время паузы.
Как это устроено
Когда скрипт запускается
- он проверяет, все ли температуры ниже нижнего порога.
- Если это так, он либо запускает процесс, либо возобновляет его, если он уже выполняется, и устанавливает переменную:
run = True
- В результате, следующий тест заключается в том, что если все температуры ниже максимального порога, если нет, процесс приостанавливается, сценарий устанавливает:
run = False
, делая следующий тест, если все температуры ниже самого низкого и так далее...
Как убить это
Сценарий может быть убит
kill "$(pgrep -f temp_run.py)"