Управление вентилятором Radeon RX-6xx0

Материал из ALT Linux Wiki

Введение

Столкнулся с проблемой перегрева видюхи RX-6700XT на игровых нагрузках — и не только её самой, поскольку она ведь и вокруг себя изрядно греет.

  • Процессор прямо над нею кипятится — мéста между видюхой, крышкой и стенками отнюдь не завались.
  • М2-накопитель посреди видюхи и проца тоже знатно подгорает — хоть и с радиатором, и от проц-кулера на него дует… горячим.
  • Дополнительным винчестерам в корзине, вставленной в пространство 5-дюймовых отсеков, жарко и душно.
  • Да и тем, что в нижних 3,5-дюймовых, ни разу не уютно.

До некоторой степени спасает вариант поставить (скорей, положить) перед открытой крышкой системника большой комнатный вентилятор — для всего, кроме самой видюхи: она ж к нему краем, и толку ноль. А заводская авторегулировка видюхиного ШИМа как-то не особо способствует её охлаждению даже зимой, о жаре за бортом вовсе молчу.

Реализация

Пошарив по просторам, нарыл массу графических «мониторилок» — но ни одной «крутилки» именно для АМД, хотя для ненаВидии — завались (один лишь «позеленевший от зависти» чего стóит). И это невзирая на то, что всё нужное доступно прямо из системы, без нужды ковыряться в проприетарщине… Странное дело.

При этом для командной строки наваяно всякого на разных языках от рубина до питона, но к чему плодить сущности, если всё можно сделать перманентно доступным башем? Есть и на нём. Проникся довольно замороченным решением amdgpu-fancontrol и выстругал на скорую руку собственный упрощённый вариант, для которого понадобится создать всего пару файлов — скрипт да юнит к нему.

Запускающий юнит

/lib/systemd/system/amdgpufan.service:

[Unit]
Description = AMD GPU fan control

[Service]
ExecStart = /usr/local/sbin/amdgpufan
Restart = on-failure
RestartSec = 5

[Install]
WantedBy = default.target

Как включать юниты, все давно знают. :)

Сам скрипт

/usr/local/sbin/amdgpufan:

#!/bin/sh

[ $UID -eq 0 ] || { # Check user permissions.
    echo "Writing to /sys requires root privileges."
    exit 1
}

## User variables ################################################
card=0          # Vega rather has number 1
rate=3          # check frequency
step=5          # min to max divider
part=$[step-2]  # steps num except first and last
within=2        # temperature borders and pwm diff tolerance
min_tmp=45      # no need cooling lower

## System variables ##############################################
gpuinfo=/sys/kernel/debug/dri/$card/amdgpu_pm_info
dev_dir=/sys/class/drm/card$card/device
sys_dir=`ls -d $dev_dir/hwmon/*`
sys_lvl=${dev_dir}/power_dpm_force_performance_level
sys_clk=${dev_dir}/pp_od_clk_voltage
sys_tmp=${sys_dir}/temp1_input # 1:edge, 2:junction, 3:memory
sys_pwm=${sys_dir}/pwm1
sys_fan=${sys_pwm}_enable

## Calculated variables ##########################################
# Achievable frequencies for gpu & mem:
mhz=(`awk '/^(M|S)/{gsub("Mhz","");print $3}' $sys_clk | sort -V`)
max_tmp=$[`cat $sys_dir/temp*_crit | sort -V | head -1`/1000]
max_pwm=`cat ${sys_pwm}_max`
min_pwm=`cat ${sys_pwm}_min`
gap_pwm=$[(max_pwm-min_pwm)/step]
gap_tmp=$[(max_tmp-min_tmp)/step]

reset(){ # Sudden break.
    printf "Exiting and s"
    setmode auto
    exit 0
}

setmode(){ # Change as mode as gpu & mem frequency.
    echo "etting clock & fan mode to '$1'."
    case $1 in
        auto)   mode=2;;
        manual) mode=1
                echo m 1 ${mhz[0]}  >$sys_clk
                echo s 1 ${mhz[1]}  >$sys_clk
        ;;
    esac
    echo $mode  >$sys_fan
    echo $1     >$sys_lvl
}

main(){ # Whole magic.
    cur_pwm=`cat $sys_pwm`
    cur_tmp=$[`cat $sys_tmp`/1000]
    [[ `cat $sys_fan` -eq 1 ]] || {
        printf "S"
        setmode manual
    }
    if [[ $cur_tmp -gt $max_tmp ]]; then
        echo "$cur_tmp°C exceeds critical, set 100% blowing."
        new_pwm=$max_pwm
    elif [[ $cur_tmp -le $min_tmp ]]; then
        new_pwm=$min_pwm
    else
        for i in `seq 0 $part`; do
            [[ $cur_tmp -ge $[min_tmp+gap_tmp*i]     ]] &&
            [[ $cur_tmp -le $[min_tmp+gap_tmp*(i+1)] ]] && {
                new_pwm=$[min_pwm+gap_pwm*(i+1)]
                break
            }
        done
    fi
    printf "%3d°C @%3d PWM" $cur_tmp $cur_pwm
    [[ $cur_pwm -ge $[new_pwm-within] ]] &&
    [[ $cur_pwm -le $[new_pwm+within] ]] &&
    echo "." || { # Change PWM if differ.
        for i in `seq 0 $part`; do
            [[ $cur_tmp -ge $[min_tmp+gap_tmp*i-within] ]] &&
            [[ $cur_tmp -le $[min_tmp+gap_tmp*i+within] ]] && {
                echo "."
                break
            }
        done || {
            printf ", switching to %3d.\n" $new_pwm
            echo $new_pwm >$sys_pwm
        }
    }
}

