Linux CPU utilization

From Rosetta Code
Revision as of 09:37, 27 May 2015 by Paul (talk | contribs) (Created page with "{{draft task}}'''Task''': Display the current CPU utilization, calculated from <code>/proc/stat</code>. '''Background''': Most Linux kernels provide a virtual <code>[https:/...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Linux CPU utilization is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Task: Display the current CPU utilization, calculated from /proc/stat.

Background:

Most Linux kernels provide a virtual /proc filesytem, providing an interface to various internal data structures. One of these internal structures (/proc/stat) includes information on the amount of time (in USER_HZ) spent in various states. From this information, once can, with a little effort, determine the current level of CPU utilization as the percent of time spent in any states other than "idle".

To do this, we:

  1. read the first line of /proc/stat
  2. discard the first word of that first line (it's always cpu)
  3. sum all of the times found on that first line to get the total time
  4. divide the fourth column ("idle") by the total time to the fraction of time spent being idle
  5. subtract the previous fraction from 1.0 to get the time spent being not idle
  6. multiple by 100 to get a percentage

The times in /proc/stat are monotonically increasing, and begin at some point during the kernel's initialisation (ie during boot up). So the steps above will give the total CPU utilization since boot, which may or may not be useful to some. To get a more real-time utilization, we simply repeat the steps above with some small sleep interval in between, and instead of using the absolute total and idle times, we use use the total time delta and the idle time delta to compute the utilization.

This project is based on this blog post by Paul Colby, and the Bash version comes from there.

C++

<lang cpp>#include <iostream>

  1. include <numeric>
  2. include <fstream>
  3. include <unistd.h>
  4. include <vector>

std::vector<size_t> get_cpu_times() {

   std::ifstream proc_stat("/proc/stat");
   proc_stat.ignore(5, ' '); // Skip the 'cpu' prefix.
   std::vector<size_t> times;
   for (size_t time; proc_stat >> time; times.push_back(time));
   return times;

}

bool get_cpu_times(size_t &idle_time, size_t &total_time) {

   const std::vector<size_t> cpu_times = get_cpu_times();
   if (cpu_times.size() < 3)
       return false;
   idle_time = cpu_times[3];
   total_time = std::accumulate(cpu_times.begin(), cpu_times.end(), 0);
   return true;

}

int main(int, char *[]) {

   size_t previous_idle_time=0, previous_total_time=0;
   for (size_t idle_time, total_time; get_cpu_times(idle_time, total_time); sleep(1)) {
       const float idle_time_delta = idle_time - previous_idle_time;
       const float total_time_delta = total_time - previous_total_time;
       const float utilization = 100.0 * (1.0 - idle_time_delta / total_time_delta);
       std::cout << utilization << '%' << std::endl;
       previous_idle_time = idle_time;
       previous_total_time = total_time;
   }

}</lang>

Output:
5.77731%
2.24439%
1.50754%
1.50754%
2.50627%

UNIX Shell

Works with: bash

Example borrowed from https://github.com/pcolby/scripts/blob/master/cpu.sh verbatim. <lang bash>#!/bin/bash

  1. by Paul Colby (http://colby.id.au), no rights reserved ;)

PREV_TOTAL=0 PREV_IDLE=0

while true; do

 # Get the total CPU statistics, discarding the 'cpu ' prefix.
 CPU=(`sed -n 's/^cpu\s//p' /proc/stat`)
 IDLE=${CPU[3]} # Just the idle CPU time.
 # Calculate the total CPU time.
 TOTAL=0
 for VALUE in "${CPU[@]}"; do
   let "TOTAL=$TOTAL+$VALUE"
 done
 # Calculate the CPU usage since we last checked.
 let "DIFF_IDLE=$IDLE-$PREV_IDLE"
 let "DIFF_TOTAL=$TOTAL-$PREV_TOTAL"
 let "DIFF_USAGE=(1000*($DIFF_TOTAL-$DIFF_IDLE)/$DIFF_TOTAL+5)/10"
 echo -en "\rCPU: $DIFF_USAGE%  \b\b"
 # Remember the total and idle CPU times for the next check.
 PREV_TOTAL="$TOTAL"
 PREV_IDLE="$IDLE"
 # Wait before checking again.
 sleep 1

done</lang>

Output:
CPU: 1%