Advertisement
Guest User

rpimonitor-helper.sh

a guest
Dec 6th, 2015
442
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 12.24 KB | None | 0 0
  1. #!/bin/bash
  2. #
  3. # cpu load and dvfs daemon for H3
  4. #
  5. # Extracts dvfs information from script.bin and let a daemon later
  6. # convert cpufreq into Vcore. Also generates cpuload statistics from
  7. # /proc/stat since /proc/loadavg is not precise enough
  8. #
  9. # Copyright 2015 - Thomas Kaiser - http://kaiser-edv.de/
  10. #
  11. # This program is free software: you can redistribute it and/or modify
  12. # it under the terms of the GNU General Public License as published by
  13. # the Free Software Foundation, either version 3 of the License, or
  14. # (at your option) any later version.
  15. #
  16. # This program is distributed in the hope that it will be useful,
  17. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19. # GNU General Public License for more details.
  20. #
  21. # You should have received a copy of the GNU General Public License
  22. # along with this program.  If not, see <http://www.gnu.org/licenses/>.
  23.  
  24. CheckInterval=2.5       # time in seconds between two checks
  25. DiskCheckInterval=60    # time in seconds between disk checks
  26. CheckAllDisks=FALSE     # if set to anything else than FALSE you've to adjust
  27.                         # your data collection settings: both name and regexp. And
  28.                         # display/graph settings should also match the count of
  29.                         # disks since the values for all found disks will be written
  30.                         # space delimited to the temp file. With 4 disks you might
  31.                         # use
  32.                         #
  33.                         # dynamic.12.name=hddtemp1,hddtemp2,hddtemp3,hddtemp4
  34.                         # dynamic.12.source=/tmp/disktemp
  35.                         # dynamic.12.regexp=^(\S+)\s(\S+)\s(\S+)\s(\S+)
  36.                         #
  37.                         # And please keep in mind that disk enumeration might not
  38.                         # be persistent across reboots so become familiar with
  39.                         # udev rules, access disks by UUID or use /dev/disk/by-id/
  40.                         # 'blkid' and 'udevadm info --query=property --name=/dev/sda'
  41.                         # are your friends and help you to get the idea.
  42.  
  43. CpuStatCheckInterval=10 # define in which interval CPU statistics should be queried
  44.  
  45. TempCheckInterval=180   # In case you want to query external weather stations via HTTP
  46.                         # define an interval here and adjust the GetExternalTemp function
  47.  
  48. # in case you're doing disk related tests and are interested in precise thermal measurements
  49. # then uncomment the next line
  50. # DiskCheckInterval=1
  51.  
  52. Main() {
  53.     # preparations
  54.     export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
  55.     CheckPrerequisits "$@"
  56.  
  57.         # ensure we're writing to files instead of symlinks
  58.         CreateTempDir
  59.  
  60.         # parse dvfs table and create GetVCore funtion
  61.         ParseDVFSTable
  62.         source /tmp/dvfs-table
  63.  
  64.     # start the infinite loop to collect data
  65.     while true ; do
  66.         # get VCore
  67.         read CPUFreq </sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq
  68.         GetVCore ${CPUFreq} >/tmp/VCore
  69.  
  70.         # check disk temperature(s). We execute this only every ${DiskCheckInterval} since
  71.         # it's a bit costly (S.M.A.R.T. queries).
  72.         TimeNow=$(( $(date "+%s") / ${DiskCheckInterval} ))
  73.         if [[ ${TimeNow} -gt ${LastDiskCheck} ]]; then
  74.             # time for a disk check. If ${CheckAllDisks} is FALSE and /dev/sda exists we
  75.             # only query this device otherwise all available (might be none)
  76.             CheckDisks
  77.             # update check timestamp
  78.             LastDiskCheck=${TimeNow}
  79.         fi
  80.  
  81.         # External temperature from weather stations
  82.         TimeNow=$(( $(date "+%s") / ${TempCheckInterval} ))
  83.         if [[ ${TimeNow} -gt ${LastTempCheck} ]]; then
  84.             # read in external temp values from 2 different web sources
  85.             ExternalTemp=$(GetExternalTemp)
  86.             LastExternalTemp=$(SanitizeValue ${ExternalTemp} ${LastExternalTemp} | tee /tmp/externaltemp)
  87.             LastTempCheck=${TimeNow}
  88.         fi
  89.        
  90.         # cpustat
  91.         TimeNow=$(( $(date "+%s") / ${CpuStatCheckInterval} ))
  92.         if [[ ${TimeNow} -gt ${LastCpuStatCheck} ]]; then
  93.             ProcessStats
  94.             LastCpuStatCheck=${TimeNow}
  95.         fi
  96.         sleep ${CheckInterval}
  97.     done
  98. } # Main
  99.  
  100. CheckPrerequisits() {
  101.     # prerequisits
  102.     # write PID to pidfile, ensure deletion
  103.     if [ $# -eq 1 ]; then
  104.         echo $$ >"${1}"
  105.         trap "rm \"${1}\" ; exit 0" 0 1 2 3 15
  106.     fi
  107.  
  108.     # ensure bin2fex, links, hddtemp and smartmontools  are installed
  109.     which links >/dev/null 2>&1 || apt-get -f -qq -y install links
  110.     which bin2fex >/dev/null 2>&1 || apt-get -f -qq -y install sunxi-tools
  111.     which hddtemp >/dev/null 2>&1 || apt-get -f -qq -y install hddtemp
  112.     which smartctl >/dev/null 2>&1 || apt-get -f -qq -y install smartmontools
  113.  
  114.     Path2ScriptBin="$(df | awk -F" " '/^\/dev\/mmcblk0p1/ {print $6}')"
  115.     if [ ! -f "${Path2ScriptBin}/script.bin" ]; then
  116.             echo "Can not find script.bin. Ensure boot partition is mounted" >&2
  117.         logger "Can not find script.bin. Ensure boot partition is mounted"
  118.             exit 1
  119.     fi
  120.     unset LANG
  121.     LastDiskCheck=0
  122.     LastTempCheck=0
  123.     LastUserStat=0
  124.     LastNiceStat=0
  125.     LastSystemStat=0
  126.     LastIdleStat=0
  127.     LastIOWaitStat=0
  128.     LastIrqStat=0
  129.     LastSoftIrqStat=0
  130.     LastCpuStatCheck=0
  131. } # CheckPrerequisits
  132.  
  133. ParseDVFSTable() {
  134.     # extract DRAM and dvfs settings from script.bin
  135.     bin2fex <"${Path2ScriptBin}/script.bin" 2>/dev/null | \
  136.         egrep "^LV._|^LV_|extrem|boot_clock|_freq|^dram_" | \
  137.         egrep -v "cpu_freq|dram_freq" | while read ; do
  138.         echo "# ${REPLY}"
  139.     done >/tmp/dvfs-table
  140.  
  141.     echo -e '\nGetVCore() {' >>/tmp/dvfs-table
  142.  
  143.     # parse /tmp/dvfs-table to get dvfs entries
  144.     grep "^# LV._freq" /tmp/dvfs-table | sort -r | while read ; do
  145.         set ${REPLY}
  146.         CPUFreq=$4
  147.         # if [ ${CPUFreq} -eq 0 ]; then
  148.         #   echo -e "if [ \$1 -ge $(( ${CPUFreq} / 1000 )) ]; then\n\techo -n ${VCore}\nel\c" >>/tmp/dvfs-table
  149.         #   break
  150.         # else
  151.         #   VCore=$(grep -A1 "^# $2" /tmp/dvfs-table | tail -n1 | awk -F" " '{print $4}')
  152.         #   echo -e "if [ \$1 -ge $(( ${CPUFreq} / 1000 )) ]; then\n\techo -n ${VCore}\nel\c" >>/tmp/dvfs-table
  153.         if [ ${CPUFreq} -ne 0 ]; then
  154.             VCore=$(grep -A1 "^# $2" /tmp/dvfs-table | tail -n1 | awk -F" " '{print $4}')
  155.             echo -e "if [ \$1 -le $(( ${CPUFreq} / 1000 )) ]; then\n\techo -n ${VCore}\nel\c" >>/tmp/dvfs-table
  156.         fi
  157.     done
  158.     # VCore=$(grep -A1 "^# LV1_freq" /tmp/dvfs-table | tail -n1 | awk -F" " '{print $4}')
  159.     echo -e "se\n\techo -n ${VCore}\nfi\n}" >>/tmp/dvfs-table
  160. } # ParseDVFSTable
  161.  
  162. CreateTempDir() {
  163.     # create a safe temporary dir with the three files therein and symlinks to /tmp/
  164.     MyTempDir=$(mktemp -d /tmp/rpimonitor.XXXXXX)
  165.     if [ ! -d "${MyTempDir}" ]; then
  166.         MyTempDir=/tmp/rpimonitor.$RANDOM.$RANDOM.$RANDOM.$$
  167.         (umask 077 && mkdir ${MyTempDir}) || (echo "Failed to create temp dir. Aborting" >&2 ; exit 1)
  168.     fi
  169.     for file in VCore cpustat externaltemp disktemp dvfs-table; do
  170.         echo -n "0" > "${MyTempDir}/${file}"
  171.         chmod 644 "${MyTempDir}/${file}"
  172.         ln -f -s ${MyTempDir}/${file} /tmp/${file}
  173.     done
  174.     chmod 711 "${MyTempDir}"
  175. } #CreateTempFiles
  176.  
  177. CheckDisks() {
  178.     # We check either /dev/sda or all available block devices -- see above for
  179.     # contents/consequences of $CheckAllDisks
  180.     if [ "X${CheckAllDisks}" = "XFALSE" -a -L /sys/block/sda ]; then
  181.         DiskTemp=$(GetDiskTemp /dev/sda)
  182.         LastDiskTemp=$(SanitizeValue ${DiskTemp} ${LastDiskTemp} | tee /tmp/disktemp)
  183.     else
  184.         DiskTemp=""
  185.         for diskdevice in /sys/block/sd* ; do
  186.             RawDiskTemp=$(GetDiskTemp /dev/${diskdevice##*/})
  187.             DiskTemp="${DiskTemp}$(SanitizeValue ${RawDiskTemp}) "
  188.         done
  189.         if [ "X${DiskTemp}" = "X " ]; then
  190.             echo -n "0" >/tmp/disktemp
  191.         else
  192.             echo "${DiskTemp}" >/tmp/disktemp
  193.         fi
  194.     fi
  195. } # CheckDisks
  196.  
  197. GetDiskTemp() {
  198.     # get disk temperate using hddtemp (doesn't wake up sleeping disks and knows how to deal
  199.     # with different disks due to an included database with known disk models).
  200.    
  201.     # RawTemp=$(/usr/sbin/hddtemp -n ${1} 2>/dev/null)
  202.     RawTemp=$(/usr/sbin/smartctl -d sat -a ${1} | awk -F" " '/Temperature_Cel/ {printf ("%0.0f",$10); }')
  203.     if [ "X${RawTemp}" = "X" ]; then
  204.         # drive is sleeping, we return 0
  205.         echo 0
  206.     else
  207.         echo ${RawTemp} | awk '{printf ("%0.0f",$1*1000); }'
  208.     fi
  209.    
  210.     # The commented smartctl call below is meant as an alternative and an example for USB
  211.     # disks in external enclosures that are able to answer S.M.A.R.T. queries since they're
  212.     # SAT capable:
  213.     #
  214.     # /usr/sbin/smartctl -d sat -a ${1} | awk -F" " '/Temperature_Cel/ {printf ("%0.0f",$10); }'
  215.     #
  216.     # You should be aware that not every enclosure supports that and that some USB-to-SATA
  217.     # bridges require different parameters (eg. '-d usbjmicron' -- have a close look at
  218.     # https://www.smartmontools.org/wiki/Supported_USB-Devices and test with smartctl to
  219.     # get the correct value of the correct attribute).
  220.     #
  221.     # You should also be aware that a query by smartctl always wakes up sleeping disks. So
  222.     # in case you want to query an external USB disk only if it's neither standby nor sleeping
  223.     # and in case the enclosure is SAT capable think about prefixing the smartctl call with
  224.     # something like:
  225.     #
  226.     # /sbin/hdparm -C ${1} | egrep -q "standby|sleeping" || /usr/sbin/smartctl ...
  227.     #
  228.     # In case you try to query multiple disks you might end up with something like
  229.     #
  230.     # case ${1} in
  231.     #     /dev/sda) /usr/sbin/hddtemp -n ${1} ... ;;
  232.     #     /dev/sdb) /usr/sbin/smartctl -d usbprolific -a ${1} ... ;;
  233.     #     /dev/sdc) /sbin/hdparm -C ${1} | egrep -q "standby|sleeping" || /usr/sbin/smartctl -d sat ... ;;
  234.     # esac
  235. } # GetDiskTemp
  236.  
  237. ProcessStats() {
  238.     set $(awk -F" " '/^cpu / {print $2"\t"$3"\t"$4"\t"$5"\t"$6"\t"$7"\t"$8}' </proc/stat)
  239.     UserStat=$1
  240.     NiceStat=$2
  241.     SystemStat=$3
  242.     IdleStat=$4
  243.     IOWaitStat=$5
  244.     IrqStat=$6
  245.     SoftIrqStat=$7
  246.    
  247.     UserDiff=$(( ${UserStat} - ${LastUserStat} ))
  248.     NiceDiff=$(( ${NiceStat} - ${LastNiceStat} ))
  249.     SystemDiff=$(( ${SystemStat} - ${LastSystemStat} ))
  250.     IdleDiff=$(( ${IdleStat} - ${LastIdleStat} ))
  251.     IOWaitDiff=$(( ${IOWaitStat} - ${LastIOWaitStat} ))
  252.     IrqDiff=$(( ${IrqStat} - ${LastIrqStat} ))
  253.     SoftIrqDiff=$(( ${SoftIrqStat} - ${LastSoftIrqStat} ))
  254.    
  255.     Total=$(( ${UserDiff} + ${NiceDiff} + ${SystemDiff} + ${IdleDiff} + ${IOWaitDiff} + ${IrqDiff} + ${SoftIrqDiff} ))
  256.     CPULoad=$(( ( ${Total} - ${IdleDiff} ) * 100 / ${Total} ))
  257.     UserLoad=$(( ${UserDiff} *100 / ${Total} ))
  258.     SystemLoad=$(( ${SystemDiff} *100 / ${Total} ))
  259.     NiceLoad=$(( ${NiceDiff} *100 / ${Total} ))
  260.     IOWaitLoad=$(( ${IOWaitDiff} *100 / ${Total} ))
  261.     IrqCombinedLoad=$(( ( ${IrqDiff} + ${SoftIrqDiff} ) *100 / ${Total} ))
  262.    
  263.     echo "${CPULoad} ${SystemLoad} ${UserLoad} ${NiceLoad} ${IOWaitLoad} ${IrqCombinedLoad}" >/tmp/cpustat
  264.  
  265.     LastUserStat=${UserStat}
  266.     LastNiceStat=${NiceStat}
  267.     LastSystemStat=${SystemStat}
  268.     LastIdleStat=${IdleStat}
  269.     LastIOWaitStat=${IOWaitStat}
  270.     LastIrqStat=${IrqStat}
  271.     LastSoftIrqStat=${SoftIrqStat}
  272. } # ProcessStats
  273.  
  274. GetExternalTemp() {
  275.     # function that parses meteo.physik.uni-muenchen.de and mingaweda.de
  276.     # temperature values for Munich and compares them. When values are out
  277.     # of bounds then only the other value will be returned otherwise the average
  278.     ExternalTemp1=$(/usr/bin/links -http.fake-user-agent 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/600.7.12 (KHTML, like Gecko) Version/8.0.7 Safari/600.7.12' -dump "http://www.meteo.physik.uni-muenchen.de/dokuwiki/doku.php?id=wetter:stadt:messung" | awk -F" " '/Lufttemperatur/ {printf ("%0.0f",$4*1000); }')
  279.     ExternalTemp2=$(/usr/bin/links -http.fake-user-agent 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/600.7.12 (KHTML, like Gecko) Version/8.0.7 Safari/600.7.12' -dump "http://www.mingaweda.de/wetterdaten/" | awk -F" " '/Ausfu:hrliche/ {printf ("%0.0f",$2*1000); }')
  280.    
  281.     if [ "X${ExternalTemp2}" = "X" ]; then
  282.         ExternalTemp2=${ExternalTemp1}
  283.     elif [ "X${ExternalTemp1}" = "X" ]; then
  284.         ExternalTemp1=${ExternalTemp2}
  285.     fi
  286.  
  287.     echo $(( ( ${ExternalTemp1} + ${ExternalTemp2} ) / 2 ))
  288. } # GetExternalTemp
  289.  
  290. SanitizeValue() {
  291.     # keep thermal values in the range of 0°C-100°C since sometimes the values are massively out
  292.     # of range and then your graphs suffer from this. If a second argument is supplied then create
  293.     # an average value to smooth graphs (useful for PMU and SoC)
  294.     if [[ ${1} -lt 0 ]]; then
  295.         echo -n 0
  296.     elif [[ ${1} -ge 100000 ]]; then
  297.         echo -n ${1}
  298.     else
  299.         if [[ "X$2" = "X" ]]; then
  300.             echo -n ${1}
  301.         else
  302.             echo -n $(( ( $1 + $2 * 5 ) / 6 ))
  303.         fi
  304.     fi
  305. } # SanitizeValue
  306.  
  307. Main "$@"
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement