Скрипт контроля частот и вентиляторов видеокарт AMD Radeon: различия между версиями

Материал из Linux Wiki
Перейти к навигацииПерейти к поиску
Строка 8: Строка 8:
<source lang=awk>
<source lang=awk>
#!/bin/bash
#!/bin/bash
# By Rain ;)


tt1='65'
###################################
tt2='70'
toh='80'
tco='85'
hyst='1'


fmin='15'
# IDLE ZONE - [hyst]-[tt1]-[hyst] - ZONE 1 - [hyst]-[tt2]-[hyst] - ZONE 2 - [hyst]-[toh] - OVERHEAT ZONE [Cut-off] - CUT-OFF ZONE
tfan='60'
# For example, for 65 / 70 / 80 / 85 and hysteresis level = 1; and fan min=15; target=60 and max=100:
fmax='100'
#  .............. |  64-66  | ............... |  69-71  | .............. |  79-80  | ..........................  | 85 .................
#        idle    |          |      zone1      |          |    zone2      |          |          overheat          |      cutoff
# fan down to 15  | do noth. |  fan up to 60  | do noth. | fan up to 100  | do noth. | fan to 100; clock step down | halt all; fan to 100
#
# For idle zone fan decremental step is 1%
# For zone 1 fan incremental step is 2%
# For zone 2 fan incremental step is 5%
#
# If temperature goes lower than "$toh-(double hysteresis)" - <=77 C - core clock will be restored to config values
#
# TODO: looks like, no need to use hysteresis in between zone2 and overheat zones anymore


sleep='5'
###################################


corelow='800'
tt1='65' # First target temperature. Fan will be between fmin and tfan
memlow='1000'
tt2='70' # Second target temperatune. Fan will be up to fmax
toh='80' # Overheat temperature. Reducing frequencies, fan to fmax
tco='85' # Cut-off temperature. Shutting down all mining processes
hyst='1' # Hysteresis


conf='/home/rain/config/cards.conf'
fmin='15' # Minimal fan speed
tfan='60' # Maximum fan speed for first zone
fmax='100' # Maximum fan speed
 
ohfs='5' # Overheat frequency reducing step
fups='50' # Clock restore step
trst='75' # Clock restore temperature
 
sleep='5' # internal timer
 
corelow='300'
memlow='1000' # not used
 
conf='/home/rain/config/cards.conf' # cgminer/sgminer config file for getting core/mem frequencies
rrdb='/home/rain/.gpustat.rrd'
site='/tmp/site'
 
###################################
 
 
if [ "${1}" != 'single' ]
then
 
mkdir -p -m 755 "${site}"
 
if [ -z "${RRD}" ]
then
if [ -x '/usr/bin/rrdtool' ]
then
rrd='nice -n 19 /usr/bin/rrdtool'
fi
else
rrd=': '
fi
 
[ ! -e "${rrdb}" ] && ${rrd} create "${rrdb}" \
--step 60 \
DS:gpu0temp:GAUGE:120:U:U \
DS:gpu1temp:GAUGE:120:U:U \
DS:gpu2temp:GAUGE:120:U:U \
DS:gpu3temp:GAUGE:120:U:U \
DS:gpu4temp:GAUGE:120:U:U \
DS:gpu5temp:GAUGE:120:U:U \
DS:gpu6temp:GAUGE:120:U:U \
DS:gpu7temp:GAUGE:120:U:U \
DS:gpu8temp:GAUGE:120:U:U \
DS:gpu9temp:GAUGE:120:U:U \
RRA:MIN:0.5:1:80  \
RRA:MIN:0.5:8:210  \
RRA:MIN:0.5:80:600  \
RRA:MIN:0.5:600:1100 \
RRA:AVERAGE:0.5:1:80  \
RRA:AVERAGE:0.5:8:210  \
RRA:AVERAGE:0.5:80:600  \
RRA:AVERAGE:0.5:600:1100 \
RRA:MAX:0.5:1:80 \
RRA:MAX:0.5:8:210 \
RRA:MAX:0.5:80:600 \
RRA:MAX:0.5:600:1100
 
mkgraph() {
umask 022
if [ "$3" == 'normal' ];then
        size='--width 400 --height 200'
elif [ "$3" == 'large' ]; then
        size='--width 900 --height 450'
fi
$rrd graph "${2}" --imgformat PNG \
DEF:gpu0tempmi="${1}":gpu0temp:MIN \
DEF:gpu1tempmi="${1}":gpu1temp:MIN \
DEF:gpu2tempmi="${1}":gpu2temp:MIN \
DEF:gpu3tempmi="${1}":gpu3temp:MIN \
DEF:gpu4tempmi="${1}":gpu4temp:MIN \
DEF:gpu5tempmi="${1}":gpu5temp:MIN \
DEF:gpu6tempmi="${1}":gpu6temp:MIN \
DEF:gpu7tempmi="${1}":gpu7temp:MIN \
DEF:gpu8tempmi="${1}":gpu8temp:MIN \
DEF:gpu9tempmi="${1}":gpu9temp:MIN \
  \
DEF:gpu0tempav="${1}":gpu0temp:AVERAGE \
DEF:gpu1tempav="${1}":gpu1temp:AVERAGE \
DEF:gpu2tempav="${1}":gpu2temp:AVERAGE \
DEF:gpu3tempav="${1}":gpu3temp:AVERAGE \
DEF:gpu4tempav="${1}":gpu4temp:AVERAGE \
DEF:gpu5tempav="${1}":gpu5temp:AVERAGE \
DEF:gpu6tempav="${1}":gpu6temp:AVERAGE \
DEF:gpu7tempav="${1}":gpu7temp:AVERAGE \
DEF:gpu8tempav="${1}":gpu8temp:AVERAGE \
DEF:gpu9tempav="${1}":gpu9temp:AVERAGE \
  \
DEF:gpu0tempma="${1}":gpu0temp:MAX \
DEF:gpu1tempma="${1}":gpu1temp:MAX \
DEF:gpu2tempma="${1}":gpu2temp:MAX \
DEF:gpu3tempma="${1}":gpu3temp:MAX \
DEF:gpu4tempma="${1}":gpu4temp:MAX \
DEF:gpu5tempma="${1}":gpu5temp:MAX \
DEF:gpu6tempma="${1}":gpu6temp:MAX \
DEF:gpu7tempma="${1}":gpu7temp:MAX \
DEF:gpu8tempma="${1}":gpu8temp:MAX \
DEF:gpu9tempma="${1}":gpu9temp:MAX \
  \
CDEF:cdefmida=gpu0tempav,gpu0tempmi,- \
CDEF:cdefmidb=gpu1tempav,gpu1tempmi,- \
CDEF:cdefmidc=gpu2tempav,gpu2tempmi,- \
CDEF:cdefmidd=gpu3tempav,gpu3tempmi,- \
CDEF:cdefmide=gpu4tempav,gpu4tempmi,- \
CDEF:cdefmidf=gpu5tempav,gpu5tempmi,- \
CDEF:cdefmidg=gpu6tempav,gpu6tempmi,- \
CDEF:cdefmidh=gpu7tempav,gpu7tempmi,- \
CDEF:cdefmidi=gpu8tempav,gpu8tempmi,- \
CDEF:cdefmidj=gpu9tempav,gpu9tempmi,- \
  \
CDEF:cdefmada=gpu0tempma,gpu0tempav,- \
CDEF:cdefmadb=gpu1tempma,gpu1tempav,- \
CDEF:cdefmadc=gpu2tempma,gpu2tempav,- \
CDEF:cdefmadd=gpu3tempma,gpu3tempav,- \
CDEF:cdefmade=gpu4tempma,gpu4tempav,- \
CDEF:cdefmadf=gpu5tempma,gpu5tempav,- \
CDEF:cdefmadg=gpu6tempma,gpu6tempav,- \
CDEF:cdefmadh=gpu7tempma,gpu7tempav,- \
CDEF:cdefmadi=gpu8tempma,gpu8tempav,- \
CDEF:cdefmadj=gpu9tempma,gpu9tempav,- \
  \
LINE2:gpu0tempav#ff0000:'GPU 0' \
LINE0:gpu0tempmi#ff0000: \
AREA:cdefmida#ff000044::STACK \
AREA:cdefmada#ff000044::STACK \
GPRINT:gpu0tempmi:MIN:"(Min\: %3.1lf°C \t/" \
GPRINT:gpu0tempav:LAST:"Curr\: %3.1lf°C \t/" \
GPRINT:gpu0tempma:MAX:"Max\: %3.1lf°C)\n" \
\
LINE2:gpu1tempav#ffa800:"GPU 1" \
LINE0:gpu1tempmi#ffa800: \
AREA:cdefmidb#ffa80044::STACK \
AREA:cdefmadb#ffa80044::STACK \
GPRINT:gpu1tempmi:MIN:"(Min\: %3.1lf°C \t/" \
GPRINT:gpu1tempav:LAST:"Curr\: %3.1lf°C \t/" \
GPRINT:gpu1tempma:MAX:"Max\: %3.1lf°C)\n" \
\
LINE2:gpu2tempav#fff600:"GPU 2" \
LINE0:gpu2tempmi#fff600: \
AREA:cdefmidc#fff60044::STACK \
AREA:cdefmadc#fff60044::STACK \
GPRINT:gpu2tempmi:MIN:"(Min\: %3.1lf°C \t/" \
GPRINT:gpu2tempav:LAST:"Curr\: %3.1lf°C \t/" \
GPRINT:gpu2tempma:MAX:"Max\: %3.1lf°C)\n" \
\
LINE2:gpu3tempav#6cff00:"GPU 3" \
LINE0:gpu3tempmi#6cff00: \
AREA:cdefmidd#6cff0044::STACK \
AREA:cdefmadd#6cff0044::STACK \
GPRINT:gpu3tempmi:MIN:"(Max\: %3.1lf°C \t/" \
GPRINT:gpu3tempav:LAST:"Curr\: %3.1lf°C \t/" \
GPRINT:gpu3tempma:MAX:"Max\: %3.1lf°C)\n" \
\
LINE2:gpu4tempav#00ffc0:'GPU 4' \
LINE0:gpu4tempmi#00ffc0: \
AREA:cdefmide#00ffc044::STACK \
AREA:cdefmade#00ffc044::STACK \
GPRINT:gpu4tempmi:MIN:"(Min\: %3.1lf°C \t/" \
GPRINT:gpu4tempav:LAST:"Curr\: %3.1lf°C \t/" \
GPRINT:gpu4tempma:MAX:"Max\: %3.1lf°C)\n" \
\
LINE2:gpu5tempav#009cff:'GPU 5' \
LINE0:gpu5tempmi#009cff: \
AREA:cdefmidf#009cff44::STACK \
AREA:cdefmadf#009cff44::STACK \
GPRINT:gpu5tempmi:MIN:"(Min\: %3.1lf°C \t/" \
GPRINT:gpu5tempav:LAST:"Curr\: %3.1lf°C \t/" \
GPRINT:gpu5tempma:MAX:"Max\: %3.1lf°C)\n" \
\
LINE2:gpu6tempav#0030ff:'GPU 6' \
LINE0:gpu6tempmi#0030ff: \
AREA:cdefmidg#0030ff44::STACK \
AREA:cdefmadg#0030ff44::STACK \
GPRINT:gpu6tempmi:MIN:"(Min\: %3.1lf°C \t/" \
GPRINT:gpu6tempav:LAST:"Curr\: %3.1lf°C \t/" \
GPRINT:gpu6tempma:MAX:"Max\: %3.1lf°C)\n" \
\
LINE2:gpu7tempav#c000ff:'GPU 7' \
LINE0:gpu7tempmi#c000ff: \
AREA:cdefmidh#c000ff44::STACK \
AREA:cdefmadh#c000ff44::STACK \
GPRINT:gpu7tempmi:MIN:"(Min\: %3.1lf°C \t/" \
GPRINT:gpu7tempav:LAST:"Curr\: %3.1lf°C \t/" \
GPRINT:gpu7tempma:MAX:"Max\: %3.1lf°C)\n" \
\
LINE2:gpu8tempav#d4d2d5:'GPU 8' \
LINE0:gpu8tempmi#d4d2d5: \
AREA:cdefmidi#d4d2d544::STACK \
AREA:cdefmadi#d4d2d544::STACK \
GPRINT:gpu8tempmi:MIN:"(Min\: %3.1lf°C \t/" \
GPRINT:gpu8tempav:LAST:"Curr\: %3.1lf°C \t/" \
GPRINT:gpu8tempma:MAX:"Max\: %3.1lf°C)\n" \
\
LINE2:gpu9tempav#000000:'GPU 9' \
LINE0:gpu9tempmi#000000: \
AREA:cdefmidj#00000044::STACK \
AREA:cdefmadj#00000044::STACK \
GPRINT:gpu9tempmi:MIN:"(Min\: %3.1lf°C \t/" \
GPRINT:gpu9tempav:LAST:"Curr\: %3.1lf°C \t/" \
GPRINT:gpu9tempma:MAX:"Max\: %3.1lf°C)\n" \
${size} \
--title "${4}" \
-s ${5} \
--watermark="${HOSTNAME}" \
--slope-mode \
--lazy 1>/dev/null &
}
 
