yambar/examples/scripts/cpu.sh
Daniel Eklöf 9718c6f31e
examples: scripts: cpu: fix idle and total calculation
* include iowait in idle
* guest/guestnice is accounted in user/nice, so need to subtract them
  to not count them twice
2020-11-25 20:41:44 +01:00

124 lines
3 KiB
Bash
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# cpu.sh - measures CPU usage at a configurable sample interval
#
# Usage: cpu.sh INTERVAL_IN_SECONDS
#
# This script will emit the following tags on stdout (N is the number
# of logical CPUs):
#
# Name Type
# --------------------
# cpu range 0-100
# cpu0 range 0-100
# cpu1 range 0-100
# ...
# cpuN-1 range 0-100
#
# I.e. cpu is the average (or aggregated) CPU usage, while cpuX is a
# specific CPUs usage.
#
# Example configuration (update every second):
#
# - script:
# path: /path/to/cpu.sh
# args: [1]
# content: {string: {text: "{cpu}%"}}
#
interval=${1}
case ${interval} in
''|*[!0-9]*)
echo "interval must be an integer"
exit 1
;;
*)
;;
esac
# Get number of CPUs, by reading /proc/stat
# The output looks like:
#
# cpu A B C D ...
# cpu0 A B C D ...
# cpu1 A B C D ...
# cpuN A B C D ...
#
# The first line is a summary line, accounting *all* CPUs
IFS=$'\n' readarray -t all_cpu_stats < <(grep -e "^cpu" /proc/stat)
cpu_count=$((${#all_cpu_stats[@]} - 1))
# Arrays of previous idle and total stats, needed to calculate the
# difference between each sample.
prev_idle=()
prev_total=()
for i in $(seq ${cpu_count}); do
prev_idle+=(0)
prev_total+=(0)
done
prev_average_idle=0
prev_average_total=0
while true; do
IFS=$'\n' readarray -t all_cpu_stats < <(grep -e "^cpu" /proc/stat)
usage=() # CPU usage in percent, 0 <= x <= 100
average_idle=0 # All CPUs idle time since boot
average_total=0 # All CPUs total time since boot
for i in $(seq 0 $((cpu_count - 1))); do
# Split this CPUs stats into an array
stats=($(echo "${all_cpu_stats[$((i + 1))]}"))
# man procfs(5)
user=${stats[1]}
nice=${stats[2]}
system=${stats[3]}
idle=${stats[4]}
iowait=${stats[5]}
irq=${stats[6]}
softirq=${stats[7]}
steal=${stats[8]}
guest=${stats[9]}
guestnice=${stats[10]}
# Guest time already accounted for in user
user=$((user - guest))
nice=$((nice - guestnice))
idle=$((idle + iowait))
total=$((user + nice + system + irq + softirq + idle + steal + guest + guestnice))
average_idle=$((average_idle + idle))
average_total=$((average_total + total))
# Diff since last sample
diff_idle=$((idle - prev_idle[i]))
diff_total=$((total - prev_total[i]))
usage[i]=$((100 * (diff_total - diff_idle) / diff_total))
prev_idle[i]=${idle}
prev_total[i]=${total}
done
diff_average_idle=$((average_idle - prev_average_idle))
diff_average_total=$((average_total - prev_average_total))
average_usage=$((100 * (diff_average_total - diff_average_idle) / diff_average_total))
prev_average_idle=${average_idle}
prev_average_total=${average_total}
echo "cpu|range:0-100|${average_usage}"
for i in $(seq 0 $((cpu_count - 1))); do
echo "cpu${i}|range:0-100|${usage[i]}"
done
echo ""
sleep "${interval}"
done