File: /volume1/@appstore/MailPlus-Server/bin/watch-multiple-mimedefangs.tcl
#!/bin/sh
# -*-Mode: TCL;-*-
#
# Copyright (C) 2007 Roaring Penguin Software Inc. This file may be
# distributed under the terms of the GNU General Public License, Version 2,
# or (at your option) any later version.
# Next line restarts using wish \
exec wish "$0" -- "$@" ; clear; echo "*****"; echo "Cannot find 'wish' -- you need Tcl/Tk installed to run this program"; exit 1
# Main update interval (ms)
set MainUpdateInterval 1500
# Busy worker update interval (ms)
set BusyWorkerUpdateInterval 3000
# Trace command - pid is appended
set TraceCommand "strace -s 100 -t -p"
# Command to run SSH
set SSHCommand "ssh"
# Command to run md-mx-ctrl
set MD_MX_CTRL "md-mx-ctrl -i"
# Archive readings?
set DoArchive 0
# Have we done a redraw since the last update?
# Start out set to yes to kick things off!
set DoneARedrawSinceLastUpdate 1
# Use new-style "rawload1" command?
set NewStyle 0
set NewStyleShowScans 0
set NewStyleShowRelayoks 0
set NewStyleShowSenderoks 0
set NewStyleShowRecipoks 0
# Time scale for graph y-axes (seconds)
set NewStyleTimeInterval 1
set MachinesAwaitingReply {}
if {[info exists env(MD_MX_CTRL)]} {
set x $env(MD_MX_CTRL)
if {"$x" != ""} {
set MD_MX_CTRL $x
}
}
proc strip_zeros { num } {
return [regsub {\.0+$} $num ""]
}
# Don't edit anything below here!
set Machines {}
set ctr 0
set after_token {}
proc find_machine { mach } {
global Machines
set index 0
foreach m $Machines {
if {"[lindex $m 0]" == "$mach"} {
return $index
}
incr index
}
return -1
}
proc add_machine { mach } {
if {[find_machine $mach] >= 0} {
return
}
global Machines
if {[catch {
set fp [open_connection $mach]
lappend Machines [list $mach $fp]
} err]} {
puts stderr $err
}
}
proc host_plus_user { mach } {
if { [string match "*@*" $mach] } {
return $mach
}
return "root@$mach"
}
proc del_machine { mach } {
global Machines
global Data
set mnew {}
set index 0
set did_something 0
foreach m $Machines {
if { "[lindex $m 0]" == "$mach"} {
catch {
close [lindex $m 1]
}
catch { unset Data($mach,busy) }
catch { unset Data($mach,time) }
catch { unset Data($mach,persec) }
catch { unset Data($mach,busy_snap) }
catch { unset Data($mach,persec_snap) }
catch { unset Data($mach,time_snap) }
catch { unset Data($mach,qsize) }
catch { unset Data($mach,busyworkerwin) }
catch { unset Data($mach,busyworkerafter) }
catch { unset Data($mach,error) }
set did_something 1
continue
}
lappend mnew $m
}
set Machines $mnew
if {$did_something} {
reconfigure
}
}
proc open_connection { mach } {
global SSHCommand
global MD_MX_CTRL
set hmach [host_plus_user $mach]
set fp [open "| $SSHCommand $hmach $MD_MX_CTRL" "r+"]
fconfigure $fp -blocking 0
#fconfigure $fp -translation binary
fileevent $fp readable [list connection_readable $mach $fp]
return $fp
}
proc connection_readable { mach fp } {
global DoArchive
global MachinesAwaitingReply
global after_token
# Delete from MachinesAwaitingReply
set index [lsearch -exact $MachinesAwaitingReply $mach]
if {$index >= 0} {
set MachinesAwaitingReply [lreplace $MachinesAwaitingReply $index $index]
}
gets $fp line
if {"$line" == ""} {
if {[eof $fp]} {
catch { close $fp }
del_machine $mach
}
} else {
set index [find_machine $mach]
if {$index >= 0} {
if {[catch { update_machine $line $index $mach } err]} {
mach_set_status_error $mach $index $err
}
if {$DoArchive} {
if {[catch { log_stats $mach $line } err]} {
puts stderr $err
}
}
}
}
# If all machines have replied, redraw
if {[llength $MachinesAwaitingReply] == 0} {
if {"$after_token" != ""} {
after cancel $after_token
set after_token {}
}
redraw
}
}
proc log_stats { mach line } {
set dir "~/.watch-multiple-mimedefangs/$mach"
if {![file isdirectory $dir]} {
file mkdir $dir
}
set fp [open "$dir/data" "a"]
puts $fp "[clock seconds] $line"
close $fp
}
proc get_machine_windows { } {
set kids [winfo children .top]
set result {}
set hi 0
foreach k $kids {
if {[regexp {^\.top\.name([0-9]+)$} $k dummy index]} {
if {$index > $hi} {
set hi $index
}
}
}
foreach k $kids {
if {[regexp {^\.top\.[^0-9]+([0-9]+)$} $k dummy index]} {
if {$index <= $hi} {
lappend result $k
}
}
}
return $result
}
proc mach_set_status_error { mach index err } {
global Data
set Data($mach,error) 1
.top.name$index configure -foreground red
.top.c$index itemconfigure statusText -text $err
.top.c$index delete withtag data1
.top.c$index delete withtag data2
.top.c$index delete withtag data3
}
proc mach_set_status_normal { mach index status } {
global Data
set Data($mach,error) 0
.top.name$index configure -foreground black
.top.c$index itemconfigure statusText -text $status
}
proc mach_populate_data { mach index line } {
global Data
global NewStyle
if {$NewStyle} {
mach_populate_data_new_style $mach $index $line
return
}
foreach { msg0 msg1 msg5 msg10 busy0 busy1 busy5 busy10 ms0 ms1 ms5 ms10 a0 a1 a5 a10 r0 r1 r5 r10 busy idle stopped killed msgs activations qsize qnum uptime} $line { break }
set total_workers [expr $busy + $idle + $stopped + $killed]
set ms0 [format "%.0f" $ms0]
set msg0 [format "%.2f" [expr $msg0 / 10.0]]
lappend Data($mach,busy) $busy0
lappend Data($mach,time) $ms0
lappend Data($mach,persec) $msg0
set Data($mach,total_workers) $total_workers
set Data($mach,busy_snap) $busy
set Data($mach,persec_snap) $msg0
set Data($mach,time_snap) $ms0
set Data($mach,qsize) $qsize
schedule_redraw
}
proc mach_populate_data_new_style { mach index line } {
global Data
foreach { scans avgbusyscans scantime relayoks avgbusyrelayoks relayoktime senderoks avgbusysenderoks senderoktime recipoks avgbusyrecipoks recipoktime busyworkers idleworkers stoppedworkers killedworkers msgs activations qsize numqueued uptime back } $line { break }
set scantime [format "%.0f" $scantime]
set relayoktime [format "%.0f" $relayoktime]
set senderoktime [format "%.0f" $senderoktime]
set recipoktime [format "%.0f" $recipoktime]
set total_workers [expr $busyworkers + $idleworkers + $stoppedworkers + $killedworkers]
set back [expr 1.0 * $back]
set scanspersec [expr (1.0 * $scans) / $back ]
set relayokspersec [expr (1.0 * $relayoks) / $back ]
set senderokspersec [expr (1.0 * $senderoks) / $back ]
set recipokspersec [expr (1.0 * $recipoks) / $back ]
set scanspersec [format "%.2f" $scanspersec]
set relayokspersec [format "%.2f" $relayokspersec]
set senderokspersec [format "%.2f" $senderokspersec]
set recipokspersec [format "%.2f" $recipokspersec]
lappend Data($mach,busy) $busyworkers
lappend Data($mach,scantime) $scantime
lappend Data($mach,scanspersec) $scanspersec
lappend Data($mach,relayoktime) $relayoktime
lappend Data($mach,relayokspersec) $relayokspersec
lappend Data($mach,senderoktime) $senderoktime
lappend Data($mach,senderokspersec) $senderokspersec
lappend Data($mach,recipoktime) $recipoktime
lappend Data($mach,recipokspersec) $recipokspersec
set Data($mach,total_workers) $total_workers
set Data($mach,busy_snap) $busyworkers
set Data($mach,scanspersec_snap) $scanspersec
set Data($mach,relayokspersec_snap) $relayokspersec
set Data($mach,senderokspersec_snap) $senderokspersec
set Data($mach,recipokspersec_snap) $recipokspersec
set Data($mach,scantime_snap) $scantime
set Data($mach,relayoktime_snap) $relayoktime
set Data($mach,senderoktime_snap) $senderoktime
set Data($mach,recipoktime_snap) $recipoktime
set Data($mach,qsize) $qsize
set Data($mach,numqueued) $numqueued
schedule_redraw
}
proc schedule_redraw {} {
global MainUpdateInterval
global after_token
if {"$after_token" == ""} {
set after_token [after $MainUpdateInterval redraw]
}
}
proc redraw_new_style {} {
global Machines
global after_token
global Data
global TotalData
global NewStyleShowScans NewStyleShowRelayoks NewStyleShowSenderoks NewStyleShowRecipoks
set after_token ""
set index 0
set scanspersec_total 0
set relayokspersec_total 0
set senderokspersec_total 0
set recipokspersec_total 0
set scantime_total 0
set relayoktime_total 0
set senderoktime_total 0
set recipoktime_total 0
set busyworkers_total 0
set totalworkers_total 0
set busyworkers_active 0
set totalworkers_active 0
set num_machines 0
set num_graphs 1
if {$NewStyleShowScans} {
incr num_graphs 2
}
if {$NewStyleShowRelayoks} {
incr num_graphs 2
}
if {$NewStyleShowSenderoks} {
incr num_graphs 2
}
if {$NewStyleShowRecipoks} {
incr num_graphs 2
}
set wid [winfo width .top.clabels]
.top.clabels delete all
set spacing [expr $wid / (1.0 * $num_graphs)]
set x [expr $spacing / 2.0]
.top.clabels create text $x 2 -anchor n -fill "#A00000" -text "Busy Workers"
if {$NewStyleShowScans} {
set x [expr $x + $spacing]
.top.clabels create text $x 2 -anchor n -fill "#00A000" -text "Scans/d"
set x [expr $x + $spacing]
.top.clabels create text $x 2 -anchor n -fill "#0000A0" -text "ms/scan"
}
if {$NewStyleShowRelayoks} {
set x [expr $x + $spacing]
.top.clabels create text $x 2 -anchor n -fill "#808000" -text "Relays/d"
set x [expr $x + $spacing]
.top.clabels create text $x 2 -anchor n -fill "#008080" -text "ms/relay"
}
if {$NewStyleShowSenderoks} {
set x [expr $x + $spacing]
.top.clabels create text $x 2 -anchor n -fill "#808080" -text "Senders/d"
set x [expr $x + $spacing]
.top.clabels create text $x 2 -anchor n -fill "#800080" -text "ms/sender"
}
if {$NewStyleShowRecipoks} {
set x [expr $x + $spacing]
.top.clabels create text $x 2 -anchor n -fill "#008000" -text "Recips/d"
set x [expr $x + $spacing]
.top.clabels create text $x 2 -anchor n -fill "#000000" -text "ms/recip"
}
foreach m $Machines {
set mach [lindex $m 0]
if {![info exists Data($mach,busy)]} {
incr index
continue
}
if {$Data($mach,error)} {
incr index
continue
}
# Update totals
set busy $Data($mach,busy_snap)
set totalworkers $Data($mach,total_workers)
# Only update worker counts for machines that are actually doing something
if {$Data($mach,scanspersec_snap) > 0 || $Data($mach,relayokspersec_snap) > 0 || $Data($mach,senderokspersec_snap) > 0 || $Data($mach,recipokspersec_snap) > 0} {
set totalworkers_active [expr $totalworkers_active + $totalworkers]
set busyworkers_active [expr $busyworkers_active + 1.0*$busy]
}
set totalworkers_total [expr $totalworkers_total + $totalworkers]
set busyworkers_total [expr $busyworkers_total + 1.0*$busy]
set scanspersec_total [expr $scanspersec_total + 1.0*$Data($mach,scanspersec_snap)]
set scantime_total [expr $scantime_total + (1.0*$Data($mach,scanspersec_snap) * $Data($mach,scantime_snap))]
set relayokspersec_total [expr $relayokspersec_total + 1.0*$Data($mach,relayokspersec_snap)]
set relayoktime_total [expr $relayoktime_total + (1.0*$Data($mach,relayokspersec_snap) * $Data($mach,relayoktime_snap))]
set senderokspersec_total [expr $senderokspersec_total + 1.0*$Data($mach,senderokspersec_snap)]
set senderoktime_total [expr $senderoktime_total + (1.0*$Data($mach,senderokspersec_snap) * $Data($mach,senderoktime_snap))]
set recipokspersec_total [expr $recipokspersec_total + 1.0*$Data($mach,recipokspersec_snap)]
set recipoktime_total [expr $recipoktime_total + (1.0*$Data($mach,recipokspersec_snap) * $Data($mach,recipoktime_snap))]
set graph 0
set Data($mach,busy) [graph [expr $graph / (1.0 * $num_graphs)] [expr ($graph + 1.0) / (1.0 * $num_graphs)] 0 $Data($mach,total_workers) $Data($mach,busy) $index "Busy" $graph "#A00000" 1]
if {$totalworkers > 0} {
set pctbusy [expr int((1.0*$busy) / (1.0*$totalworkers) * 100)]
} else {
set pctbusy 100
}
if {$pctbusy < 80} {
.top.busy$index configure -background #D9D9D9 -foreground "#A00000"
} elseif {$pctbusy < 90} {
.top.busy$index configure -background #C0C000 -foreground "#A00000"
} else {
.top.busy$index configure -background #C00000 -foreground "#000000"
}
.top.busy$index configure -text "$busy/$totalworkers\n$pctbusy%"
incr graph
if {$NewStyleShowScans} {
set Data($mach,scanspersec) [graph [expr $graph / (1.0 * $num_graphs)] [expr ($graph + 1.0) / (1.0 * $num_graphs)] 0 auto $Data($mach,scanspersec) $index "Scans/s" $graph "#00A000" 1]
incr graph
set Data($mach,scantime) [graph [expr $graph / (1.0 * $num_graphs)] [expr ($graph + 1.0) / (1.0 * $num_graphs)] 0 auto $Data($mach,scantime) $index "ms/scan" $graph "#0000A0" 1]
incr graph
set s $Data($mach,scanspersec_snap)
set h [human_number [expr $s * 3600]]
set d [human_number [expr $s * 86400]]
if {$s == 0} {
.top.scanspersec$index configure -text "-"
.top.scantime$index configure -text "-"
} else {
.top.scanspersec$index configure -text [format "%.2f\n%s/h\n%s/d" $s $h $d]
.top.scantime$index configure -text $Data($mach,scantime_snap)
}
} else {
set Data($mach,scanspersec) {}
set Data($mach,scantime) {}
}
if {$NewStyleShowRelayoks} {
set Data($mach,relayokspersec) [graph [expr $graph / (1.0 * $num_graphs)] [expr ($graph + 1.0) / (1.0 * $num_graphs)] 0 auto $Data($mach,relayokspersec) $index "Relayoks/s" $graph "#808000" 1]
incr graph
set Data($mach,relayoktime) [graph [expr $graph / (1.0 * $num_graphs)] [expr ($graph + 1.0) / (1.0 * $num_graphs)] 0 auto $Data($mach,relayoktime) $index "ms/relayok" $graph "#008080" 1]
incr graph
set s $Data($mach,relayokspersec_snap)
set h [human_number [expr $s * 3600]]
set d [human_number [expr $s * 86400]]
if {$s == 0} {
.top.relayspersec$index configure -text "-"
.top.relaytime$index configure -text "-"
} else {
.top.relayspersec$index configure -text [format "%.2f\n%s/h\n%s/d" $s $h $d]
.top.relaytime$index configure -text $Data($mach,relayoktime_snap)
}
} else {
set Data($mach,relayokspersec) {}
set Data($mach,relayoktime) {}
}
if {$NewStyleShowSenderoks} {
set Data($mach,senderokspersec) [graph [expr $graph / (1.0 * $num_graphs)] [expr ($graph + 1.0) / (1.0 * $num_graphs)] 0 auto $Data($mach,senderokspersec) $index "Senderoks/s" $graph "#808080" 1]
incr graph
set Data($mach,senderoktime) [graph [expr $graph / (1.0 * $num_graphs)] [expr ($graph + 1.0) / (1.0 * $num_graphs)] 0 auto $Data($mach,senderoktime) $index "ms/senderok" $graph "#800080" 1]
incr graph
set s $Data($mach,senderokspersec_snap)
set h [human_number [expr $s * 3600]]
set d [human_number [expr $s * 86400]]
if {$s == 0} {
.top.senderspersec$index configure -text "-"
.top.sendertime$index configure -text "-"
} else {
.top.senderspersec$index configure -text [format "%.2f\n%s/h\n%s/d" $s $h $d]
.top.sendertime$index configure -text $Data($mach,senderoktime_snap)
}
} else {
set Data($mach,senderokspersec) {}
set Data($mach,senderoktime) {}
}
if {$NewStyleShowRecipoks} {
set Data($mach,recipokspersec) [graph [expr $graph / (1.0 * $num_graphs)] [expr ($graph + 1.0) / (1.0 * $num_graphs)] 0 auto $Data($mach,recipokspersec) $index "Recipoks/s" $graph "#008000" 1]
incr graph
set Data($mach,recipoktime) [graph [expr $graph / (1.0 * $num_graphs)] [expr ($graph + 1.0) / (1.0 * $num_graphs)] 0 auto $Data($mach,recipoktime) $index "ms/recipok" $graph "#000000" 1]
incr graph
set s $Data($mach,recipokspersec_snap)
set h [human_number [expr $s * 3600]]
set d [human_number [expr $s * 86400]]
if {$s == 0} {
.top.recipspersec$index configure -text "-"
.top.reciptime$index configure -text "-"
} else {
.top.recipspersec$index configure -text [format "%.2f\n%s/h\n%s/d" $s $h $d]
.top.reciptime$index configure -text $Data($mach,recipoktime_snap)
}
} else {
set Data($mach,recipokspersec) {}
set Data($mach,recipoktime) {}
}
incr index
}
lappend TotalData(busy) $busyworkers_total
lappend TotalData(total) $totalworkers_total
lappend TotalData(scanspersec) $scanspersec_total
set scantime_avg [expr $scantime_total / ($scanspersec_total + 0.000000001)]
set relayoktime_avg [expr $relayoktime_total / ($relayokspersec_total + 0.000000001)]
set senderoktime_avg [expr $senderoktime_total / ($senderokspersec_total + 0.000000001)]
set recipoktime_avg [expr $recipoktime_total / ($recipokspersec_total + 0.000000001)]
lappend TotalData(scantime) $scantime_avg
lappend TotalData(relayokspersec) $relayokspersec_total
lappend TotalData(relayoktime) $relayoktime_avg
lappend TotalData(senderokspersec) $senderokspersec_total
lappend TotalData(senderoktime) $senderoktime_avg
lappend TotalData(recipokspersec) $recipokspersec_total
lappend TotalData(recipoktime) $recipoktime_avg
set graph 0
set TotalData(busy) [graph [expr $graph / (1.0 * $num_graphs)] [expr ($graph + 1.0) / (1.0 * $num_graphs)] 0 $totalworkers_total $TotalData(busy) $index "Busy" $graph "#A00000" 1]
if {$totalworkers_total > 0} {
set busyworkers_total [expr int($busyworkers_total)]
set pctbusy [expr int((1.0 * $busyworkers_total) / (1.0 * $totalworkers_total) * 100)]
} else {
set pctbusy 100
}
if {$totalworkers_active > 0} {
set busyworkers_active [expr int($busyworkers_active)]
set apct [expr int((1.0 * $busyworkers_active) / (1.0 * $totalworkers_active) * 100)]
} else {
set apct 100
}
.top.busytotal configure -text "$busyworkers_total/$totalworkers_total\n$pctbusy%\n$busyworkers_active/$totalworkers_active\n$apct%"
incr graph
if {$NewStyleShowScans} {
set TotalData(scanspersec) [graph [expr $graph / (1.0 * $num_graphs)] [expr ($graph + 1.0) / (1.0 * $num_graphs)] 0 auto $TotalData(scanspersec) $index "Scans/s" $graph "#00A000" 1]
incr graph
set TotalData(scantime) [graph [expr $graph / (1.0 * $num_graphs)] [expr ($graph + 1.0) / (1.0 * $num_graphs)] 0 auto $TotalData(scantime) $index "ms/scan" $graph "#0000A0" 1]
incr graph
set h [human_number [expr $scanspersec_total * 3600]]
set d [human_number [expr $scanspersec_total * 86400]]
.top.scanspersectotal configure -text [format "%.2f\n%s/h\n%s/d" $scanspersec_total $h $d]
.top.avgscantime configure -text [format "%.0f" $scantime_avg]
} else {
set TotalData(scanspersec) {}
set TotalData(scantime) {}
}
if {$NewStyleShowRelayoks} {
set TotalData(relayokspersec) [graph [expr $graph / (1.0 * $num_graphs)] [expr ($graph + 1.0) / (1.0 * $num_graphs)] 0 auto $TotalData(relayokspersec) $index "Relayoks/s" $graph "#808000" 1]
incr graph
set TotalData(relayoktime) [graph [expr $graph / (1.0 * $num_graphs)] [expr ($graph + 1.0) / (1.0 * $num_graphs)] 0 auto $TotalData(relayoktime) $index "ms/relayok" $graph "#008080" 1]
incr graph
set h [human_number [expr $relayokspersec_total * 3600]]
set d [human_number [expr $relayokspersec_total * 86400]]
.top.relayspersectotal configure -text [format "%.2f\n%s/h\n%s/d" $relayokspersec_total $h $d]
.top.avgrelaytime configure -text [format "%.0f" $relayoktime_avg]
} else {
set TotalData(relayokspersec) {}
set TotalData(relayoktime) {}
}
if {$NewStyleShowSenderoks} {
set TotalData(senderokspersec) [graph [expr $graph / (1.0 * $num_graphs)] [expr ($graph + 1.0) / (1.0 * $num_graphs)] 0 auto $TotalData(senderokspersec) $index "Senderoks/s" $graph "#808080" 1]
incr graph
set TotalData(senderoktime) [graph [expr $graph / (1.0 * $num_graphs)] [expr ($graph + 1.0) / (1.0 * $num_graphs)] 0 auto $TotalData(senderoktime) $index "ms/senderok" $graph "#800080" 1]
incr graph
set h [human_number [expr $senderokspersec_total * 3600]]
set d [human_number [expr $senderokspersec_total * 86400]]
.top.senderspersectotal configure -text [format "%.2f\n%s/h\n%s/d" $senderokspersec_total $h $d]
.top.avgsendertime configure -text [format "%.0f" $senderoktime_avg]
set s [human_number $senderokspersec_total]
} else {
set TotalData(senderokspersec) {}
set TotalData(senderoktime) {}
}
if {$NewStyleShowRecipoks} {
set TotalData(recipokspersec) [graph [expr $graph / (1.0 * $num_graphs)] [expr ($graph + 1.0) / (1.0 * $num_graphs)] 0 auto $TotalData(recipokspersec) $index "Recipoks/s" $graph "#008000" 1]
incr graph
set TotalData(recipoktime) [graph [expr $graph / (1.0 * $num_graphs)] [expr ($graph + 1.0) / (1.0 * $num_graphs)] 0 auto $TotalData(recipoktime) $index "ms/recipok" $graph "#000000" 1]
incr graph
set h [human_number [expr $recipokspersec_total * 3600]]
set d [human_number [expr $recipokspersec_total * 86400]]
.top.recipspersectotal configure -text [format "%.2f\n%s/h\n%s/d" $recipokspersec_total $h $d]
.top.avgreciptime configure -text [format "%.0f" $recipoktime_avg]
} else {
set TotalData(recipokspersec) {}
set TotalData(recipoktime) {}
}
update
}
proc redraw {} {
global Machines
global NewStyle
global after_token
global Data
global TotalData
global DoneARedrawSinceLastUpdate
set DoneARedrawSinceLastUpdate 1
if {$NewStyle} {
redraw_new_style
return
}
set after_token ""
set index 0
set persec_total 0
set busy_workers_total 0
set avail_workers_total 0
set msgs_per_sec_total 0
set ms_per_scan_total 0
set num_machines 0
foreach m $Machines {
set mach [lindex $m 0]
if {![info exists Data($mach,busy)]} {
incr index
continue
}
if {$Data($mach,error)} {
incr index
continue
}
set busy $Data($mach,busy_snap)
set total_workers $Data($mach,total_workers)
set msg0 $Data($mach,persec_snap)
set ms0 $Data($mach,time_snap)
set persec_total [expr $persec_total + $msg0]
# Format $busy to have as many characters as $total_workers
set l [string length $total_workers]
set busy [format "%${l}d" $busy]
.top.busy$index configure -text "$busy/$total_workers"
.top.persec$index configure -text $msg0
.top.time$index configure -text $ms0
if {$busy == $total_workers} {
.top.name$index configure -background "#CCCC00"
} else {
.top.name$index configure -background "#D9D9D9"
}
set Data($mach,busy) [graph 0 [expr 1.0/3] 0 $Data($mach,total_workers) $Data($mach,busy) $index "Busy" 1 red 1]
set Data($mach,persec) [graph [expr 1.0/3] [expr 2.0/3] 0 auto $Data($mach,persec) $index "Msgs/Sec" 2 green 1]
set Data($mach,time) [graph [expr 2.0/3] 1 0 auto $Data($mach,time) $index "ms/scan" 3 blue 1]
incr index
if {$ms0 > 0 || $Data($mach,busy_snap) > 0 || $msg0 > 0} {
incr num_machines
incr busy_workers_total $Data($mach,busy_snap)
incr avail_workers_total $Data($mach,total_workers);
incr ms_per_scan_total $ms0
}
}
lappend TotalData(busy) $busy_workers_total
if {$num_machines > 0} {
lappend TotalData(time) [expr 1.0 * $ms_per_scan_total / (1.0 * $num_machines)]
} else {
lappend TotalData(time) 0
}
lappend TotalData(persec) $persec_total
incr index
set TotalData(busy) [graph 0 [expr 1.0/3] 0 $avail_workers_total $TotalData(busy) $index "Busy" 1 red 1]
set TotalData(persec) [graph [expr 1.0/3] [expr 2.0/3] 0 auto $TotalData(persec) $index "Msgs/Sec" 2 green 1]
set TotalData(time) [graph [expr 2.0/3] 1 0 auto $TotalData(time) $index "ms/scan" 3 blue 1]
set msgs_per_sec_total $persec_total
set hour [human_number [expr $persec_total * 3600.0]]
set day [human_number [expr $persec_total * 86400.0]]
set persec_total [strip_zeros [format "%.1f" $persec_total]]
.top.c configure -text "Total throughput $persec_total/s = $hour/hour = $day/day"
set l [string length $avail_workers_total]
set busy_workers_total [format "%${l}d" $busy_workers_total]
.top.busytotal configure -text "$busy_workers_total/$avail_workers_total"
.top.persectotal configure -text [strip_zeros [format "%.1f" $msgs_per_sec_total]]
if {$num_machines > 0} {
.top.avgtime configure -text [strip_zeros [format "%.0f" [expr 1.0 * $ms_per_scan_total / (1.0 * $num_machines)]]]
} else {
.top.avgtime configure -text "--"
}
update
}
proc graph { start_frac end_frac min max data index label tag fill_color line_width} {
global NewStyleTimeInterval
set tag "data$tag"
set c .top.c$index
set h [winfo height $c]
set w [winfo width $c]
set x0 [expr int($start_frac * $w)]
set x1 [expr int($end_frac * $w)]
set x0 [expr $x0 + 40]
set x1 [expr $x1 - 5]
set diff [expr $x1 - $x0]
set gridline_spacing 15
if {[llength $data] > $diff} {
set toChop [expr [llength $data] - $diff]
set data [lrange $data $toChop end]
}
set multiplier 1
if {"$label" == "Scans/s"} {
if {$NewStyleTimeInterval == 3600} {
set label "Scans/h"
set multiplier 3600
} elseif {$NewStyleTimeInterval == 86400} {
set label "Scans/d"
set multiplier 86400
}
}
if {"$label" == "Senderoks/s"} {
if {$NewStyleTimeInterval == 3600} {
set label "Senderoks/h"
set multiplier 3600
} elseif {$NewStyleTimeInterval == 86400} {
set label "Senderoks/d"
set multiplier 86400
}
}
if {"$label" == "Relayoks/s"} {
if {$NewStyleTimeInterval == 3600} {
set label "Relayoks/h"
set multiplier 3600
} elseif {$NewStyleTimeInterval == 86400} {
set label "Relayoks/d"
set multiplier 86400
}
}
if {"$label" == "Recipoks/s"} {
if {$NewStyleTimeInterval == 3600} {
set label "Recipoks/h"
set multiplier 3600
} elseif {$NewStyleTimeInterval == 86400} {
set label "Recipoks/d"
set multiplier 86400
}
}
if {"$min" == "auto"} {
set min [lindex $data 0]
foreach thing $data {
if {$thing < $min} {set min $thing}
}
set min [expr $multiplier * $min]
set min [nicenum $min 1]
}
if {"$max" == "auto"} {
set max [lindex $data 0]
foreach thing $data {
if {$thing > $max} {set max $thing}
}
set max [expr $multiplier * $max]
set max [nicenum $max 0]
}
set x $x0
$c delete withtag $tag
set coords {}
if {$max == $min} {
set max [expr $max + 1.0]
}
set diff [expr 1.0 * ($max - $min)]
set num_gridlines [expr int((1.0 * $h) / (1.0 * $gridline_spacing))]
if {$num_gridlines > 10} {
set num_gridlines 10
}
if {$num_gridlines < 1} {
set num_gridlines 1
}
set delta [nicenum [expr $diff / $num_gridlines] 1]
foreach point $data {
set y [expr $point * $multiplier - $min]
set y [expr (1.0 * $y * $h) / (1.0 * $diff)]
set y [expr $h - $y]
if {$y < 1} {
set y 1
}
if {$y >= $h} {
set y [expr $h - 1]
}
lappend coords $x $y
incr x
}
if {$delta > 0.0} {
set last_phys_y 99999
for {set y $min} {$y <= $max} {set y [expr $y + $delta]} {
set cy [expr (1.0 * ($y-$min) * $h) / (1.0 * $diff)]
set cy [expr $h - $cy]
if {$cy <= 0} {
continue
}
if {$cy > [expr $h-1]} {
set cy [expr $h-1]
}
if {($last_phys_y - $cy) >= (2 * $gridline_spacing)} {
set last_phys_y $cy
set anc w
if {$cy < $gridline_spacing} {
set anc nw
}
if {$cy >= ($h - $gridline_spacing)} {
set anc sw
}
$c create line [expr $x0 - 10] $cy $x1 $cy -fill "#A0A0A0" -tags $tag
$c create text [expr $x0 - 37] $cy -text [human_number $y] -tag $tag -anchor $anc
} else {
$c create line $x0 $cy $x1 $cy -fill "#DDDDDD" -tags $tag
}
}
} else {
$c create text [expr $x0 - 37] 0 -anchor nw -text [human_number $max] -tag $tag
$c create text [expr $x0 - 37] $h -anchor sw -text [human_number $min] -tag $tag
}
if {[llength $coords] >= 4} {
$c create line $coords -fill $fill_color -width $line_width -tags $tag
}
return $data
}
proc update_machine { line index mach } {
if {[string match "ERROR *" $line]} {
mach_set_status_error $mach $index $line
return
}
mach_set_status_normal $mach $index ""
mach_populate_data $mach $index $line
}
proc interactive_add_machine {} {
set mach [.top.new get]
if {"$mach" != ""} {
add_machine $mach
reconfigure
}
}
proc reconfigure_new_style {} {
global Machines
global NewStyleShowScans NewStyleShowRelayoks NewStyleShowSenderoks NewStyleShowRecipoks
catch { destroy .top.name }
catch { destroy .top.busy }
catch { destroy .top.scanspersec }
catch { destroy .top.scantime }
catch { destroy .top.relayspersec }
catch { destroy .top.relaytime }
catch { destroy .top.senderspersec }
catch { destroy .top.sendertime }
catch { destroy .top.recipspersec }
catch { destroy .top.reciptime }
catch { destroy .top.c }
set col 2
set canv_width 200
label .top.name -text "Machine Name"
label .top.busy -text "Busy Workers " -foreground "#A00000"
grid .top.name -row 0 -column 0 -sticky new
grid .top.busy -row 0 -column 1 -sticky new
catch { destroy .top.clabels}
canvas .top.clabels -width $canv_width -height 10 -takefocus 0 -borderwidth 0 -background #ffffff -highlightthickness 0
if {$NewStyleShowScans} {
incr canv_width 200
label .top.scanspersec -text "Scans/s " -foreground "#00A000"
grid .top.scanspersec -row 0 -column $col -sticky new
incr col
label .top.scantime -text "ms/scan " -foreground "#0000A0"
grid .top.scantime -row 0 -column $col -sticky new
incr col
}
if {$NewStyleShowRelayoks} {
incr canv_width 200
label .top.relayspersec -text "Relays/s " -foreground "#808000"
grid .top.relayspersec -row 0 -column $col -sticky new
incr col
label .top.relaytime -text "ms/relay " -foreground "#008080"
grid .top.relaytime -row 0 -column $col -sticky new
incr col
}
if {$NewStyleShowSenderoks} {
incr canv_width 200
label .top.senderspersec -text "Senders/s " -foreground "#808080"
grid .top.senderspersec -row 0 -column $col -sticky new
incr col
label .top.sendertime -text "ms/sender " -foreground "#800080"
grid .top.sendertime -row 0 -column $col -sticky new
incr col
}
if {$NewStyleShowRecipoks} {
incr canv_width 200
label .top.recipspersec -text "Recips/s " -foreground "#008000"
grid .top.recipspersec -row 0 -column $col -sticky new
incr col
label .top.reciptime -text "ms/recip " -foreground "#000000"
grid .top.reciptime -row 0 -column $col -sticky new
incr col
}
grid .top.clabels -row 0 -column $col -sticky nsew
grid rowconfigure .top 0 -weight 0
set index 0
foreach m $Machines {
grid_machine_new_style $m $index
incr index
}
# If a machine has been deleted, destroy its windows
catch { destroy .top.name$index }
catch { destroy .top.busy$index }
catch { destroy .top.scanspersec$index }
catch { destroy .top.scantime$index }
catch { destroy .top.relayspersec$index }
catch { destroy .top.relaytime$index }
catch { destroy .top.senderspersec$index }
catch { destroy .top.sendertime$index }
catch { destroy .top.recipspersec$index }
catch { destroy .top.reciptime$index }
catch { destroy .top.c$index }
# Bottom row of labels
catch { destroy .top.totalrow }
catch { destroy .top.busytotal }
catch { destroy .top.scanspersectotal }
catch { destroy .top.avgscantime }
catch { destroy .top.relayspersectotal }
catch { destroy .top.avgrelaytime }
catch { destroy .top.senderspersectotal }
catch { destroy .top.avgsendertime }
catch { destroy .top.recipspersectotal }
catch { destroy .top.avgreciptime }
# Mop up total window if a machine has been deleted
set row [expr $index + 1]
catch { destroy .top.c$row }
set col 2
label .top.totalrow -text "Totals:"
label .top.busytotal -foreground "#A00000"
grid .top.totalrow -row $row -column 0 -sticky new
grid .top.busytotal -row $row -column 1 -sticky new
if {$NewStyleShowScans} {
label .top.scanspersectotal -foreground "#00A000"
grid .top.scanspersectotal -row $row -column $col -sticky new
incr col
label .top.avgscantime -foreground "#0000A0"
grid .top.avgscantime -row $row -column $col -sticky new
incr col
}
if {$NewStyleShowRelayoks} {
label .top.relayspersectotal -foreground "#808000"
grid .top.relayspersectotal -row $row -column $col -sticky new
incr col
label .top.avgrelaytime -foreground "#008080"
grid .top.avgrelaytime -row $row -column $col -sticky new
incr col
}
if {$NewStyleShowSenderoks} {
label .top.senderspersectotal -foreground "#808080"
grid .top.senderspersectotal -row $row -column $col -sticky new
incr col
label .top.avgsendertime -foreground "#800080"
grid .top.avgsendertime -row $row -column $col -sticky new
incr col
}
if {$NewStyleShowRecipoks} {
label .top.recipspersectotal -foreground "#008000"
grid .top.recipspersectotal -row $row -column $col -sticky new
incr col
label .top.avgreciptime -foreground "#000000"
grid .top.avgreciptime -row $row -column $col -sticky new
incr col
}
set num_items [expr $col-1]
canvas .top.c$index -width $canv_width -height 60 -takefocus 0 -borderwidth 0 -background #FFFFEE -highlightthickness 0
grid .top.c$index -row $row -column $col -sticky nsew -pady 1
grid rowconfigure .top $row -weight 3
for {set i 0} {$i < $col} {incr i} {
grid columnconfigure .top $i -weight 0
}
grid columnconfigure .top $col -weight 1
incr index
incr row
# Now a spot for adding a new machine...
catch { destroy .top.newlab }
catch { destroy .top.new }
catch { destroy .top.all }
label .top.newlab -text "Add Machine: "
entry .top.new -width 20
grid .top.newlab -row $row -column 0
grid .top.new -row $row -column 1 -columnspan [expr $col - 1] -sticky ew
bind .top.new <Return> interactive_add_machine
button .top.all -text "Summary" -command all_or_summary
grid .top.all -row $row -column [expr $col] -sticky w
grid rowconfigure .top $row -weight 0
wm deiconify .top
}
proc all_or_summary {} {
set text [.top.all cget -text]
set win [get_machine_windows]
set rowcol [grid size .top]
set rows [lindex $rowcol 1]
if {"$text" == "Summary"} {
.top.all configure -text "All"
foreach w $win {
grid remove $w
}
for {set i 1} {$i < [expr $rows - 2]} {incr i} {
grid rowconfigure .top $i -weight 0
}
} else {
.top.all configure -text "Summary"
foreach w $win {
grid $w
}
for {set i 1} {$i < [expr $rows - 2]} {incr i} {
grid rowconfigure .top $i -weight 1
}
}
# Cancel any user-specified geometry
wm geometry .top ""
}
proc reconfigure {} {
global Machines
global NewStyle
if {$NewStyle} {
reconfigure_new_style
return
}
set index 0
foreach m $Machines {
grid_machine $m $index
incr index
}
# Top row of labels
catch { destroy .top.busy }
catch { destroy .top.persec }
catch { destroy .top.time }
catch { destroy .top.c }
catch { destroy .top.name }
label .top.name -text "Machine Name"
label .top.busy -text "Busy Workers" -foreground "#A00000"
label .top.persec -text "Msgs/s" -foreground "#00A000"
label .top.time -text " ms/scan " -foreground "#0000A0"
label .top.c -text ""
grid .top.name -row 0 -column 0 -sticky new
grid .top.busy -row 0 -column 1 -sticky new
grid .top.persec -row 0 -column 2 -sticky new
grid .top.time -row 0 -column 3 -sticky new
grid .top.c -row 0 -column 4 -sticky new
grid rowconfigure .top 0 -weight 0
# If a machine has been deleted, destroy its windows
catch { destroy .top.name$index}
catch { destroy .top.busy$index}
catch { destroy .top.persec$index}
catch { destroy .top.time$index}
catch { destroy .top.c$index}
incr index
# Bottom row of labels
catch { destroy .top.busytotal }
catch { destroy .top.persectotal }
catch { destroy .top.avgtime }
catch { destroy .top.totalrow }
catch { destroy .top.c$index }
# Mop up total window if a machine has been deleted
set i [expr $index + 1]
catch { destroy .top.c$i }
label .top.totalrow -text "Totals:"
label .top.busytotal
label .top.persectotal
label .top.avgtime
canvas .top.c$index -width 400 -height 60 -takefocus 0 -borderwidth 0 -background #FFFFF0 -highlightthickness 0
grid .top.totalrow -row $index -column 0 -sticky new
grid .top.busytotal -row $index -column 1 -sticky new
grid .top.persectotal -row $index -column 2 -sticky new
grid .top.avgtime -row $index -column 3 -sticky new
grid .top.c$index -row $index -column 4 -sticky nsew -pady 1
grid rowconfigure .top $index -weight 3
incr index
# Now a spot for adding a new machine...
catch { destroy .top.newlab }
catch { destroy .top.new }
label .top.newlab -text "Add Machine: "
entry .top.new -width 20
grid .top.newlab -row $index -column 0
grid .top.new -row $index -column 1 -columnspan 3 -sticky ew
bind .top.new <Return> interactive_add_machine
button .top.all -text "Summary" -command all_or_summary
grid .top.all -row $index -column 4 -sticky w
grid rowconfigure .top $index -weight 0
grid columnconfigure .top 0 -weight 0
grid columnconfigure .top 1 -weight 0
grid columnconfigure .top 2 -weight 0
grid columnconfigure .top 3 -weight 0
grid columnconfigure .top 4 -weight 1
wm deiconify .top
}
proc busyworkers { mach } {
global ctr
global Data
incr ctr
set w .workers$ctr
catch { destroy $w }
toplevel $w
wm title $w "Busy workers: $mach"
wm iconname $w "$mach workers"
set Data($mach,busyworkerwin) $w
# Open a new SSH connection for the busyworkers info
global SSHCommand
global MD_MX_CTRL
set hmach [host_plus_user $mach]
set fp [open "| $SSHCommand $hmach $MD_MX_CTRL" "r+"]
fconfigure $fp -blocking 0
fileevent $fp readable [list busyworkers_readable $mach $fp]
tickle_busyworkers $mach $fp
text $w.t -width 80 -height 35
pack $w.t -side left -expand 1 -fill both
$w.t tag bind pid <Enter> [list enter_pid $w.t]
$w.t tag bind pid <Leave> [list leave_pid $w.t]
$w.t tag bind pid <ButtonPress-1> [list trace_worker $w.t $mach]
}
proc tickle_busyworkers { mach fp } {
global Data
catch {
set Data($mach,busydata) ""
# We have to use the old command for backware-compatibility.
puts $fp "busyslaves\nfoo_no_such_command"
flush $fp
}
}
proc busyworkers_readable { mach fp } {
global Data
gets $fp line
if {"$line" == ""} {
if {[eof $fp]} {
close $fp
catch { destroy $Data($mach,busyworkerwin) }
}
return
}
if {"$line" != "error: Unknown command"} {
lappend Data($mach,busydata) $line
return
}
update_busyworkers $mach $fp
global BusyWorkerUpdateInterval
after $BusyWorkerUpdateInterval [list tickle_busyworkers $mach $fp]
}
proc trace_worker { w mach } {
global TraceCommand
set tags [$w tag names current]
set index [lsearch -glob $tags "Z*"]
if {$index >= 0} {
set tag [lindex $tags $index]
set pid [string range $tag 1 end]
ssh $mach "$TraceCommand $pid" "Process $pid on $mach"
}
}
proc enter_pid { w } {
set tags [$w tag names current]
set index [lsearch -glob $tags "Z*"]
if {$index >= 0} {
set tag [lindex $tags $index]
$w tag configure $tag -foreground "#A00000"
}
}
proc leave_pid { w } {
set tags [$w tag names current]
set index [lsearch -glob $tags "Z*"]
if {$index >= 0} {
set tag [lindex $tags $index]
$w tag configure $tag -foreground "#000000"
}
}
proc compare_workers { a b } {
set acmd [lindex $a 3]
set bcmd [lindex $b 3]
set x [string compare $bcmd $acmd]
if {$x != 0} {
return $x
}
set an [lindex $a 0]
set bn [lindex $b 0]
set aago [lindex $a 5]
set bago [lindex $b 5]
if {[string match "ago=*" $aago] && [string match "ago=*" $bago]} {
set aago [string range $aago 4 end]
set bago [string range $bago 4 end]
set x [expr $bago - $aago]
if {$x != 0} {
return $x
}
}
return [expr $an - $bn]
}
proc update_busyworkers { mach fp} {
global Data
set w $Data($mach,busyworkerwin)
if {![winfo exists $w]} {
catch { close $fp }
return
}
$w.t configure -state normal
$w.t delete 1.0 end
# Clear out tags
foreach tag [$w.t tag names] {
if {"$tag" != "pid"} {
$w.t tag delete $tag
}
}
set busyguys [lsort -command compare_workers $Data($mach,busydata)]
set count(scan) 0
set count(relayok) 0
set count(senderok) 0
set count(recipok) 0
foreach line $busyguys {
set lst [split $line]
set workerno [lindex $lst 0]
set pid [lindex $lst 2]
set cmd [lindex $lst 3]
incr count($cmd)
set len [string length "$workerno B $pid "]
set line [string range $line $len end]
$w.t insert end [format "%4d" $workerno] workerno
$w.t insert end " "
$w.t tag delete "Z$pid"
$w.t insert end [format "%6d" $pid] [list pid "Z$pid"]
$w.t insert end " $line\n"
}
set title "Busy workers: $mach"
foreach cmd {scan relayok senderok recipok} {
if {$count($cmd) > 0} {
set c $count($cmd)
append title " $cmd=$c"
}
}
wm title $w $title
}
proc popup_machine_menu { m index x y} {
catch { destroy .m }
menu .m -tearoff 0
.m add command -label "SSH" -command [list ssh $m]
.m add command -label "Busy Workers" -command [list busyworkers $m]
.m add separator
.m add command -label "Delete" -command [list del_machine $m]
tk_popup .m $x $y
}
proc grid_machine_new_style { m index } {
global NewStyleShowScans NewStyleShowRelayoks NewStyleShowSenderoks NewStyleShowRecipoks
set m [lindex $m 0]
set disp_m $m
if {[regexp {@(.*)$} $m foo host]} {
set disp_m $host
}
# Chop off domain name from host
if {[regexp {^([^.]+)\.} $disp_m foo new_m]} {
set disp_m $new_m
}
set row [expr $index + 1]
catch { destroy .top.name$index }
catch { destroy .top.busy$index }
catch { destroy .top.scanspersec$index }
catch { destroy .top.scantime$index }
catch { destroy .top.relayspersec$index }
catch { destroy .top.relaytime$index }
catch { destroy .top.senderspersec$index }
catch { destroy .top.sendertime$index }
catch { destroy .top.recipspersec$index }
catch { destroy .top.reciptime$index }
catch { destroy .top.c$index }
set column 2
set canv_width 200
label .top.name$index -text $disp_m -relief raised
bind .top.name$index <ButtonPress-1> [list popup_machine_menu $m $index %X %Y]
bind .top.name$index <ButtonPress-2> [list popup_machine_menu $m $index %X %Y]
bind .top.name$index <ButtonPress-3> [list popup_machine_menu $m $index %X %Y]
label .top.busy$index -text "" -foreground "#A00000"
grid .top.name$index -row $row -column 0 -sticky new
grid .top.busy$index -row $row -column 1 -sticky new
if {$NewStyleShowScans} {
label .top.scanspersec$index -foreground "#00A000"
grid .top.scanspersec$index -row $row -column $column -sticky new
incr column
label .top.scantime$index -foreground "#0000A0"
grid .top.scantime$index -row $row -column $column -sticky new
incr column
incr canv_width 200
}
if {$NewStyleShowRelayoks} {
label .top.relayspersec$index -foreground "#808000"
grid .top.relayspersec$index -row $row -column $column -sticky new
incr column
label .top.relaytime$index -foreground "#008080"
grid .top.relaytime$index -row $row -column $column -sticky new
incr column
incr canv_width 200
}
if {$NewStyleShowSenderoks} {
label .top.senderspersec$index -foreground "#808080"
grid .top.senderspersec$index -row $row -column $column -sticky new
incr column
label .top.sendertime$index -foreground "#800080"
grid .top.sendertime$index -row $row -column $column -sticky new
incr column
incr canv_width 200
}
if {$NewStyleShowRecipoks} {
label .top.recipspersec$index -foreground "#008000"
grid .top.recipspersec$index -row $row -column $column -sticky new
incr column
label .top.reciptime$index -foreground "#000000"
grid .top.reciptime$index -row $row -column $column -sticky new
incr column
incr canv_width 200
}
canvas .top.c$index -width $canv_width -height 60 -takefocus 0 -borderwidth 0 -background #FFFFFF -highlightthickness 0
grid .top.c$index -row $row -column $column -sticky nsew -pady 1
grid rowconfigure .top $row -weight 1
}
proc grid_machine { m index } {
set m [lindex $m 0]
set row [expr $index + 1]
catch { destroy .top.name$index}
catch { destroy .top.busy$index}
catch { destroy .top.persec$index}
catch { destroy .top.time$index}
catch { destroy .top.c$index}
set disp_m $m
if {[regexp {@(.*)$} $m foo host]} {
set disp_m $host
}
label .top.name$index -text $disp_m -relief raised
bind .top.name$index <ButtonPress-1> [list popup_machine_menu $m $index %X %Y]
bind .top.name$index <ButtonPress-2> [list popup_machine_menu $m $index %X %Y]
bind .top.name$index <ButtonPress-3> [list popup_machine_menu $m $index %X %Y]
label .top.busy$index -text ""
label .top.persec$index -text ""
label .top.time$index -text ""
canvas .top.c$index -width 600 -height 60 -takefocus 0 -borderwidth 0 -background white -highlightthickness 0
.top.c$index create text 2 2 -anchor nw -text "" -tags statusText
grid .top.name$index -row $row -column 0 -sticky new
grid .top.busy$index -row $row -column 1 -sticky new
grid .top.persec$index -row $row -column 2 -sticky new
grid .top.time$index -row $row -column 3 -sticky new
grid .top.c$index -row $row -column 4 -sticky nsew -pady 1
grid rowconfigure .top $row -weight 1
}
proc kick_off_update {} {
global Machines
global NewStyle
global DoneARedrawSinceLastUpdate
global MachinesAwaitingReply
global MainUpdateInterval
if {$DoneARedrawSinceLastUpdate} {
set DoneARedrawSinceLastUpdate 0
if {$NewStyle} {
set cmd "rawload1 60"
} else {
set cmd "rawload"
}
set MachinesAwaitingReply {}
foreach m $Machines {
catch {
set fp [lindex $m 1]
puts $fp $cmd
flush $fp
lappend MachinesAwaitingReply [lindex $m 0]
}
}
}
after $MainUpdateInterval kick_off_update
}
## translated from C-code in Blt, who got it from:
## Taken from Paul Heckbert's "Nice Numbers for Graph Labels" in
## Graphics Gems (pp 61-63). Finds a "nice" number approximately
## equal to x.
proc nicenum {x floor} {
if {$x == 0} {
return 0
}
set negative 0
if {$x < 0} {
set x [expr -$x]
set negative 1
}
set exponX [expr floor(log10($x))]
set fractX [expr $x/pow(10,$exponX)]; # between 1 and 10
if {$floor} {
if {$fractX < 2.0} {
set nf 1.0
} elseif {$fractX < 3.0} {
set nf 2.0
} elseif {$fractX < 4.0} {
set nf 3.0
} elseif {$fractX < 5.0} {
set nf 4.0
} elseif {$fractX < 10.0} {
set nf 5.0
} else {
set nf 10.0
}
} elseif {$fractX <= 1.0} {
set nf 1.0
} elseif {$fractX <= 1.5} {
set nf 1.5
} elseif {$fractX <= 2.0} {
set nf 2.0
} elseif {$fractX <= 2.5} {
set nf 2.5
} elseif {$fractX <= 3.0} {
set nf 3.0
} elseif {$fractX <= 4.0} {
set nf 4.0
} elseif {$fractX <= 5.0} {
set nf 5.0
} elseif {$fractX <= 6.0} {
set nf 6.0
} elseif {$fractX <= 8.0} {
set nf 8.0
} else {
set nf 10.0
}
if { $negative } {
return [expr -$nf * pow(10,$exponX)]
} else {
set value [expr $nf * pow(10,$exponX)]
return $value
}
}
proc human_number { num } {
if {$num <= 1000} {
return [strip_zeros [format "%.1f" $num]]
}
set num [expr $num / 1000.0]
if {$num <= 1000} {
set num [strip_zeros [format "%.1f" $num]]
return "${num}K"
}
set num [expr $num / 1000.0]
if {$num <= 1000} {
set num [strip_zeros [format "%.1f" $num]]
return "${num}M"
}
set num [expr $num / 1000.0]
set num [strip_zeros [format "%.1f" $num]]
return "${num}G"
}
proc pick_color { host } {
set color 0
set components {AA BB CC EE}
catch { set host [lindex $host end] }
set host [split $host ""]
foreach char $host {
set color [expr $color + 1]
binary scan $char "c" x
incr color $x
if { $color <= 0 } {
set color [expr $x + 1]
}
}
set ans "#"
expr srand($color)
for {set i 0} {$i < 3} {incr i} {
set off [expr int(4.0 * rand())]
append ans [lindex $components $off]
}
return $ans
}
proc ssh { host {cmd ""} {title ""}} {
set color [pick_color $host]
if {"$title" == ""} {
set title "SSH $host"
}
global SSHCommand
set hmach [host_plus_user $host]
exec xterm -hold -title $title -bg #000000 -fg $color -e $SSHCommand $hmach $cmd &
}
wm withdraw .
foreach mach $argv {
if {"$mach" == "-archive"} {
set DoArchive 1
continue
}
if {"$mach" == "-d"} {
set NewStyleTimeInterval 86400
continue
}
if {"$mach" == "-h"} {
set NewStyleTimeInterval 3600
continue
}
if {"$mach" == "-n"} {
set NewStyle 1
set NewStyleShowScans 1
continue
}
if {"$mach" == "-r"} {
set NewStyle 1
set NewStyleShowRelayoks 1
continue
}
if {"$mach" == "-s"} {
set NewStyle 1
set NewStyleShowSenderoks 1
continue
}
if {"$mach" == "-t"} {
set NewStyle 1
set NewStyleShowRecipoks 1
continue
}
add_machine $mach
}
catch { destroy .top}
toplevel .top
wm title .top "Watch Multiple MIMEDefangs"
wm iconname .top "MIMEDefangs"
wm withdraw .top
reconfigure
wm deiconify .top
update
kick_off_update
tkwait window .top
exit