##+##########################################################################
#
# mpstatPlot -- visual display of mpstat idle value for all processors
# by Keith Vetter 2013-02-22
#
package require Tk
set S(bar,width) 20
set S(bar,height) 87
set S(padding) 3
set S(border) 5
set CLR(bg) lightyellow
set CLR(rainbow) [list magenta yellow green cyan3 red blue purple]
proc DoDisplay {} {
global S CLR
wm overrideredirect . 1
wm geometry . +200+200
set width [expr {$S(cpus) * ($S(bar,width)+$S(padding)) + $S(padding)}]
set height [expr {$S(bar,height)}]
frame .f -bd $S(border) -relief flat -bg navyblue
canvas .c -highlightthickness 0 -bd 0 -width $width -height $height -bg $CLR(bg)
pack .f
pack .c -in .f
bind . <Button-3> exit
bind . <Control-Button-1> Hide
WindowMove setup .
# Draw our bar graph
for {set cpu 0} {$cpu < $S(cpus)} {incr cpu} {
set x0 [expr {$cpu * ($S(bar,width) + $S(padding)) + $S(padding)}]
set x1 [expr {$x0 + $S(bar,width)}]
set y0 $S(bar,height)
set y1 0
set clr [lindex $CLR(rainbow) [expr {$cpu % [llength $CLR(rainbow)]}]]
.c create rect $x0 $y0 $x1 $y1 -fill white
.c create rect $x0 $y0 $x1 $y1 -tag bar$cpu -fill $clr
}
}
##+##########################################################################
#
# StatsOneLine -- Processes one line from mpstat and updates display
#
proc StatsOneLine {line} {
lassign $line when ampm cpu usr nice sys iowait irq soft steal guest idle
if {[string is integer -strict $cpu]} {
AdjustBarHeight $cpu $idle
}
}
##+##########################################################################
#
# Parse /proc/cpuinfo for the number of cpus on this machine
#
proc HowManyProcessors {} {
set fin [open /proc/cpuinfo r]
set data [read $fin]; list
close $fin
set ::S(cpus) [llength [regexp -all -inline processor $data]]
set ::S(cpus,list) {}
for {set i 0} {$i < $::S(cpus)} {incr i} {
lappend ::S(cpus,list) $i
}
}
##+##########################################################################
#
# AdjustBarHeight -- changes the bar graph height for a particular cpu
#
proc AdjustBarHeight {cpu percent} {
set tag bar$cpu
lassign [.c coords $tag] x0 y0 x1 y1
set newY [expr {$::S(bar,height) - $::S(bar,height)*$percent/100}]
.c coords $tag $x0 $newY $x1 $y1
}
##+##########################################################################
#
# WindowMove -- Allows mouse to move window (window manager can't with overrideredirect)
#
proc WindowMove {what w} {
global _WM_
set w [winfo toplevel $w]
if {$what eq "setup"} {
set _WM_($w,moving) {}
bind $w <1> [list WindowMove down %W]
bind $w <Motion> [list WindowMove move %W]
bind $w <ButtonRelease-1> [list WindowMove up %W]
return
}
if {$what eq "down"} {
set dx [expr {[winfo pointerx $w] - [winfo x $w]}]
set dy [expr {[winfo pointery $w] - [winfo y $w]}]
set _WM_($w,moving) [list $dx $dy]
} elseif {$what eq "up"} {
set _WM_($w,moving) {}
} else {
if {! [info exists _WM_($w,moving)]} return
if {$_WM_($w,moving) eq {}} return
lassign $_WM_($w,moving) dx dy
set gx [expr {[winfo pointerx $w] - $dx}]
set gy [expr {[winfo pointery $w] - $dy}]
wm geom $w +$gx+$gy
}
}
##+##########################################################################
#
# Go -- Open pipe to mpstat and set up a fileevent handler
#
proc Go {{cnt 30}} {
set fin [open "|mpstat -P [join $::S(cpus,list) ,] 1 $cnt" r]
fconfigure $fin -blocking false
fileevent $fin readable [list isReadable $fin]
vwait ::DONE
close $fin
}
##+##########################################################################
#
# isReadable -- Called when another line from mpstat is available
#
proc isReadable { fin } {
set status [catch { gets $fin line } result]
if { $status != 0 } {
# Error on the channel
puts "error reading $fin: $result"
set ::DONE 2
} elseif { $result >= 0 } {
# Successfully read the channel
if {![string match {[0-9]*} $line]} return
set stats [StatsOneLine $line]
} elseif { [eof $fin] } {
set ::DONE 1
} elseif { [fblocked $fin] } {
# Read blocked. Just return
} else {
# Something else
puts "can't happen"
set ::DONE 3
}
}
##+##########################################################################
#
# Withdraw ourselves temporarily
#
proc Hide {} {
wm withdraw .
after 5000 wm deiconify .
}
if {! [file exists /proc/cpuinfo] || [auto_execok mpstat] eq ""} {
tk_messageBox -icon error -message "Only works on Linux" -title "mpstat Plot : ERROR"
return
}
HowManyProcessors
DoDisplay
update
after idle {Go ""}
return
Jorge - 2013-03-14 19:13:28looks like the widget is showing the CPU activity representing the free CPU usage with the fucsia color, then a fully used CPU is represented with a bar entirely white. (tested on Ubuntu)