# http://localhost/index.html generator
 
(echo -n "<html><head><style> body {font-family: Courier, monospace;}</style></head><body><b>"
hostname
echo "</b><br><br>"
/home/rain/bin/sysinfo.sh | sed 's/$/<br>/g' | sed 's/ /\&nbsp\;/g'
echo "<br><li><a href=/gputemp.html>GPU Temp</a>"
echo "<br><iframe src=/dyn.html frameborder=0 height=50% width=100%></iframe></body></html>") > /tmp/index.html
 
touch '/tmp/dyn.html'
chmod 644 '/tmp/index.html' '/tmp/dyn.html'
fi
 
# Never use sgminer API if NOAPI is set


[ ! -z "${NOAPI}" ] && cmd="false :"
[ ! -z "${NOAPI}" ] && cmd="false :"
Строка 31: Строка 264:
     echo -ne "\e[0;36m[\e[0;35m"$(date +%Y-%m-%d" "%H:%M:%S)"\e[0;36m]\e[0;0m "
     echo -ne "\e[0;36m[\e[0;35m"$(date +%Y-%m-%d" "%H:%M:%S)"\e[0;36m]\e[0;0m "
}
}
# Allow log for debugging purposes
debugme() {
[ "${DEBUG}" == '1' ] && {
showdate
echo "${1}"
} >> /tmp/ffc.log
}
# Halt all GPU activity. Change it if needed


do_halt() {
do_halt() {
        /home/rain/bin/gpuoff 1>/dev/null 2>/dev/null
/home/rain/bin/gpuoff 1>/dev/null 2>/dev/null
        /home/rain/bin/ethminerctl suspend
/home/rain/bin/ethminerctl suspend
        pkill -9 Hashcat
pkill -9 Hashcat
}
}
# XMPP notifications
#if [ "${1}" != 'single' ]
# then
# rm -f /tmp/sendxmpp 2>/dev/null
# touch /tmp/sendxmpp
# ( tail -qF /tmp/sendxmpp 2>/dev/null | sendxmpp -c -r $(hostname) -i -t rigs@conference.linuxoid.in ) &
#fi


sayto() {
sayto() {
    (cat - ; echo -n " on $(hostname)") | sendxmpp -t rain@jabberworld.info
(cat - | tr -d '\n' ; echo -n " on $(hostname)") | sendxmpp -t -r $(hostname) -c rigs@conference.linuxoid.in
# cat - >> /tmp/sendxmpp
}
}
# cgminer/sgminer core/mem clocks config parser


getcoreconf(){
getcoreconf(){
        awk '/gpu-engine/{
awk '/gpu-engine/{
                        gsub(/[0-9]+\-|\"/, "", $3)
gsub(/[0-9]+\-|\"/, "", $3)
                        split($3, core, ",")
split($3, core, ",")
                        c='$1'+1
c='$1'+1
                        print core[c]
print core[c]
                }' "${conf}"
}' "${conf}"
}
}


getmemconf(){
getmemconf(){
        awk '/gpu-memclock/{
awk '/gpu-memclock/{
                        gsub(/[0-9]+\-|\"/, "", $3)
gsub(/[0-9]+\-|\"/, "", $3)
                        split($3, mem, ",")
split($3, mem, ",")
                        c='$1'+1
c='$1'+1
                        print mem[c]
print mem[c]
                }' "${conf}"
}' "${conf}"
}
}
# Function for setting GPU clocks. 1-st parameter is a card number. If parameter is not set - all cards are used


setfreqs() {
setfreqs() {
for i in $(seq 0 $(($(aticonfig --lsa | grep -c '[0-9]\.')-1)))
[ -z "${1}" ] && card="$(seq 0 $(($(aticonfig --lsa | grep -c '[0-9]\.')-1)))" || card="${1}"
        do
for i in ${card}
                aticonfig --od-enable 1>/dev/null
do
# Allowing overclocking
aticonfig --od-enable 1>/dev/null


                core="$(getcoreconf "${i}")"
# Getting core and memory clocks. If getcoreconf/getmemconf returns nothing - using GPU 0 clocks
                [ -z "${core}" ] && core="$(getcoreconf 0)"
# (sgminer behavior - if one parameter is set - it used for all cards)
core="$(getcoreconf "${i}")"
[ -z "${core}" ] && core="$(getcoreconf 0)"


                mem="$(getmemconf "${i}")"
mem="$(getmemconf "${i}")"
                [ -z "${mem}" ] && core="$(getmemconf 0)"
[ -z "${mem}" ] && core="$(getmemconf 0)"


                [[ ! -z "${core}" && ! -z "${mem}" ]] && {
# Setting GPU clocks
                        aticonfig --od-setclocks=$core,$mem --adapter=$i 1>/dev/null
[[ ! -z "${core}" && ! -z "${mem}" ]] && {
                        freqs[$1]='1'
aticonfig --od-setclocks=$core,$mem --adapter=$i 1>/dev/null
                }
debugme "Setting freqs for GPU $i"
        done
# Clocks state flag. 1 = clocks set from config file, 2 = clocks is reduced.
freqs[$i]='1'
}
done
# Setting Powertune to 120% via atitweak utility
[ -x /home/rain/bin/atitweak ] && /home/rain/bin/atitweak -p 20 > /dev/null
debugme "Setting powertune"
}
}
###################################


case "${1}" in
case "${1}" in
        freqs)
freqs)
                                setfreqs $i
setfreqs
        ;;
;;
        *)
*)
 
# [ "${1}" != 'single' ] && echo "Hello, i'm online" | sayto
 
