#!/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