[Keith Vetter] 2013-03-08 : Here's a cpu activity widget that shows the amount of activity for each cpu on your machine. It's Linux specific--it uses mpstat and /proc/cpuinfo. It works by running mpstat which writes cpu usage information which a fileevent reads mpstats and updates the display. mpstat has a 1 second granularity. I wrote a version that read from /proc/stat directly but faster granularity wasn't worth the extra complexity. ===== ##+########################################################################## # # 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 . exit bind . 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 [list WindowMove move %W] bind $w [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 ===== <>Enter Category Here