# Main loop
while :
do
# If NOAPI is not set - checking API availibility
$cmd nc -w 1 -z localhost 4028 && {
api='1' # API detected flag
ffci='0' # $fan array initialisation flag
debugme "API detected"
# Fetching API data
  devdata="$(/home/rain/bin/api-example.py devs | sed -r 's/, |\{|\}/\n/g;s/(\n)u|'\''/\1/g')"
} || {
api='0' # API not detected
 
# sgminer process detection '
# ffci must be set to 0 and $fan array must be filled with real data every time when sgminer started or stopped
if pidof sgminer 1>/dev/null
then
if [ -z "${sgdetect}" ]
then
debugme "sgminer detected"
ffci='0'
sgdetect='1'
fi
else
if [ ! -z "${sgdetect}" ]
then
debugme "sgminer disabled"
unset sgdetect
ffci='0'
fi
fi
 
debugme "sgminer=$sgdetect"
 
[ "${ffci}" != '1' ] && {
# init fan array
for j in $(seq 0 $(($(aticonfig --lsa | grep -c '[0-9]\.')-1)))
do
fan[$j]="$(DISPLAY=:0.$j aticonfig --pplib-cmd "get fanspeed 0" | awk '/Result/{gsub(/%/, "", $4); print $4}')"
debugme "Writing array data for GPU $j"
done
 
# Setting clocks for all cards
if [ "${1}" != 'single' ]
then
setfreqs
fi
 
ffci='1'
}
 
# Fetching data from aticonfig utility
atidata="$(aticonfig --odgt --odgc --adapter=all 2>/dev/null)"
debugme "Getting atidata"
 
#### fans and core frequency control section ####
 
# Parsing aticonfig output and extracting card number, temperature, core and memory clocks
# TODO: next time use this for all aticonfig data processing. For now we will see core clock updates only in next cycle
 
for cdat in $(echo "${atidata}" | tr '\n' ' ' | sed 's/Adapter/\n&/g'| sort | sed -nr '/Adapter/N;s/\n/ /gp' | sed -r 's/^Adapter ([0-9]+) - .*Current Peak : *([0-9]+) +([0-9]+).*Temperature - ([0-9]{1,3}).[0-9]+ C.*/\1:\4:\2:\3/g')
do
 
# Separating values between different variables
cnt="${cdat%:*:*}"
cn="${cnt%:*}" # Card number
#ct="${cnt#*:}" # Card temperature # TODO: use array in the future and remove this variable
ct[$cn]="${cnt#*:}" # Card temperature array
 
ccmf="${cdat#*:*:}"
ccf="${ccmf%:*}" # Card core clock
cmf="${ccmf#*:}" # Card memory clock
 
[ "${freqs[$cn]}" == '1' ] && {
cmax[$cn]=${ccf} # max core freq array
mmax[$cn]=${cmf} # max mem  freq array
}
 
debugme "Processing GPU $cn -> ${ct[$cn]} C"
if [ "${1}" != 'single' ]
then
# If card temperature is over $tco - halting mining, fans to $fmax (usually 100%)
[ "${ct[$cn]}" -ge "${tco}" ] && {
# halt mining
debugme "Cutoff temp on $cn"
fan[$cn]=${fmax}
DISPLAY=:0.$cn aticonfig --pplib-cmd "set fanspeed 0 ${fmax}" 1>/dev/null
# showdate  >> /tmp/ffc.log
echo "ALERT! Critical temperature (${ct[$cn]}C) on GPU ${cn}" | sayto
do_halt
}
 
# If card temperature great than $toh, but still less than $tco (80-85 degr. zone) - set fans to max speed and reduce core clocks
[[ "${ct[$cn]}" -ge "${toh}" && "${ct[$cn]}" -lt "${tco}" ]] && {
ftalk='25'
# reduce freqs
debugme "Overheat on ${cn}: ${freqs[$cn]}"
# [ "${freqs[$cn]}" == '1' ] && {
# showdate >> /tmp/ffc.log
# echo "GPU $cn overheat, reducing clocks" >> /tmp/ffc.log
 
debugme "Setting max fan speed on ${cn}"
fan[$cn]=${fmax}
DISPLAY=:0.$cn aticonfig --pplib-cmd "set fanspeed 0 ${fmax}" 1>/dev/null
 
[ "${ccf}" -gt "$((${corelow}+${ohfs}))" ] && {
ccf=$((${ccf}-${ohfs}))
 
[ "${freqs[$cn]}" == '1' ] && {
echo "GPU $cn overheat (${ct[$cn]} C), starting core clock reducing" | sayto
}
 
freqs[$cn]='2'
debugme "Reducing freqs on $cn to ${ccf}/${cmf}"
aticonfig --od-setclocks=${ccf},${cmf} --adapter=$cn 1>/dev/null
} || {
 
echo "No more space in frequency range on card ${cn} for clock reducing" | sayto
debugme "No more space in frequency range on card ${cn} for clock reducing"
}
# }
}
 
# If card temperature goes below overheat level - report about new frequencies
 
[[ "${ct[$cn]}" -lt "$((${toh}-${hyst}))" ]] && {
[ ${freqs[$cn]} == '2' ] && {
[ ${ftalk} -gt '0' ] && let ftalk-=1
[ ${ftalk} == '1' ] && {
echo "GPU $cn clocks reduced to ${ccf}/${cmf}" | sayto
ftalk='0'
}
}
}
 
# If card temperature decreased to safe level - $trst - restore core clocks
 
[[ "${ct[$cn]}" -le "${trst}" ]] && {
 
[ "${freqs[$cn]}" == '2' ] && {
[ "$((${cmax[$cn]}-${ccf}))" -gt "${fups}"  ] && {
aticonfig --od-setclocks=$((${ccf}+${fups})),$cmf --adapter=$cn 1>/dev/null
} || {
setfreqs "${cn}"
debugme "Clocks restored on GPU $cn"
echo "Clocks restored on GPU $cn" | sayto
}
}
}
 
# If card temperature in second zone (typically 70-80 degr) - allowing fan speed to be up to $fmax
 
[[ "${ct[$cn]}" -gt "$((${tt2}+${hyst}))" && "${ct[$cn]}" -lt "$((${toh}-${hyst}))" ]] && {
debugme "2-nd fan zone on $cn"
# allow fans to 100%
 
[ "${fan[$cn]}" -lt "${fmax}" ] && {
# old="${fan[$cn]}"
let fan[$cn]+=5
 
[ "${fan[$cn]}" -lt "${tfan}" ] && {
fan[$cn]=${tfan}
debugme "Fast heating on $cn"
}
 
[ "${fan[$cn]}" -gt "${fmax}" ] && fan[$cn]="${fmax}"
debugme "Setting fan to ${fan[$cn]} on GPU $cn"
# showdate  >> /tmp/ffc.log
# echo "GPU ${cn} ${ct[$cn]}: setting fan $old -> ${fan[$cn]}"  >> /tmp/ffc.log
DISPLAY=:0.$cn aticonfig --pplib-cmd "set fanspeed 0 ${fan[$cn]}" 1>/dev/null
}
}
 
# If card temperature in 1-st zone (65-70 degr) - fan speed can be up to $tfan
 
[[ "${ct[$cn]}" -gt "$((${tt1}+${hyst}))" && "${ct[$cn]}" -lt "$((${tt2}-${hyst}))" ]] && {
# allow fans to $tfan
debugme "1-nd fan zone on $cn"
[ "${freqs[$cn]}" == '2' ] && {
setfreqs "${cn}"
}
 
[ "${fan[$cn]}" -lt "${tfan}" ] && {
# old="${fan[$cn]}"
let fan[$cn]+=2
[ "${fan[$cn]}" -gt "${tfan}" ] && fan[$cn]="${tfan}"
# showdate  >> /tmp/ffc.log
# echo "GPU ${cn} ${ct[$cn]}: setting fan $old -> ${fan[$cn]}"  >> /tmp/ffc.log
debugme "Setting fan to ${fan[$cn]} on GPU $cn"
DISPLAY=:0.$cn aticonfig --pplib-cmd "set fanspeed 0 ${fan[$cn]}" 1>/dev/null
}
}
 
# If card temerature less than first target - fan goes idle
 
[ "${ct[$cn]}" -lt "$((${tt1}-${hyst}))" ] && {
# decrease fan speed
debugme "Low temp on $cn"
# old="${fan[$cn]}"
let fan[$cn]-=1
[ "${fan[$cn]}" -lt "${fmin}" ] && fan[$cn]="${fmin}"
# showdate  >> /tmp/ffc.log
# echo "GPU ${cn} ${ct[$cn]}: setting fan $old -> ${fan[$cn]}"  >> /tmp/ffc.log
DISPLAY=:0.$cn aticonfig --pplib-cmd "set fanspeed 0 ${fan[$cn]}" 1>>/dev/null
}
 
fi


        while :
done
                do
        $cmd nc -w 1 -z localhost 4028 && {
        api='1'
        ffci='0'
        devdata="$(/home/rain/bin/api-example.py devs | sed -r 's/, |\{|\}/\n/g;s/(\n)u|'\''/\1/g')"
        } || {
        api='0'


        [ "${ffci}" != '1' ] && {
# TODO: сделать это все как-то покрасивее; возможно - вынести 60 тут и выше (создание базы) в переменную
#      init fan array
[ -z "${st}" ] && st='60'
        for j in $(seq 0 $(($(aticonfig --lsa | grep -c '[0-9]\.')-1)))
let st-=$((60/$sleep))
                do
[ "${st}" -le '0' ] && {
                fan[$j]="$(DISPLAY=:0.$j aticonfig --pplib-cmd "get fanspeed 0" | awk '/Result/{gsub(/%/, "", $4); print $4}')"
st='60'
        done
$rrd update "${rrdb}" N$(
s=10
for t in ${!ct[@]}
do
echo -n ":${ct[$t]}"
let s-=1
done


        setfreqs
for i in $(seq 1 $s)
do
echo -n :U
done
)


        ffci='1'
mkgraph "${rrdb}" "${site}"/gpustat.h.png              'normal' "GPU Temp, час" -60min
         }
mkgraph "${rrdb}" "${site}"/gpustat.h.large.png         'large'  "GPU Temp, час" -60min


                        atidata="$(aticonfig --odgt --odgc --adapter=all 2>/dev/null)"
mkgraph "${rrdb}" "${site}"/gpustat.d.png              'normal' "GPU Temp, день" -24h
mkgraph "${rrdb}" "${site}"/gpustat.d.large.png        'large'  "GPU Temp, день" -24h


# fans
mkgraph "${rrdb}" "${site}"/gpustat.m.png              'normal' "GPU Temp, месяц" -30d
                        for cdat in $(echo "${atidata}" | sed -nr '/Adapter/N;s/Adapter ([0-9]+).*\n.*Sensor.* - ([0-9]+)\.[0-9]+ C/\1:\2/gp')
mkgraph "${rrdb}" "${site}"/gpustat.m.large.png        'large'  "GPU Temp, месяц" -30d
                                do
                                        cn="${cdat%:*}"
                                        ct="${cdat#*:}"


                                        [ "${ct}" -ge "${tco}" ] && {
mkgraph "${rrdb}" "${site}"/gpustat.y.png              'normal' "GPU Temp, год" -12mon
                                                # halt mining
mkgraph "${rrdb}" "${site}"/gpustat.y.large.png        'large' "GPU Temp, год" -12mon
                                                DISPLAY=:0.$cn aticonfig --pplib-cmd "set fanspeed 0 ${fmax}" 1>/dev/null
#                                              showdate >> /tmp/ffc.log
                                                echo -n "ALERT! Critical temperature ($ct) on $cn" | sayto
                                                do_halt
                                        }


                                        [[ "${ct}" -ge "${toh}" && "${ct}" -lt "${tco}" ]] && {
}
                                                # reduce freqs
                                                [ "${freqs[$cn]}" == '1' ] && {
#                                                      showdate >> /tmp/ffc.log
#                                                      echo "GPU $cn overheat, reducing clocks" >> /tmp/ffc.log


                                                        echo -n "GPU $cn overheat, reducing clocks" | sayto
devdata="$((
                                                        freqs[$cn]='2'
                                                        aticonfig --od-setclocks=$corelow,$memlow --adapter=$cn 1>/dev/null
                                                        DISPLAY=:0.$cn aticonfig --pplib-cmd "set fanspeed 0 ${fmax}" 1>/dev/null
                                                }
                                        }


                                        [[ "${ct}" -gt "$((${tt2}+${hyst}))" && "${ct}" -lt "$((${toh}-${hyst}))" ]] && {
# Exporting fan speed for 2-nd part of this script
                                                # allow fans to 100%
for f in ${!fan[@]}
                                                [ "${freqs[$cn]}" == '2' ] && {
do
                                                        setfreqs "${cn}"
echo "Fan Speed $f ${fan[$f]}"
                                                }
done


                                                [ "${fan[$cn]}" -lt "${fmax}" ] && {
# ...and exporting frequency state
#                                                       old="${fan[$cn]}"
for c in ${!freqs[@]}
                                                        let fan[$cn]+=5
do
                                                        [ "${fan[$cn]}" -gt "${fmax}" ] && fan[$cn]="${fmax}"
echo "Freq State $c ${freqs[$c]}"
#                                                      showdate  >> /tmp/ffc.log
done
#                                                      echo "GPU ${cn} $ct: setting fan $old -> ${fan[$cn]}"  >> /tmp/ffc.log
                                                        DISPLAY=:0.$cn aticonfig --pplib-cmd "set fanspeed 0 ${fan[$cn]}" 1>/dev/null
                                                }
                                        }


                                        [[ "${ct}" -gt "$((${tt1}+${hyst}))" && "${ct}" -lt "$((${tt2}-${hyst}))" ]] && {
# Transforming aticonfig data for sgminer API compatible format... With some additions
                                                # allow fans to $tfan
echo "${atidata}"
                                                [ "${freqs[$cn]}" == '2' ] && {
                                                        setfreqs "${cn}"
                                                }


                                                [ "${fan[$cn]}" -lt "${tfan}" ] && {
) | awk '
#                                                      old="${fan[$cn]}"
                                                        let fan[$cn]+=2
                                                        [ "${fan[$cn]}" -gt "${tfan}" ] && fan[$cn]="${tfan}"
#                                                      showdate  >> /tmp/ffc.log
#                                                      echo "GPU ${cn} $ct: setting fan $old -> ${fan[$cn]}"  >> /tmp/ffc.log
                                                        DISPLAY=:0.$cn aticonfig --pplib-cmd "set fanspeed 0 ${fan[$cn]}" 1>/dev/null
                                                }
                                        }


/^Adapter/{
a=$2
name=$0
gsub(/^Adapter.* - /, "", name)
}


                                        [ "${ct}" -lt "$((${tt1}-${hyst}))" ] && {
/Temp/{
                                                # decrease fan speed
OFMT="%.f"
#                                              old="${fan[$cn]}"
temp[a]=$5+0
                                                let fan[$cn]-=1
}
                                                [ "${fan[$cn]}" -lt "${fmin}" ] && fan[$cn]="${fmin}"
#                                              showdate  >> /tmp/ffc.log
#                                              echo "GPU ${cn} $ct: setting fan $old -> ${fan[$cn]}"  >> /tmp/ffc.log
                                                DISPLAY=:0.$cn aticonfig --pplib-cmd "set fanspeed 0 ${fan[$cn]}" 1>>/dev/null
                                        }


/Speed/{
speed[$3]=$4
}


                        done
/Freq State/{
freqs[$3]=$4
}


                        devdata="$((
/Clocks/{
core[a]=$4
mem[a]=$5
}


                        for f in ${!fan[@]}
/load/{
                                do
load[a]=$4
                                        echo "Fan Speed $f ${fan[$f]}"
gsub(/%/, "", load[a])
                        done


                        echo "${atidata}"
print "GPU: "a
print "Devname: "name
print "Temperature: " temp[a]
print "Fan Percent: " speed[a]
print "Freq State: " freqs[a]
print "GPU Clock: " core[a]
print "Memory Clock: " mem[a]
print "GPU Activity: " load[a]
print "Status: uAlive"
print "Enabled: U"
print "Utility"
}
')"
}


                        ) | awk '
