Как запускать или убивать задачи, когда температура ядра поднимается выше / ниже определенного значения?

Я хотел бы написать короткий скрипт, который запускается вручную один раз, а затем должен:

  • запустить команду, если все температуры ниже 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

Как пользоваться

  1. Скопируйте скрипт в пустой файл, сохраните его как temp_run.py
  2. Запустите его, лучше всего до запуска процесса (скрипт запустит процесс), с (впоследствии) 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)"
Другие вопросы по тегам