Linux CPU utilization

From Rosetta Code
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, as a percentage, calculated from /proc/stat.


Background

Most Linux kernels provide a virtual   /proc   filesystem, 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, we can, with a little effort, determine the current level of CPU utilization, as a percent of time spent in any states other than idle.

To do this:

  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 get 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 initialization (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.

AWK

BEGIN {
  prev_total = 0
  prev_idle = 0
  while (getline < "/proc/stat") {
    close("/proc/stat")
    idle = $5
    total = 0
    for (i=2; i<=NF; i++)
      total += $i
    print (1-(idle-prev_idle)/(total-prev_total))*100"%"
    prev_idle = idle
    prev_total = total
    system("sleep 1")
  }
}

Invocation and output:

>$ awk -f cpu.awk
28.4785%
7.32323%
7.30479%
6.07595%
6.32911%

Alternatively, the output can continuously overwrite itself to remain on a single line a la the UNIX Shell version, by replacing the print line with:

    printf "\rCPU: %5.1f%%  \b\b",(1-(idle-prev_idle)/(total-prev_total))*100

C

On Linux, sleep accepts seconds, on Windows, milliseconds. So if you are planning to test this on Windows and then port it to Linux .....The implementation below has been tested on a Linux machine.

#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<stdio.h>

int main(int argC,char* argV[])
{
	char str[100];
	const char d[2] = " ";
	char* token;
	int i = 0,times,lag;
	long int sum = 0, idle, lastSum = 0,lastIdle = 0;
	long double idleFraction;
	
	if(argC!=3)
		printf("Usage : %s <number of times /proc/stat should be polled followed by delay in seconds.>",argV[0]);
	
	else{
		times = atoi(argV[1]);
		lag = atoi(argV[2]);
		
		while(times>0){
			FILE* fp = fopen("/proc/stat","r");
	                i = 0;
			fgets(str,100,fp);
			fclose(fp);
			token = strtok(str,d);
	                sum = 0;
			while(token!=NULL){
				token = strtok(NULL,d);
				if(token!=NULL){
					sum += atoi(token);
			
				if(i==3)
					idle = atoi(token);
		
				i++;
			        }
		        }
	                idleFraction = 100 - (idle-lastIdle)*100.0/(sum-lastSum);
		        printf("Busy for : %lf %% of the time.", idleFraction);
	
		        lastIdle = idle;
		        lastSum = sum;
	
		
		        times--;
		        sleep(lag);
		}	
	}
	return 0;
}

Invocation and output :

/home/aamrun/rosettaCode>./cpuStat 3 1
Busy for : 2.627333 % of the time.
Busy for : 0.000000 % of the time.
Busy for : 0.000000 % of the time.

C++

#include <fstream>
#include <iostream>
#include <numeric>
#include <unistd.h>
#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() < 4)
        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;
    }
}
Output:
5.77731%
2.24439%
1.50754%
1.50754%
2.50627%

Library: Qt

Qt Console Variant 1