trap "reset" SIGINT SIGTERM # Handle signals.

while :; do # Go on!
    main
    sleep ${rate}s
done

Пояснения

  1. В системных переменных отслеживаю sys_tmp не по самому горячему датчику температуры перехода, а по ГПУ (иначе тишины не достичь), но в качестве предельной температуры max_tmp выбираю минимальную из критических — датчик памяти.
  2. Пользовательскими переменными задаю:
    • № видюхи (судя по статьям от спецов, при наличии встройки оная будет пронумерована единичкой);
    • частоту опроса температуры rate со сменой значения в ШИМ-контроллере при необходимости (чтоб и не дать перегреться, и не надоело листать портянку журнала, не обязательно проверять температуру ежесекундно);
    • температуру min_tmp, ниже которой мослать вентилятором бессмысленно — с завода вентилятор не включается до 52 градусов, а при остывании останавливается на 46;
    • шаг gap_tmp между диапазонами температур;
    • шаг gap_pwm между значениями ШИМа в заданных температурных диапазонах (и это не об/мин, как можно подумать, а нечто вроде процента от максимума — но не из 100, а из 255).
    • whithin — допустимый разброс задаваемого значения ШИМ с текущим, а также перехлёст температурных диапазонов, дабы вентилятор не дёргался по одному градусу, внося сумятицу в ума и сердца;
  3. Скрипт сделал а-ля «резидентным» (см. цикл while) — запускать по таймеру не стал, дабы между его запусками не оставлять видюху в ручном режиме без управления (см. функцию setmode).

Пример работы

Ночью колебания 35..39°C с отключёнными вентиляторами видюхи.

Утро: веб-сёрфинг, общение, редактирование и пр.

Переключение ШИМа после 5-минутного прогрева до 48°C на 20% (51), далее — колебания в пределах 50..55°C.

В процессе завтрака (не за компьютером) температура за четверть часа падает до 42°C, ШИМ обнуляется, далее — колебания как ночью.

Будним днём с повышением забортной температуры системная тоже подрастает и гуляет в рамках 40°+ без запуска вентиляторов.

Запуск игры

 60°C @ 69 PWM, changing to  90.
 59°C @ 89 PWM, changing to  70.
 60°C @ 69 PWM, changing to  90.
 57°C @ 89 PWM, changing to  70.
 54°C @ 69 PWM.
 59°C @ 69 PWM.
 62°C @ 69 PWM, changing to  90.
 77°C @ 89 PWM.

Активная фаза игры

 82°C @ 89 PWM, changing to 140.
 62°C @138 PWM, changing to  90.
 59°C @ 89 PWM, changing to  70.
 62°C @ 69 PWM, changing to  90.
 60°C @ 89 PWM.
…
 61°C @ 89 PWM.
 62°C @ 89 PWM.
 58°C @ 89 PWM, changing to  70.
 60°C @ 69 PWM, changing to  90.
 75°C @ 89 PWM.

Игра завершена

Плавное падение температуры:

 53°C @ 89 PWM, changing to  70.
 52°C @ 69 PWM.
 40°C @ 69 PWM.
 39°C @ 69 PWM, changing to   0.
 40°C @  0 PWM, changing to  70.
 39°C @ 69 PWM, changing to   0.
 39°C @  0 PWM.

Утро — вход в систему

Веб-сёрфинг, редактирование и пр.:

 40°C @  0 PWM, changing to  70.
 41°C @ 69 PWM.

Далее — колебания 42-55°C при ШИМ 69.

Перезапуск скрипта в жару

По нулевому значению ШИМ на старте видно, что автонастройка не включает вентиляторы как минимум до 50°C:

мая 25 18:01:19 comp.ill amdgpufan[2544596]:  49°C @ 69 PWM.
мая 25 18:01:21 comp.ill systemd[1]: Stopping AMD GPU fan control...
мая 25 18:01:21 comp.ill amdgpufan[2544596]: Завершено
мая 25 18:01:21 comp.ill amdgpufan[2544596]: Exiting and setting fan mode to 'auto'.
мая 25 18:01:21 comp.ill systemd[1]: amdgpufan.service: Deactivated successfully.
мая 25 18:01:21 comp.ill systemd[1]: Stopped AMD GPU fan control.
мая 25 18:01:21 comp.ill systemd[1]: amdgpufan.service: Consumed 1.034s CPU time.
мая 25 18:01:21 comp.ill systemd[1]: Started AMD GPU fan control.
мая 25 18:01:21 comp.ill amdgpufan[2558019]: Wrong fan mode, setting to 'manual'.
мая 25 18:01:21 comp.ill amdgpufan[2558019]:  49°C @  0 PWM, changing to  70.
мая 25 18:01:26 comp.ill amdgpufan[2558019]:  49°C @ 69 PWM.

Игра по жаре

 92°C @ 87 PWM, changing to 140.

Далее колебания на 90+°C при ШИМ 138.

Выводы

На данный момент ночью, по прохладе, большой внешний вентилятор уже точно не нужен: игрушки на ультрах в высоком разрешении прогревают самый горячий компонент видюхи не выше 96 градусов, тогда как прежде и с вентилятором за сотку вылезало. Вечером в пределах +30 на улице тоже обошёлся без вентилятора. Как оно в дневную жару, опробовать пока не довелось, но по результатам отчитаюсь.

Когда не ломанная / не чиненная железяка работает не так, как ожидается, порой на помощь спешат чип и… программные средства. Пусть без рюшечек и фантиков, зато задача решена на системном уровне. Ну, и есть надежда, что дружелюбного софта тоже не придётся долго ждать.

Обратная связь

@gbIMoBou

Другие статьи