Скрипт контроля частот и вентиляторов видеокарт 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