9
\$\begingroup\$

Inspired by this question: To calculate the total CPU usage as a percentage

I wrote the following bash script (as an answer) to calculate the CPU usage for a (configurable) period over all CPU cores on a host.

#!/bin/bash
#CORECOUNT=$(grep cpu /proc/stat | grep -v 'cpu ' | wc -l)
#echo $CORECOUNT cores not needed for calculation though
DELAY=${1:-1}
function getstat() {
 grep 'cpu ' /proc/stat | sed -e 's/ */x/g' -e 's/^cpux//'
}
function extract() {
 echo 1ドル | cut -d 'x' -f 2ドル
}
function change() {
 local e=$(extract $ENDSTAT 1ドル)
 local b=$(extract $STARTSTAT 1ドル)
 local diff=$(( $e - $b ))
 echo $diff
}
#Record the start statistics
STARTSTAT=$(getstat)
sleep $DELAY
#Record the end statistics
ENDSTAT=$(getstat)
#http://www.mjmwired.net/kernel/Documentation/filesystems/proc.txt#1236
#echo "From $STARTSTAT"
#echo "TO $ENDSTAT"
# usr nice sys idle iowait irq guest
#From 177834 168085 1276260 3584351494 144468 154895 0 0 0 0
#TO 177834 168085 1276261 3584351895 144468 154895 0 0 0 0
USR=$(change 1)
SYS=$(change 3)
IDLE=$(change 4)
IOW=$(change 5)
#echo USR $USR SYS $SYS IDLE $IDLE IOW $IOW
ACTIVE=$(( $USR + $SYS + $IOW ))
TOTAL=$(($ACTIVE + $IDLE))
PCT=$(( $ACTIVE * 100 / $TOTAL ))
echo "BUSY $ACTIVE TOTAL $TOTAL $PCT %"

The key features I wanted to ensure are just a single read of the stat file at the beginning, and another single read at the end.

There is some debate about what constitutes 'active' time (Is IOWait busy, or idle time?) If you have insights on that, I would appreciate that too.

All suggestions and criticisms welcome.

asked Sep 9, 2014 at 15:32
\$\endgroup\$

2 Answers 2

6
\$\begingroup\$

Nice script :-)

getstat is a bit odd:

  • It runs a grep and then a sed, when probably a single sed (or awk) could do the job
  • It replaces spaces with x, but not very clear why:
    • I see that extract uses x as the separator, but it could just as well use space for that
    • I also see that using x as the separator makes the change function slightly simpler, because it lets you write extract $ENDSTAT instead of extract "$ENDSTAT", but then again, having to quote doesn't seem a big problem

In extract, you run an echo and then a cut:

echo 1ドル | cut -d 'x' -f 2ドル

In bash you can use here strings, which is better than using echo:

cut -d 'x' -f 2ドル <<< 1ドル

But actually, if we keep the spaces as the separator in getstat, then we can rewrite both of these functions with fewer extra processes:

function getstat() {
 sed -ne '/^cpu */s/^cpu *//p' /proc/stat
 # that is:
 # -n to not print lines by default
 # for lines matching /^cpu */, delete /^cpu */, and print the line
}
function extract() {
 # example 1st param: "437797 1219 185341 549955584 58662 4 7083 0 0 0"
 # example 2nd param: 1, 2, 3, ... (the n-th column to use)
 n=2ドル # saving the position param
 set -- 1ドル # reset positional params from 1,ドル so that 1ドル=437797, 2ドル=1219, ...
 echo ${!n} # echo the n-th positional param
}
function change() {
 local e=$(extract "$ENDSTAT" 1ドル)
 local b=$(extract "$STARTSTAT" 1ドル)
 echo $(( $e - $b ))
}
answered Sep 9, 2014 at 15:49
\$\endgroup\$
4
\$\begingroup\$

Thanks rolfl for originally solving the problem! (What a doozy...) I thought I'd share my own version using AWK. Although it is extremely dense, I think it is still more readable than the original.

{ cat /proc/stat; sleep "$DELAY"; cat /proc/stat; } | \
 awk '/^cpu / {usr=2ドル-usr; sys=4ドル-sys; idle=5ドル-idle; iow=6ドル-iow} \
 END {total=usr+sys+idle+iow; printf "%.2f\n", (total-idle)*100/total}'
  • The first part in { } outputs the contents of /proc/stat twice, separated by DELAY seconds.
  • The awk expression filters only lines starting with 'cpu '
  • The first matching row will set usr, sys, idle, and iow. Because the vars are initially unset, subtracting their values has no effect.
  • The second matching row will set usr, sys, idle, and iow to the difference between the new value and the old value because of the subtraction.
  • The END block computes the total, multiplies by 100 to get percent, and formats to 2 decimal places
answered Nov 24, 2015 at 2:23
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.