# Indication part


                                /^Adapter/{
data="$(echo -n "${devdata}" | gawk '
                                        a=$2
                                        name=$0
                                        gsub(/^Adapter.* - /, "", name)
                                }


                                /Temp/{
function pbar(prog, min, max)
                                        OFMT="%.f"
{
                                        temp[a]=$5+0
p=""
                                }
if (min=="") min=10
if (max=="") max=100
inc=((max-min)/10)+0.1
for (i=min; i<=max; i+=inc) {
if (i>prog) p=p" "
else p=p"|"
}
return p
}


                                /Speed/{
/Temperature/{
                                        speed[$3]=$4
OFMT="%.f"
                                }
temp=$2+0
if (temp>79) ctemp="\\e[5;91m"
else
if (temp>69) ctemp="\\e[0;33m"
else
ctemp="\\e[0;32m"
}


                                /Clocks/{
/Fan Percent/{
                                        core[a]=$4
OFMT="%.f"
                                        mem[a]=$5
fan=$3+0
                                }
if (fan>75) cfan="\\e[31m"
else
if (fan>45) cfan="\\e[33m"
else
cfan="\\e[32m"
}


                                /load/{
/Freq State/{
                                        load[a]=$4
if ($3=="1") fstate="\\e[32m"
                                        gsub(/%/, "", load[a])
if ($3=="2") fstate="\\e[91m"
}


                                        print "GPU: "a
/GPU Activity/{
                                        print "Devname: "name
act=$3
                                        print "Temperature: " temp[a]
if (act<80) cact="\\e[0;31m"
                                        print "Fan Percent: " speed[a]
else
                                        print "GPU Clock: " core[a]
if (act<90) cact="\\e[0;33m"
                                        print "Memory Clock: " mem[a]
else
                                        print "GPU Activity: " load[a]
cact="\\e[0;32m"
                                        print "Status: uAlive"
}
                                        print "Enabled: U"
                                        print "Utility"
                                        }
                        ')"
        }


                        data="$(echo -n "${devdata}" | gawk '
/GPU Clock/{
core=$3
}


                                        function pbar(prog, min, max)
