The benchmarks provided by the tclbench package are very interesting and useful, but sometimes hard to read. For examples, see [Tcl Benchmarks] and [Tcl Normalized Benchmarks]. What we really need is a good way to plot relative benchmark performance, so that you can easily see how different versions of Tcl differ from each other. I wrote this little script, using BLT for graphing, and a little bit of GUI cruft around a simple parser for the [Tcl Benchmarks] output. Apologies for the obvious use of [Tcl/Tk Template Applications], but you're free to improve on this. :-) ---- #!/bin/sh # If running in a UNIX shell, restart wish on the next line \ exec wish "$0" ${1+"$@"} #-------------------------------------------------- # # plotTclBench.tcl # # Plot tclBench comparison in BLT widget # #-------------------------------------------------- #-------------------------------------------------- # # myAppMain # # Performs basic initialization of myApp. # #-------------------------------------------------- proc myAppMain { argc argv } { #-------------------------------------------------- # Construct the UI #-------------------------------------------------- myAppInitGui . #-------------------------------------------------- # If we have an argument, then open the file #-------------------------------------------------- if { [llength $argv] > 0 } { myAppFileOpen [lindex $argv 0] } } #-------------------------------------------------- # # myAppInitGui # # Construct and initialize UI # #-------------------------------------------------- proc myAppInitGui { root } { #-------------------------------------------------- # treat root window "." as a special case #-------------------------------------------------- if {$root == "."} { set base "" } else { set base $root } #-------------------------------------------------- # Define the menu bar #-------------------------------------------------- package require Tk menu $base.menu $root config -menu $base.menu foreach m {File Help} { # Use [string tolower] to ensure magic menu names are right - DKF set $m [menu $base.menu.[string tolower $m] -tearoff 0] $base.menu add cascade -label $m -underline 0 -menu [set $m] } $File add command -underline 0 -label "Open..." -command myAppFileOpen $File add separator $File add command -underline 1 -label "Exit" -command myAppExit $Help add command -label About -command myAppHelpAbout #-------------------------------------------------- # Set window manager properties for myApp #-------------------------------------------------- wm protocol $root WM_DELETE_WINDOW { myAppExit } wm title $root "Tcl Bench Comparison" # Add a BLT Graph widget package require BLT blt::graph .g Blt_ZoomStack .g bind Graph {displayClosest %x %y} grid .g grid columnconfigure . 0 -weight 1 grid rowconfigure . 0 -weight 1 # Add some instructions and closes display grid [label .label -text "Click to zoom. Click B3 to unzoom"] -sticky w grid [label .nearest -text ""] -sticky w # Add a normalization selector grid [frame .f -relief raised] grid [label .f.label -text "Normalize graph to:"] -sticky w update } proc displayClosest {x y} { global valArray global testNames catch { .g element closest $x $y valArray set index $valArray(index) .nearest configure -text "Test [lindex $testNames $index]" } } #-------------------------------------------------- # # File Procedures # # Note that opening, saving, and closing files # are all intertwined. This code assumes that # new/open/close/exit may lose some data. # #-------------------------------------------------- set myAppFileName "" set myAppChangedFlag 0 set myAppFileTypes { {{All Files} * } } proc myAppFileOpen { {filename ""} } { global myAppFileName global myAppChangedFlag global myAppFileTypes global benchData global data global interpNames global testNames if {$filename == ""} { set filename [tk_getOpenFile -filetypes $myAppFileTypes] } if {$filename != ""} { if { [catch {open $filename r} fp] } { error "Cannot Open File $filename for Reading" } #-------------------------------------------------- # insert code for "open" operation #-------------------------------------------------- # read tclbench data into list of lines set benchData [split [read $fp [file size $filename]] "\n"] close $fp set myAppFileName $filename set myAppChangedFlag 0 # process header - look for interpreter names (versions) set interpNames [list] for {set i 0} {$i < [llength $benchData]} {incr i} { set line [lindex $benchData $i] if {[string match "000*" $line] } { break } if {[string match "Benchmark*" $line]} { scan $line "Benchmark %d:%s " junk shortName lappend interpNames $shortName } } # now that we've got the "000 VERSIONS" line, # figure out how wide to make that left side # label field set shortName [lindex [lindex $interpNames 0] 0] set labelEnd [expr {[string first $shortName $line]-4}] # parse the columns into data lists, starting from # the right hand side. It is hard to tell how wide # to make the label field on the left, so we just # start on the right, and put everything else in # the X axis values for {incr i} {$i<[llength $benchData]-2} {incr i} { set line [lindex $benchData $i] set line [lindex $benchData $i] # parse values set valueList [string range $line $labelEnd end] for {set j 0} {$j<[llength $interpNames]} {incr j} { set name [lindex $interpNames end-$j] set dataItem [lindex $valueList end-$j] if { ! [string is double $dataItem] } { set dataItem 1 } lappend data($name) $dataItem } # get label string set labelString [string range $line 0 $labelEnd] lappend testNames $labelString scan $line "%d" testNum lappend x $testNum } # Create a BLT graph data vector for every interpName set symbols [list circle square diamond plus cross splus scross triangle arrow] set colors [list black blue red green cyan magenta yellow orange brown] set i 0 foreach name $interpNames { catch {rename y_$name ""} blt::vector create y_$name y_$name set $data($name) .g element create $name -xdata $x -ydata y_$name \ -symbol [lindex $symbols $i] -fill [lindex $colors $i] incr i } # Add names to normalization menu catch {destroy [winfo children .f]} grid [label .f.label -text "Normalize graph to:"] -row 0 set i 1 foreach name $interpNames { set bname [string map {. _} $name] set b [button .f.b_$bname -text $name -command "normalize $name"] grid $b -row 0 -column $i incr i } } } proc normalize {name} { global interpNames y_$name dup temp foreach name $interpNames { set vec y_$name $vec expr {$vec / temp} } blt::vector destroy temp } proc myAppExit { } { exit } #-------------------------------------------------- # Cut/Copy/Paste # # These procedures generate events # for all Tk Widgets in the GUI #-------------------------------------------------- proc myAppEditCut { } { event generate [focus] <> } proc myAppEditCopy { } { event generate [focus] <> } proc myAppEditPaste { } { event generate [focus] <> } proc myAppSearchBindingsAndEval {event bindtags script} { foreach tag $bindtags { foreach sequence [bind $tag] { if {[string first $event $sequence] == 0} { return [uplevel $script] } } } } proc myAppConfigEditMenu {menu bindtags} { foreach {event index} { <> 0 <> 1 <> 2 } { $menu entryconfigure $index -state disabled myAppSearchBindingsAndEval $event $bindtags { $menu entryconfigure $index -state normal } } } #-------------------------------------------------- # Help Operations #-------------------------------------------------- proc myAppHelpAbout { } { tk_messageBox -message "tclbench data plotter" } #-------------------------------------------------- # Execute the main procedure #-------------------------------------------------- myAppMain $argc $argv ---- [Category Application] | [Category Graphics] | [Category Plotting] | [Category Performance]