Accurate calculation of CPU usage given in percentage in Linux?
According the htop source code, my assumptions looks like they are valid:
(see static inline double LinuxProcessList_scanCPUTime(LinuxProcessList* this)
function at LinuxProcessList.c)
// Guest time is already accounted in usertime
usertime = usertime - guest; # As you see here, it subtracts guest from user time
nicetime = nicetime - guestnice; # and guest_nice from nice time
// Fields existing on kernels >= 2.6
// (and RHEL's patched kernel 2.4...)
unsigned long long int idlealltime = idletime + ioWait; # ioWait is added in the idleTime
unsigned long long int systemalltime = systemtime + irq + softIrq;
unsigned long long int virtalltime = guest + guestnice;
unsigned long long int totaltime = usertime + nicetime + systemalltime + idlealltime + steal + virtalltime;
And so, from fields listed in the first line of /proc/stat
: (see section 1.8 at documentation)
user nice system idle iowait irq softirq steal guest guest_nice
cpu 74608 2520 24433 1117073 6176 4054 0 0 0 0
Algorithmically, we can calculate the CPU usage percentage like:
PrevIdle = previdle + previowait
Idle = idle + iowait
PrevNonIdle = prevuser + prevnice + prevsystem + previrq + prevsoftirq + prevsteal
NonIdle = user + nice + system + irq + softirq + steal
PrevTotal = PrevIdle + PrevNonIdle
Total = Idle + NonIdle
# differentiate: actual value minus the previous one
totald = Total - PrevTotal
idled = Idle - PrevIdle
CPU_Percentage = (totald - idled)/totald
The following is a bash script which is based on Vangelis's answer. It produces output like this:
total 49.1803
cpu0 14.2857
cpu1 100
cpu2 28.5714
cpu3 100
cpu4 30
cpu5 25
Create a file called get_cpu_usage.sh
Run it using the following command: bash get_cpu_usage.sh 0.2
The argument is the number of seconds to measure. In this case it's 200 milliseconds.
The contents are:
#!/bin/sh
sleepDurationSeconds=$1
previousDate=$(date +%s%N | cut -b1-13)
previousStats=$(cat /proc/stat)
sleep $sleepDurationSeconds
currentDate=$(date +%s%N | cut -b1-13)
currentStats=$(cat /proc/stat)
cpus=$(echo "$currentStats" | grep -P 'cpu' | awk -F " " '{print $1}')
for cpu in $cpus
do
currentLine=$(echo "$currentStats" | grep "$cpu ")
user=$(echo "$currentLine" | awk -F " " '{print $2}')
nice=$(echo "$currentLine" | awk -F " " '{print $3}')
system=$(echo "$currentLine" | awk -F " " '{print $4}')
idle=$(echo "$currentLine" | awk -F " " '{print $5}')
iowait=$(echo "$currentLine" | awk -F " " '{print $6}')
irq=$(echo "$currentLine" | awk -F " " '{print $7}')
softirq=$(echo "$currentLine" | awk -F " " '{print $8}')
steal=$(echo "$currentLine" | awk -F " " '{print $9}')
guest=$(echo "$currentLine" | awk -F " " '{print $10}')
guest_nice=$(echo "$currentLine" | awk -F " " '{print $11}')
previousLine=$(echo "$previousStats" | grep "$cpu ")
prevuser=$(echo "$previousLine" | awk -F " " '{print $2}')
prevnice=$(echo "$previousLine" | awk -F " " '{print $3}')
prevsystem=$(echo "$previousLine" | awk -F " " '{print $4}')
previdle=$(echo "$previousLine" | awk -F " " '{print $5}')
previowait=$(echo "$previousLine" | awk -F " " '{print $6}')
previrq=$(echo "$previousLine" | awk -F " " '{print $7}')
prevsoftirq=$(echo "$previousLine" | awk -F " " '{print $8}')
prevsteal=$(echo "$previousLine" | awk -F " " '{print $9}')
prevguest=$(echo "$previousLine" | awk -F " " '{print $10}')
prevguest_nice=$(echo "$previousLine" | awk -F " " '{print $11}')
PrevIdle=$((previdle + previowait))
Idle=$((idle + iowait))
PrevNonIdle=$((prevuser + prevnice + prevsystem + previrq + prevsoftirq + prevsteal))
NonIdle=$((user + nice + system + irq + softirq + steal))
PrevTotal=$((PrevIdle + PrevNonIdle))
Total=$((Idle + NonIdle))
totald=$((Total - PrevTotal))
idled=$((Idle - PrevIdle))
CPU_Percentage=$(awk "BEGIN {print ($totald - $idled)/$totald*100}")
if [[ "$cpu" == "cpu" ]]; then
echo "total "$CPU_Percentage
else
echo $cpu" "$CPU_Percentage
fi
done