Linux CPU utilization: Difference between revisions
(Added Icon/Unicon) |
|||
Line 137: | Line 137: | ||
<pre>1.6090321637810434 % |
<pre>1.6090321637810434 % |
||
</pre> |
</pre> |
||
=={{header|Icon}} and {{header|Unicon}}== |
|||
<lang 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</lang> |
|||
{{out}} |
|||
<pre>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%</pre> |
|||
=={{header|J}}== |
=={{header|J}}== |
Revision as of 14:23, 17 January 2017
- 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:
- read the first line of
/proc/stat
- discard the first word of that first line (it's always
cpu
) - sum all of the times found on that first line to get the total time
- divide the fourth column ("idle") by the total time, to get the fraction of time spent being idle
- subtract the previous fraction from 1.0 to get the time spent being not idle
- multiple by 100 to get a percentage
- read the first line of
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.
C++
<lang cpp>#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; }
}</lang>
- Output:
5.77731% 2.24439% 1.50754% 1.50754% 2.50627%
Fortran
<lang 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 </lang>
- Output:
CPU Usage Press Ctrl<C> to end 7.51 % 18.23 % 4.60 % 4.53 % 3.53 % 2.53 %
Haskell
<lang 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 " %"</lang>
- Output:
1.6090321637810434 %
Icon and Unicon
<lang 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</lang>
- 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
<lang j>cputpct=:3 :0
if. 0>nc<'PREVCPUTPCT' do. PREVCPUTPCT=:0 end. old=. PREVCPUTPCT PREVCPUTPCT=:0 { 0.1,~0&".;._2 fread '/proc/stat' 100*1-(4&{ % +/) PREVCPUTPCT - old
)</lang>
Example use:
<lang j> cputpct 1.76237</lang>
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.
Perl 6
<lang perl6>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);
}</lang>
Python
<lang 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)</lang>
- 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>#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))
</lang>
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.
<lang Tcl># 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</lang>
- Output:
CPU: 10% CPU: 3% CPU: 1%
UNIX Shell
Example taken, verbatim, from Github. <lang bash>#!/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[@]}"; 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:
Each successive output overwrites the previous output, so there is only ever one line, but that line keeps updating in-place.
CPU: 1%
Ursa
<lang 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) " ")) 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</lang>
zkl
<lang zkl>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);
}</lang>
- 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