I learned how to calculate CPU utilization when I started to use dzen from dzens gcpubar source.

Later, I read the `man proc` and knew more about it:

`/proc/stat`kernel/system statistics. Varies with architecture. Common entries include:

`cpu 3357 0 4313 1362393`The amount of time, measured in units of

`USER_HZ`(1/100ths of a second on most architectures, use`sysconf(_SC_CLK_TCK)`to obtain the right value), that the system spent in user mode, user mode with low priority (nice), system mode, and the idle task, respectively.The last value should be USER_HZ times the second entry in the uptime pseudo-file.In Linux 2.6 this line includes three additional columns: iowait - time waiting for I/O to complete (since 2.5.41); irq - time servicing interrupts (since 2.6.0-test4); softirq - time servicing softirqs (since 2.6.0-test4).

Since Linux 2.6.11, there is an eighth column, steal - stolen time, which is the time spent in other operating systems when running in a virtualized environment

Since Linux 2.6.24, there is a ninth column, guest, whichis the time spent running a virtual CPU for guest operating systems under the control of the Linux kernel.

It said the number is measured in units of

`USER_HZ`and I assume that also applies on columns after fourth column. The easy way is to sum of all difference of two consecutive samples of those numbers. That sum represents the processed time between two sampling time. In which, the difference of column four is the idling time. If sum minus this idling time, that is the CPU utilization, divide it by sum, then its the percentage of CPU utilization.

Here is a sample of first few lines of `/proc/stat`:

cpu 972478 47 394033 6711061 136593 2572 9139 0 0 0 cpu0 487126 17 199314 3294038 89582 2572 8539 0 0 0 cpu1 485352 29 194719 3417023 47011 0 599 0 0 0

If you count the columns, there is a tenth column, I have no idea what tenth column means. It wasnt mentioned in manpage.

Anyway, here is a sample code:

while :; do # 0 1:user 2:unice 3:sys 4:idle 5:iowait 6:irq 7:softirq 8:steal 9:guest 10:? ncpu=($(line</proc/stat)) sum="${ncpu[]:1}" cpu_total=$((${sum// /+})) cpu_maxval=$((cpu_total - ocpu_total)) cpu_val=$((cpu_maxval - (ncpu[4]-ocpu[4]))) cpu_percentage=$((100 * cpu_val / cpu_maxval)) ocpu=("${ncpu[]}") ocpu_total=$cpu_total echo "$cpu_percentage%" sleep 1 done

There are few tricky things, I used `line` to grab first line since I only need to know the total percentage of all process units. After that, it is fed to Bash array `ncpu` initialization. Pretty neat, isnt it?

Then, the code assigns `sum` with a string representation of `ncpu` of elements from second to last. The first one is `"cpu"`, we dont need that. Replacing all spaces with plus sign, so it will read like `123+456+...`. Feed it to arithmetic expansion, we get the sum of all numbers. Minus it with previous sum, that is sum of difference of two samples, `cpu_maxval`.

Then, minus the difference of idling time, its the utilization time, `cpu_val`. Let `cpu_val` be divided by `cpu_maxval`, we get the percentage. Job is done.

I had to check the kernel source directly to find out what the last few columns were:

ReplyDeleteseq_printf(p, "cpu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",

(unsigned long long)cputime64_to_clock_t(user),

(unsigned long long)cputime64_to_clock_t(nice),

(unsigned long long)cputime64_to_clock_t(system),

(unsigned long long)cputime64_to_clock_t(idle),

(unsigned long long)cputime64_to_clock_t(iowait),

(unsigned long long)cputime64_to_clock_t(irq),

(unsigned long long)cputime64_to_clock_t(softirq),

(unsigned long long)cputime64_to_clock_t(steal),

(unsigned long long)cputime64_to_clock_t(guest),

(unsigned long long)cputime64_to_clock_t(guest_nice));