Uses: Qt (Components:{{#foreach: component$n$|{{{component$n$}}}Property "Uses library" (as page type) with input value "library/Qt/{{{component$n$}}}" contains invalid characters or is incomplete and therefore can cause unexpected results during a query or annotation process., }})

A very basic Qt-port of the the C++ implementation above.

#include <QFile>
#include <unistd.h>

int main(int, char *[]) {
    int prevIdleTime = 0, prevTotalTime = 0;
    for (QFile file("/proc/stat"); file.open(QFile::ReadOnly); file.close()) {
        const QList<QByteArray> times = file.readLine().simplified().split(' ').mid(1);
        const int idleTime = times.at(3).toInt();
        int totalTime = 0;
        foreach (const QByteArray &time, times) {
            totalTime += time.toInt();
        }
        qInfo("%5.1f%%", (1 - (1.0*idleTime-prevIdleTime) / (totalTime-prevTotalTime)) * 100.0);
        prevIdleTime = idleTime;
        prevTotalTime = totalTime;
        sleep(1);
    }
}
Output:
 31.7%
  7.3%
 10.3%
  1.3%
  4.0%

Qt Console Variant 2

Uses: Qt (Components:{{#foreach: component$n$|{{{component$n$}}}Property "Uses library" (as page type) with input value "library/Qt/{{{component$n$}}}" contains invalid characters or is incomplete and therefore can cause unexpected results during a query or annotation process., }})

An event-based Qt console implementation. Note, this version does not rely on any system-dependant headers or functions.

#include <QCoreApplication>
#include <QFile>

class CpuUsage : public QObject {
public:
    CpuUsage() : prevIdleTime(0), prevTotalTime(0) { }

protected:
    virtual void timerEvent(QTimerEvent *)
    {
        QFile file("/proc/stat");
        file.open(QFile::ReadOnly);
        const QList<QByteArray> times = file.readLine().simplified().split(' ').mid(1);
        const int idleTime = times.at(3).toInt();
        int totalTime = 0;
        foreach (const QByteArray &time, times) {
            totalTime += time.toInt();
        }
        qInfo("%5.1f%%", (1 - (1.0*idleTime-prevIdleTime) / (totalTime-prevTotalTime)) * 100.0);
        prevIdleTime = idleTime;
        prevTotalTime = totalTime;
    }

private:
    int prevIdleTime;
    int prevTotalTime;
};

int main(int argc, char *argv[]) {
    QCoreApplication app(argc, argv);
    CpuUsage usage;
    usage.startTimer(1000);
    return app.exec();
}
Output:
 31.7%
  4.2%
  3.5%
 16.2%
  2.5%
  4.5%

Qt GUI

Uses: Qt (Components:{{#foreach: component$n$|{{{component$n$}}}Property "Uses library" (as page type) with input value "library/Qt/{{{component$n$}}}" contains invalid characters or is incomplete and therefore can cause unexpected results during a query or annotation process., }})

A GUI version, using the Qt framework.

#include <QApplication>
#include <QFile>
#include <QProgressDialog>

class CpuUsage : public QProgressDialog {
public:
    CpuUsage() : prevIdleTime(0), prevTotalTime(0)
    {
        connect(this, &QProgressDialog::canceled, &QApplication::quit);
        setLabelText(tr("CPU utilization"));
        setCancelButtonText(tr("Quit"));
        startTimer(500);
    }

protected:
    virtual void timerEvent(QTimerEvent *)
    {
        QFile file("/proc/stat");
        file.open(QFile::ReadOnly);
        const QList<QByteArray> times = file.readLine().simplified().split(' ').mid(1);
        const int idleTime = times.at(3).toInt();
        int totalTime = 0;
        foreach (const QByteArray &time, times) {
            totalTime += time.toInt();
        }
        setValue((1 - (1.0*idleTime-prevIdleTime) / (totalTime-prevTotalTime)) * 100.0);
        prevIdleTime = idleTime;
        prevTotalTime = totalTime;
    }

private:
    int prevIdleTime;
    int prevTotalTime;
};

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    CpuUsage usage;
    usage.show();
    return app.exec();
}
Output:

File:Linux CPU utilization Qt GUI.png

C#

var prevIdle = 0f;
var prevTotal = 0f;

while (true)
{
    var cpuLine = File
        .ReadAllLines("/proc/stat")
        .First()
        .Split(' ', StringSplitOptions.RemoveEmptyEntries)
        .Skip(1)
        .Select(float.Parse)
        .ToArray();

    var idle = cpuLine[3];
    var total = cpuLine.Sum();

    var percent = 100.0 * (1.0 - (idle - prevIdle) / (total - prevTotal));
    Console.WriteLine($"{percent:0.00}%");

    prevIdle = idle;
    prevTotal = total;

    Thread.Sleep(1000);
}

Output:

20.88%
15.38%
8.33%
8.33%
0.00%
8.33%

Dart

#!/usr/bin/env dart
import 'dart:io';

List<int> load() {
  File f = File('/proc/stat');
  List<String> lines = f.readAsLinesSync();

  List<int> loads = lines[0]
      .substring("cpu  ".length)
      .split(" ")
      .map((String token) => int.parse(token))
      .toList();

  int idle = loads[3];
  int total = loads.reduce((int a, int b) => a + b);

  return [idle, total];
}

void main() {
  List<int> idleTotalPrev = [0, 0];

  while (true) {
    List<int> idleTotal = load();
    int dTotal = idleTotal[0] - idleTotalPrev[0];
    int dLoad = idleTotal[1] - idleTotalPrev[1];
    idleTotalPrev = idleTotal;

    double percent = 100.0 * (1.0 - dTotal / dLoad);
    print("${percent.toStringAsFixed(2)}%");

    sleep(const Duration(seconds: 1));
  }
}

Output:

13.27%
1.25%
0.75%
1.37%
0.63%
0.63%

Fortran

Program CPUusage
    implicit none
    integer :: ios, i
    integer :: oldidle, oldsum, sumtimes = 0
    real :: percent = 0.
    character(len = 4) lineID ! 'cpu '
    integer, dimension(9) :: times = 0

    write(*, *) 'CPU Usage'
    write(*, *) 'Press Ctrl<C> to end'
    do while (.true.)
        open(unit = 7, file = '/proc/stat', status = 'old', action = 'read', iostat = ios)
        if (ios /= 0) then
            print *, 'Error opening /proc/stat'
            stop
        else
            read(unit = 7, fmt = *, iostat = ios) lineID, (times(i), i = 1, 9)
            close(7)
            if (lineID /= 'cpu ') then
                print *, 'Error reading /proc/stat'
                stop
            end if
            sumtimes = sum(times)
            percent = (1. - real((times(4) - oldidle)) / real((sumtimes - oldsum))) * 100.
            write(*, fmt = '(F6.2,A2)') percent, '%'
            oldidle = times(4)
            oldsum = sumtimes
            call sleep(1)
        end if
    end do
end program CPUusage
Output:
CPU Usage
 Press Ctrl<C> to end
  7.51 %
 18.23 %
  4.60 %
  4.53 %
  3.53 %
  2.53 %

Go

Translation of: Kotlin
package main

import (
    "bufio"
    "fmt"
    "log"
    "os"
    "strconv"
    "strings"
    "time"
)

func main() {
    fmt.Println("CPU usage % at 1 second intervals:\n")
    var prevIdleTime, prevTotalTime uint64
    for i := 0; i < 10; i++ {
        file, err := os.Open("/proc/stat")
        if err != nil {
            log.Fatal(err)
        }
        scanner := bufio.NewScanner(file)
        scanner.Scan()
        firstLine := scanner.Text()[5:] // get rid of cpu plus 2 spaces
        file.Close()
        if err := scanner.Err(); err != nil {
            log.Fatal(err)
        }
        split := strings.Fields(firstLine)
        idleTime, _ := strconv.ParseUint(split[3], 10, 64)
        totalTime := uint64(0)
        for _, s := range split {
            u, _ := strconv.ParseUint(s, 10, 64)
            totalTime += u
        }
        if i > 0 {
            deltaIdleTime := idleTime - prevIdleTime
            deltaTotalTime := totalTime - prevTotalTime
            cpuUsage := (1.0 - float64(deltaIdleTime)/float64(deltaTotalTime)) * 100.0
            fmt.Printf("%d : %6.3f\n", i, cpuUsage)
        }
        prevIdleTime = idleTime
        prevTotalTime = totalTime
        time.Sleep(time.Second)
    }
}
Output:

Sample output:

CPU usage % at 1 second intervals:

1 :  5.025
2 :  7.035
3 :  6.030
4 :  3.941
5 :  2.538
6 :  2.010
7 :  2.020
8 :  3.015
9 :  2.000

Haskell

import Data.List ( (!!) ) 

splitString :: Char -> String -> [String]
splitString c [] = []
splitString c s = let ( item , rest ) = break ( == c ) s
                      ( _ , next ) = break ( /= c ) rest
		  in item : splitString c next    
		  
computeUsage :: String -> Double
computeUsage s = (1.0 - ((lineElements !! 3 ) /  sum times)) * 100
   where
      lineElements = map (fromInteger . read ) $ tail $ splitString ' ' s
      times = tail lineElements

main :: IO ( )      
main = do 
   theTimes <- fmap lines $ readFile "/proc/stat" 
   putStr $ show $ computeUsage $ head theTimes
   putStrLn " %"
Output:
1.6090321637810434 %

Icon and Unicon

#
# utilization.icn, percentage of running cpu time used versus idle time
#
# tectonics: unicon -s utilization.icn -x
#
procedure main()
    local stats, n, total, newtotal, delta, idle, idled
    stats := gather()
    idle := stats[4]
    total := newtotal := 0
    every n := !stats do total +:= n
    write("Overall utilization:  ", (1 - (real(idle) / total)) * 100, "%")

    idle := stats[4]
    delay(100)

    stats := gather()
    every n := !stats do newtotal +:= n
    delta := newtotal - total
    idled := stats[4] - idle
    write("Interval utilization: ", (1 - (real(idled) / delta)) * 100, "%")
end

procedure gather()
    local f, line, stats

    f := open("/proc/stat", "r") | stop("Cannot open /proc/stat")
    line := read(f)
    close(f)

    stats := []
    line ? {
         tab(upto(' ')) & tab(many(' '))
         while put(stats, tab(upto(' '))) do tab(many(' '))
         put(stats, tab(0))
    }
    return stats
end
Output:
prompt$ unicon -s utilization.icn -x
Overall utilization:  4.995469613984859%
Interval utilization: 10.52631578947368%
prompt$ ./utilization
Overall utilization:  4.994924759070784%
Interval utilization: 0.0%
prompt$ ./utilization
Overall utilization:  4.994135168922565%
Interval utilization: 4.878048780487809%

J

cputpct=:3 :0
  if. 0>nc<'PREVCPUTPCT' do. PREVCPUTPCT=:0 end.
  old=. PREVCPUTPCT
  PREVCPUTPCT=: (1+i.8){0".}:2!:0{{)nsed '2,$d' /proc/stat}}
  100*1-(3&{ % +/) PREVCPUTPCT - old
)

Example use:

   cputpct''
1.76237

Notes: this gives the average non-idle time since the last time this verb was used. If for some reason /proc/stat were not updated between calls, the result would be 100 (percent), which seems appropriate.

Java

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public static void main(String[] args) throws IOException {
    double[] percentages = parseUtilization(procStat());
    System.out.printf("%-10s %5.2f%%%n", "idle", percentages[0] * 100);
    System.out.printf("%-10s %5.2f%%", "not-idle", percentages[1] * 100);
}

static String procStat() throws IOException {
    File file = new File("/proc/stat");
    try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
        return reader.readLine();
    }
}

/** @return idle and not-idle percentage values */
static double[] parseUtilization(String string) {
    string = string.substring(4).stripLeading();
    int total = 0;
    double idle = 0;
    double notIdle;
    int index = 0;
    for (String value : string.split(" ")) {
        if (index == 3)
            idle = Integer.parseInt(value);
        total += Integer.parseInt(value);
        index++;
    }
    idle /= total;
    notIdle = 1 - idle;
    return new double[] { idle, notIdle };
}
idle       93.33%
not-idle    6.67%


An alternate demonstration

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.text.NumberFormat;
import java.time.Duration;
import java.util.Timer;
import java.util.TimerTask;

/* Idiomatic Java
 *This certainly could've been done much shorter, but I'm glad with the way it came out
 * */
public class Main {

    public static void main(String[] args) throws FileNotFoundException {
        // this demonstrates the use of Duration class
        final var period = Duration.ofSeconds(1);
        new Timer().schedule(new CpuUtilizationTask(), 0, period.toMillis());
    }

    /* By extending the TimerTask abstract class, we're able to use the
     * Timer scheduling class */
    static class CpuUtilizationTask extends TimerTask {

        private final String STAT_FILE_HEADER = "cpu  ";
        private final NumberFormat percentFormatter;
        private final RandomAccessFile statPointer;
        long previousIdleTime = 0, previousTotalTime = 0;

        public CpuUtilizationTask() throws FileNotFoundException {
            this.percentFormatter = NumberFormat.getPercentInstance();
            percentFormatter.setMaximumFractionDigits(2);
            var statFile = new File("/proc/stat");
            /* by using the RandomAcessFile, we're able to keep an open file stream for
             * as long as this object lives, making further file openings unnecessary */
            this.statPointer = new RandomAccessFile(statFile, "r");
        }

        @Override
        public void run() {

            try {
                var values = statPointer.readLine()
                        .substring(STAT_FILE_HEADER.length())
                        .split(" ");

                /* because Java doesn't have unsigned primitive types, we have to use the boxed
                 * Long's parseUsigned method. It does what it says it does.
                 * The rest of the arithmetic can go on as normal.
                 * I've seen solutions reading the value as integers. They're NOT!*/
                var idleTime = Long.parseUnsignedLong(values[3]);
                var totalTime = 0L;
                for (String value : values) {
                    totalTime += Long.parseUnsignedLong(value);
                }

                var idleTimeDelta = idleTime - previousIdleTime;
                var totalTimeDelta = totalTime - previousTotalTime;
                var utilization = 1 - ((double) idleTimeDelta) / totalTimeDelta;

                /* Again, this is showing one more advantage of doing idiomatic Java
                 * we're doing locale aware percentage formatting */
                System.out.println(percentFormatter.format(utilization));

                previousIdleTime = idleTime;
                previousTotalTime = totalTime;

                // take us back to the beginning of the file, so we don't have to reopen it
                statPointer.seek(0);
            } catch (IOException ioException) {
                ioException.printStackTrace();
            }
        }

    }
}

Julia

Works with: Julia version 0.6
Translation of: Python
function main()
    lastidle = lasttotal = 0
    while true
        ln = readline("/proc/stat")
        fields = parse.(Float64, split(ln)[2:end])
        idle, total = fields[4], sum(fields)
        Δidle, Δtotal = idle - lastidle, total - lasttotal
        lastidle, lasttotal = idle, total
        utilization = 100 * (1 - Δidle / Δtotal)
        @printf "%5.1f%%\r" utilization
        sleep(5)
    end
end

main()

Kotlin

// version 1.1.3

import java.io.FileReader
import java.io.BufferedReader

fun main(args: Array<String>) {
    println("CPU usage % at 1 second intervals:\n")
    var prevIdleTime = 0L
    var prevTotalTime = 0L
    repeat(10) {
        val br = BufferedReader(FileReader("/proc/stat"))
        val firstLine = br.readLine().drop(5)  // get rid of cpu plus 2 spaces
        br.close()
        val split = firstLine.split(' ')
        val idleTime = split[3].toLong()    
        val totalTime = split.map { it.toLong() }.sum()
        if (it > 0) {
            val deltaIdleTime  = idleTime  - prevIdleTime
            val deltaTotalTime = totalTime - prevTotalTime
            val cpuUsage = (1.0 - deltaIdleTime.toDouble() / deltaTotalTime) * 100.0
            println("$it : ${"%6.3f".format(cpuUsage)}")
        }
        prevIdleTime  = idleTime
        prevTotalTime = totalTime
        Thread.sleep(1000)
    }
}

Sample output:

CPU usage % at 1 second intervals:

1 : 13.043
2 :  8.491
3 :  4.478
4 :  3.553
5 :  2.500
6 :  4.975
7 :  1.015
8 :  4.040
9 :  2.525

Nim

import math, sequtils, strutils

let firstLine = "/proc/stat".readLines(1)[0]
let values = firstLine.splitWhitespace()[1..^1].map(parseInt)
let totalTime = sum(values)
let idleFrac = values[3] / totalTime
let notIdlePerc = (1 - idleFrac) * 100
echo "CPU utilization = ", notIdlePerc.formatFloat(ffDecimal, precision = 1), " %"
Output:
CPU utilization = 7.9 %

Perl

$last_total = 0;
$last_idle  = 0;

while () {
    @cpu = split /\s+/, `head -1 /proc/stat`;
    shift @cpu;
    $this_total  = 0;
    $this_total += $_ for @cpu;
    $delta_total = $this_total - $last_total;
    $this_idle   = $cpu[3]     - $last_idle;
    $delta_idle  = $this_idle  - $last_idle;
    $last_total  = $this_total;
    $last_idle   = $this_idle;
    printf "Utilization: %0.1f%%\n", 100 * (1 - $delta_idle / $delta_total);
    sleep 1;
}
Output:
Utilization: 38.6%
Utilization: 96.1%
Utilization: 83.3%
^C

Phix

Translation of: Python
--without js -- (file i/o)
with javascript_semantics -- (using the following constant)
sequence line = "cpu  259246 7001 60190 34250993 137517 772 0"

atom last_idle = 0, last_total = 0
--while true do
--  integer fn = open("/proc/stat","r")
--  sequence line = trim(gets(fn))
--  close(fn)
    line = split(line)[2..$]
    for i=1 to length(line) do
        {{line[i]}} = scanf(line[i],"%d")
    end for
    atom idle = line[4], total = sum(line),
         idle_delta = idle - last_idle,
         total_delta = total - last_total
    last_idle = idle
    last_total = total
    atom utilisation = 100*(1-idle_delta/total_delta)
    printf(1,"%5.1f%%\n",{utilisation})
--  printf(1,"%5.1f%%\r",{utilisation})
--  sleep(1)
--  if get_key()=#1B then exit end if
--end while

PicoLisp

(scl 8)
(let (Idl 0  Ttl 0)
   (loop
      (use (L I S)
         (in "/proc/stat"
            (read)
            (setq L (make (do 10 (link (read))))) )
         (setq I (get L 4)  S (sum prog L))
         (prinl
            (round
               (*/
                  100.0
                  (-
                     1.0
                     (*/
                        1.0
                        (- I (swap 'Idl I))
                        (- S (swap 'Ttl S)) ) )
                  1.0 )
               1 )
            '% )
         (wait 1000) ) ) )

Python

from __future__ import print_function
from time import sleep


last_idle = last_total = 0
while True:
    with open('/proc/stat') as f:
        fields = [float(column) for column in f.readline().strip().split()[1:]]
    idle, total = fields[3], sum(fields)
    idle_delta, total_delta = idle - last_idle, total - last_total
    last_idle, last_total = idle, total
    utilisation = 100.0 * (1.0 - idle_delta / total_delta)
    print('%5.1f%%' % utilisation, end='\r')
    sleep(5)
Output:

Lines end in \r which causes old values to be overwritten by new when \r is supported otherwise successive figures appear on separate lines.

 26.5%
 12.4%
 10.6%
 49.5%
 15.5%
 13.8%
  8.3%
 11.0%
 18.5%
 13.9%
 11.8%
 35.6%

Racket

#lang racket/base

(require racket/string)

(define (get-stats) ; returns total and idle times as two values
  (define line (call-with-input-file* "/proc/stat" read-line))
  (define numbers (map string->number (cdr (string-split line))))
  (values (apply + numbers) (list-ref numbers 3)))

(define prev-stats #f)

(define (report-cpu-utilization)
  ;; lazy: fixed string instead of keeping the last time
  (define prompt (if prev-stats "last second" "since boot"))
  (define-values [cur-total cur-idle] (get-stats))
  (define prev (or prev-stats '(0 0)))
  (set! prev-stats (list cur-total cur-idle))
  (define total (- cur-total (car prev)))
  (define idle (- cur-idle (cadr prev)))
  (printf "Utilization (~a): ~a%\n" prompt
          (/ (round (* 10000 (- 1 (/ idle total)))) 100.0)))

(let loop ()
  (report-cpu-utilization)
  (sleep 1)
  (loop))

Raku

(formerly Perl 6)

my $last-total = 0;
my $last-idle  = 0;

loop {
    my $Δ-total = (my $this-total = [+] my @cpu = "/proc/stat".IO.lines[0].words[1..*]) - $last-total;
    my $Δ-idle  = (my $this-idle  = @cpu[3]) - $last-idle;
    $last-total = $this-total;
    $last-idle  = $this-idle;
    print "\b" x 40, (100 * (1 - $Δ-idle / $Δ-total)).fmt("Utilization: %0.1f%% ");
    sleep(1);
}

REXX

This REXX version tests to see if the   /proc/stat   file was updated.

It also supports the (user) option to   HALT   the process   (by pressing Ctrl-Break).

/*REXX pgm displays current CPU utilization (as a percentage) as per file:  /proc/stat  */
signal on halt                                   /*enable handling of Ctrl─Break (halt).*/
numeric digits 20                                /*ensure enough decimal digits for pgm.*/
parse arg n wait iFID .                          /*obtain optional arguments from the CL*/
if    n=='' |    n=","  then    n= 10            /*Not specified?  Then use the default.*/
if wait=='' | wait=","  then wait=  1            /* "      "         "   "   "     "    */
if iFID=='' | iFID=","  then iFID= '/proc/stat'  /* "      "         "   "   "     "    */
prevTot  = 0;           prevIdle= 0              /*initialize the prevTot and prevIdle. */

  do j=1  for n                                  /*process CPU utilization   N   times. */
  parse value  linein(iFID, 1)  with  .  $       /*read the 1st line and ignore 1st word*/
  tot= 0                                         /*initalize  TOT  (total time) to zero.*/
             do k=1  for min(8, words($) )       /*only process up to eight numbers in $*/
             @.k= word($,k)                      /*assign  the times to an array (@).   */
             tot= tot + @.k                      /*add all the times from the 1st line. */
             end   /*k*/                         /*@.4  is the idle time for this cycle.*/

  div= tot - prevTot                             /*DIV may be zero if file isn't updated*/
  if div\=0  then say format(((1-(@.4-prevIdle)/div))*100,3,5)"%"    /*display CPU busy.*/
  prevTot= tot;    prevIdle= @.4                 /*set the previous  TOT  and  prevIdle.*/
  call sleep wait                                /*cause this pgm to sleep   WAIT  secs.*/
  end   /*j*/
                                                 /*stick a fork in it,  we're all done. */
halt:                                            /*come here when   Ctrl-Break  pressed.*/


Standard ML

val delay = Time.fromSeconds 2

fun p100 (part, full) = (200 * part div full + 1) div 2

val read1stLine =
  (fn strm => TextIO.inputLine strm before TextIO.closeIn strm) o TextIO.openIn

val getColumns = Option.map (String.tokens Char.isSpace) o read1stLine

fun cpuStat list = (List.nth (list, 3), foldl op+ 0 list)

fun printStat (list, (idle, total)) =
  let
    val newStat as (idle', total') = cpuStat (map (valOf o Int.fromString) list)
  in
    print (Int.toString (100 - p100 (idle' - idle, total' - total)) ^ "%\n");
    OS.Process.sleep delay;
    newStat
  end

fun mainLoop prev =
  case getColumns "/proc/stat" of
    SOME ("cpu" :: list) => mainLoop (printStat (list, prev))
  | _ => ()

val () = mainLoop (0, 0)

Tcl

This is coded a little bit awkwardly in order to correspond neatly to the task description.

proc stat fulfills the task description in two ways:

  • if called normally, it returns aggregate CPU utilization since boot
  • if called within a coroutine, it prints on stdout and repeats every 1s until the coroutine is terminated

A more reusable implementation might take a command as an argument to stat, and allow that command to interrupt the loop with return false or even break.

# forgive the pun!
proc stat {} {

    set fd [open /proc/stat r]
    set prevtotal 0
    set previdle 0

    while {1} {
        # read the first line of /proc/stat
        set line [gets $fd]
        seek $fd 0
        # discard the first word of that first line (it's always cpu)
        set line [lrange $line 1 end]
        # sum all of the times found on that first line to get the total time
        set total [::tcl::mathop::+ {*}$line]

        # parse each field out of line (we only need $idle)
        lassign $line user nice system idle iowait irq softirq steal guest guest_nice

        # update against previous measurement
        incr idle -$previdle
        incr total -$prevtotal
        incr previdle $idle
        incr prevtotal $total

        # divide the fourth column ("idle") by the total time, to get the fraction of time spent being idle
        set frac [expr {$idle * 1.0 / $total}]
        # subtract the previous fraction from 1.0 to get the time spent being not idle
        set frac [expr {1 - $frac}]
        # multiply by 100 to get a percentage 
        set frac [expr {round($frac*100)}]

        if {[info coroutine] eq ""} {
            return $frac ;# if we're called outside a coroutine, return a number
        } else {
            puts [format CPU:%3d%% $frac]  ;# else print output
            yieldto after 1000 [info coroutine]
        }
    }
}

coroutine watchstat stat
Output:
CPU: 10%
CPU:  3%
CPU:  1%

UNIX Shell

Works with: bash

Example taken, verbatim, from Github.

#!/bin/bash
# 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[@]:0:8}"; do
    TOTAL=$((TOTAL+VALUE))
  done

  # Calculate the CPU usage since we last checked.
  DIFF_IDLE=$((IDLE-PREV_IDLE))
  DIFF_TOTAL=$((TOTAL-PREV_TOTAL))
  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
Output:
Each successive output overwrites the previous output, so there is only ever one line, but that line keeps updating in-place.
CPU: 1%

Ursa

#
# linux cpu utilization
#

# define variables to hold last idle and last total
decl int last_idle last_total

# loop indefintely
while true
	# read the first line from /proc/stat
	decl string line
	decl file f
	f.open "/proc/stat"
	set line (in string f)

	# get the data from the first line
	decl int i
	decl int<> fields
	fields.clear
	for (set i 2) (< i (size (split (trim line) " "))) (inc i)
		append (int (split (trim line) " ")<i>) fields
	end for

	# get idle stat and total
	decl int idle total
	set idle fields<3>
	set total (int (+ fields))

	# set idle_delta and total_delta
	decl int idle_delta total_delta
	set idle_delta (int (- idle last_idle))
	set total_delta (int (- total last_total))

	# set last_idle and last_total
	set last_idle idle
	set last_total total

	# set percentage utilization
	decl double utilization
	set utilization (* 100 (- 1 (/ idle_delta total_delta)))

	# output percentage
	out utilization "%\r" console
	
	# close f, it will be reopened at the top of the loop
	f.close

	# sleep 2.5 seconds
	sleep 2500

	# clear the line of output
	for (set i 0)  (< i (+ (size (string utilization)) 1.0)) (inc i)
		out "\b" console
	end for
	for (set i 0) (< i (+ (size (string utilization)) 1.0)) (inc i)
		out " " console
	end for
	out "\r" console
end while

Wren

Library: Wren-fmt

For some reason (probably because it's a virtual file) Wren-cli is unable to read /proc/stat properly. We therefore need to fall back on an embedded program with the C host getting the first line of the file for us so we can analyze it.

The figure at time 0 is the cumulative CPU usage since boot time.

/* Linux_CPU_utilization.wren */

import "./fmt" for Fmt

class C {
    // get the first line from /proc/stat
    foreign static procStat1

    foreign static sleep(secs)
}

var prevIdleTime = 0
var prevTotalTime = 0
System.print("CPU usage \% at 1 second intervals:\n") 
for (i in 0..9) {
    var line = C.procStat1[3..-1].trim()
    var times = line.split(" ")[0..7].map { |t| Num.fromString(t) }.toList
    var totalTime = times.reduce { |acc, t| acc + t }
    var idleTime = times[3]
    var deltaIdleTime = idleTime - prevIdleTime
    var deltaTotalTime = totalTime - prevTotalTime
    var cpuUsage = (1 - deltaIdleTime/deltaTotalTime) * 100
    Fmt.print("$d : $6.3f", i, cpuUsage)
    prevIdleTime = idleTime
    prevTotalTime = totalTime
    C.sleep(1)
}


We now embed this in the following C program, compile and run it.

/* gcc Linux_CPU_utilization.c -o Linux_CPU_utilization -lwren -lm */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "wren.h"

/* C <=> Wren interface functions */

void C_procStat1(WrenVM* vm) {
    FILE* fp = fopen("/proc/stat","r");
    char str[100];
    fgets(str, 100, fp);
    fclose(fp);
    wrenSetSlotString(vm, 0, str);
}

void C_sleep(WrenVM* vm) {
    int seconds = (int)wrenGetSlotDouble(vm, 1);
    sleep(seconds);
}

WrenForeignMethodFn bindForeignMethod(
    WrenVM* vm,
    const char* module,
    const char* className,
    bool isStatic,
    const char* signature) {
    if (strcmp(module, "main") == 0) {
        if (strcmp(className, "C") == 0) {
            if (isStatic && strcmp(signature, "procStat1") == 0)  return C_procStat1;
            if (isStatic && strcmp(signature, "sleep(_)") == 0)   return C_sleep;
        }
    }
    return NULL;
}

static void writeFn(WrenVM* vm, const char* text) {
    printf("%s", text);
}

void errorFn(WrenVM* vm, WrenErrorType errorType, const char* module, const int line, const char* msg) {
    switch (errorType) {
        case WREN_ERROR_COMPILE:
            printf("[%s line %d] [Error] %s\n", module, line, msg);
            break;
        case WREN_ERROR_STACK_TRACE:
            printf("[%s line %d] in %s\n", module, line, msg);
            break;
        case WREN_ERROR_RUNTIME:
            printf("[Runtime Error] %s\n", msg);
            break;
    }
}

char *readFile(const char *fileName) {
    FILE *f = fopen(fileName, "r");
    fseek(f, 0, SEEK_END);
    long fsize = ftell(f);
    rewind(f);
    char *script = malloc(fsize + 1);
    fread(script, 1, fsize, f);
    fclose(f);
    script[fsize] = 0;
    return script;
}

static void loadModuleComplete(WrenVM* vm, const char* module, WrenLoadModuleResult result) {
    if( result.source) free((void*)result.source);
}

WrenLoadModuleResult loadModule(WrenVM* vm, const char* name) {
    WrenLoadModuleResult result = {0};
    if (strcmp(name, "random") != 0 && strcmp(name, "meta") != 0) {
        result.onComplete = loadModuleComplete;
        char fullName[strlen(name) + 6];
        strcpy(fullName, name);
        strcat(fullName, ".wren");
        result.source = readFile(fullName);
    }
    return result;
}

int main(int argc, char **argv) {
    WrenConfiguration config;
    wrenInitConfiguration(&config);
    config.writeFn = &writeFn;
    config.errorFn = &errorFn;
    config.bindForeignMethodFn = &bindForeignMethod;
    config.loadModuleFn = &loadModule;
    WrenVM* vm = wrenNewVM(&config);
    const char* module = "main";
    const char* fileName = "Linux_CPU_utilization.wren";
    char *script = readFile(fileName);
    WrenInterpretResult result = wrenInterpret(vm, module, script);
    switch (result) {
        case WREN_RESULT_COMPILE_ERROR:
            printf("Compile Error!\n");
            break;
        case WREN_RESULT_RUNTIME_ERROR:
            printf("Runtime Error!\n");
            break;
        case WREN_RESULT_SUCCESS:
            break;
    }
    wrenFreeVM(vm);
    free(script);
    return 0;
}
Output:

Sample output:

CPU usage % at 1 second intervals:

0 :  3.018
1 :  1.378
2 :  1.748
3 :  1.129
4 :  0.755
5 :  1.746
6 :  2.114
7 :  1.004
8 :  1.375
9 :  1.253

zkl

Translation of: Python
last_idle,last_total:=0,0;
while(True){
   f:=File("/proc/stat");  // open each time to get fresh data
      fields:=f.readln().strip().split()[1,*];
   f.close();
   idle, total := fields[3].toFloat(),fields.sum(0.0);
   idle_delta, total_delta := idle - last_idle, total - last_total;
   last_idle, last_total = idle, total;
   utilisation := 100.0 * (1.0 - idle_delta / total_delta);
   print("%5.1f%%\r".fmt(utilisation)); // stay on this line, overwrite old value
   Atomic.sleep(5);
}
Output:

Shown on multiple lines, in xterm output stays on one line, overwriting itself.

 33.3%
  1.2%
  1.5%
  1.1%
  1.6%
  1.1%
  1.8%
^CCntl C noted