diff --git a/README.md b/README.md index 8954cdb..ba9200a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # GPU Fan Controller — Delta QFR1212GHE -Автоматическое управление вентилятором на Tesla V100-PCIE-32GB по температуре GPU. +Автоматическое управление вентилятором на Tesla V100-PCIE-32GB (1 или 2 карты) по температуре GPU. +Вентилятор обдувает обе карты. Скрипт автоматически определяет количество карт и берёт max(temp) для логики. Burst по каждой карте отдельно. ## Подключение diff --git a/scripts/gpu_fan_ctrl.sh b/scripts/gpu_fan_ctrl.sh index 2f2c760..985aace 100644 --- a/scripts/gpu_fan_ctrl.sh +++ b/scripts/gpu_fan_ctrl.sh @@ -1,8 +1,8 @@ #!/bin/bash -# GPU Fan Controller — Delta QFR1212GHE +# 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. -# Порог burst: temp > 45°C ИЛИ рост >= 3°C за 2 секунды. +# Если 2 карты: берём max(temp0, temp1) для логики. Burst проверяется по каждой карте отдельно. LOG=/home/romanown/gpu_fan.log DEV=/dev/ttyUSB0 @@ -28,14 +28,37 @@ prevTime=0 burstTimer=0 lastMode=0 noDataCount=0 +gpuCount=0 echo "[START] $(date) GPU Fan Ctrl PID=$$" while true; do - TEMP=$(nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader -i 0 | tr -cd '0-9') + # Определяем количество 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 [ -z "$TEMP" ] || ! [ "$TEMP" -gt 0 ] 2>/dev/null; then + if [ $gpuCount -eq 0 ]; then noDataCount=$((noDataCount + 1)) if [ $noDataCount -ge 10 ]; then echo "[ERROR] nvidia-smi failed 10+ times, aborting" @@ -44,15 +67,8 @@ while true; do sleep 1; continue fi noDataCount=0 - - # Burst: temp rose TH_BURST_ROISE in BURST_WINDOW - if [ $prevTemp -gt 0 ] && [ $((prevTime != 0 ? now - prevTime : 99999)) -le $BURST_WINDOW ]; then - rise=$((TEMP - prevTemp)) - if [ $rise -ge $TH_BURST_ROISE ]; then - burstTimer=$BURST_DURATION - echo "[BURST-rise] rise=$rise°C in $((now-prevTime))s → mode 6" - fi - fi + + TEMP=$maxTemp # берём max для логики # Если в burst-режиме — держим режим 6 if [ $burstTimer -gt 0 ]; then @@ -62,12 +78,11 @@ while true; do lastMode=6 echo "6" >&3 fi - prevTemp=$TEMP; prevTime=$now sleep 1; continue fi # Если burst истёк И temp >= TH_BURST — новый burst - if [ $TEMP -ge $TH_BURST ]; then + 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 @@ -88,11 +103,11 @@ while true; do # Отправляем только если режим изменился if [ $newMode -ne $lastMode ]; then - echo "[MODE $newMode] temp=$TEMP°C (hysteresis: no-change zone)" + echo "[MODE $newMode] max_temp=$TEMP°C (gpuCount=$gpuCount) (hysteresis: no-change zone)" lastMode=$newMode echo "$newMode" >&3 fi - prevTemp=$TEMP; prevTime=$now + prevTime=$now sleep 1 done