/Devname/{
                                        {
name=$0
                                                p=""
gsub(/Devname: /, " | ", name)
                                                if (min=="") min=10
}
                                                if (max=="") max=100
                                                inc=((max-min)/10)+0.1
                                                for (i=min; i<=max; i+=inc) {
                                                        if (i>prog) p=p" "
                                                                else p=p"|"
                                                }
                                                return p
                                        }


                                        /Temperature/{
/Status/{
                                                OFMT="%.f"
stat=$2
                                                temp=$2+0
if (stat=="uAlive") stat="\\e[36m"
                                                if (temp>79) ctemp="\\e[5;31m"
else stat="\\e[5;31m"
                                                        else
}
                                                                if (temp>69) ctemp="\\e[0;33m"
                                                                        else
                                                                                ctemp="\\e[0;32m"
                                        }


                                        /Fan Percent/{
/Memory Clock/{
                                                OFMT="%.f"
mem=$3
                                                fan=$3+0
}
                                                if (fan>75) cfan="\\e[31m"
                                                        else
                                                                if (fan>45) cfan="\\e[33m"
                                                                        else
                                                                                cfan="\\e[32m"
                                        }


                                        /GPU Activity/{
/Enabled/{
                                                act=$3
en=$2
                                                if (act<80) cact="\\e[0;31m"
if (en=="uN") en="X"
                                                        else
else
                                                                if (act<90) cact="\\e[0;33m"
if (en=="U") en="U"
                                                                        else
else en="Y"
                                                                                cact="\\e[0;32m"
}
                                        }


                                        /GPU Clock/{
/^GPU:/{
                                                core=$3
gnum=$2
                                        }
}


                                        /Devname/{
/Utility/{
                                                name=$0
printf "%-67s %-48s %-22s %-61s %s\n",
                                                gsub(/Devname: /, " | ", name)
stat en " GPU "gnum": \\e[0;0m["ctemp pbar(temp, 30, 85) "\\e[0m] " ctemp temp"C\\e[0m",
                                        }
"| FAN: ["cfan pbar(fan)"\\e[0m] " cfan fan"% \\e[0m",
"| "fstate core"/"mem"\\e[0m",
"| Load: \\e[0;0m["cact pbar(act, 50, 99) "\\e[0m] " cact act"%\\e[0;0m",
name
}'
)"


                                        /Status/{
[ "${api}" == '1' ] &&\
                                                stat=$2
data="\t\t\t=========== sgminer stat ===========\n${data}" ||\
                                                if (stat=="uAlive") stat="\\e[36m"
data="\t\t\t=========== aticonfig stat ===========\n${data}"
                                                        else stat="\\e[5;31m"
                                        }


                                        /Memory Clock/{
[ "${1}" == 'single' ] && {
                                                mem=$3
echo -e "${data}"
                                        }
break
} || {
clear
echo -e "${data}"


                                        /Enabled/{
# http://localhost/dyn.html generator
                                                en=$2
(echo -ne "\n* "
                                                if (en=="uN") en="X"
echo $(/home/rain/bin/ethspeed single) @ $(date +%H:%M:%S)
                                                        else
echo -ne "\n"
                                                if (en=="U") en="U"
echo -e "${data}") | LANG=C awk '
                                                        else en="Y"
BEGIN {
                                        }
        print "<html>"
print "<title>"strftime()"</title>"
        print "<meta http-equiv=\"refresh\" content=\"10;\">"
        print "<head><style> body '{'font-family: Courier, monospace;'}'</style></head><body>"
}


                                        /^GPU:/{
{
                                                gnum=$2
                                        }


                                        /Utility/{
gsub(/ /, "\\&nbsp;", $0)
                                                printf "%-67s %-47s %-12s %-61s %s\n",
gsub(/\t/, "\\&emsp;", $0)
                                                        stat en " GPU "gnum": \\e[0;32m["ctemp pbar(temp, 30, 85) "\\e[0m] " ctemp temp"C\\e[0m",
gsub(/$/, "<br>", $0)
                                                        "| FAN: ["cfan pbar(fan)"\\e[0m] " cfan fan"% \\e[0m",
gsub(/\[([0-9];)?31m/, "</font><font color=red>", $0)
                                                        "| "core"/"mem,
gsub(/\[([0-9];)?91m/, "</font><font color=red><span class=redcode>", $0)
                                                        "| Load: \\e[0;32m["cact pbar(act, 50, 99) "\\e[0m] " cact act"%\\e[0;0m",
gsub(/\[([0-9];)?33m/, "</font><font color=darkorange><span class=yellowcode>", $0)
                                                        name
gsub(/\[([0-9];)?32m/, "</font><font color=green><span class=greencode>", $0)
                                        }'
gsub(/\[36m/, "<font color=blue>", $0)
                                        )"
gsub(/\[(0;)?0m/, "</font></span>", $0)
print $0


                [ "${api}" == '1' ] &&\
}
                        data="\t\t\t=========== sgminer stat ===========\n${data}" ||\
                        data="\t\t\t=========== aticonfig stat ===========\n${data}"


                [ "${1}" == 'single' ] && {
END {
                        echo -e "${data}"
print "</body></html>"
                        break
}' > /tmp/dyn.html
                        } || {
}
                        clear
                        echo -e "${data}"
                        }


                sleep "${sleep}"
debugme "Sleeping..."
        done
sleep "${sleep}"
done


        ;;
;;
esac
esac
</source>
</source>


[[Category:Майнинг]][[Category:Radeon]][[Category:Видеокарта]]
[[Category:Майнинг]][[Category:Radeon]][[Category:Видеокарта]]

Версия 11:47, 11 июля 2016

Данный скрипт предназначен для управления частотами и вентиляторами в ригах на базе видеокарт AMD Radeon. Помимо управления, скрипт выводит текущее состояние карт. Если доступно API sgminer (или подобного майнера с такой же структурой вывода данных), то используются его данные и управление отдается ему, а скрипт просто выводит статистику.

ToDo: Дописать
ToDo: В setfreqs $i лишняя. Убрать и/или переделать на возможность указания определенной карты

#!/bin/bash
# By Rain ;)

###################################

# IDLE ZONE - [hyst]-[tt1]-[hyst] - ZONE 1 - [hyst]-[tt2]-[hyst] - ZONE 2 - [hyst]-[toh] - OVERHEAT ZONE [Cut-off] - CUT-OFF ZONE
# For example, for 65 / 70 / 80 / 85 and hysteresis level = 1; and fan min=15; target=60 and max=100:
#  .............. |  64-66   | ............... |  69-71   | .............. |  79-80   | ..........................  | 85 .................
#        idle     |          |      zone1      |          |     zone2      |          |           overheat          |       cutoff
# fan down to 15  | do noth. |  fan up to 60   | do noth. | fan up to 100  | do noth. | fan to 100; clock step down | halt all; fan to 100
#
# For idle zone fan decremental step is 1%
# For zone 1 fan incremental step is 2%
# For zone 2 fan incremental step is 5%
#
# If temperature goes lower than "$toh-(double hysteresis)" - <=77 C - core clock will be restored to config values
#
# TODO: looks like, no need to use hysteresis in between zone2 and overheat zones anymore

###################################

tt1='65' # First target temperature. Fan will be between fmin and tfan
tt2='70' # Second target temperatune. Fan will be up to fmax
toh='80' # Overheat temperature. Reducing frequencies, fan to fmax
tco='85' # Cut-off temperature. Shutting down all mining processes
hyst='1' # Hysteresis

fmin='15' # Minimal fan speed
tfan='60' # Maximum fan speed for first zone
fmax='100' # Maximum fan speed

ohfs='5' # Overheat frequency reducing step
fups='50' # Clock restore step
trst='75' # Clock restore temperature

sleep='5' # internal timer

corelow='300'
memlow='1000' # not used

conf='/home/rain/config/cards.conf' # cgminer/sgminer config file for getting core/mem frequencies
rrdb='/home/rain/.gpustat.rrd'
site='/tmp/site'

###################################


if [ "${1}" != 'single' ]
	then

mkdir -p -m 755 "${site}"

if [ -z "${RRD}" ]
	then
		if [ -x '/usr/bin/rrdtool' ]
			then
			rrd='nice -n 19 /usr/bin/rrdtool'
		fi
	else
		rrd=': '
fi

[ ! -e "${rrdb}" ] && ${rrd} create "${rrdb}" \
--step 60 \
DS:gpu0temp:GAUGE:120:U:U \
DS:gpu1temp:GAUGE:120:U:U \
DS:gpu2temp:GAUGE:120:U:U \
DS:gpu3temp:GAUGE:120:U:U \
DS:gpu4temp:GAUGE:120:U:U \
DS:gpu5temp:GAUGE:120:U:U \
DS:gpu6temp:GAUGE:120:U:U \
DS:gpu7temp:GAUGE:120:U:U \
DS:gpu8temp:GAUGE:120:U:U \
DS:gpu9temp:GAUGE:120:U:U \
RRA:MIN:0.5:1:80  \
RRA:MIN:0.5:8:210  \
RRA:MIN:0.5:80:600  \
RRA:MIN:0.5:600:1100 \
RRA:AVERAGE:0.5:1:80  \
RRA:AVERAGE:0.5:8:210  \
RRA:AVERAGE:0.5:80:600  \
RRA:AVERAGE:0.5:600:1100 \
RRA:MAX:0.5:1:80 \
RRA:MAX:0.5:8:210 \
RRA:MAX:0.5:80:600 \
RRA:MAX:0.5:600:1100

mkgraph() {
umask 022
if [ "$3" == 'normal' ];then
        size='--width 400 --height 200'
elif [ "$3" == 'large' ]; then
        size='--width 900 --height 450'
fi
$rrd graph "${2}" --imgformat PNG \
DEF:gpu0tempmi="${1}":gpu0temp:MIN \
DEF:gpu1tempmi="${1}":gpu1temp:MIN \
DEF:gpu2tempmi="${1}":gpu2temp:MIN \
DEF:gpu3tempmi="${1}":gpu3temp:MIN \
DEF:gpu4tempmi="${1}":gpu4temp:MIN \
DEF:gpu5tempmi="${1}":gpu5temp:MIN \
DEF:gpu6tempmi="${1}":gpu6temp:MIN \
DEF:gpu7tempmi="${1}":gpu7temp:MIN \
DEF:gpu8tempmi="${1}":gpu8temp:MIN \
DEF:gpu9tempmi="${1}":gpu9temp:MIN \
								   \
DEF:gpu0tempav="${1}":gpu0temp:AVERAGE \
DEF:gpu1tempav="${1}":gpu1temp:AVERAGE \
DEF:gpu2tempav="${1}":gpu2temp:AVERAGE \
DEF:gpu3tempav="${1}":gpu3temp:AVERAGE \
DEF:gpu4tempav="${1}":gpu4temp:AVERAGE \
DEF:gpu5tempav="${1}":gpu5temp:AVERAGE \
DEF:gpu6tempav="${1}":gpu6temp:AVERAGE \
DEF:gpu7tempav="${1}":gpu7temp:AVERAGE \
DEF:gpu8tempav="${1}":gpu8temp:AVERAGE \
DEF:gpu9tempav="${1}":gpu9temp:AVERAGE \
								   \
DEF:gpu0tempma="${1}":gpu0temp:MAX \
DEF:gpu1tempma="${1}":gpu1temp:MAX \
DEF:gpu2tempma="${1}":gpu2temp:MAX \
DEF:gpu3tempma="${1}":gpu3temp:MAX \
DEF:gpu4tempma="${1}":gpu4temp:MAX \
DEF:gpu5tempma="${1}":gpu5temp:MAX \
DEF:gpu6tempma="${1}":gpu6temp:MAX \
DEF:gpu7tempma="${1}":gpu7temp:MAX \
DEF:gpu8tempma="${1}":gpu8temp:MAX \
DEF:gpu9tempma="${1}":gpu9temp:MAX \
								   \
CDEF:cdefmida=gpu0tempav,gpu0tempmi,- \
CDEF:cdefmidb=gpu1tempav,gpu1tempmi,- \
CDEF:cdefmidc=gpu2tempav,gpu2tempmi,- \
CDEF:cdefmidd=gpu3tempav,gpu3tempmi,- \
CDEF:cdefmide=gpu4tempav,gpu4tempmi,- \
CDEF:cdefmidf=gpu5tempav,gpu5tempmi,- \
CDEF:cdefmidg=gpu6tempav,gpu6tempmi,- \
CDEF:cdefmidh=gpu7tempav,gpu7tempmi,- \
CDEF:cdefmidi=gpu8tempav,gpu8tempmi,- \
CDEF:cdefmidj=gpu9tempav,gpu9tempmi,- \
									  \
CDEF:cdefmada=gpu0tempma,gpu0tempav,- \
CDEF:cdefmadb=gpu1tempma,gpu1tempav,- \
CDEF:cdefmadc=gpu2tempma,gpu2tempav,- \
CDEF:cdefmadd=gpu3tempma,gpu3tempav,- \
CDEF:cdefmade=gpu4tempma,gpu4tempav,- \
CDEF:cdefmadf=gpu5tempma,gpu5tempav,- \
CDEF:cdefmadg=gpu6tempma,gpu6tempav,- \
CDEF:cdefmadh=gpu7tempma,gpu7tempav,- \
CDEF:cdefmadi=gpu8tempma,gpu8tempav,- \
CDEF:cdefmadj=gpu9tempma,gpu9tempav,- \
									  \
LINE2:gpu0tempav#ff0000:'GPU 0' \
LINE0:gpu0tempmi#ff0000: \
AREA:cdefmida#ff000044::STACK \
AREA:cdefmada#ff000044::STACK \
GPRINT:gpu0tempmi:MIN:"(Min\: %3.1lf°C \t/" \
GPRINT:gpu0tempav:LAST:"Curr\: %3.1lf°C \t/" \
GPRINT:gpu0tempma:MAX:"Max\: %3.1lf°C)\n" \
											\
LINE2:gpu1tempav#ffa800:"GPU 1" \
LINE0:gpu1tempmi#ffa800: \
AREA:cdefmidb#ffa80044::STACK \
AREA:cdefmadb#ffa80044::STACK \
GPRINT:gpu1tempmi:MIN:"(Min\: %3.1lf°C \t/" \
GPRINT:gpu1tempav:LAST:"Curr\: %3.1lf°C \t/" \
GPRINT:gpu1tempma:MAX:"Max\: %3.1lf°C)\n" \
											\
LINE2:gpu2tempav#fff600:"GPU 2" \
LINE0:gpu2tempmi#fff600: \
AREA:cdefmidc#fff60044::STACK \
AREA:cdefmadc#fff60044::STACK \
GPRINT:gpu2tempmi:MIN:"(Min\: %3.1lf°C \t/" \
GPRINT:gpu2tempav:LAST:"Curr\: %3.1lf°C \t/" \
GPRINT:gpu2tempma:MAX:"Max\: %3.1lf°C)\n" \
											\
LINE2:gpu3tempav#6cff00:"GPU 3" \
LINE0:gpu3tempmi#6cff00: \
AREA:cdefmidd#6cff0044::STACK \
AREA:cdefmadd#6cff0044::STACK \
GPRINT:gpu3tempmi:MIN:"(Max\: %3.1lf°C \t/" \
GPRINT:gpu3tempav:LAST:"Curr\: %3.1lf°C \t/" \
GPRINT:gpu3tempma:MAX:"Max\: %3.1lf°C)\n" \
											\
LINE2:gpu4tempav#00ffc0:'GPU 4' \
LINE0:gpu4tempmi#00ffc0: \
AREA:cdefmide#00ffc044::STACK \
AREA:cdefmade#00ffc044::STACK \
GPRINT:gpu4tempmi:MIN:"(Min\: %3.1lf°C \t/" \
GPRINT:gpu4tempav:LAST:"Curr\: %3.1lf°C \t/" \
GPRINT:gpu4tempma:MAX:"Max\: %3.1lf°C)\n" \
											\
LINE2:gpu5tempav#009cff:'GPU 5' \
LINE0:gpu5tempmi#009cff: \
AREA:cdefmidf#009cff44::STACK \
AREA:cdefmadf#009cff44::STACK \
GPRINT:gpu5tempmi:MIN:"(Min\: %3.1lf°C \t/" \
GPRINT:gpu5tempav:LAST:"Curr\: %3.1lf°C \t/" \
GPRINT:gpu5tempma:MAX:"Max\: %3.1lf°C)\n" \
											\
LINE2:gpu6tempav#0030ff:'GPU 6' \
LINE0:gpu6tempmi#0030ff: \
AREA:cdefmidg#0030ff44::STACK \
AREA:cdefmadg#0030ff44::STACK \
GPRINT:gpu6tempmi:MIN:"(Min\: %3.1lf°C \t/" \
GPRINT:gpu6tempav:LAST:"Curr\: %3.1lf°C \t/" \
GPRINT:gpu6tempma:MAX:"Max\: %3.1lf°C)\n" \
											\
LINE2:gpu7tempav#c000ff:'GPU 7' \
LINE0:gpu7tempmi#c000ff: \
AREA:cdefmidh#c000ff44::STACK \
AREA:cdefmadh#c000ff44::STACK \
GPRINT:gpu7tempmi:MIN:"(Min\: %3.1lf°C \t/" \
GPRINT:gpu7tempav:LAST:"Curr\: %3.1lf°C \t/" \
GPRINT:gpu7tempma:MAX:"Max\: %3.1lf°C)\n" \
											\
LINE2:gpu8tempav#d4d2d5:'GPU 8' \
LINE0:gpu8tempmi#d4d2d5: \
AREA:cdefmidi#d4d2d544::STACK \
AREA:cdefmadi#d4d2d544::STACK \
GPRINT:gpu8tempmi:MIN:"(Min\: %3.1lf°C \t/" \
GPRINT:gpu8tempav:LAST:"Curr\: %3.1lf°C \t/" \
GPRINT:gpu8tempma:MAX:"Max\: %3.1lf°C)\n" \
											\
LINE2:gpu9tempav#000000:'GPU 9' \
LINE0:gpu9tempmi#000000: \
AREA:cdefmidj#00000044::STACK \
AREA:cdefmadj#00000044::STACK \
GPRINT:gpu9tempmi:MIN:"(Min\: %3.1lf°C \t/" \
GPRINT:gpu9tempav:LAST:"Curr\: %3.1lf°C \t/" \
GPRINT:gpu9tempma:MAX:"Max\: %3.1lf°C)\n" \
${size} \
--title "${4}" \
-s ${5} \
--watermark="${HOSTNAME}" \
--slope-mode \
--lazy 1>/dev/null &
}

# http://localhost/index.html generator

(echo -n "<html><head><style> body {font-family: Courier, monospace;}</style></head><body><b>"
hostname
echo "</b><br><br>"
/home/rain/bin/sysinfo.sh | sed 's/$/<br>/g' | sed 's/ /\&nbsp\;/g'
echo "<br><li><a href=/gputemp.html>GPU Temp</a>"
echo "<br><iframe src=/dyn.html frameborder=0 height=50% width=100%></iframe></body></html>") > /tmp/index.html

touch '/tmp/dyn.html'
chmod 644 '/tmp/index.html' '/tmp/dyn.html'
fi

# Never use sgminer API if NOAPI is set

[ ! -z "${NOAPI}" ] && cmd="false :"

showdate() {
    echo -ne "\e[0;36m[\e[0;35m"$(date +%Y-%m-%d" "%H:%M:%S)"\e[0;36m]\e[0;0m "
}

# Allow log for debugging purposes

debugme() {
[ "${DEBUG}" == '1' ] && {
	showdate
	echo "${1}"
} >> /tmp/ffc.log
}

# Halt all GPU activity. Change it if needed

do_halt() {
	/home/rain/bin/gpuoff 1>/dev/null 2>/dev/null
	/home/rain/bin/ethminerctl suspend
	pkill -9 Hashcat
}

# XMPP notifications

#if [ "${1}" != 'single' ]
#	then
#	rm -f /tmp/sendxmpp 2>/dev/null
#	touch /tmp/sendxmpp
#	( tail -qF /tmp/sendxmpp 2>/dev/null | sendxmpp -c -r $(hostname) -i -t rigs@conference.linuxoid.in ) &
#fi

sayto() {
	(cat - | tr -d '\n' ; echo -n " on $(hostname)") | sendxmpp -t -r $(hostname) -c rigs@conference.linuxoid.in
#	cat - >> /tmp/sendxmpp
}

# cgminer/sgminer core/mem clocks config parser

getcoreconf(){
	awk '/gpu-engine/{
			gsub(/[0-9]+\-|\"/, "", $3)
			split($3, core, ",")
			c='$1'+1
			print core[c]
		}' "${conf}"
}

getmemconf(){
	awk '/gpu-memclock/{
			gsub(/[0-9]+\-|\"/, "", $3)
			split($3, mem, ",")
			c='$1'+1
			print mem[c]
		}' "${conf}"
}

# Function for setting GPU clocks. 1-st parameter is a card number. If parameter is not set - all cards are used

setfreqs() {
[ -z "${1}" ] && card="$(seq 0 $(($(aticonfig --lsa | grep -c '[0-9]\.')-1)))" || card="${1}"
for i in ${card}
	do
# Allowing overclocking
		aticonfig --od-enable 1>/dev/null

# Getting core and memory clocks. If getcoreconf/getmemconf returns nothing - using GPU 0 clocks
# (sgminer behavior - if one parameter is set - it used for all cards)
		core="$(getcoreconf "${i}")"
		[ -z "${core}" ] && core="$(getcoreconf 0)"

		mem="$(getmemconf "${i}")"
		[ -z "${mem}" ] && core="$(getmemconf 0)"

# Setting GPU clocks
		[[ ! -z "${core}" && ! -z "${mem}" ]] && {
			aticonfig --od-setclocks=$core,$mem --adapter=$i 1>/dev/null
			debugme "Setting freqs for GPU $i"
# Clocks state flag. 1 = clocks set from config file, 2 = clocks is reduced.
			freqs[$i]='1'
		}
	done
# Setting Powertune to 120% via atitweak utility
	[ -x /home/rain/bin/atitweak ] && /home/rain/bin/atitweak -p 20 > /dev/null
	debugme "Setting powertune"
}

###################################

case "${1}" in
	freqs)
		setfreqs
	;;
	*)

# [ "${1}" != 'single' ] && echo "Hello, i'm online" | sayto

# Main loop
	while :
		do
# If NOAPI is not set - checking API availibility
	$cmd nc -w 1 -z localhost 4028 && {
	api='1' # API detected flag
	ffci='0' # $fan array initialisation flag
	debugme "API detected"
# Fetching API data
   	devdata="$(/home/rain/bin/api-example.py devs | sed -r 's/, |\{|\}/\n/g;s/(\n)u|'\''/\1/g')"
	} || {
	api='0' # API not detected

# sgminer process detection '
# ffci must be set to 0 and $fan array must be filled with real data every time when sgminer started or stopped
	if pidof sgminer 1>/dev/null
		then
			if [ -z "${sgdetect}" ]
				then
					debugme "sgminer detected"
					ffci='0'
					sgdetect='1'
		fi
	else
		if [ ! -z "${sgdetect}" ]
			then
			debugme "sgminer disabled"
			unset sgdetect
			ffci='0'
		fi
	fi

	debugme "sgminer=$sgdetect"

	[ "${ffci}" != '1' ] && {
# init fan array
	for j in $(seq 0 $(($(aticonfig --lsa | grep -c '[0-9]\.')-1)))
		do
		fan[$j]="$(DISPLAY=:0.$j aticonfig --pplib-cmd "get fanspeed 0" | awk '/Result/{gsub(/%/, "", $4); print $4}')"
		debugme "Writing array data for GPU $j"
	done

# Setting clocks for all cards
	if [ "${1}" != 'single' ]
		then
			setfreqs
	fi

	ffci='1'
	}

# Fetching data from aticonfig utility
			atidata="$(aticonfig --odgt --odgc --adapter=all 2>/dev/null)"
			debugme "Getting atidata"

#### fans and core frequency control section ####

# Parsing aticonfig output and extracting card number, temperature, core and memory clocks
# TODO: next time use this for all aticonfig data processing. For now we will see core clock updates only in next cycle

			for cdat in $(echo "${atidata}" | tr '\n' ' ' | sed 's/Adapter/\n&/g'| sort | sed -nr '/Adapter/N;s/\n/ /gp' | sed -r 's/^Adapter ([0-9]+) - .*Current Peak : *([0-9]+) +([0-9]+).*Temperature - ([0-9]{1,3}).[0-9]+ C.*/\1:\4:\2:\3/g')
				do

# Separating values between different variables
					cnt="${cdat%:*:*}"
					cn="${cnt%:*}" # Card number
					#ct="${cnt#*:}" # Card temperature # TODO: use array in the future and remove this variable
					ct[$cn]="${cnt#*:}" # Card temperature array

					ccmf="${cdat#*:*:}"
					ccf="${ccmf%:*}" # Card core clock
					cmf="${ccmf#*:}" # Card memory clock

					[ "${freqs[$cn]}" == '1' ] && {
						cmax[$cn]=${ccf} # max core freq array
						mmax[$cn]=${cmf} # max mem  freq array
					}

					debugme "Processing GPU $cn -> ${ct[$cn]} C"
					if [ "${1}" != 'single' ]
						then
# If card temperature is over $tco - halting mining, fans to $fmax (usually 100%)
					[ "${ct[$cn]}" -ge "${tco}" ] && {
						# halt mining
						debugme "Cutoff temp on $cn"
						fan[$cn]=${fmax}
						DISPLAY=:0.$cn aticonfig --pplib-cmd "set fanspeed 0 ${fmax}" 1>/dev/null
#						showdate  >> /tmp/ffc.log
						echo "ALERT! Critical temperature (${ct[$cn]}C) on GPU ${cn}" | sayto
						do_halt
					}

# If card temperature great than $toh, but still less than $tco (80-85 degr. zone) - set fans to max speed and reduce core clocks
					[[ "${ct[$cn]}" -ge "${toh}" && "${ct[$cn]}" -lt "${tco}" ]] && {
						ftalk='25'
						# reduce freqs
						debugme "Overheat on ${cn}: ${freqs[$cn]}"
#						[ "${freqs[$cn]}" == '1' ] && {
#							showdate >> /tmp/ffc.log
#							echo "GPU $cn overheat, reducing clocks" >> /tmp/ffc.log

							debugme "Setting max fan speed on ${cn}"
							fan[$cn]=${fmax}
							DISPLAY=:0.$cn aticonfig --pplib-cmd "set fanspeed 0 ${fmax}" 1>/dev/null

							[ "${ccf}" -gt "$((${corelow}+${ohfs}))" ] && {
								ccf=$((${ccf}-${ohfs}))

								[ "${freqs[$cn]}" == '1' ] && {
									echo "GPU $cn overheat (${ct[$cn]} C), starting core clock reducing" | sayto
								}

								freqs[$cn]='2'
								debugme "Reducing freqs on $cn to ${ccf}/${cmf}"
								aticonfig --od-setclocks=${ccf},${cmf} --adapter=$cn 1>/dev/null
							} || {

								echo "No more space in frequency range on card ${cn} for clock reducing" | sayto
								debugme "No more space in frequency range on card ${cn} for clock reducing"
							}
#						}
					}

# If card temperature goes below overheat level - report about new frequencies

					[[ "${ct[$cn]}" -lt "$((${toh}-${hyst}))" ]] && {
						[ ${freqs[$cn]} == '2' ] && {
							[ ${ftalk} -gt '0' ] && let ftalk-=1
							[ ${ftalk} == '1' ] && {
								echo "GPU $cn clocks reduced to ${ccf}/${cmf}" | sayto
								ftalk='0'
							}
						}
					}

# If card temperature decreased to safe level - $trst - restore core clocks

					[[ "${ct[$cn]}" -le "${trst}" ]] && {

						[ "${freqs[$cn]}" == '2' ] && {
							[ "$((${cmax[$cn]}-${ccf}))" -gt "${fups}"  ] && {
								aticonfig --od-setclocks=$((${ccf}+${fups})),$cmf --adapter=$cn 1>/dev/null
							} || {
								setfreqs "${cn}"
								debugme "Clocks restored on GPU $cn"
								echo "Clocks restored on GPU $cn" | sayto
							}
						}
					}

# If card temperature in second zone (typically 70-80 degr) - allowing fan speed to be up to $fmax

					[[ "${ct[$cn]}" -gt "$((${tt2}+${hyst}))" && "${ct[$cn]}" -lt "$((${toh}-${hyst}))" ]] && {
						debugme "2-nd fan zone on $cn"
						# allow fans to 100%

						[ "${fan[$cn]}" -lt "${fmax}" ] && {
#							old="${fan[$cn]}"
							let fan[$cn]+=5

							[ "${fan[$cn]}" -lt "${tfan}" ] && {
								fan[$cn]=${tfan}
								debugme "Fast heating on $cn"
							}

							[ "${fan[$cn]}" -gt "${fmax}" ] && fan[$cn]="${fmax}"
							debugme "Setting fan to ${fan[$cn]} on GPU $cn"
#							showdate  >> /tmp/ffc.log
#							echo "GPU ${cn} ${ct[$cn]}: setting fan $old -> ${fan[$cn]}"  >> /tmp/ffc.log
							DISPLAY=:0.$cn aticonfig --pplib-cmd "set fanspeed 0 ${fan[$cn]}" 1>/dev/null
						}
					}

# If card temperature in 1-st zone (65-70 degr) - fan speed can be up to $tfan

					[[ "${ct[$cn]}" -gt "$((${tt1}+${hyst}))" && "${ct[$cn]}" -lt "$((${tt2}-${hyst}))" ]] && {
						# allow fans to $tfan
						debugme "1-nd fan zone on $cn"
						[ "${freqs[$cn]}" == '2' ] && {
							setfreqs "${cn}"
						}

						[ "${fan[$cn]}" -lt "${tfan}" ] && {
#							old="${fan[$cn]}"
							let fan[$cn]+=2
							[ "${fan[$cn]}" -gt "${tfan}" ] && fan[$cn]="${tfan}"
#							showdate  >> /tmp/ffc.log
#							echo "GPU ${cn} ${ct[$cn]}: setting fan $old -> ${fan[$cn]}"  >> /tmp/ffc.log
							debugme "Setting fan to ${fan[$cn]} on GPU $cn"
							DISPLAY=:0.$cn aticonfig --pplib-cmd "set fanspeed 0 ${fan[$cn]}" 1>/dev/null
						}
					}

# If card temerature less than first target - fan goes idle

					[ "${ct[$cn]}" -lt "$((${tt1}-${hyst}))" ] && {
						# decrease fan speed
						debugme "Low temp on $cn"
#						old="${fan[$cn]}"
						let fan[$cn]-=1
						[ "${fan[$cn]}" -lt "${fmin}" ] && fan[$cn]="${fmin}"
#						showdate  >> /tmp/ffc.log
#						echo "GPU ${cn} ${ct[$cn]}: setting fan $old -> ${fan[$cn]}"  >> /tmp/ffc.log
						DISPLAY=:0.$cn aticonfig --pplib-cmd "set fanspeed 0 ${fan[$cn]}" 1>>/dev/null
					}

					fi

			done

# TODO: сделать это все как-то покрасивее; возможно - вынести 60 тут и выше (создание базы) в переменную
			[ -z "${st}" ] && st='60'
			let st-=$((60/$sleep))
			[ "${st}" -le '0' ] && {
			st='60'
			$rrd update "${rrdb}" N$(
				s=10
				for t in ${!ct[@]}
					do
					echo -n ":${ct[$t]}"
					let s-=1
				done

				for i in $(seq 1 $s)
					do
						echo -n :U
				done
			)

			mkgraph "${rrdb}" "${site}"/gpustat.h.png               'normal' "GPU Temp, час" -60min
			mkgraph "${rrdb}" "${site}"/gpustat.h.large.png         'large'  "GPU Temp, час" -60min

			mkgraph "${rrdb}" "${site}"/gpustat.d.png               'normal' "GPU Temp, день" -24h
			mkgraph "${rrdb}" "${site}"/gpustat.d.large.png         'large'  "GPU Temp, день" -24h

			mkgraph "${rrdb}" "${site}"/gpustat.m.png               'normal' "GPU Temp, месяц" -30d
			mkgraph "${rrdb}" "${site}"/gpustat.m.large.png         'large'  "GPU Temp, месяц" -30d

			mkgraph "${rrdb}" "${site}"/gpustat.y.png               'normal' "GPU Temp, год" -12mon
			mkgraph "${rrdb}" "${site}"/gpustat.y.large.png         'large'  "GPU Temp, год" -12mon

			}

			devdata="$((

# Exporting fan speed for 2-nd part of this script
			for f in ${!fan[@]}
				do
					echo "Fan Speed $f ${fan[$f]}"
			done

# ...and exporting frequency state
			for c in ${!freqs[@]}
				do
					echo "Freq State $c ${freqs[$c]}"
			done

# Transforming aticonfig data for sgminer API compatible format... With some additions
			echo "${atidata}"

			) | awk '

				/^Adapter/{
					a=$2
					name=$0
					gsub(/^Adapter.* - /, "", name)
				}

				/Temp/{
					OFMT="%.f"
					temp[a]=$5+0
				}

				/Speed/{
					speed[$3]=$4
				}

				/Freq State/{
					freqs[$3]=$4
				}

				/Clocks/{
					core[a]=$4
					mem[a]=$5
				}

				/load/{
					load[a]=$4
					gsub(/%/, "", load[a])

					print "GPU: "a
					print "Devname: "name
					print "Temperature: " temp[a]
					print "Fan Percent: " speed[a]
					print "Freq State: " freqs[a]
					print "GPU Clock: " core[a]
					print "Memory Clock: " mem[a]
					print "GPU Activity: " load[a]
					print "Status: uAlive"
					print "Enabled: U"
					print "Utility"
					}
			')"
	}

# Indication part

			data="$(echo -n "${devdata}" | gawk '

					function pbar(prog, min, max)
					{
						p=""
						if (min=="") min=10
						if (max=="") max=100
						inc=((max-min)/10)+0.1
						for (i=min; i<=max; i+=inc) {
							if (i>prog) p=p" "
								else p=p"|"
						}
						return p
					}

					/Temperature/{
						OFMT="%.f"
						temp=$2+0
						if (temp>79) ctemp="\\e[5;91m"
							else
								if (temp>69) ctemp="\\e[0;33m"
									else
										ctemp="\\e[0;32m"
					}

					/Fan Percent/{
						OFMT="%.f"
						fan=$3+0
						if (fan>75) cfan="\\e[31m"
							else
								if (fan>45) cfan="\\e[33m"
									else
										cfan="\\e[32m"
					}

					/Freq State/{
						if ($3=="1") fstate="\\e[32m"
						if ($3=="2") fstate="\\e[91m"
					}

					/GPU Activity/{
						act=$3
						if (act<80) cact="\\e[0;31m"
							else
								if (act<90) cact="\\e[0;33m"
									else
										cact="\\e[0;32m"
					}

					/GPU Clock/{
						core=$3
					}

					/Devname/{
						name=$0
						gsub(/Devname: /, " | ", name)
					}

					/Status/{
						stat=$2
						if (stat=="uAlive") stat="\\e[36m"
							else stat="\\e[5;31m"
					}

					/Memory Clock/{
						mem=$3
					}

					/Enabled/{
						en=$2
						if (en=="uN") en="X"
							else
						if (en=="U") en="U"
							else en="Y"
					}

					/^GPU:/{
						gnum=$2
					}

					/Utility/{
						printf "%-67s %-48s %-22s %-61s %s\n",
							stat en " GPU "gnum": \\e[0;0m["ctemp pbar(temp, 30, 85) "\\e[0m] " ctemp temp"C\\e[0m",
							"| FAN: ["cfan pbar(fan)"\\e[0m] " cfan fan"% \\e[0m",
							"| "fstate core"/"mem"\\e[0m",
							"| Load: \\e[0;0m["cact pbar(act, 50, 99) "\\e[0m] " cact act"%\\e[0;0m",
							name
					}'
					)"

		[ "${api}" == '1' ] &&\
			data="\t\t\t=========== sgminer stat ===========\n${data}" ||\
			data="\t\t\t=========== aticonfig stat ===========\n${data}"

		[ "${1}" == 'single' ] && {
			echo -e "${data}"
			break
			} || {
			clear
			echo -e "${data}"

# http://localhost/dyn.html generator
			(echo -ne "\n* "
			echo $(/home/rain/bin/ethspeed single) @ $(date +%H:%M:%S)
			echo -ne "\n"
			echo -e "${data}") | LANG=C awk '
				BEGIN {
				        print "<html>"
						print "<title>"strftime()"</title>"
				        print "<meta http-equiv=\"refresh\" content=\"10;\">"
				        print "<head><style> body '{'font-family: Courier, monospace;'}'</style></head><body>"
				}

				{

				gsub(/ /, "\\&nbsp;", $0)
				gsub(/\t/, "\\&emsp;", $0)
				gsub(/$/, "<br>", $0)
				gsub(/\[([0-9];)?31m/, "</font><font color=red>", $0)
				gsub(/\[([0-9];)?91m/, "</font><font color=red><span class=redcode>", $0)
				gsub(/\[([0-9];)?33m/, "</font><font color=darkorange><span class=yellowcode>", $0)
				gsub(/\[([0-9];)?32m/, "</font><font color=green><span class=greencode>", $0)
				gsub(/\[36m/, "<font color=blue>", $0)
				gsub(/\[(0;)?0m/, "</font></span>", $0)
				print $0

				}

				END {
				print "</body></html>"
				}' > /tmp/dyn.html
			}

		debugme "Sleeping..."
		sleep "${sleep}"
	done

	;;
esac