1#!/bin/sh 2# -*-Mode: TCL;-*- 3# 4# Copyright (C) 2007 Roaring Penguin Software Inc. This file may be 5# distributed under the terms of the GNU General Public License, Version 2, 6# or (at your option) any later version. 7 8# Next line restarts using wish \ 9exec wish "$0" -- "$@" ; clear; echo "*****"; echo "Cannot find 'wish' -- you need Tcl/Tk installed to run this program"; exit 1 10 11# Main update interval (ms) 12set MainUpdateInterval 1500 13 14# Busy worker update interval (ms) 15set BusyWorkerUpdateInterval 3000 16 17# Trace command - pid is appended 18set TraceCommand "strace -s 100 -t -p" 19 20# Command to run SSH 21set SSHCommand "ssh" 22 23# Command to run md-mx-ctrl 24set MD_MX_CTRL "md-mx-ctrl -i" 25 26# Archive readings? 27set DoArchive 0 28 29# Have we done a redraw since the last update? 30# Start out set to yes to kick things off! 31set DoneARedrawSinceLastUpdate 1 32 33# Use new-style "rawload1" command? 34set NewStyle 0 35set NewStyleShowScans 0 36set NewStyleShowRelayoks 0 37set NewStyleShowSenderoks 0 38set NewStyleShowRecipoks 0 39 40# Time scale for graph y-axes (seconds) 41set NewStyleTimeInterval 1 42 43set MachinesAwaitingReply {} 44 45if {[info exists env(MD_MX_CTRL)]} { 46 set x $env(MD_MX_CTRL) 47 if {"$x" != ""} { 48 set MD_MX_CTRL $x 49 } 50} 51 52proc strip_zeros { num } { 53 return [regsub {\.0+$} $num ""] 54} 55 56# Don't edit anything below here! 57set Machines {} 58set ctr 0 59set after_token {} 60proc find_machine { mach } { 61 global Machines 62 set index 0 63 foreach m $Machines { 64 if {"[lindex $m 0]" == "$mach"} { 65 return $index 66 } 67 incr index 68 } 69 return -1 70} 71 72proc add_machine { mach } { 73 if {[find_machine $mach] >= 0} { 74 return 75 } 76 77 global Machines 78 if {[catch { 79 set fp [open_connection $mach] 80 lappend Machines [list $mach $fp] 81 } err]} { 82 puts stderr $err 83 } 84} 85 86proc host_plus_user { mach } { 87 if { [string match "*@*" $mach] } { 88 return $mach 89 } 90 return "root@$mach" 91} 92 93proc del_machine { mach } { 94 global Machines 95 global Data 96 set mnew {} 97 set index 0 98 set did_something 0 99 foreach m $Machines { 100 if { "[lindex $m 0]" == "$mach"} { 101 catch { 102 close [lindex $m 1] 103 } 104 catch { unset Data($mach,busy) } 105 catch { unset Data($mach,time) } 106 catch { unset Data($mach,persec) } 107 catch { unset Data($mach,busy_snap) } 108 catch { unset Data($mach,persec_snap) } 109 catch { unset Data($mach,time_snap) } 110 catch { unset Data($mach,qsize) } 111 catch { unset Data($mach,busyworkerwin) } 112 catch { unset Data($mach,busyworkerafter) } 113 catch { unset Data($mach,error) } 114 set did_something 1 115 continue 116 } 117 lappend mnew $m 118 } 119 set Machines $mnew 120 if {$did_something} { 121 reconfigure 122 } 123} 124 125proc open_connection { mach } { 126 global SSHCommand 127 global MD_MX_CTRL 128 set hmach [host_plus_user $mach] 129 set fp [open "| $SSHCommand $hmach $MD_MX_CTRL" "r+"] 130 fconfigure $fp -blocking 0 131 #fconfigure $fp -translation binary 132 fileevent $fp readable [list connection_readable $mach $fp] 133 return $fp 134} 135 136proc connection_readable { mach fp } { 137 global DoArchive 138 global MachinesAwaitingReply 139 global after_token 140 141 # Delete from MachinesAwaitingReply 142 set index [lsearch -exact $MachinesAwaitingReply $mach] 143 if {$index >= 0} { 144 set MachinesAwaitingReply [lreplace $MachinesAwaitingReply $index $index] 145 } 146 gets $fp line 147 148 if {"$line" == ""} { 149 if {[eof $fp]} { 150 catch { close $fp } 151 del_machine $mach 152 } 153 } else { 154 set index [find_machine $mach] 155 if {$index >= 0} { 156 if {[catch { update_machine $line $index $mach } err]} { 157 mach_set_status_error $mach $index $err 158 } 159 160 if {$DoArchive} { 161 if {[catch { log_stats $mach $line } err]} { 162 puts stderr $err 163 } 164 } 165 } 166 } 167 168 # If all machines have replied, redraw 169 if {[llength $MachinesAwaitingReply] == 0} { 170 if {"$after_token" != ""} { 171 after cancel $after_token 172 set after_token {} 173 } 174 redraw 175 } 176} 177 178proc log_stats { mach line } { 179 set dir "~/.watch-multiple-mimedefangs/$mach" 180 if {![file isdirectory $dir]} { 181 file mkdir $dir 182 } 183 set fp [open "$dir/data" "a"] 184 puts $fp "[clock seconds] $line" 185 close $fp 186} 187 188proc get_machine_windows { } { 189 set kids [winfo children .top] 190 set result {} 191 set hi 0 192 foreach k $kids { 193 if {[regexp {^\.top\.name([0-9]+)$} $k dummy index]} { 194 if {$index > $hi} { 195 set hi $index 196 } 197 } 198 } 199 foreach k $kids { 200 if {[regexp {^\.top\.[^0-9]+([0-9]+)$} $k dummy index]} { 201 if {$index <= $hi} { 202 lappend result $k 203 } 204 } 205 } 206 return $result 207} 208 209proc mach_set_status_error { mach index err } { 210 global Data 211 set Data($mach,error) 1 212 .top.name$index configure -foreground red 213 .top.c$index itemconfigure statusText -text $err 214 .top.c$index delete withtag data1 215 .top.c$index delete withtag data2 216 .top.c$index delete withtag data3 217} 218 219proc mach_set_status_normal { mach index status } { 220 global Data 221 set Data($mach,error) 0 222 .top.name$index configure -foreground black 223 .top.c$index itemconfigure statusText -text $status 224} 225 226proc mach_populate_data { mach index line } { 227 global Data 228 global NewStyle 229 230 if {$NewStyle} { 231 mach_populate_data_new_style $mach $index $line 232 return 233 } 234 235 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 } 236 set total_workers [expr $busy + $idle + $stopped + $killed] 237 set ms0 [format "%.0f" $ms0] 238 set msg0 [format "%.2f" [expr $msg0 / 10.0]] 239 240 lappend Data($mach,busy) $busy0 241 lappend Data($mach,time) $ms0 242 lappend Data($mach,persec) $msg0 243 set Data($mach,total_workers) $total_workers 244 set Data($mach,busy_snap) $busy 245 set Data($mach,persec_snap) $msg0 246 set Data($mach,time_snap) $ms0 247 set Data($mach,qsize) $qsize 248 schedule_redraw 249} 250 251proc mach_populate_data_new_style { mach index line } { 252 global Data 253 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 } 254 255 set scantime [format "%.0f" $scantime] 256 set relayoktime [format "%.0f" $relayoktime] 257 set senderoktime [format "%.0f" $senderoktime] 258 set recipoktime [format "%.0f" $recipoktime] 259 260 set total_workers [expr $busyworkers + $idleworkers + $stoppedworkers + $killedworkers] 261 262 set back [expr 1.0 * $back] 263 set scanspersec [expr (1.0 * $scans) / $back ] 264 set relayokspersec [expr (1.0 * $relayoks) / $back ] 265 set senderokspersec [expr (1.0 * $senderoks) / $back ] 266 set recipokspersec [expr (1.0 * $recipoks) / $back ] 267 268 set scanspersec [format "%.2f" $scanspersec] 269 set relayokspersec [format "%.2f" $relayokspersec] 270 set senderokspersec [format "%.2f" $senderokspersec] 271 set recipokspersec [format "%.2f" $recipokspersec] 272 273 lappend Data($mach,busy) $busyworkers 274 lappend Data($mach,scantime) $scantime 275 lappend Data($mach,scanspersec) $scanspersec 276 lappend Data($mach,relayoktime) $relayoktime 277 lappend Data($mach,relayokspersec) $relayokspersec 278 lappend Data($mach,senderoktime) $senderoktime 279 lappend Data($mach,senderokspersec) $senderokspersec 280 lappend Data($mach,recipoktime) $recipoktime 281 lappend Data($mach,recipokspersec) $recipokspersec 282 283 set Data($mach,total_workers) $total_workers 284 set Data($mach,busy_snap) $busyworkers 285 set Data($mach,scanspersec_snap) $scanspersec 286 set Data($mach,relayokspersec_snap) $relayokspersec 287 set Data($mach,senderokspersec_snap) $senderokspersec 288 set Data($mach,recipokspersec_snap) $recipokspersec 289 set Data($mach,scantime_snap) $scantime 290 set Data($mach,relayoktime_snap) $relayoktime 291 set Data($mach,senderoktime_snap) $senderoktime 292 set Data($mach,recipoktime_snap) $recipoktime 293 set Data($mach,qsize) $qsize 294 set Data($mach,numqueued) $numqueued 295 296 schedule_redraw 297} 298 299proc schedule_redraw {} { 300 global MainUpdateInterval 301 global after_token 302 if {"$after_token" == ""} { 303 set after_token [after $MainUpdateInterval redraw] 304 } 305} 306 307proc redraw_new_style {} { 308 global Machines 309 global after_token 310 global Data 311 global TotalData 312 global NewStyleShowScans NewStyleShowRelayoks NewStyleShowSenderoks NewStyleShowRecipoks 313 314 set after_token "" 315 set index 0 316 317 set scanspersec_total 0 318 set relayokspersec_total 0 319 set senderokspersec_total 0 320 set recipokspersec_total 0 321 set scantime_total 0 322 set relayoktime_total 0 323 set senderoktime_total 0 324 set recipoktime_total 0 325 set busyworkers_total 0 326 set totalworkers_total 0 327 set busyworkers_active 0 328 set totalworkers_active 0 329 set num_machines 0 330 331 set num_graphs 1 332 if {$NewStyleShowScans} { 333 incr num_graphs 2 334 } 335 if {$NewStyleShowRelayoks} { 336 incr num_graphs 2 337 } 338 if {$NewStyleShowSenderoks} { 339 incr num_graphs 2 340 } 341 if {$NewStyleShowRecipoks} { 342 incr num_graphs 2 343 } 344 345 set wid [winfo width .top.clabels] 346 .top.clabels delete all 347 set spacing [expr $wid / (1.0 * $num_graphs)] 348 set x [expr $spacing / 2.0] 349 .top.clabels create text $x 2 -anchor n -fill "#A00000" -text "Busy Workers" 350 if {$NewStyleShowScans} { 351 set x [expr $x + $spacing] 352 .top.clabels create text $x 2 -anchor n -fill "#00A000" -text "Scans/d" 353 set x [expr $x + $spacing] 354 .top.clabels create text $x 2 -anchor n -fill "#0000A0" -text "ms/scan" 355 } 356 if {$NewStyleShowRelayoks} { 357 set x [expr $x + $spacing] 358 .top.clabels create text $x 2 -anchor n -fill "#808000" -text "Relays/d" 359 set x [expr $x + $spacing] 360 .top.clabels create text $x 2 -anchor n -fill "#008080" -text "ms/relay" 361 } 362 if {$NewStyleShowSenderoks} { 363 set x [expr $x + $spacing] 364 .top.clabels create text $x 2 -anchor n -fill "#808080" -text "Senders/d" 365 set x [expr $x + $spacing] 366 .top.clabels create text $x 2 -anchor n -fill "#800080" -text "ms/sender" 367 } 368 if {$NewStyleShowRecipoks} { 369 set x [expr $x + $spacing] 370 .top.clabels create text $x 2 -anchor n -fill "#008000" -text "Recips/d" 371 set x [expr $x + $spacing] 372 .top.clabels create text $x 2 -anchor n -fill "#000000" -text "ms/recip" 373 } 374 375 foreach m $Machines { 376 set mach [lindex $m 0] 377 if {![info exists Data($mach,busy)]} { 378 incr index 379 continue 380 } 381 if {$Data($mach,error)} { 382 incr index 383 continue 384 } 385 386 # Update totals 387 set busy $Data($mach,busy_snap) 388 set totalworkers $Data($mach,total_workers) 389 390 # Only update worker counts for machines that are actually doing something 391 if {$Data($mach,scanspersec_snap) > 0 || $Data($mach,relayokspersec_snap) > 0 || $Data($mach,senderokspersec_snap) > 0 || $Data($mach,recipokspersec_snap) > 0} { 392 set totalworkers_active [expr $totalworkers_active + $totalworkers] 393 set busyworkers_active [expr $busyworkers_active + 1.0*$busy] 394 } 395 396 set totalworkers_total [expr $totalworkers_total + $totalworkers] 397 set busyworkers_total [expr $busyworkers_total + 1.0*$busy] 398 399 set scanspersec_total [expr $scanspersec_total + 1.0*$Data($mach,scanspersec_snap)] 400 set scantime_total [expr $scantime_total + (1.0*$Data($mach,scanspersec_snap) * $Data($mach,scantime_snap))] 401 set relayokspersec_total [expr $relayokspersec_total + 1.0*$Data($mach,relayokspersec_snap)] 402 set relayoktime_total [expr $relayoktime_total + (1.0*$Data($mach,relayokspersec_snap) * $Data($mach,relayoktime_snap))] 403 set senderokspersec_total [expr $senderokspersec_total + 1.0*$Data($mach,senderokspersec_snap)] 404 set senderoktime_total [expr $senderoktime_total + (1.0*$Data($mach,senderokspersec_snap) * $Data($mach,senderoktime_snap))] 405 set recipokspersec_total [expr $recipokspersec_total + 1.0*$Data($mach,recipokspersec_snap)] 406 set recipoktime_total [expr $recipoktime_total + (1.0*$Data($mach,recipokspersec_snap) * $Data($mach,recipoktime_snap))] 407 408 set graph 0 409 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] 410 if {$totalworkers > 0} { 411 set pctbusy [expr int((1.0*$busy) / (1.0*$totalworkers) * 100)] 412 } else { 413 set pctbusy 100 414 } 415 if {$pctbusy < 80} { 416 .top.busy$index configure -background #D9D9D9 -foreground "#A00000" 417 } elseif {$pctbusy < 90} { 418 .top.busy$index configure -background #C0C000 -foreground "#A00000" 419 } else { 420 .top.busy$index configure -background #C00000 -foreground "#000000" 421 } 422 423 .top.busy$index configure -text "$busy/$totalworkers\n$pctbusy%" 424 425 incr graph 426 427 if {$NewStyleShowScans} { 428 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] 429 incr graph 430 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] 431 incr graph 432 set s $Data($mach,scanspersec_snap) 433 set h [human_number [expr $s * 3600]] 434 set d [human_number [expr $s * 86400]] 435 if {$s == 0} { 436 .top.scanspersec$index configure -text "-" 437 .top.scantime$index configure -text "-" 438 } else { 439 .top.scanspersec$index configure -text [format "%.2f\n%s/h\n%s/d" $s $h $d] 440 .top.scantime$index configure -text $Data($mach,scantime_snap) 441 } 442 } else { 443 set Data($mach,scanspersec) {} 444 set Data($mach,scantime) {} 445 } 446 447 if {$NewStyleShowRelayoks} { 448 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] 449 incr graph 450 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] 451 incr graph 452 set s $Data($mach,relayokspersec_snap) 453 set h [human_number [expr $s * 3600]] 454 set d [human_number [expr $s * 86400]] 455 if {$s == 0} { 456 .top.relayspersec$index configure -text "-" 457 .top.relaytime$index configure -text "-" 458 } else { 459 .top.relayspersec$index configure -text [format "%.2f\n%s/h\n%s/d" $s $h $d] 460 .top.relaytime$index configure -text $Data($mach,relayoktime_snap) 461 } 462 } else { 463 set Data($mach,relayokspersec) {} 464 set Data($mach,relayoktime) {} 465 } 466 if {$NewStyleShowSenderoks} { 467 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] 468 incr graph 469 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] 470 incr graph 471 set s $Data($mach,senderokspersec_snap) 472 set h [human_number [expr $s * 3600]] 473 set d [human_number [expr $s * 86400]] 474 if {$s == 0} { 475 .top.senderspersec$index configure -text "-" 476 .top.sendertime$index configure -text "-" 477 } else { 478 .top.senderspersec$index configure -text [format "%.2f\n%s/h\n%s/d" $s $h $d] 479 .top.sendertime$index configure -text $Data($mach,senderoktime_snap) 480 } 481 } else { 482 set Data($mach,senderokspersec) {} 483 set Data($mach,senderoktime) {} 484 } 485 if {$NewStyleShowRecipoks} { 486 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] 487 incr graph 488 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] 489 incr graph 490 set s $Data($mach,recipokspersec_snap) 491 set h [human_number [expr $s * 3600]] 492 set d [human_number [expr $s * 86400]] 493 if {$s == 0} { 494 .top.recipspersec$index configure -text "-" 495 .top.reciptime$index configure -text "-" 496 } else { 497 .top.recipspersec$index configure -text [format "%.2f\n%s/h\n%s/d" $s $h $d] 498 .top.reciptime$index configure -text $Data($mach,recipoktime_snap) 499 } 500 } else { 501 set Data($mach,recipokspersec) {} 502 set Data($mach,recipoktime) {} 503 } 504 incr index 505 } 506 lappend TotalData(busy) $busyworkers_total 507 lappend TotalData(total) $totalworkers_total 508 lappend TotalData(scanspersec) $scanspersec_total 509 set scantime_avg [expr $scantime_total / ($scanspersec_total + 0.000000001)] 510 set relayoktime_avg [expr $relayoktime_total / ($relayokspersec_total + 0.000000001)] 511 set senderoktime_avg [expr $senderoktime_total / ($senderokspersec_total + 0.000000001)] 512 set recipoktime_avg [expr $recipoktime_total / ($recipokspersec_total + 0.000000001)] 513 lappend TotalData(scantime) $scantime_avg 514 lappend TotalData(relayokspersec) $relayokspersec_total 515 lappend TotalData(relayoktime) $relayoktime_avg 516 lappend TotalData(senderokspersec) $senderokspersec_total 517 lappend TotalData(senderoktime) $senderoktime_avg 518 lappend TotalData(recipokspersec) $recipokspersec_total 519 lappend TotalData(recipoktime) $recipoktime_avg 520 521 set graph 0 522 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] 523 if {$totalworkers_total > 0} { 524 set busyworkers_total [expr int($busyworkers_total)] 525 set pctbusy [expr int((1.0 * $busyworkers_total) / (1.0 * $totalworkers_total) * 100)] 526 } else { 527 set pctbusy 100 528 } 529 530 if {$totalworkers_active > 0} { 531 set busyworkers_active [expr int($busyworkers_active)] 532 set apct [expr int((1.0 * $busyworkers_active) / (1.0 * $totalworkers_active) * 100)] 533 } else { 534 set apct 100 535 } 536 .top.busytotal configure -text "$busyworkers_total/$totalworkers_total\n$pctbusy%\n$busyworkers_active/$totalworkers_active\n$apct%" 537 incr graph 538 539 if {$NewStyleShowScans} { 540 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] 541 incr graph 542 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] 543 incr graph 544 set h [human_number [expr $scanspersec_total * 3600]] 545 set d [human_number [expr $scanspersec_total * 86400]] 546 .top.scanspersectotal configure -text [format "%.2f\n%s/h\n%s/d" $scanspersec_total $h $d] 547 .top.avgscantime configure -text [format "%.0f" $scantime_avg] 548 } else { 549 set TotalData(scanspersec) {} 550 set TotalData(scantime) {} 551 } 552 553 if {$NewStyleShowRelayoks} { 554 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] 555 incr graph 556 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] 557 incr graph 558 set h [human_number [expr $relayokspersec_total * 3600]] 559 set d [human_number [expr $relayokspersec_total * 86400]] 560 .top.relayspersectotal configure -text [format "%.2f\n%s/h\n%s/d" $relayokspersec_total $h $d] 561 .top.avgrelaytime configure -text [format "%.0f" $relayoktime_avg] 562 } else { 563 set TotalData(relayokspersec) {} 564 set TotalData(relayoktime) {} 565 } 566 if {$NewStyleShowSenderoks} { 567 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] 568 incr graph 569 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] 570 incr graph 571 set h [human_number [expr $senderokspersec_total * 3600]] 572 set d [human_number [expr $senderokspersec_total * 86400]] 573 .top.senderspersectotal configure -text [format "%.2f\n%s/h\n%s/d" $senderokspersec_total $h $d] 574 .top.avgsendertime configure -text [format "%.0f" $senderoktime_avg] 575 set s [human_number $senderokspersec_total] 576 } else { 577 set TotalData(senderokspersec) {} 578 set TotalData(senderoktime) {} 579 } 580 if {$NewStyleShowRecipoks} { 581 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] 582 incr graph 583 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] 584 incr graph 585 set h [human_number [expr $recipokspersec_total * 3600]] 586 set d [human_number [expr $recipokspersec_total * 86400]] 587 .top.recipspersectotal configure -text [format "%.2f\n%s/h\n%s/d" $recipokspersec_total $h $d] 588 .top.avgreciptime configure -text [format "%.0f" $recipoktime_avg] 589 } else { 590 set TotalData(recipokspersec) {} 591 set TotalData(recipoktime) {} 592 } 593 update 594} 595 596proc redraw {} { 597 global Machines 598 global NewStyle 599 global after_token 600 global Data 601 global TotalData 602 global DoneARedrawSinceLastUpdate 603 604 set DoneARedrawSinceLastUpdate 1 605 if {$NewStyle} { 606 redraw_new_style 607 return 608 } 609 610 set after_token "" 611 set index 0 612 set persec_total 0 613 set busy_workers_total 0 614 set avail_workers_total 0 615 set msgs_per_sec_total 0 616 set ms_per_scan_total 0 617 set num_machines 0 618 619 foreach m $Machines { 620 set mach [lindex $m 0] 621 if {![info exists Data($mach,busy)]} { 622 incr index 623 continue 624 } 625 if {$Data($mach,error)} { 626 incr index 627 continue 628 } 629 630 set busy $Data($mach,busy_snap) 631 set total_workers $Data($mach,total_workers) 632 set msg0 $Data($mach,persec_snap) 633 set ms0 $Data($mach,time_snap) 634 set persec_total [expr $persec_total + $msg0] 635 # Format $busy to have as many characters as $total_workers 636 set l [string length $total_workers] 637 set busy [format "%${l}d" $busy] 638 .top.busy$index configure -text "$busy/$total_workers" 639 .top.persec$index configure -text $msg0 640 .top.time$index configure -text $ms0 641 if {$busy == $total_workers} { 642 .top.name$index configure -background "#CCCC00" 643 } else { 644 .top.name$index configure -background "#D9D9D9" 645 } 646 647 set Data($mach,busy) [graph 0 [expr 1.0/3] 0 $Data($mach,total_workers) $Data($mach,busy) $index "Busy" 1 red 1] 648 set Data($mach,persec) [graph [expr 1.0/3] [expr 2.0/3] 0 auto $Data($mach,persec) $index "Msgs/Sec" 2 green 1] 649 set Data($mach,time) [graph [expr 2.0/3] 1 0 auto $Data($mach,time) $index "ms/scan" 3 blue 1] 650 incr index 651 652 if {$ms0 > 0 || $Data($mach,busy_snap) > 0 || $msg0 > 0} { 653 incr num_machines 654 incr busy_workers_total $Data($mach,busy_snap) 655 incr avail_workers_total $Data($mach,total_workers); 656 incr ms_per_scan_total $ms0 657 } 658 } 659 lappend TotalData(busy) $busy_workers_total 660 if {$num_machines > 0} { 661 lappend TotalData(time) [expr 1.0 * $ms_per_scan_total / (1.0 * $num_machines)] 662 } else { 663 lappend TotalData(time) 0 664 } 665 lappend TotalData(persec) $persec_total 666 667 incr index 668 set TotalData(busy) [graph 0 [expr 1.0/3] 0 $avail_workers_total $TotalData(busy) $index "Busy" 1 red 1] 669 set TotalData(persec) [graph [expr 1.0/3] [expr 2.0/3] 0 auto $TotalData(persec) $index "Msgs/Sec" 2 green 1] 670 set TotalData(time) [graph [expr 2.0/3] 1 0 auto $TotalData(time) $index "ms/scan" 3 blue 1] 671 672 set msgs_per_sec_total $persec_total 673 set hour [human_number [expr $persec_total * 3600.0]] 674 set day [human_number [expr $persec_total * 86400.0]] 675 set persec_total [strip_zeros [format "%.1f" $persec_total]] 676 .top.c configure -text "Total throughput $persec_total/s = $hour/hour = $day/day" 677 set l [string length $avail_workers_total] 678 set busy_workers_total [format "%${l}d" $busy_workers_total] 679 .top.busytotal configure -text "$busy_workers_total/$avail_workers_total" 680 .top.persectotal configure -text [strip_zeros [format "%.1f" $msgs_per_sec_total]] 681 if {$num_machines > 0} { 682 .top.avgtime configure -text [strip_zeros [format "%.0f" [expr 1.0 * $ms_per_scan_total / (1.0 * $num_machines)]]] 683 } else { 684 .top.avgtime configure -text "--" 685 } 686 update 687} 688 689proc graph { start_frac end_frac min max data index label tag fill_color line_width} { 690 global NewStyleTimeInterval 691 692 set tag "data$tag" 693 set c .top.c$index 694 set h [winfo height $c] 695 set w [winfo width $c] 696 set x0 [expr int($start_frac * $w)] 697 set x1 [expr int($end_frac * $w)] 698 set x0 [expr $x0 + 40] 699 set x1 [expr $x1 - 5] 700 set diff [expr $x1 - $x0] 701 set gridline_spacing 15 702 if {[llength $data] > $diff} { 703 set toChop [expr [llength $data] - $diff] 704 set data [lrange $data $toChop end] 705 } 706 707 set multiplier 1 708 709 if {"$label" == "Scans/s"} { 710 if {$NewStyleTimeInterval == 3600} { 711 set label "Scans/h" 712 set multiplier 3600 713 } elseif {$NewStyleTimeInterval == 86400} { 714 set label "Scans/d" 715 set multiplier 86400 716 } 717 } 718 if {"$label" == "Senderoks/s"} { 719 if {$NewStyleTimeInterval == 3600} { 720 set label "Senderoks/h" 721 set multiplier 3600 722 } elseif {$NewStyleTimeInterval == 86400} { 723 set label "Senderoks/d" 724 set multiplier 86400 725 } 726 } 727 if {"$label" == "Relayoks/s"} { 728 if {$NewStyleTimeInterval == 3600} { 729 set label "Relayoks/h" 730 set multiplier 3600 731 } elseif {$NewStyleTimeInterval == 86400} { 732 set label "Relayoks/d" 733 set multiplier 86400 734 } 735 } 736 if {"$label" == "Recipoks/s"} { 737 if {$NewStyleTimeInterval == 3600} { 738 set label "Recipoks/h" 739 set multiplier 3600 740 } elseif {$NewStyleTimeInterval == 86400} { 741 set label "Recipoks/d" 742 set multiplier 86400 743 } 744 } 745 746 if {"$min" == "auto"} { 747 set min [lindex $data 0] 748 foreach thing $data { 749 if {$thing < $min} {set min $thing} 750 } 751 set min [expr $multiplier * $min] 752 set min [nicenum $min 1] 753 } 754 if {"$max" == "auto"} { 755 set max [lindex $data 0] 756 foreach thing $data { 757 if {$thing > $max} {set max $thing} 758 } 759 set max [expr $multiplier * $max] 760 set max [nicenum $max 0] 761 } 762 763 set x $x0 764 $c delete withtag $tag 765 set coords {} 766 if {$max == $min} { 767 set max [expr $max + 1.0] 768 } 769 set diff [expr 1.0 * ($max - $min)] 770 set num_gridlines [expr int((1.0 * $h) / (1.0 * $gridline_spacing))] 771 if {$num_gridlines > 10} { 772 set num_gridlines 10 773 } 774 if {$num_gridlines < 1} { 775 set num_gridlines 1 776 } 777 778 set delta [nicenum [expr $diff / $num_gridlines] 1] 779 foreach point $data { 780 set y [expr $point * $multiplier - $min] 781 set y [expr (1.0 * $y * $h) / (1.0 * $diff)] 782 set y [expr $h - $y] 783 if {$y < 1} { 784 set y 1 785 } 786 if {$y >= $h} { 787 set y [expr $h - 1] 788 } 789 lappend coords $x $y 790 incr x 791 } 792 if {$delta > 0.0} { 793 set last_phys_y 99999 794 for {set y $min} {$y <= $max} {set y [expr $y + $delta]} { 795 set cy [expr (1.0 * ($y-$min) * $h) / (1.0 * $diff)] 796 set cy [expr $h - $cy] 797 if {$cy <= 0} { 798 continue 799 } 800 if {$cy > [expr $h-1]} { 801 set cy [expr $h-1] 802 } 803 if {($last_phys_y - $cy) >= (2 * $gridline_spacing)} { 804 set last_phys_y $cy 805 set anc w 806 if {$cy < $gridline_spacing} { 807 set anc nw 808 } 809 if {$cy >= ($h - $gridline_spacing)} { 810 set anc sw 811 } 812 $c create line [expr $x0 - 10] $cy $x1 $cy -fill "#A0A0A0" -tags $tag 813 $c create text [expr $x0 - 37] $cy -text [human_number $y] -tag $tag -anchor $anc 814 } else { 815 $c create line $x0 $cy $x1 $cy -fill "#DDDDDD" -tags $tag 816 } 817 } 818 } else { 819 $c create text [expr $x0 - 37] 0 -anchor nw -text [human_number $max] -tag $tag 820 $c create text [expr $x0 - 37] $h -anchor sw -text [human_number $min] -tag $tag 821 } 822 if {[llength $coords] >= 4} { 823 $c create line $coords -fill $fill_color -width $line_width -tags $tag 824 } 825 return $data 826} 827proc update_machine { line index mach } { 828 if {[string match "ERROR *" $line]} { 829 mach_set_status_error $mach $index $line 830 return 831 } 832 mach_set_status_normal $mach $index "" 833 834 mach_populate_data $mach $index $line 835} 836 837proc interactive_add_machine {} { 838 set mach [.top.new get] 839 if {"$mach" != ""} { 840 add_machine $mach 841 reconfigure 842 } 843} 844 845proc reconfigure_new_style {} { 846 global Machines 847 global NewStyleShowScans NewStyleShowRelayoks NewStyleShowSenderoks NewStyleShowRecipoks 848 catch { destroy .top.name } 849 catch { destroy .top.busy } 850 catch { destroy .top.scanspersec } 851 catch { destroy .top.scantime } 852 catch { destroy .top.relayspersec } 853 catch { destroy .top.relaytime } 854 catch { destroy .top.senderspersec } 855 catch { destroy .top.sendertime } 856 catch { destroy .top.recipspersec } 857 catch { destroy .top.reciptime } 858 catch { destroy .top.c } 859 860 set col 2 861 set canv_width 200 862 label .top.name -text "Machine Name" 863 label .top.busy -text "Busy Workers " -foreground "#A00000" 864 grid .top.name -row 0 -column 0 -sticky new 865 grid .top.busy -row 0 -column 1 -sticky new 866 catch { destroy .top.clabels} 867 canvas .top.clabels -width $canv_width -height 10 -takefocus 0 -borderwidth 0 -background #ffffff -highlightthickness 0 868 if {$NewStyleShowScans} { 869 incr canv_width 200 870 label .top.scanspersec -text "Scans/s " -foreground "#00A000" 871 grid .top.scanspersec -row 0 -column $col -sticky new 872 incr col 873 label .top.scantime -text "ms/scan " -foreground "#0000A0" 874 grid .top.scantime -row 0 -column $col -sticky new 875 incr col 876 } 877 if {$NewStyleShowRelayoks} { 878 incr canv_width 200 879 label .top.relayspersec -text "Relays/s " -foreground "#808000" 880 grid .top.relayspersec -row 0 -column $col -sticky new 881 incr col 882 label .top.relaytime -text "ms/relay " -foreground "#008080" 883 grid .top.relaytime -row 0 -column $col -sticky new 884 incr col 885 } 886 if {$NewStyleShowSenderoks} { 887 incr canv_width 200 888 label .top.senderspersec -text "Senders/s " -foreground "#808080" 889 grid .top.senderspersec -row 0 -column $col -sticky new 890 incr col 891 label .top.sendertime -text "ms/sender " -foreground "#800080" 892 grid .top.sendertime -row 0 -column $col -sticky new 893 incr col 894 } 895 if {$NewStyleShowRecipoks} { 896 incr canv_width 200 897 label .top.recipspersec -text "Recips/s " -foreground "#008000" 898 grid .top.recipspersec -row 0 -column $col -sticky new 899 incr col 900 label .top.reciptime -text "ms/recip " -foreground "#000000" 901 grid .top.reciptime -row 0 -column $col -sticky new 902 incr col 903 } 904 905 grid .top.clabels -row 0 -column $col -sticky nsew 906 grid rowconfigure .top 0 -weight 0 907 set index 0 908 foreach m $Machines { 909 grid_machine_new_style $m $index 910 incr index 911 } 912 913 # If a machine has been deleted, destroy its windows 914 catch { destroy .top.name$index } 915 catch { destroy .top.busy$index } 916 catch { destroy .top.scanspersec$index } 917 catch { destroy .top.scantime$index } 918 catch { destroy .top.relayspersec$index } 919 catch { destroy .top.relaytime$index } 920 catch { destroy .top.senderspersec$index } 921 catch { destroy .top.sendertime$index } 922 catch { destroy .top.recipspersec$index } 923 catch { destroy .top.reciptime$index } 924 catch { destroy .top.c$index } 925 926 # Bottom row of labels 927 catch { destroy .top.totalrow } 928 catch { destroy .top.busytotal } 929 catch { destroy .top.scanspersectotal } 930 catch { destroy .top.avgscantime } 931 catch { destroy .top.relayspersectotal } 932 catch { destroy .top.avgrelaytime } 933 catch { destroy .top.senderspersectotal } 934 catch { destroy .top.avgsendertime } 935 catch { destroy .top.recipspersectotal } 936 catch { destroy .top.avgreciptime } 937 938 # Mop up total window if a machine has been deleted 939 set row [expr $index + 1] 940 catch { destroy .top.c$row } 941 942 set col 2 943 label .top.totalrow -text "Totals:" 944 label .top.busytotal -foreground "#A00000" 945 grid .top.totalrow -row $row -column 0 -sticky new 946 grid .top.busytotal -row $row -column 1 -sticky new 947 if {$NewStyleShowScans} { 948 label .top.scanspersectotal -foreground "#00A000" 949 grid .top.scanspersectotal -row $row -column $col -sticky new 950 incr col 951 label .top.avgscantime -foreground "#0000A0" 952 grid .top.avgscantime -row $row -column $col -sticky new 953 incr col 954 } 955 if {$NewStyleShowRelayoks} { 956 label .top.relayspersectotal -foreground "#808000" 957 grid .top.relayspersectotal -row $row -column $col -sticky new 958 incr col 959 label .top.avgrelaytime -foreground "#008080" 960 grid .top.avgrelaytime -row $row -column $col -sticky new 961 incr col 962 } 963 if {$NewStyleShowSenderoks} { 964 label .top.senderspersectotal -foreground "#808080" 965 grid .top.senderspersectotal -row $row -column $col -sticky new 966 incr col 967 label .top.avgsendertime -foreground "#800080" 968 grid .top.avgsendertime -row $row -column $col -sticky new 969 incr col 970 } 971 if {$NewStyleShowRecipoks} { 972 label .top.recipspersectotal -foreground "#008000" 973 grid .top.recipspersectotal -row $row -column $col -sticky new 974 incr col 975 label .top.avgreciptime -foreground "#000000" 976 grid .top.avgreciptime -row $row -column $col -sticky new 977 incr col 978 } 979 set num_items [expr $col-1] 980 981 canvas .top.c$index -width $canv_width -height 60 -takefocus 0 -borderwidth 0 -background #FFFFEE -highlightthickness 0 982 grid .top.c$index -row $row -column $col -sticky nsew -pady 1 983 grid rowconfigure .top $row -weight 3 984 985 for {set i 0} {$i < $col} {incr i} { 986 grid columnconfigure .top $i -weight 0 987 } 988 grid columnconfigure .top $col -weight 1 989 990 incr index 991 incr row 992 # Now a spot for adding a new machine... 993 catch { destroy .top.newlab } 994 catch { destroy .top.new } 995 catch { destroy .top.all } 996 997 label .top.newlab -text "Add Machine: " 998 entry .top.new -width 20 999 grid .top.newlab -row $row -column 0 1000 grid .top.new -row $row -column 1 -columnspan [expr $col - 1] -sticky ew 1001 bind .top.new <Return> interactive_add_machine 1002 button .top.all -text "Summary" -command all_or_summary 1003 grid .top.all -row $row -column [expr $col] -sticky w 1004 grid rowconfigure .top $row -weight 0 1005 1006 wm deiconify .top 1007} 1008 1009proc all_or_summary {} { 1010 set text [.top.all cget -text] 1011 set win [get_machine_windows] 1012 set rowcol [grid size .top] 1013 set rows [lindex $rowcol 1] 1014 1015 if {"$text" == "Summary"} { 1016 .top.all configure -text "All" 1017 foreach w $win { 1018 grid remove $w 1019 } 1020 for {set i 1} {$i < [expr $rows - 2]} {incr i} { 1021 grid rowconfigure .top $i -weight 0 1022 } 1023 } else { 1024 .top.all configure -text "Summary" 1025 foreach w $win { 1026 grid $w 1027 } 1028 for {set i 1} {$i < [expr $rows - 2]} {incr i} { 1029 grid rowconfigure .top $i -weight 1 1030 } 1031 } 1032 1033 # Cancel any user-specified geometry 1034 wm geometry .top "" 1035} 1036 1037proc reconfigure {} { 1038 global Machines 1039 global NewStyle 1040 if {$NewStyle} { 1041 reconfigure_new_style 1042 return 1043 } 1044 1045 set index 0 1046 foreach m $Machines { 1047 grid_machine $m $index 1048 incr index 1049 } 1050 1051 # Top row of labels 1052 catch { destroy .top.busy } 1053 catch { destroy .top.persec } 1054 catch { destroy .top.time } 1055 catch { destroy .top.c } 1056 catch { destroy .top.name } 1057 1058 label .top.name -text "Machine Name" 1059 label .top.busy -text "Busy Workers" -foreground "#A00000" 1060 label .top.persec -text "Msgs/s" -foreground "#00A000" 1061 label .top.time -text " ms/scan " -foreground "#0000A0" 1062 label .top.c -text "" 1063 grid .top.name -row 0 -column 0 -sticky new 1064 grid .top.busy -row 0 -column 1 -sticky new 1065 grid .top.persec -row 0 -column 2 -sticky new 1066 grid .top.time -row 0 -column 3 -sticky new 1067 grid .top.c -row 0 -column 4 -sticky new 1068 1069 grid rowconfigure .top 0 -weight 0 1070 # If a machine has been deleted, destroy its windows 1071 catch { destroy .top.name$index} 1072 catch { destroy .top.busy$index} 1073 catch { destroy .top.persec$index} 1074 catch { destroy .top.time$index} 1075 catch { destroy .top.c$index} 1076 1077 incr index 1078 # Bottom row of labels 1079 catch { destroy .top.busytotal } 1080 catch { destroy .top.persectotal } 1081 catch { destroy .top.avgtime } 1082 catch { destroy .top.totalrow } 1083 catch { destroy .top.c$index } 1084 1085 # Mop up total window if a machine has been deleted 1086 set i [expr $index + 1] 1087 catch { destroy .top.c$i } 1088 1089 label .top.totalrow -text "Totals:" 1090 label .top.busytotal 1091 label .top.persectotal 1092 label .top.avgtime 1093 canvas .top.c$index -width 400 -height 60 -takefocus 0 -borderwidth 0 -background #FFFFF0 -highlightthickness 0 1094 1095 grid .top.totalrow -row $index -column 0 -sticky new 1096 grid .top.busytotal -row $index -column 1 -sticky new 1097 grid .top.persectotal -row $index -column 2 -sticky new 1098 grid .top.avgtime -row $index -column 3 -sticky new 1099 grid .top.c$index -row $index -column 4 -sticky nsew -pady 1 1100 grid rowconfigure .top $index -weight 3 1101 incr index 1102 # Now a spot for adding a new machine... 1103 catch { destroy .top.newlab } 1104 catch { destroy .top.new } 1105 1106 label .top.newlab -text "Add Machine: " 1107 entry .top.new -width 20 1108 grid .top.newlab -row $index -column 0 1109 grid .top.new -row $index -column 1 -columnspan 3 -sticky ew 1110 bind .top.new <Return> interactive_add_machine 1111 button .top.all -text "Summary" -command all_or_summary 1112 grid .top.all -row $index -column 4 -sticky w 1113 grid rowconfigure .top $index -weight 0 1114 1115 grid columnconfigure .top 0 -weight 0 1116 grid columnconfigure .top 1 -weight 0 1117 grid columnconfigure .top 2 -weight 0 1118 grid columnconfigure .top 3 -weight 0 1119 grid columnconfigure .top 4 -weight 1 1120 wm deiconify .top 1121} 1122 1123proc busyworkers { mach } { 1124 global ctr 1125 global Data 1126 incr ctr 1127 set w .workers$ctr 1128 catch { destroy $w } 1129 toplevel $w 1130 wm title $w "Busy workers: $mach" 1131 wm iconname $w "$mach workers" 1132 set Data($mach,busyworkerwin) $w 1133 1134 # Open a new SSH connection for the busyworkers info 1135 global SSHCommand 1136 global MD_MX_CTRL 1137 set hmach [host_plus_user $mach] 1138 set fp [open "| $SSHCommand $hmach $MD_MX_CTRL" "r+"] 1139 fconfigure $fp -blocking 0 1140 fileevent $fp readable [list busyworkers_readable $mach $fp] 1141 1142 tickle_busyworkers $mach $fp 1143 1144 text $w.t -width 80 -height 35 1145 pack $w.t -side left -expand 1 -fill both 1146 $w.t tag bind pid <Enter> [list enter_pid $w.t] 1147 $w.t tag bind pid <Leave> [list leave_pid $w.t] 1148 $w.t tag bind pid <ButtonPress-1> [list trace_worker $w.t $mach] 1149} 1150 1151proc tickle_busyworkers { mach fp } { 1152 global Data 1153 1154 catch { 1155 set Data($mach,busydata) "" 1156 # We have to use the old command for backware-compatibility. 1157 puts $fp "busyslaves\nfoo_no_such_command" 1158 flush $fp 1159 } 1160} 1161 1162proc busyworkers_readable { mach fp } { 1163 global Data 1164 1165 gets $fp line 1166 if {"$line" == ""} { 1167 if {[eof $fp]} { 1168 close $fp 1169 catch { destroy $Data($mach,busyworkerwin) } 1170 } 1171 return 1172 } 1173 if {"$line" != "error: Unknown command"} { 1174 lappend Data($mach,busydata) $line 1175 return 1176 } 1177 update_busyworkers $mach $fp 1178 global BusyWorkerUpdateInterval 1179 after $BusyWorkerUpdateInterval [list tickle_busyworkers $mach $fp] 1180} 1181proc trace_worker { w mach } { 1182 global TraceCommand 1183 set tags [$w tag names current] 1184 set index [lsearch -glob $tags "Z*"] 1185 if {$index >= 0} { 1186 set tag [lindex $tags $index] 1187 set pid [string range $tag 1 end] 1188 ssh $mach "$TraceCommand $pid" "Process $pid on $mach" 1189 } 1190} 1191proc enter_pid { w } { 1192 set tags [$w tag names current] 1193 set index [lsearch -glob $tags "Z*"] 1194 if {$index >= 0} { 1195 set tag [lindex $tags $index] 1196 $w tag configure $tag -foreground "#A00000" 1197 } 1198} 1199 1200proc leave_pid { w } { 1201 set tags [$w tag names current] 1202 set index [lsearch -glob $tags "Z*"] 1203 if {$index >= 0} { 1204 set tag [lindex $tags $index] 1205 $w tag configure $tag -foreground "#000000" 1206 } 1207} 1208 1209proc compare_workers { a b } { 1210 set acmd [lindex $a 3] 1211 set bcmd [lindex $b 3] 1212 set x [string compare $bcmd $acmd] 1213 if {$x != 0} { 1214 return $x 1215 } 1216 1217 set an [lindex $a 0] 1218 set bn [lindex $b 0] 1219 1220 set aago [lindex $a 5] 1221 set bago [lindex $b 5] 1222 if {[string match "ago=*" $aago] && [string match "ago=*" $bago]} { 1223 set aago [string range $aago 4 end] 1224 set bago [string range $bago 4 end] 1225 set x [expr $bago - $aago] 1226 if {$x != 0} { 1227 return $x 1228 } 1229 } 1230 1231 return [expr $an - $bn] 1232} 1233 1234proc update_busyworkers { mach fp} { 1235 global Data 1236 set w $Data($mach,busyworkerwin) 1237 if {![winfo exists $w]} { 1238 catch { close $fp } 1239 return 1240 } 1241 $w.t configure -state normal 1242 $w.t delete 1.0 end 1243 1244 # Clear out tags 1245 foreach tag [$w.t tag names] { 1246 if {"$tag" != "pid"} { 1247 $w.t tag delete $tag 1248 } 1249 } 1250 1251 set busyguys [lsort -command compare_workers $Data($mach,busydata)] 1252 1253 set count(scan) 0 1254 set count(relayok) 0 1255 set count(senderok) 0 1256 set count(recipok) 0 1257 1258 foreach line $busyguys { 1259 set lst [split $line] 1260 set workerno [lindex $lst 0] 1261 set pid [lindex $lst 2] 1262 set cmd [lindex $lst 3] 1263 incr count($cmd) 1264 set len [string length "$workerno B $pid "] 1265 set line [string range $line $len end] 1266 $w.t insert end [format "%4d" $workerno] workerno 1267 $w.t insert end " " 1268 $w.t tag delete "Z$pid" 1269 $w.t insert end [format "%6d" $pid] [list pid "Z$pid"] 1270 $w.t insert end " $line\n" 1271 1272 } 1273 1274 set title "Busy workers: $mach" 1275 foreach cmd {scan relayok senderok recipok} { 1276 if {$count($cmd) > 0} { 1277 set c $count($cmd) 1278 append title " $cmd=$c" 1279 } 1280 } 1281 wm title $w $title 1282} 1283 1284proc popup_machine_menu { m index x y} { 1285 catch { destroy .m } 1286 menu .m -tearoff 0 1287 .m add command -label "SSH" -command [list ssh $m] 1288 .m add command -label "Busy Workers" -command [list busyworkers $m] 1289 .m add separator 1290 .m add command -label "Delete" -command [list del_machine $m] 1291 tk_popup .m $x $y 1292} 1293 1294proc grid_machine_new_style { m index } { 1295 global NewStyleShowScans NewStyleShowRelayoks NewStyleShowSenderoks NewStyleShowRecipoks 1296 set m [lindex $m 0] 1297 1298 set disp_m $m 1299 if {[regexp {@(.*)$} $m foo host]} { 1300 set disp_m $host 1301 } 1302 1303 # Chop off domain name from host 1304 if {[regexp {^([^.]+)\.} $disp_m foo new_m]} { 1305 set disp_m $new_m 1306 } 1307 set row [expr $index + 1] 1308 catch { destroy .top.name$index } 1309 catch { destroy .top.busy$index } 1310 catch { destroy .top.scanspersec$index } 1311 catch { destroy .top.scantime$index } 1312 catch { destroy .top.relayspersec$index } 1313 catch { destroy .top.relaytime$index } 1314 catch { destroy .top.senderspersec$index } 1315 catch { destroy .top.sendertime$index } 1316 catch { destroy .top.recipspersec$index } 1317 catch { destroy .top.reciptime$index } 1318 catch { destroy .top.c$index } 1319 1320 set column 2 1321 set canv_width 200 1322 label .top.name$index -text $disp_m -relief raised 1323 bind .top.name$index <ButtonPress-1> [list popup_machine_menu $m $index %X %Y] 1324 bind .top.name$index <ButtonPress-2> [list popup_machine_menu $m $index %X %Y] 1325 bind .top.name$index <ButtonPress-3> [list popup_machine_menu $m $index %X %Y] 1326 label .top.busy$index -text "" -foreground "#A00000" 1327 grid .top.name$index -row $row -column 0 -sticky new 1328 grid .top.busy$index -row $row -column 1 -sticky new 1329 1330 if {$NewStyleShowScans} { 1331 label .top.scanspersec$index -foreground "#00A000" 1332 grid .top.scanspersec$index -row $row -column $column -sticky new 1333 incr column 1334 label .top.scantime$index -foreground "#0000A0" 1335 grid .top.scantime$index -row $row -column $column -sticky new 1336 incr column 1337 incr canv_width 200 1338 } 1339 if {$NewStyleShowRelayoks} { 1340 label .top.relayspersec$index -foreground "#808000" 1341 grid .top.relayspersec$index -row $row -column $column -sticky new 1342 incr column 1343 label .top.relaytime$index -foreground "#008080" 1344 grid .top.relaytime$index -row $row -column $column -sticky new 1345 incr column 1346 incr canv_width 200 1347 } 1348 if {$NewStyleShowSenderoks} { 1349 label .top.senderspersec$index -foreground "#808080" 1350 grid .top.senderspersec$index -row $row -column $column -sticky new 1351 incr column 1352 label .top.sendertime$index -foreground "#800080" 1353 grid .top.sendertime$index -row $row -column $column -sticky new 1354 incr column 1355 incr canv_width 200 1356 } 1357 if {$NewStyleShowRecipoks} { 1358 label .top.recipspersec$index -foreground "#008000" 1359 grid .top.recipspersec$index -row $row -column $column -sticky new 1360 incr column 1361 label .top.reciptime$index -foreground "#000000" 1362 grid .top.reciptime$index -row $row -column $column -sticky new 1363 incr column 1364 incr canv_width 200 1365 } 1366 canvas .top.c$index -width $canv_width -height 60 -takefocus 0 -borderwidth 0 -background #FFFFFF -highlightthickness 0 1367 grid .top.c$index -row $row -column $column -sticky nsew -pady 1 1368 grid rowconfigure .top $row -weight 1 1369} 1370proc grid_machine { m index } { 1371 set m [lindex $m 0] 1372 set row [expr $index + 1] 1373 1374 catch { destroy .top.name$index} 1375 catch { destroy .top.busy$index} 1376 catch { destroy .top.persec$index} 1377 catch { destroy .top.time$index} 1378 catch { destroy .top.c$index} 1379 1380 set disp_m $m 1381 if {[regexp {@(.*)$} $m foo host]} { 1382 set disp_m $host 1383 } 1384 1385 label .top.name$index -text $disp_m -relief raised 1386 bind .top.name$index <ButtonPress-1> [list popup_machine_menu $m $index %X %Y] 1387 bind .top.name$index <ButtonPress-2> [list popup_machine_menu $m $index %X %Y] 1388 bind .top.name$index <ButtonPress-3> [list popup_machine_menu $m $index %X %Y] 1389 label .top.busy$index -text "" 1390 label .top.persec$index -text "" 1391 label .top.time$index -text "" 1392 canvas .top.c$index -width 600 -height 60 -takefocus 0 -borderwidth 0 -background white -highlightthickness 0 1393 .top.c$index create text 2 2 -anchor nw -text "" -tags statusText 1394 grid .top.name$index -row $row -column 0 -sticky new 1395 grid .top.busy$index -row $row -column 1 -sticky new 1396 grid .top.persec$index -row $row -column 2 -sticky new 1397 grid .top.time$index -row $row -column 3 -sticky new 1398 grid .top.c$index -row $row -column 4 -sticky nsew -pady 1 1399 grid rowconfigure .top $row -weight 1 1400 1401} 1402 1403proc kick_off_update {} { 1404 global Machines 1405 global NewStyle 1406 global DoneARedrawSinceLastUpdate 1407 global MachinesAwaitingReply 1408 global MainUpdateInterval 1409 1410 if {$DoneARedrawSinceLastUpdate} { 1411 set DoneARedrawSinceLastUpdate 0 1412 if {$NewStyle} { 1413 set cmd "rawload1 60" 1414 } else { 1415 set cmd "rawload" 1416 } 1417 1418 set MachinesAwaitingReply {} 1419 foreach m $Machines { 1420 catch { 1421 set fp [lindex $m 1] 1422 puts $fp $cmd 1423 flush $fp 1424 lappend MachinesAwaitingReply [lindex $m 0] 1425 } 1426 } 1427 } 1428 after $MainUpdateInterval kick_off_update 1429} 1430 1431## translated from C-code in Blt, who got it from: 1432## Taken from Paul Heckbert's "Nice Numbers for Graph Labels" in 1433## Graphics Gems (pp 61-63). Finds a "nice" number approximately 1434## equal to x. 1435proc nicenum {x floor} { 1436 1437 if {$x == 0} { 1438 return 0 1439 } 1440 1441 set negative 0 1442 1443 if {$x < 0} { 1444 set x [expr -$x] 1445 set negative 1 1446 } 1447 1448 set exponX [expr floor(log10($x))] 1449 set fractX [expr $x/pow(10,$exponX)]; # between 1 and 10 1450 if {$floor} { 1451 if {$fractX < 2.0} { 1452 set nf 1.0 1453 } elseif {$fractX < 3.0} { 1454 set nf 2.0 1455 } elseif {$fractX < 4.0} { 1456 set nf 3.0 1457 } elseif {$fractX < 5.0} { 1458 set nf 4.0 1459 } elseif {$fractX < 10.0} { 1460 set nf 5.0 1461 } else { 1462 set nf 10.0 1463 } 1464 } elseif {$fractX <= 1.0} { 1465 set nf 1.0 1466 } elseif {$fractX <= 1.5} { 1467 set nf 1.5 1468 } elseif {$fractX <= 2.0} { 1469 set nf 2.0 1470 } elseif {$fractX <= 2.5} { 1471 set nf 2.5 1472 } elseif {$fractX <= 3.0} { 1473 set nf 3.0 1474 } elseif {$fractX <= 4.0} { 1475 set nf 4.0 1476 } elseif {$fractX <= 5.0} { 1477 set nf 5.0 1478 } elseif {$fractX <= 6.0} { 1479 set nf 6.0 1480 } elseif {$fractX <= 8.0} { 1481 set nf 8.0 1482 } else { 1483 set nf 10.0 1484 } 1485 if { $negative } { 1486 return [expr -$nf * pow(10,$exponX)] 1487 } else { 1488 set value [expr $nf * pow(10,$exponX)] 1489 return $value 1490 } 1491} 1492 1493proc human_number { num } { 1494 if {$num <= 1000} { 1495 return [strip_zeros [format "%.1f" $num]] 1496 } 1497 set num [expr $num / 1000.0] 1498 if {$num <= 1000} { 1499 set num [strip_zeros [format "%.1f" $num]] 1500 return "${num}K" 1501 } 1502 set num [expr $num / 1000.0] 1503 if {$num <= 1000} { 1504 set num [strip_zeros [format "%.1f" $num]] 1505 return "${num}M" 1506 } 1507 set num [expr $num / 1000.0] 1508 set num [strip_zeros [format "%.1f" $num]] 1509 return "${num}G" 1510} 1511 1512proc pick_color { host } { 1513 set color 0 1514 set components {AA BB CC EE} 1515 1516 catch { set host [lindex $host end] } 1517 set host [split $host ""] 1518 foreach char $host { 1519 set color [expr $color + 1] 1520 binary scan $char "c" x 1521 incr color $x 1522 if { $color <= 0 } { 1523 set color [expr $x + 1] 1524 } 1525 } 1526 set ans "#" 1527 expr srand($color) 1528 for {set i 0} {$i < 3} {incr i} { 1529 set off [expr int(4.0 * rand())] 1530 append ans [lindex $components $off] 1531 } 1532 return $ans 1533} 1534 1535proc ssh { host {cmd ""} {title ""}} { 1536 set color [pick_color $host] 1537 if {"$title" == ""} { 1538 set title "SSH $host" 1539 } 1540 global SSHCommand 1541 set hmach [host_plus_user $host] 1542 exec xterm -hold -title $title -bg #000000 -fg $color -e $SSHCommand $hmach $cmd & 1543} 1544 1545wm withdraw . 1546foreach mach $argv { 1547 if {"$mach" == "-archive"} { 1548 set DoArchive 1 1549 continue 1550 } 1551 if {"$mach" == "-d"} { 1552 set NewStyleTimeInterval 86400 1553 continue 1554 } 1555 if {"$mach" == "-h"} { 1556 set NewStyleTimeInterval 3600 1557 continue 1558 } 1559 1560 if {"$mach" == "-n"} { 1561 set NewStyle 1 1562 set NewStyleShowScans 1 1563 continue 1564 } 1565 if {"$mach" == "-r"} { 1566 set NewStyle 1 1567 set NewStyleShowRelayoks 1 1568 continue 1569 } 1570 if {"$mach" == "-s"} { 1571 set NewStyle 1 1572 set NewStyleShowSenderoks 1 1573 continue 1574 } 1575 if {"$mach" == "-t"} { 1576 set NewStyle 1 1577 set NewStyleShowRecipoks 1 1578 continue 1579 } 1580 add_machine $mach 1581} 1582 1583catch { destroy .top} 1584toplevel .top 1585wm title .top "Watch Multiple MIMEDefangs" 1586wm iconname .top "MIMEDefangs" 1587wm withdraw .top 1588reconfigure 1589wm deiconify .top 1590update 1591kick_off_update 1592tkwait window .top 1593exit 1594