Files
gpu-fan-ctrl/scripts/gpu_fan_ctrl.sh
T

114 lines
3.2 KiB
Bash

#!/bin/bash
# GPU Fan Controller — Delta QFR1212GHE (1 или 2 Tesla V100)
# Режимы: 2=STANDBY(<25), 3=LOW(<30), 4=MED(<35), 5=HIGH(<40), 6=FULL(>45 или burst)
# Режим 1 (STOP) — не используется, фан всегда крутится минимум на standby.
# Если 2 карты: берём max(temp0, temp1) для логики. Burst проверяется по каждой карте отдельно.
LOG=/home/romanown/gpu_fan.log
DEV=/dev/ttyUSB0
stty -F "$DEV" 115200
exec 3>"$DEV"
exec 1>>"$LOG" 2>&1
# Пороги
TH_COLD=25
TH_LOW=30
TH_MED=35
TH_HIGH=40
TH_BURST=45
TH_BURST_ROISE=3
BURST_WINDOW=2
BURST_DURATION=120
# Хистерезис (мёртвая зона 2°)
HYST=2
prevTemp=0
prevTime=0
burstTimer=0
lastMode=0
noDataCount=0
gpuCount=0
echo "[START] $(date) GPU Fan Ctrl PID=$$"
while true; do
# Определяем количество GPU и читаем все температуры
ALLTEMP=$(nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader | tr -cd '0-9\n')
now=$(date +%s)
gpuCount=0
maxTemp=0
burstTriggered=0
while IFS= read -r t; do
[ -z "$t" ] && continue
[ "$t" -lt 0 ] 2>/dev/null && continue
gpuCount=$((gpuCount + 1))
if [ "$t" -gt "$maxTemp" ]; then maxTemp=$t; fi
# Burst по каждой карте отдельно
if [ $prevTime -gt 0 ] && [ $((prevTime != 0 ? now - prevTime : 99999)) -le $BURST_WINDOW ]; then
rise=$((t - prevTemp))
if [ $rise -ge $TH_BURST_ROISE ]; then
burstTriggered=1
echo "[BURST-rise] GPU${gpuCount}: rise=$rise°C in $((now-prevTime))s → mode 6"
fi
fi
prevTemp=$t # сохраняем для следующей итерации
done <<< "$ALLTEMP"
if [ $gpuCount -eq 0 ]; then
noDataCount=$((noDataCount + 1))
if [ $noDataCount -ge 10 ]; then
echo "[ERROR] nvidia-smi failed 10+ times, aborting"
exit 1
fi
sleep 1; continue
fi
noDataCount=0
TEMP=$maxTemp # берём max для логики
# Если в burst-режиме — держим режим 6
if [ $burstTimer -gt 0 ]; then
burstTimer=$((burstTimer - 1))
if [ $lastMode -ne 6 ]; then
echo "[MODE 6] full speed (burst, ${burstTimer}s remain)"
lastMode=6
echo "6" >&3
fi
sleep 1; continue
fi
# Если burst истёк И temp >= TH_BURST — новый burst
if [ $TEMP -ge $TH_BURST ] || [ $burstTriggered -eq 1 ]; then
burstTimer=$BURST_DURATION
echo "[MODE 6] full speed (re-burst: $TEMP°C)"
lastMode=6; prevTemp=$TEMP; prevTime=$now
echo "6" >&3
sleep 1; continue
fi
# Обычная логика с хистерезисом
newMode=5 # default: HIGH (35-39)
if [ $TEMP -lt $((TH_COLD - HYST)) ]; then
newMode=2 # STANDBY (< 23)
elif [ $TEMP -lt $((TH_LOW - HYST)) ]; then
newMode=3 # LOW (< 28)
elif [ $TEMP -lt $((TH_MED - HYST)) ]; then
newMode=4 # MED (< 33)
fi
# Отправляем только если режим изменился
if [ $newMode -ne $lastMode ]; then
echo "[MODE $newMode] max_temp=$TEMP°C (gpuCount=$gpuCount) (hysteresis: no-change zone)"
lastMode=$newMode
echo "$newMode" >&3
fi
prevTime=$now
sleep 1
done