#!/bin/ksh
# the next line restarts using the OS dependent executable \
if [ "$OSTYPE" = "cygwin" ]; then PLATFORM="Windows_NT"; SCRIPT=$(cygpath -w $0); else PLATFORM=$(uname -s); SCRIPT=$0; fi; exec ${0%vsd*}vsdwish$PLATFORM "$SCRIPT" -- "$@"

# Visual StatDisplay (vsd)
# $Id: vsd.tcl,v 1.137 2007-11-19 16:51:01 otisa Exp $
#

if {[string equal $tcl_platform(platform) "windows"]} {
    set isWindows 1
} else {
    set isWindows 0
}

if {![info exists vsd(restarting)]} {
    namespace import blt::vector
    namespace import blt::spline
    namespace import blt::graph
    namespace import blt::stripchart
    namespace import blt::barchart
    namespace import blt::busy
    namespace import blt::bitmap
}
#if {$isWindows} {
#    console show
   # the executable is in $GEMSTONE/bin; libs are in $GEMSTONE/bin
#    set libdir [file dirname [info nameofexecutable]]
#    set libext [info sharedlibextension]

#    tix resetoptions TK TK

#    global tixOption
#     set tixOption(bg)           "SystemButtonFace"
#     set tixOption(dark1_bg)     "SystemButtonHighlight"
#     set tixOption(dark1_fg)     "black"
#     set tixOption(dark2_bg)     "SystemBackground"
#     set tixOption(dark2_fg)     "black"
#     set tixOption(inactive_bg)  "SystemBackground"
#     set tixOption(inactive_fg)  "black"

#     set tixOption(light1_bg)    #ececec ;# off white
#     set tixOption(light1_fg)    "white"
#     set tixOption(light2_bg)    #fcfcfc ;# white
#     set tixOption(light2_fg)    "white"

#     set tixOption(active_bg)    "SystemButtonHighlight"
#     set tixOption(active_fg)    $tixOption(fg)
#     set tixOption(disabled_fg)  "SystemDisabledText"

#     set tixOption(input1_bg)    "SystemScrollbar"
#     set tixOption(input2_bg)    "SystemScrollbar"
#     set tixOption(output1_bg)   $tixOption(dark1_bg)
#     set tixOption(output2_bg)   $tixOption(bg)

#     set tixOption(select_fg)    "SystemHighlightText"
#     set tixOption(select_bg)    "SystemHighlight"


#     if [info exists sltcl(guifont)] {
# 	set tixOption(font)         $sltcl(guifont)
#     } else {
# 	set tixOption(font)         $sltcl(systemfont)
#     }
#     if [info exists sltcl(menufont)] {
# 	set tixOption(menu_font)    $sltcl(menufont)
#     } else {
# 	set tixOption(menu_font)    $tixOption(font)
#     }
#     set tixOption(bold_font)    [lreplace $tixOption(font) 2 2 "bold"]
#     set tixOption(italic_font)    [lreplace $tixOption(font) 2 2 "italic"]
#     set tixOption(fixed_font)   "ansifixed"
#     tixAppContext:CheckFontSets .
#     option add *font $tixOption(font)
#     if [info exists sltcl(menufont)] {
# 	option add *Menu.font $sltcl(menufont)
# 	option add *Menubutton.font $sltcl(menufont)
#     }
#     if [info exists sltcl(messagefont)] {
# 	option add *Text.font $sltcl(messagefont)
# 	option add *Message.font $sltcl(messagefont)
#     }
#     if [info exists sltcl(statusfont)] {
# 	option add *TixBalloon.font $sltcl(statusfont)
#     }
	
#    option add *selectColor SystemHighlight


#     option add *Text.background SystemWindow
#     option add *Listbox.background SystemWindow
#     option add *Entry.background SystemWindow
#     option add *TixComboBox.background SystemWindow
#     option add *TixComboBox*Listbox.exportSelection 0
#     option add *TixHList.background SystemWindow
#     option add *TixHList.activeForeground SystemWindowText
#     option add *TixHList.selectBackground SystemHighlight
#     option add *TixHList.selectForeground SystemHighlightText
#     option add *TixHList.foreground SystemWindowText
#     option add *TixHList.activeBackground SystemWindow
#     option add *TixTList.background SystemWindow
#     option add *TixTList.activeForeground SystemWindowText
#     option add *TixTList.selectBackground SystemHighlight
#     option add *TixTList.selectForeground SystemHighlightText


#    if [info exists sltcl(scrollwidth)] {
#	option add *Scrollbar.width $sltcl(scrollwidth)
#    }
#} else {
    # the executable is in $GEMSTONE/bin; libs are in $GEMSTONE/lib
#    set libdir [file join [file dirname [file dirname [info nameofexecutable]]] "lib"]
#    set libext [info sharedlibextension]
#    if {![info exists vsd(restarting)]} {
#	load [file join $libdir libBLT$libext] Blt
#	load [file join $libdir libtix$libext] Tix
#	load [file join $libdir libsltcl$libext] Sltcl
#    }
#}

set vsd(infoScript) [info script]

option add *Text.font normalTextFont
bind Entry <Control-a> +break


#set tcl_precision 10

proc patchTix {} {
    global tixSep
    # hack fixes for bug in Tix4.0.5
    if {[info commands "tixHList::GoState-33"] != ""} {
	set tixSep "::"
    } else {
	set tixSep ":"
    }

    proc tixHList${tixSep}GoState-33 {w x y} {
	global tixSep
	set ent [tixHList${tixSep}GetNearest $w $y]
	if {$ent != {}} {
	    $w anchor set $ent
	    if {[$w selection includes $ent]} {
		$w selection clear $ent
	    } else {
		$w selection set $ent
	    }
	    tixHList${tixSep}Browse $w $ent
	}
    }
}

if 0 {
    tixBind TixComboEntry <Next>	{
	global tixSep
	tixComboBox${tixSep}EntDirKey [tixGetMegaWidget %W TixComboBox] pagedown
    }
proc tixHList::Keyboard-Activate {w} {
    if {[tixHList::GetState $w] != 0} {
	return
    }
    set ent [$w info anchor]

    if {$ent == ""} {
	return
    }

    if {[$w cget -selectmode] == "single"} {
	$w select clear
	$w select set $ent
    }

    set command [$w cget -command]
    if {$command != {}} {
	set bind(specs) {%V}
	set bind(%V)    $ent

	tixEvalCmdBinding $w $command bind $ent
    }
}

proc tixHList::Keyboard-Browse {w} {
    if {[tixHList::GetState $w] != 0} {
	return
    }
    set ent [$w info anchor]

    if {$ent == ""} {
	return
    }

    if {[$w cget -selectmode] == "single"} {
	$w select clear
	$w select set $ent
    }

    tixHList::Browse $w $ent
}

proc tixHList${tixSep}UpDown {w spec mod} {
    global tixSep
    if {[tixHList${tixSep}GetState $w] != 0} {
	return
    }
    set anchor [$w info anchor]
    set done 0

    if {$anchor == ""} {
	set anchor [lindex [$w info children] 0]

	if {$anchor == {}} {
	    return
	}

	if {[$w entrycget $anchor -state] != "disabled"} {
	    # That's a good anchor
	    set done 1
	} else {
	    # We search for the first non-disabled entry (downward)
	    set spec next
	}
    }

    set ent $anchor
    # Find the prev/next non-disabled entry
    #
    while {!$done} {
	set ent [$w info $spec $ent]
	if {$ent == {}} {
	    break
	}
	if {[$w entrycget $ent -state] == "disabled"} {
	    continue
	}
	if [$w info hidden $ent] {
	    continue
	}
	break
    }

    if {$ent == {}} {
	return
    } else {
	$w see $ent
	$w anchor set $ent

	set selMode [$w cget -selectmode]
       if {$mod == "s" && ($selMode == "extended" || $selMode == "multiple")} {
	    global $w:priv:shiftanchor

	    if ![info exists $w:priv:shiftanchor] {
		set $w:priv:shiftanchor $anchor
	    }

	    $w selection clear
	    $w selection set $ent [set $w:priv:shiftanchor]
    
	    tixHList${tixSep}Browse $w $ent
	} else {
	    catch {
		uplevel #0 unset $w:priv:shiftanchor
	    }
	}
    }
}
} ;# if 0

proc myBusyOn {w} {
    busy hold $w
    update
}
proc myBusyOff {w} {
    if [winfo exists $w] {
	busy release $w
	busy forget $w
    }
}

####################

proc showAxis {graph axis} {
    $graph $axis configure -hide false
}
proc showMarker {graph id} {
    $graph marker configure $id -hide false
}
proc hideAxis {graph axis} {
    $graph $axis configure -hide true
}
proc hideMarker {graph id} {
    $graph marker configure $id -hide true
}
proc mapLegend {graph bool} {
    $graph legend configure -hide [expr {!$bool}]
}
proc isLegendMapped {graph} {
    expr {! [$graph legend cget -hide]}
}


#################### 

# The following Copyright applies to the tkerror implementation

# Copyright (c) 1993 Xerox Corporation.
# Use and copying of this software and preparation of derivative works based
# upon this software are permitted. Any distribution of this software or
# derivative works must comply with all applicable United States export
# control laws. This software is made available AS IS, and Xerox Corporation
# makes no warranty about the software, its performance or its conformity to
# any specification.

proc tkerror { msg } {
    global errorInfo
    global vsd isWindows

    if {$isWindows} {
	set font "ansifixed"
    } else {
	set font "fixed"
    }

    set base ".errorInfo"
    set title "Error Info"
    if [info exists errorInfo] {
	set savedErrorInfo $errorInfo
    } else {
	set savedErrorInfo {no errorInfo}
    }
    # Create a toplevel to contain the error trace back
    if [catch {
	# Choose a unique name
	for {set x 1} {$x<10} {set x [expr $x+1]} {
	    if {! [winfo exists $base-$x]} {
		break
	    }
	}
	set title $title-$x
	set name $base-$x

	toplevel $name -bd 2
	wm title $name $title
	wm group $name .
	wm minsize $name 20 5
    
	frame $name.buttons
	pack $name.buttons -side top -fill x
    
	if {! [info exists vsd(maintainer)]} {
	    set vsd(maintainer) "vsd@gemstone.com"
	}

	button $name.buttons.quit -text "Ignore" -command [list destroy $name]
	pack append $name.buttons $name.buttons.quit {left}

	if {$isWindows} {
	    button $name.buttons.copy -text "Copy to Clipboard" \
		-command [list CopyError $name]
	    pack append $name.buttons $name.buttons.copy {right}
	} else {
	    button $name.buttons.mailto -text "Mail to $vsd(maintainer)" \
		-command [list MailError $name]
	    pack append $name.buttons $name.buttons.mailto {right}
	}

	global widgetText TextType

	message $name.ex -font $font -aspect 1000 -text \
"Please type a few words of explanation if you
are going to report this error. If you are logged
in as another user include your actual email address."
	pack $name.ex -side top -fill x
	text $name.user -font $font -width 60 -bd 2 -relief raised
	$name.user configure -height 5
	$name.user insert end "What happened: "
	$name.user tag add sel 1.0 1.14
	focus $name.user
	pack $name.user -side top -fill both -expand true
	$name.user mark set hlimit 1.0
	set widgetText($name.user,extend) 0
	set widgetText($name.user,geo) {}
	set TextType($name.user) text

	frame $name.msg
	pack $name.msg -side top -fill both -expand true

	text $name.msg.t -font $font -width 60 -bd 2 -relief raised \
		-setgrid true -yscrollcommand [list $name.msg.sy set]
	scrollbar $name.msg.sy -orient vertical -command [list $name.msg.t yview]
	$name.msg.t configure -height 20
	$name.msg.t insert end [getSysInfo]
	$name.msg.t insert end $savedErrorInfo
	pack $name.msg.sy -side right -fill y
	pack $name.msg.t -side left -fill both -expand true
	set widgetText($name.msg.t,extend) 0
	set widgetText($name.msg.t,geo) {}
	set TextType($name.msg.t) text

	tkwait visibility $name

    }] {
	puts stderr "tkerror: $msg"
	puts stderr "*** TCL Trace ***"
	puts stderr $savedErrorInfo
   }
}

proc getSysInfo {} {
    global vsd argv argv0 env tk_version isWindows tcl_platform
    set res ""
    if {[info commands clock] != ""} {
	append res "Date: [clock format [clock seconds]]\n"
    } elseif {![catch {eval exec $vsd(exec:date)} date]} {
	append res "Date: $date\n"
    }
    if [info exists env(USER)] {
	append res "$env(USER) got an error\n"
    }
    append res "command line: $argv0 $argv\n"
    append res "vsd version: $vsd(version)\n"
    append res "sltcl version: $vsd(sltclVer)\n"
    append res "TK version: $tk_version\n"
    append res "TCL version: [info tclversion]\n"
    if [info exists tcl_platform] {
	append res "host=[info hostname], type=$tcl_platform(machine), "
	append res "os=$tcl_platform(os) $tcl_platform(osVersion)\n"
    } elseif {! $isWindows} {
	catch {eval exec $vsd(exec:uname)} uname
	append res "$uname\n\n"
    }
    catch {pwd} pwdResult
    append res "Working directory is: $pwdResult"
    if {$vsd(statsrc) != {}} {
	append res "Info on current data file:\n"
	catch {$vsd(statsrc) -info} fileinfo
	foreach i $fileinfo {
	    append res "  $i\n"
	}
    }
    append res "\n"
    return $res
}

proc CopyError { w } {
    global vsd argv argv0
    set errText "To: $vsd(maintainer)\n"
    append errText "Subject: $argv0 error\n\n"
    append errText [$w.user get 1.0 end]
    append errText "\n\n"
    append errText [$w.msg.t get 1.0 end]
    append errText "\n"
    clipboard clear
    clipboard append $errText
    destroy $w
    return
}

proc MailError { w } {
    global vsd argv argv0
    if [catch {open /tmp/error.[pid] w} out] {
	puts stderr "Cannot open /tmp/error.[pid]"
	return
    }
    if [catch {
	puts $out "To: $vsd(maintainer)"
	puts $out "Subject: $argv0 error"
	puts $out ""
	puts $out [$w.user get 1.0 end]
	puts $out ""
	puts $out [$w.msg.t get 1.0 end]
	close $out
    } msg] {
	puts stderr "/tmp/error.[pid] $msg"
	return
    }
    if [catch {
	eval exec $vsd(exec:mail) $vsd(maintainer) < /tmp/error.[pid]
    } msg] {
	puts stderr "$vsd(exec:mail) error: $msg"
    } else {
	puts stderr "Mailed report to $vsd(maintainer)"
	destroy $w
    }
    catch {file delete -force /tmp/error.[pid]}
}

#################### some BLT graphing features ######################

proc Blt_CrosshairsOn { graph } {
    bind bltCrosshairs <Any-Motion>   {
	%W crosshairs configure -position @%x,%y
    }
    $graph crosshairs configure -color black
    bind $graph <Enter> [format {
	BltAddBindTag %s bltCrosshairs  
	%s crosshairs on
    } $graph $graph]
    bind $graph <Leave> [format {
	BltRemoveBindTag %s bltCrosshairs  
	%s crosshairs off
    } $graph $graph]
}

proc Blt_CrosshairsOff { graph } {
    bind bltCrosshairs <Any-Motion>   {}
    bind $graph <Enter> {}
    bind $graph <Leave> {}
}

proc Blt_ZoomStack { graph } {
    global bltZoom
    global bltActiveEntry
    global bltSelectedLines

    set bltActiveEntry($graph) -1
    set bltSelectedLines($graph) {}

    set bltZoom($graph,A,x) {}
    set bltZoom($graph,A,y) {}
    set bltZoom($graph,A,y2) {}
    set bltZoom($graph,B,x) {}
    set bltZoom($graph,B,y) {}
    set bltZoom($graph,B,y2) {}
    set bltZoom($graph,stack) {}
    set bltZoom($graph,corner) A

    bind $graph <1> {
	ChartHandleLeftClick %W %x %y 0
    }
    bind $graph <Control-1> {
	ChartHandleLeftClick %W %x %y 1
    }
    bind $graph <ButtonRelease-2> {
	ChartHandleMiddleClick %W %x %y 
    }
    bind $graph <ButtonPress-3> {
	ChartHandleRightClick %W
    }
}

proc removeSelectedLine {graph e} {
    global bltSelectedLines
    set l $bltSelectedLines($graph)
    set idx [lsearch -exact $l $e]
    if {$idx != -1} {
        $graph legend deactivate $e
        set bltSelectedLines($graph) [lreplace $l $idx $idx]
        #puts "DEBUG: removing $e from $l"
    }
}

proc addSelectedLine {graph e} {
    global bltSelectedLines
    set l $bltSelectedLines($graph)
    set idx [lsearch -exact $l $e]
    if {$idx != -1} {
        #puts "DEBUG: removing $e from $l"
        # it was already select so deselect it
        $graph legend deactivate $e
        set bltSelectedLines($graph) [lreplace $l $idx $idx]
    } else {
        #puts "DEBUG: adding $e to $l"
        lappend bltSelectedLines($graph) $e
        #puts "DEBUG: activating \"$bltSelectedLines($graph)\""
        eval $graph legend activate $bltSelectedLines($graph)
        # $graph legend activate $e
    }
}

proc getCommonFilter {graph filter} {
    global vsd bltSelectedLines
    foreach e $bltSelectedLines($graph) {
	set edata [$vsd(ed:$e:$graph) -info]
	if {![string equal $filter [lindex $edata 5]]} {
            return {}
        }
    }
    return $filter
}

proc getSelectedLines {graph} {
    global bltSelectedLines
    return $bltSelectedLines($graph)
}

proc clearSelectedLines {graph} {
    global bltSelectedLines
    set l $bltSelectedLines($graph)
    if {$l != {}} {
        eval $graph legend deactivate $l
        set bltSelectedLines($graph) {}
        #puts "DEBUG: clear all selected lines"
    }
    return $l
}

proc resetSelectedLines {graph lines} {
    global bltSelectedLines
    set bltSelectedLines($graph) $lines
    if {$lines != {}} {
        eval $graph legend activate $lines
        #puts "DEBUG: reset selected lines to $lines"
    }
}

proc deleteElement {graph element {doFree 1}} {
    global vsd
    global bltActiveGraph
    global bltActiveEntry

    set cleanup 0

    removeSelectedLine $graph $element

    if {$vsd($graph:chartOp) != {}} {
	chartCancelOp$vsd($graph:chartOp) $graph
    }
    if {$bltActiveEntry($graph) == $element} {
	set bltActiveEntry($graph) -1
	set cleanup 1
    }
    if {$bltActiveGraph($graph) == $element} {
	set bltActiveGraph($graph) 0
	set bltActiveGraph($graph,closest) {}
	set cleanup 1
    }
    if {$cleanup && $bltActiveEntry($graph) == -1} {
	deactivateAxis $graph
	showLineInfo $graph ""
    }
    if {$doFree} {
	$vsd(ed:$element:$graph) -free
    }
    unset vsd(ed:$element:$graph)
    set axisName [$graph element cget $element -mapy]
    $graph element delete $element
    foreach e [$graph element names] {
	if {[string equal $axisName [$graph element cget $e -mapy]]} {
	    return;
	}
    }
    # No more lines using this axis so unmap it
    hideAxis $graph ${axisName}axis
    if {[string equal $axisName "y"]} {
	$graph configure -leftmargin 2
    } else {
	$graph configure -rightmargin 2
    }
}

proc getLineUnitDescription {isAxis lineinfo} {
    set linectr [lindex $lineinfo 1]
    set linescale [lindex $lineinfo 4]
    set linefilter [lindex $lineinfo 5]
    set lineoperator [lindex $lineinfo 9]
    set lineoffset [lindex $lineinfo 12]
    set linedivider [lindex $lineinfo 13]
    if [catch {getStatType $linectr} ctrtype] {
	# This happens if its a derived line with more than one ctr
	# NYI: just go with defaults
	set ctrtype ""
	# NYI in many derived line cases the units could be figured out
	#     this should be done in statlib when the line is created
	set ctrunits "None"
	set linectr "([getCtrAlias $linectr])"
    } else {
	set ctrunits [string toupper [getStatUnits $linectr] 0 0]
	set linectr [getCtrAlias $linectr]
    }
    set axisLabel ""
    if {[string equal $linefilter "none"]} {
	if $isAxis {
	    if {[string equal $ctrtype "counter"]} {
		append axisLabel "total "
	    }
	}
	if {[string equal $ctrunits "None"]} {
	    append axisLabel $linectr
	} else {
	    append axisLabel $ctrunits
	}
    } elseif {[string equal $linefilter "aggregate"]} {
	if {[string equal $ctrunits "None"]} {
	    append axisLabel $linectr
	} else {
	    append axisLabel $ctrunits
	}
	append axisLabel " +"
    } elseif {[string equal $linefilter "smooth"]} {
	if {[string equal $ctrunits "None"]} {
	    append axisLabel $linectr
	} else {
	    append axisLabel $ctrunits
	}
	append axisLabel " ~"
    } else { # per filter 
	if {[string equal $ctrunits "None"]} {
	    append axisLabel $linectr
	} else {
	    append axisLabel $ctrunits
	}
	if {[string equal $linefilter "persecond"]} {
	    append axisLabel " / second"
	} elseif {[string equal $linefilter "persample"]} {
	    append axisLabel " / sample"
	}
    }
    if $isAxis {
	if {$linedivider != 1.0 && $linedivider != 1} {
	    if {[expr {abs($linedivider)}] >= 1.0} {
		append axisLabel " / $linedivider"
	    } else {
		append axisLabel " * [expr {1.0 / $linedivider}]"
	    }
	}
	if {$lineoffset != 0.0 && $lineoffset != 0} {
	    if {$lineoffset < 0} {
		append axisLabel " + [expr {- $lineoffset}]"
	    } else {
		append axisLabel " - $lineoffset"
	    }
	}
	if {$linescale != 1.0 && $linescale != 1} {
	    append axisLabel " * $linescale"
	}
    }
    return $axisLabel
}

proc getElementYAxisTitle {g e} {
    global vsd
    return [getLineUnitDescription 1 [$vsd(ed:$e:$g) -info]]
}

proc stripext {n} {
    set result [file rootname $n]
    while {![string equal $result $n]} {
	set n $result
	set result [file rootname $n]
    }
    return $result
}

proc calcUniqueFileName {dfid {addBaseName 0}} {
    global uniqueNameMap
    global uniqueNames
    set fullname [lindex [$dfid -info] 0]
    if {[string equal "relative" [file pathtype $fullname]]} {
	set fullname [file join [pwd] $fullname]
    }
    set dirname [file dirname $fullname]
    set dirlist [file split $dirname]
    set diridx [llength $dirlist]
    set needsBaseName 1
    if {$addBaseName} {
	set uname [stripext [file tail $fullname]]
    } else {
	incr diridx -1
	if {$diridx < 0} {
	    set needsBaseName 0
	    set uname $fullname
	} else {
	    set uname [lindex $dirlist $diridx]
            if {$diridx > 1} {
                # Want at least the parent and grandparent directory
                incr diridx -1
                set uname [file join [lindex $dirlist $diridx] $uname]
            }
	}
    }
    while {[info exists uniqueNames($uname)]} {
	set olddfid $uniqueNames($uname)
	if {$olddfid != {}} {
	    global vsd
	    set oldFileInfo [getFileInfoName $olddfid]
	    set uniqueNames($uname) {}
	    calcUniqueFileName $olddfid
	    # update vsd(filelist) and vsd(w:filelist) history
	    set newFileInfo [getFileInfoName $olddfid]
	    set newUniqueName $uniqueNameMap($olddfid)
	    set idx [lsearch -exact $vsd(filelist) $oldFileInfo]
	    if {$idx != -1} {
		set vsd(filelist) [lreplace $vsd(filelist) $idx $idx $newFileInfo]
	    }
	    set lb [$vsd(w:filelist) subwidget listbox]
	    set idx [lsearch -exact [$lb get 0 end] $oldFileInfo]
	    if {$idx != -1} {
		$lb insert $idx $newFileInfo
		incr idx
		$lb delete $idx $idx
	    }
	    addFileListMap $olddfid
	}
	incr diridx -1
	if {$diridx < 0} {
	    set needsBaseName 0
	    set uname $fullname
	    # this must be unique; its the full absolute name
	    break
	} else {
	    set uname [file join [lindex $dirlist $diridx] $uname]
	}
    }
    if {$needsBaseName} {
	# found a unique name
	set uniqueNames($uname) $dfid
	if {!$addBaseName} {
	    set uname [file join $uname [stripext [file tail $fullname]]]
	}
    } else {
	if {$addBaseName} {
	    # See how much of the extensions can be stripped off
	    while {![info exists uniqueNames([file rootname $uname])]} {
		set newname [file rootname $uname]
		if {![string equal $uname $newname]} {
		    set uname $newname
		} else {
		    break
		}
	    }
	} else {
	    calcUniqueFileName $dfid 1
	    return
	}
	set uniqueNames($uname) $dfid
    }
    set uniqueNameMap($dfid) $uname
}

proc getSortedGroupNames {} {
    global vsd
    return $vsd(sortedGroupNames)
}

proc groupFilesByPattern {dfid} {
    global vsd patternMap
    if {$vsd(combineFilePattern) == ""} {
        return
    }
    set fullname [lindex [$dfid -info] 0]
    set matches [regexp -inline -nocase -- $vsd(combineFilePattern) $fullname]
    if {$matches == {}} {
        # our pattern did not match any substring
        # so always group this file by itself
        set matches $fullname
    }
    if {[info exists patternMap($matches)]} {
        set v $patternMap($matches)
        lappend v $dfid
        set patternMap($matches) $v
    } else {
        set patternMap($matches) [list $dfid]
        lappend vsd(sortedGroupNames) $matches
    }
}

proc addUniqueFileName {dfid} {
    global uniqueNameMap
    if {[info exists uniqueNameMap($dfid)]} {
	# already added
	return
    }
    groupFilesByPattern $dfid
    
    calcUniqueFileName $dfid
}

proc getUniqueFileName {dfid} {
    global uniqueNameMap
    return $uniqueNameMap($dfid)
}

proc getShortOS {os} {
    if {[string first "Solaris" $os] != -1} {
	return "Solaris"
    } elseif {[string first "SunOS" $os] != -1} {
	return "Solaris"
    } elseif {[string first "NT" $os] != -1} {
	return "Windows"
    } elseif {[string first "Windows" $os] != -1} {
	return "Windows"
    } elseif {[string first "AIX" $os] != -1} {
	return "AIX"
    } elseif {[string first "HPUX" $os] != -1} {
	return "HPUX"
    } else {
	return $os
    }
}

proc getShortGsVer {ver} {
    set idx [string first "," $ver]
    if {$idx != -1} {
        incr idx -1
        return [string range $ver 0 $idx]
    }
    return $ver
}

proc getShortMachine {m} {
    set idx [string first " " $m]
    if {$idx == -1} {
	return $m
    }
    incr idx -1
    set res [string range $m 0 $idx]
    return [string trimright $res ":"]
}

proc getFileId {dfid} {
    # dfid is "slFile" followed by a bunch of digits
    return [string range $dfid 6 end]
}

proc getFileInfoName {dfid} {
    global vsd
    set id [getFileId $dfid]
    set finfo [$dfid -info]
    set fname [getUniqueFileName $dfid]
    set archiveFormat [lindex $finfo 1]
    if {$archiveFormat != 1} {
        set platform [lindex $finfo 2]
    } else {
        set platform [getShortOS [lindex $finfo 2]]
    }
    set gsVer [getShortGsVer [lindex $finfo 3]]
    if {$archiveFormat != 1} {
        set machine [lindex $finfo 4]
    } else {
        set machine [getShortMachine [lindex $finfo 4]]
    }
    return "$id. $fname $platform $machine $gsVer"
}

proc getTitleInfoName {dfid} {
    global vsd
    set id [getFileId $dfid]
    set finfo [$dfid -info]
    set fname [getUniqueFileName $dfid]
    if {[string match "*statArchive" $fname]} {
        set idx [string last "statArchive" $fname]
        incr idx -1
        set fname [string range $fname 0 $idx]
    }
    set gsVer [getShortGsVer [lindex $finfo 3]]
    set idx [string first " as of" $gsVer]
    if {$idx != -1} {
        incr idx -1
        set gsVer [string range $gsVer 0 $idx]
    }
    set archiveFormat [lindex $finfo 1]
    if {$archiveFormat != 1} {
        set machine [lindex [lindex $finfo 4] 1]
    } else {
        set machine [getShortMachine [lindex $finfo 4]]
    }
     return "$id. $fname $machine $gsVer"
}

proc getElementXAxisTitle {g e} {
    global vsd
    set linfo [$vsd(ed:$e:$g) -info]
    set dfids [lindex $linfo 7]
    if {[llength $dfids] == 1} {
	set dfid [lindex $dfids 0]
	return [getTitleInfoName $dfid]
    } else {
	foreach dfid $dfids {
	    append result [getUniqueFileName $dfid]
	    append result " "
	}
	return [string trimright $result]
    }
}

proc activateAxis {g e} {
    global vsd

    set axisName [$g element cget $e -mapy]
    append axisName "axis"
    $g $axisName configure -color $vsd(activecolor)
    if {$vsd($g:$axisName:showtitle)} {
	set axisLabel [getElementYAxisTitle $g $e]
	if {$axisLabel != ""} {
	    $g $axisName configure -title $axisLabel
	}
    }
    if {$vsd($g:xaxis:showtitle)} {
	set xaxisLabel [getElementXAxisTitle $g $e]
	if {$xaxisLabel != ""} {
	    $g xaxis configure -title $xaxisLabel
	}
    }
}

proc deactivateAxis {g} {
    global vsd

    $g yaxis configure -color "black"
    if {$vsd($g:yaxis:showtitle)} {
	$g yaxis configure -title $vsd(yaxis:defaultTitle)
    }
    $g y2axis configure -color "black"
    if {$vsd($g:y2axis:showtitle)} {
	$g y2axis configure -title $vsd(y2axis:defaultTitle)
    }
    if {$vsd($g:xaxis:showtitle)} {
	$g xaxis configure -title $vsd(xaxis:defaultTitle)
    }
}

proc getLineLabel {g e} {
    global vsd
    if [isLegendMapped $g] {
	set result ""
    } else {
	set lineinfo [$vsd(ed:$e:$g) -info]
	set fullname [lindex $lineinfo 0]
	# fullname = {name pid uniqueid}
	if {[lindex $fullname 1] == 0} {
	    # fix for bug 22816
	    set result [lindex $fullname 0]
	} else {
	    set result [join $fullname ", "]
	}
	append result ": "
    }
    set w [winfo toplevel $g]
    if {$vsd($w:showlinestats)} {
	set xStart [$g xaxis cget -min]
	set xEnd [$g xaxis cget -max]
	set lstats [$vsd(ed:$e:$g) -stats $xStart $xEnd]
	append result "points: [lindex $lstats 0]"
	append result " min: [lindex $lstats 1]"
	append result " max: [lindex $lstats 2]"
	append result " mean: [format %.6g [lindex $lstats 3]]"
	append result " sd: [format %.6g [lindex $lstats 4]]"
	$g marker configure triStart -coords [list [lindex $lstats 5] -Inf]
	showMarker $g triStart
	$g marker configure triEnd -coords [list [lindex $lstats 6] -Inf]
	showMarker $g triEnd
    }
    return $result
}

proc bltDoActivateGraph {graph x y new} {
    global bltActiveGraph
    global bltActiveEntry
    unset bltActiveGraph($graph,alarmid)
    unset bltActiveGraph($graph,x)
    unset bltActiveGraph($graph,y)
    set old $bltActiveGraph($graph)
    if { $old != $new } {
	if { $old != 0 } {
	    $graph legend deactivate $old
	    $graph element deactivate $old
	    $graph marker configure activeLine -text ""
	    deactivateAxis $graph
	    showLineInfo $graph ""
	    set bltActiveGraph($graph,closest) {}
	} else {
            if {[info exists bltActiveGraph($graph,oldSelectedLines)]} {
                set bltActiveGraph($graph,oldSelectedLines) [clearSelectedLines $graph]
            }
	    set legendEntry $bltActiveEntry($graph)
	    if {$legendEntry != -1} {
		if {$new != $legendEntry} {
		    $graph legend deactivate $legendEntry
		    $graph element deactivate $legendEntry
		    $graph marker configure activeLine -text ""
	            deactivateAxis $graph
		    showLineInfo $graph ""
		}
	    }
	}
        #puts "DEBUG: bltDoActivateGraph legend activate $new"
	$graph legend activate $new
	$graph element activate $new
	$graph marker configure activeLine -text [getLineLabel $graph $new]
	activateAxis $graph $new
	set bltActiveGraph($graph) $new
	showLineInfo $graph $new
	set bltActiveGraph($graph,closest) {}
    }
    bltActivatePoint $graph $x $y $new
    return
}

proc bltActivatePoint {graph x y new} {
    global bltActiveGraph
    global vsd
    if [$graph element closest $x $y info -halo 5 -interpolate 0 $new] {
	set coordinates "$info(x) $info(y)"
	if {[string equal $vsd($graph:chartOp) "Delta"]} {
	    if {[string equal $new $vsd($graph:deltaLine)]} {
		$graph config -cursor target
	    } else {
		$graph config -cursor crosshair
	    }
	} elseif {[string equal $vsd($graph:chartOp) "Compare"]} {
	    $graph config -cursor target
	} elseif {[string equal $vsd($graph:chartOp) "Trim"]} {
	    if {[string equal $new $vsd($graph:trimLine)]} {
		$graph config -cursor target
	    } else {
		$graph config -cursor crosshair
	    }
	}
	if {![string equal $coordinates $bltActiveGraph($graph,closest)]} {
	    setCurXY $graph $new $info(x) $info(y)
	    set bltActiveGraph($graph,closest) $coordinates
	}
    }
}

proc bltActivateGraph {g x y new} {
    global bltActiveGraph

    if {[info exists bltActiveGraph($g,alarmid)]} {
	set oldx $bltActiveGraph($g,x)
	set oldy $bltActiveGraph($g,y)
	if {abs($x - $oldx) < 3 && abs($y - $oldy) < 3} {
	    # still close to place that alarm already set for
	    return
	}
	# forget the old guy and setup a new one
	after cancel $bltActiveGraph($g,alarmid)
	unset bltActiveGraph($g,alarmid)
    }
    set old $bltActiveGraph($g)
    if { $old == $new } {
	# Don't bother delaying with an alarm since this is on
	# the same line
	bltActivatePoint $g $x $y $new
	return
    }

    # Set up an alarm so we can delay doing this in case the user
    # is just moving the mouse over the graph.
    set bltActiveGraph($g,x) $x
    set bltActiveGraph($g,y) $y
    set bltActiveGraph($g,alarmid) [after 500 \
					[list bltDoActivateGraph $g $x $y $new]]
    return
}

proc bltDeactivateGraph {g} {
    global bltActiveGraph
    global bltActiveEntry
    global vsd

    if {[string equal $vsd($g:chartOp) "Delta"] ||
	[string equal $vsd($g:chartOp) "Trim"] ||
	[string equal $vsd($g:chartOp) "Compare"]} {
	$g config -cursor crosshair
    }
    if {[info exists bltActiveGraph($g,alarmid)]} {
	after cancel $bltActiveGraph($g,alarmid)
	unset bltActiveGraph($g,alarmid)
	unset bltActiveGraph($g,x)
	unset bltActiveGraph($g,y)
    }
    if {![info exists bltActiveGraph($g)]} {
        return
    }
    if {$bltActiveGraph($g) == 0} {
	return
    }
    $g legend deactivate $bltActiveGraph($g)
    $g element deactivate  $bltActiveGraph($g)
    $g marker configure activeLine -text ""
    deactivateAxis $g
    set bltActiveGraph($g) 0
    if {[info exists bltActiveGraph($g,oldSelectedLines)]} {
        resetSelectedLines $g $bltActiveGraph($g,oldSelectedLines)
	unset bltActiveGraph($g,oldSelectedLines)
    }
    showLineInfo $g ""
    set bltActiveGraph($g,closest) {}
    set le $bltActiveEntry($g)
    if {$le != -1} {
	# If an active legend is in use then restore it
	$g legend activate $le
	$g element activate $le
	$g marker configure activeLine -text  [getLineLabel $g $le]
	activateAxis $g $le
	showLineInfo $g $le
    }
}

# For some reason <1> and <2> end up calling the <Leave> binding.
# So we make sure we are out of the graph before doing the <Leave> work.
proc chartHandleLeaveEvent {g x y} {
    set y [$g yaxis invtransform $y]
    set ylimits [$g yaxis limits]
    if {$y >= [lindex $ylimits 0] && $y <= [lindex $ylimits 1]} {
	set x [$g xaxis invtransform $x]
	set xlimits [$g xaxis limits]
	if {$x >= [lindex $xlimits 0] && $x <= [lindex $xlimits 1]} {
	    return
	}
    }
    bltDeactivateGraph $g
}

proc Blt_BA_ActiveGraph {W x y} {
    if [$W element closest $x $y info -interpolate true -halo 5] {
	bltActivateGraph $W $x $y $info(name)
    } else {
	bltDeactivateGraph $W
    }
}

proc Blt_ActiveGraph { graph } {
    global bltActiveGraph
    set bltActiveGraph($graph) 0
    set bltActiveGraph($graph,closest) {}
    set bltActiveGraph($graph,oldSelectedLines) {}
    bind bltActiveGraph <Any-Motion>   {Blt_BA_ActiveGraph %W %x %y}
    bind bltActiveGraph <Leave>   {
	chartHandleLeaveEvent %W %x %y
    }
    BltAddBindTag $graph bltActiveGraph
}

proc activateElement {graph new control} {
    global bltActiveEntry
    global bltSelectedLines
    set old $bltActiveEntry($graph)
    if { $old != $new } {
        if {!$control} {
            clearSelectedLines $graph
        }
        addSelectedLine $graph $new
	if { $old != -1 } {
	    #$graph legend deactivate $old
	    $graph element deactivate $old
	    $graph marker configure activeLine -text ""
	    deactivateAxis $graph
	    showLineInfo $graph ""
	}
	#$graph legend activate $new
	$graph element activate $new
	$graph marker configure activeLine -text [getLineLabel $graph $new]
	activateAxis $graph $new
	set bltActiveEntry($graph) $new
	showLineInfo $graph $new
    } else {
        if {!$control} {
            clearSelectedLines $graph
        } else {
            removeSelectedLine $graph $new
        }
	$graph legend deactivate $new
	$graph element deactivate $new
	$graph marker configure activeLine -text ""
	deactivateAxis $graph
	showLineInfo $graph ""
	set bltActiveEntry($graph) -1
    }
}

proc BltAddBindTag { graph name } {
    set oldtags [bindtags $graph]
    if { [lsearch $oldtags $name] < 0 } {
	bindtags $graph [concat $name $oldtags]
    }
}

proc BltRemoveBindTag { graph name } {
    set tagList {}
    foreach tag [bindtags $graph] {
	if { $tag != $name } {
	    lappend tagList $tag
	}
    }
    bindtags $graph $tagList
}

proc BltGetCoords { graph x y index } {

    set y2 [$graph y2axis invtransform $y]
    set coords [$graph invtransform $x $y]
    set x [lindex $coords 0]
    set y [lindex $coords 1]

    scan [$graph xaxis limits] "%s %s" xmin xmax
    scan [$graph yaxis limits] "%s %s" ymin ymax
    scan [$graph y2axis limits] "%s %s" y2min y2max

    if { $x > $xmax } { 
	set x $xmax 
    } elseif { $x < $xmin } { 
	set x $xmin 
    }

    if { $y > $ymax } { 
	set y $ymax 
    } elseif { $y < $ymin } { 
	set y $ymin 
    }

    if { $y2 > $y2max } { 
	set y2 $y2max 
    } elseif { $y2 < $y2min } { 
	set y2 $y2min 
    }

    global bltZoom
    set bltZoom($graph,$index,x) $x
    set bltZoom($graph,$index,y) $y
    set bltZoom($graph,$index,y2) $y2
}

proc updateActiveLine {g} {
    global bltActiveEntry

    if {[info exists bltActiveEntry($g)] && $bltActiveEntry($g) != -1} {
	set e $bltActiveEntry($g)
	$g marker configure activeLine -text [getLineLabel $g $e]
    }
    showMarker $g activeLine
}

proc updateAllActiveLines {} {
    global bltActiveEntry

    foreach g [array names bltActiveEntry] {
	if {$bltActiveEntry($g) != -1} {
	    updateActiveLine $g
	}
    }
}

proc BltPopZoom { graph } {
    global bltZoom

    set zoomStack $bltZoom($graph,stack)
    if { [llength $zoomStack] > 0 } {
	set cmd [lindex $zoomStack 0]
	set bltZoom($graph,stack) [lrange $zoomStack 1 end]
	eval $cmd
	BltZoomTitleLast $graph
	myBusyOn $graph
	set cmd [format {
            if {[winfo exists %s]} {
		if { $bltZoom(%s,corner) == "A" } {
		    %s marker delete "bltZoom_title"
		    updateActiveLine %s
		}
	    }
	} $graph $graph $graph $graph]
	after 2000 $cmd
	myBusyOff $graph
    } else {
	$graph marker delete "bltZoom_title"
        updateActiveLine $graph
    }
}

proc ZoomHorizontalPage {g i} {
    global vsd

    set limits [$g xaxis limits]
    set screenMin [$g xaxis transform [lindex $limits 0]]
    set screenMax [$g xaxis transform [lindex $limits 1]]
    set width [expr (($screenMax - $screenMin) - 1)]
    ZoomHorizontal $g [expr ($width * $i)]
}

proc ZoomHorizontal {g i} {
    global vsd

    set axisMin [$g xaxis cget -min]
    if {$axisMin != ""} {
	set screenMin [$g xaxis transform $axisMin]
	set axisMin [$g xaxis invtransform [expr ($screenMin + $i)]]
    }

    set axisMax [$g xaxis cget -max]
    if {$axisMax != ""} {
	set screenMax [$g xaxis transform $axisMax]
	set axisMax [$g xaxis invtransform [expr ($screenMax + $i)]]
    }

    if {$axisMin != "" || $axisMax != ""} {
	$g xaxis configure -min $axisMin -max $axisMax
	updateActiveLine $g
    }
}

proc ZoomVertical {g i} {
    global vsd
    # NYI
}

# Push the old axis limits on the stack and set the new ones

proc BltPushZoom { graph } {
    deleteAllZoomMarkers $graph

    global bltZoom
    set xA $bltZoom($graph,A,x)
    set yA $bltZoom($graph,A,y)
    set y2A $bltZoom($graph,A,y2)
    set xB $bltZoom($graph,B,x)
    set yB $bltZoom($graph,B,y)
    set y2B $bltZoom($graph,B,y2)

    if { ($xA == $xB) && ($yA == $yB) && ($y2A == $y2B) } { 
	# No delta, revert to start
	updateActiveLine $graph
	return
    }

    set cmd [format {
	%s xaxis configure -min "%s" -max "%s"
	%s yaxis configure -min "%s" -max "%s"
	%s y2axis configure -min "%s" -max "%s"
    } $graph [$graph xaxis cget -min] [$graph xaxis cget -max] \
      $graph [$graph yaxis cget -min] [$graph yaxis cget -max] \
      $graph [$graph y2axis cget -min] [$graph y2axis cget -max] ]

    if { $xA > $xB } { 
	$graph xaxis configure -min $xB -max $xA 
    } elseif { $xA < $xB } {
	$graph xaxis configure -min $xA -max $xB
    } 
    if { $yA > $yB } { 
	$graph yaxis configure -min $yB -max $yA
    } elseif { $yA < $yB } {
	$graph yaxis configure -min $yA -max $yB
    } 
    if { $y2A > $y2B } { 
	$graph y2axis configure -min $y2B -max $y2A
    } elseif { $y2A < $y2B } {
	$graph y2axis configure -min $y2A -max $y2B
    } 
    set bltZoom($graph,stack) [linsert $bltZoom($graph,stack) 0 $cmd]

    update
    updateActiveLine $graph
}

proc chartFinishOp {g} {
    global vsd
    $g config -cursor $vsd(graphcursor)
    set vsd($g:chartOp) {}
}

proc ChartHandleRightClick { graph } {
    global vsd

    chartCancelOp$vsd($graph:chartOp) $graph
    chartFinishOp $graph
}

proc deleteAllZoomMarkers {graph} {
    foreach e [$graph marker names "bltZoom_*"] {
	$graph marker delete $e
    }
}
proc chartCancelOpZoom { graph } {
    global bltZoom

    deleteAllZoomMarkers $graph
    showMarker $graph activeLine

    if { $bltZoom($graph,corner) == "A" } {
	# Reset the whole axis
	BltPopZoom $graph
    } else {
	set bltZoom($graph,corner) A
	bind $graph <Motion> { }
    }
}

proc chartCancelOpDelta { g } {
    global vsd
    unset vsd($g:deltaLine)
    if [info exists vsd($g:deltapoint1)] {
	unset vsd($g:deltapoint1)
    }
    bind $g <Any-Motion> { }
    $g marker delete "chartop_title"
    if [$g marker exists "delta_line"] {
	$g marker delete "delta_line"
    }
    showMarker $g activeLine
    chartFinishOp $g
}

proc chartCancelOpCompare { g } {
    global vsd
    if [info exists vsd($g:compareLine1)] {
	unset vsd($g:compareLine1)
    }
    if [info exists vsd($g:comparepoint1)] {
	unset vsd($g:comparepoint1)
    }
    bind $g <Any-Motion> { }
    $g marker delete "chartop_title"
    if [$g marker exists "compare_line"] {
	$g marker delete "compare_line"
    }
    showMarker $g activeLine
    chartFinishOp $g
}

proc chartCancelOpCombine { g } {
    global vsd
    bind $g <Any-Motion> { }
    $g marker delete "chartop_title"
    showMarker $g activeLine
    chartFinishOp $g
}

proc chartCancelOpMinTime { g } {
    $g marker delete "chartop_title"
    showMarker $g activeLine
    chartFinishOp $g
}

proc chartCancelOpMaxTime { g } {
    chartCancelOpMinTime $g
}

proc BltZoomTitleNext {graph} {
    global bltZoom vsd

    set level [expr [llength $bltZoom($graph,stack)] + 1]
    set title "Zoom #$level (right click to cancel)"
    $graph config -cursor bottom_right_corner
    hideMarker $graph activeLine
    $graph marker create text -name "bltZoom_title" -text $title \
	    -coords {-Inf Inf} -anchor nw -bg {} -font vsdsf
}

proc BltZoomTitleLast {graph} {
    global bltZoom vsd

    set level [llength $bltZoom($graph,stack)]
    if { $level > 0 } {
	hideMarker $graph activeLine
	set title "Zoom #$level"
     	$graph marker create text -name "bltZoom_title" -text $title \
		-coords {-Inf Inf} -anchor nw -bg {} -font vsdsf
    }
}

proc getSelectedLine {g} {
    global bltActiveEntry
    global bltActiveGraph

    set e $bltActiveGraph($g)
    if {$e != 0} {
	return $e
    }
    set e $bltActiveEntry($g)    
    if {$e != -1} {
	return $e
    }
    return ""
}

proc chartOp {graph x y control} {
    global vsd
    global bltActiveGraph

    set e $bltActiveGraph($graph)
    if {$e != 0} {
	activateElement $graph $e $control
    }
}

proc chartOpZoom {graph x y control} {
    global vsd
    global bltZoom

    BltGetCoords $graph $x $y $bltZoom($graph,corner)
    if { $bltZoom($graph,corner) == "A" } {
	# First corner selected, start watching motion events

	BltZoomTitleNext $graph 
	bind $graph <Any-Motion> { 
	    BltGetCoords %W %x %y B
	    BltBox %W
	}
	set bltZoom($graph,corner) B
    } else {
	bind $graph <Any-Motion> { }
	BltPushZoom $graph
	chartFinishOp $graph
	set bltZoom($graph,corner) A
    }
}

proc DeltaLine {g x y} {
    global vsd
    set yaxis [$g element cget $vsd($g:deltaLine) -mapy]
    set x1 [lindex $vsd($g:deltapoint1) 0]
    set y1 [lindex $vsd($g:deltapoint1) 1]
    set x2 [$g xaxis invtransform $x]
    set y2 [$g ${yaxis}axis invtransform $y]
    set coords {$x1 $y1 $x2 $y2}
    if [$g marker exists "delta_line"] {
	$g marker configure "delta_line" -coords $coords
    } else {
	$g marker create line -coords $coords -name "delta_line" -mapy $yaxis
    }
    if [$g element closest $x $y info -halo 5 -interpolate 0 $vsd($g:deltaLine)] {
	$g marker configure "delta_line" -outline $vsd(activecolor)
    } else {
	$g marker configure "delta_line" -outline black
    }
}

proc CompareLine {g x y} {
    global vsd
    set yaxis [$g element cget $vsd($g:compareLine1) -mapy]
    set x1 [lindex $vsd($g:comparepoint1) 0]
    set y1 [lindex $vsd($g:comparepoint1) 1]
    set x2 [$g xaxis invtransform $x]
    set y2 [$g ${yaxis}axis invtransform $y]
    set coords {$x1 $y1 $x2 $y2}
    if [$g marker exists "compare_line"] {
	$g marker configure "compare_line" -coords $coords
    } else {
	$g marker create line -coords $coords -name "compare_line" -mapy $yaxis
    }
    if [$g element closest $x $y info -halo 5 -interpolate 0] {
	$g marker configure "compare_line" -outline $vsd(activecolor)
    } else {
	$g marker configure "compare_line" -outline black
    }
}

proc showData {str {wrap 0}} {
    global vsd widgetHelp
    set w .datawin
    set exists [winfo exists $w]
    if $exists {
	wm deiconify $w
	raise $w
    } else {
	set widgetHelp($w) {Log Window}
	toplevel $w
	wm title $w "Vsd Data Log"
	if {$vsd(geometry:$w) != {}} {
	    wm geometry $w $vsd(geometry:$w)
	}
	frame $w.top -relief raised -bd 1
	tixScrolledText $w.top.msg -width 375 -height 120
	[$w.top.msg subwidget text] configure -wrap none -font fixedTextFont
	pack $w.top.msg -expand yes -fill both
	pack $w.top -side top -fill both -expand yes
    }

    if {$wrap} {
	[$w.top.msg subwidget text] configure -wrap word
    } else {
	[$w.top.msg subwidget text] configure -wrap none
    }
    [$w.top.msg subwidget text] insert end $str
    [$w.top.msg subwidget text] insert end "\n"
    [$w.top.msg subwidget text] see end
}

proc elapsedTime {seconds} {
    set result ""
    set seconds [expr int($seconds)]
    if {$seconds >= 86400} {
	set days [expr int($seconds / 86400)]
	set seconds [expr $seconds % 86400]
	append result " $days day"
	if {$days != 1} {
	    append result "s"
	}
	if {$seconds != 0} {
	    append result ","
	}
    }
    if {$seconds >= 3600} {
	set hours [expr int($seconds / 3600)]
	set seconds [expr $seconds % 3600]
	append result " $hours hour"
	if {$hours != 1} {
	    append result "s"
	}
	if {$seconds != 0} {
	    append result ","
	}
    }
    if {$seconds >= 60} {
	set minutes [expr int($seconds / 60)]
	set seconds [expr $seconds % 60]
	append result " $minutes minute"
	if {$minutes != 1} {
	    append result "s"
	}
	if {$seconds != 0} {
	    append result ","
	}
    }
    if {$seconds != 0 || $result == {}} {
	append result " $seconds second"
	if {$seconds != 1} {
	    append result "s"
	}
    }
    return $result
}

proc xToStr {g x} {
    global vsd
    if {[string equal $vsd($g:xformat) "elapsed"]} {
	return [showElapsedOnTicks $g $x]
    } elseif {[string equal $vsd($g:xformat) "time"]} {
	return [showTimeOnTicks $g $x]
    } else {
	return [showDateOnTicks $g $x]
    }
}

proc chartOpDelta {g x y control} {
    global vsd

    set e $vsd($g:deltaLine)
    if [$g element closest $x $y info -halo 5 -interpolate 0 $e] {
	set scale [lindex [$vsd(ed:$e:$g) -info] 4]
	set coordinates "$info(x) $info(y) $scale"
    } else {
	# Was not over a valid point when left click happened so ignore
	return
    }
    if [info exists vsd($g:deltapoint1)] {
	# Spit the results out
	set linfo [$vsd(ed:$e:$g) -info]
	set x1 [lindex $vsd($g:deltapoint1) 0]
	set y1 [expr [lindex $vsd($g:deltapoint1) 1] / [lindex $vsd($g:deltapoint1) 2]]
	set x2 [lindex $coordinates 0]
	set y2 [expr [lindex $coordinates 1] / [lindex $coordinates 2]]
	set deltax [expr $x2 - $x1]
	set deltax [expr abs($deltax)]
	set deltay [expr $y2 - $y1]
	set units [getLineUnitDescription 0 $linfo]
	showData "\nDelta on [lrange $linfo 0 1]
  point1: [xToStr $g $x1], [stripFloat $y1]
  point2: [xToStr $g $x2], [stripFloat $y2]
  time delta =      [elapsedTime $deltax].
  value delta =      [stripFloat $deltay] $units."
	if {$deltax != 0} {
	    showData "  value/time delta = [expr $deltay / $deltax] $units per second."
	    set lstats [$vsd(ed:$e:$g) -stats $x1 $x2]
	    showData \
"  Of the [lindex $lstats 0] data points in this range:
    the min is:     [lindex $lstats 1]
    the max is:     [lindex $lstats 2]
    the average is: [lindex $lstats 3]
    the stddev is:  [lindex $lstats 4]"
	}
	chartCancelOpDelta $g
    } else {
	# Save coordinates into vsd($g:deltapoint1)
	set vsd($g:deltapoint1) $coordinates
	# start watching motion events
	$g config -cursor crosshair
	set title "Click on second data point, right click to cancel"
	$g marker create text -name "chartop_title" -text $title \
	    -coords {-Inf Inf} -anchor nw -bg {} -font vsdsf
	bind $g <Any-Motion> { 
	    DeltaLine %W %x %y
	}
    }
}

proc chartCancelOpTrim { g } {
    global vsd
    unset vsd($g:trimLine)
    unset vsd($g:trimLeft)
    bind $g <Any-Motion> { }
    $g marker delete "chartop_title"
    showMarker $g activeLine
    chartFinishOp $g
}


proc chartOpTrim {g x y control} {
    global vsd

    set e $vsd($g:trimLine)
    if [$g element closest $x $y info -halo 5 -interpolate 0 $e] {
	set ts [expr int($info(x))]
	if {$vsd($g:trimLeft)} {
	    if {$ts == 0} {
		# can't trim left the very first point as it would be treated
		# as an untrim. Besides it would be a noop since "ts" is the
		# first timestamp to keep.
		return
	    }
	    $vsd(ed:$e:$g) -trimleft $ts
	} else {
	    $vsd(ed:$e:$g) -trimright $ts
	}
	chartCancelOpTrim $g
	trimUpdate $g $e
    } else {
	# Was not over a valid point when left click happened so ignore
	return
    }
}

proc chartOpCompare {g x y control} {
    global vsd

    if [$g element closest $x $y info -halo 5 -interpolate 0] {
	set e $info(name)
	set scale [lindex [$vsd(ed:$e:$g) -info] 4]
	set coordinates "$info(x) $info(y) $scale"
    } else {
	# Was not over a valid point when left click happened so ignore
	return
    }
    if [info exists vsd($g:comparepoint1)] {
	# Spit the results out
	set e1 $vsd($g:compareLine1)
	set e2 $e
	set sameline [expr $e1 == $e2]
	set linfo [$vsd(ed:$e1:$g) -info]
	set units [getLineUnitDescription 0 $linfo]
	set lname "\"[lrange $linfo 0 1]\""
	set header "Comparing data from $lname"
	if {!$sameline} {
	    set linfo2 [$vsd(ed:$e2:$g) -info]
	    set l2name "\"[lrange $linfo2 0 1]\""
	    set units2 [getLineUnitDescription 0 $linfo2]
	    if {![string equal $units $units2]} {
		append units "&$units2"
	    }
	    append header " and $l2name"
	}
	set x1 [lindex $vsd($g:comparepoint1) 0]
	set y1 [expr [lindex $vsd($g:comparepoint1) 1] / [lindex $vsd($g:comparepoint1) 2]]
	set x2 [lindex $coordinates 0]
	set y2 [expr [lindex $coordinates 1] / [lindex $coordinates 2]]
	set deltax [expr $x2 - $x1]
	set deltax [expr abs($deltax)]
	set deltay [expr $y2 - $y1]
	showData "\n$header
  point1: [xToStr $g $x1], [stripFloat $y1]
  point2: [xToStr $g $x2], [stripFloat $y2]
  time delta =      [elapsedTime $deltax].
  value delta =      [stripFloat $deltay] $units."
	if {$deltax != 0} {
	    showData "  value/time delta = [expr $deltay / $deltax] $units per second."
	    set lstats [$vsd(ed:$e1:$g) -stats $x1 $x2]
	    showData \
"  Of the [lindex $lstats 0] $lname points in this range:
    the min is:     [lindex $lstats 1]
    the max is:     [lindex $lstats 2]
    the average is: [lindex $lstats 3]
    the stddev is:  [lindex $lstats 4]"
            if {!$sameline} {
		set lstats [$vsd(ed:$e2:$g) -stats $x1 $x2]
		showData \
"  Of the [lindex $lstats 0] $l2name points in this range:
    the min is:     [lindex $lstats 1]
    the max is:     [lindex $lstats 2]
    the average is: [lindex $lstats 3]
    the stddev is:  [lindex $lstats 4]"
            }
	}
	chartCancelOpCompare $g
    } else {
	# Save coordinates into vsd($g:comparepoint1)
	set vsd($g:compareLine1) $e
	set vsd($g:comparepoint1) $coordinates
	$g config -cursor crosshair
	set title "Click on second data point, right click to cancel"
	$g marker create text -name "chartop_title" -text $title \
	    -coords {-Inf Inf} -anchor nw -bg {} -font vsdsf
	# start watching motion events
	bind $g <Any-Motion> { 
	    CompareLine %W %x %y
	}
    }
}

proc chartOpMinTime {g x y control} {
    global vsd

    set x [$g xaxis invtransform $x]
    set xmin [lindex [$g xaxis limits] 0]
    if {$x >= $xmin} {
	$g xaxis configure -min $x
    } else {
	# reset as if no min was ever set
	$g xaxis configure -min ""
    }
    chartCancelOpMinTime $g
}

proc chartOpMaxTime {g x y control} {
    global vsd

    set x [$g xaxis invtransform $x]
    set xmax [lindex [$g xaxis limits] 1]
    if {$x <= $xmax} {
	$g xaxis configure -max $x
    } else {
	# reset as if no max was ever set
	$g xaxis configure -max ""
    }
    chartCancelOpMaxTime $g
}

proc chartOpCombine {g x y control} {
    global vsd

    set e2 [getSelectedLine $g]
    if {$e2 == {}} {
	return
    }
    set e1 [lindex $vsd($g:combineData) 0]
    if {$e2 == $e1} {
	return
    }
    set op [lindex $vsd($g:combineData) 1] 
    set l1 $vsd(ed:$e1:$g)
    set l2 $vsd(ed:$e2:$g)

    addDerivedLine [list $l1 $l2] $op

    chartCancelOpCombine $g
}

proc ChartHandleLeftClick {graph x y control} {
    global vsd

    focus $graph

    set legEntry [$graph legend get @$x,$y]
    if {$legEntry != {}} {
	activateElement $graph $legEntry $control
	if {![string equal $vsd($graph:chartOp) "Combine"]} {
	    return
	}
    }

    chartOp$vsd($graph:chartOp) $graph $x $y $control
}

proc quickZoom {g x y} {
    global vsd

    set gx [$g xaxis invtransform $x]
    set xlimits [$g xaxis limits]
    set xMinLimit [lindex $xlimits 0]
    set xMaxLimit [lindex $xlimits 1]
    if {$gx < $xMinLimit || $gx > $xMaxLimit} {
	return
    }
    set gy [$g yaxis invtransform $y]
    set ylimits [$g yaxis limits]
    if {$gy < [lindex $ylimits 0] || $gy > [lindex $ylimits 1]} {
	return
    }

    set cmd [format {
	%s xaxis configure -min "%s" -max "%s"
    } $g [$g xaxis cget -min] [$g xaxis cget -max] ]

    #We want to center 'gx' in the middle of the graph and reduce
    #the amount of X data displayed by half.
    set xrange [expr int(($xMaxLimit - $xMinLimit) / 4)]
    set xmin [expr ($gx - $xrange)]
    if {$xmin <= $xMinLimit} {
	set xmin [$g xaxis cget -min]
    }
    set xmax [expr ($gx + $xrange)]
    if {$xmax >= $xMaxLimit} {
	set xmax [$g xaxis cget -max]
    }

    set xminVal $xmin
    if {$xminVal == ""} {
	set xminVal $xMinLimit
    }
    set xmaxVal $xmax
    if {$xmaxVal == ""} {
	set xmaxVal $xMaxLimit
    }
    if {$xminVal < $xmaxVal} {
	$g xaxis configure -min $xmin -max $xmax

	global bltZoom
	set bltZoom($g,stack) [linsert $bltZoom($g,stack) 0 $cmd]
	updateActiveLine $g
    }
}

proc ChartHandleMiddleClick {graph x y} {
    global vsd

    focus $graph

    set legEntry [$graph legend get @$x,$y]
    if {$legEntry != {}} {
	deleteElement $graph $legEntry
    } else {
	quickZoom $graph $x $y
    }
}

proc BltBox {graph} {
    global bltZoom

    if { $bltZoom($graph,A,x) > $bltZoom($graph,B,x) } { 
	set x1 $bltZoom($graph,B,x)
	set x2 $bltZoom($graph,A,x) 
	set y1 $bltZoom($graph,B,y)
	set y2 $bltZoom($graph,A,y) 
    } else {
	set x1 $bltZoom($graph,A,x)
	set x2 $bltZoom($graph,B,x) 
	set y1 $bltZoom($graph,A,y)
	set y2 $bltZoom($graph,B,y) 
    }
    set coords {
	$x1 $y1 $x1 $y2 $x1 $y1 $x2 $y1 $x2 $y1 $x2 $y2 $x1 $y2 $x2 $y2 
    }
    if [$graph marker exists "bltZoom_outline"] {
	$graph marker configure "bltZoom_outline" -coords $coords
    } else {
	$graph marker create line -coords $coords -name "bltZoom_outline" \
	    -dashes { 4 2 }
    }
}

######################## start of vsd code #####################


proc searchHelp {w str {next 0} {forwards 1}} {
    global vsd
    if {$str == ""} {
	return
    }
    if {$forwards} {
	set direction "-forwards"
    } else {
	set direction "-backwards"
    }
    if [info exists vsd($w:searchidx)] {
	set idx $vsd($w:searchidx)
	if {$next} {
	    if {$forwards} {
		set idx [$w index "$idx +1chars"]
	    } else {
		set idx [$w index "$idx -1chars"]
	    }
	}
    } else {
	set idx "end"
    }
    set idx [$w search $direction -exact -nocase -- $str $idx]
    if {$idx == {}} {
	$w tag remove sel 1.0 end
	setStatus "Could not find \"$str\"."
	if {[string first $vsd(search:unfound) $str] != 0} {
	    set vsd(search:unfound) $str
	    bell
	}
    } else {
	$w see $idx
	$w tag remove sel 1.0 end
	$w tag add sel $idx "$idx +[string length $str]chars"
	set vsd($w:searchidx) $idx
    }
}

proc followHelpLink {w key} {
    doHelp $key $w
}

proc getHelpText {msgKey} {
    global vsdhelp
    set text $vsdhelp($msgKey)
    if [string match {TCLEVAL *} $text] {
	set cmd [lindex $text 1]
	set arglist [lindex $text 2]
	set text [$cmd $arglist]
    }
    return [string trimleft $text "\n"]
}

proc helpRefresh {w} {
    global vsdLinkVisited
    catch {unset vsdLinkVisited}
    restartVsd
    doHelp refresh $w
}

proc isHiddenTopic {topic} {
    expr {[string first "Topics that contain" $topic] == 0 ||
	  [lsearch -exact {"All Topics" "All Help Text" "All Statistics"} $topic] != -1}
}

proc searchAllTopics {} {
    global vsd vsdhelp
    set p $vsd(search:parent)
    set searchString [string tolower $vsd($p:st)]
    if {$searchString == {}} {
	return
    }
    
    myBusyOn .vsdhelpsearch

    set searchTopic "Topics that contain \"$searchString\":"
    if {![info exists vsdhelp($searchTopic)]} {
	set searchText ""
	foreach topic [lsort [array names vsdhelp]] {
	    if [isHiddenTopic $topic] {
		continue
	    }
	    if {[string first $searchString [string tolower $topic]] == -1} {
		set text [string tolower [getHelpText $topic]]
		if {[string first $searchString $text] == -1} {
		    continue
		}
	    }
	    append searchText "*\[" $topic "]\n"
	}
	if {$searchText == {}} {
	    set searchText "\n<em>no topics found</em>"
	}
	set vsdhelp($searchTopic) $searchText
    }
    doHelp $searchTopic [winfo toplevel $p]
    myBusyOff .vsdhelpsearch
}

proc allHelpWindows {} {
    set result {}
    foreach w [winfo children .] {
	if {[string first ".help" $w] == 0} {
	    lappend result $w
	}
    }
    return $result
}

proc rememberPosition {w} {
    global vsd
    set idx $vsd($w:helpHistoryIdx)
    set textw [$w.top.msg subwidget text]
    set vsd($w:historyPositions) [lreplace $vsd($w:historyPositions) $idx $idx [lindex [$textw yview] 0]]
}

proc closeHelpWindow {w} {
    global vsd

    #Do a focus so that the search window will go away
    focus $w
    update
    catch {unset vsd($w:helpHistoryIdx)}
    catch {unset vsd($w:helpHistory)}
    catch {unset vsd($w:historyPositions)}
    catch {unset vsd($w:normalCursor)}
    catch {unset vsd($w:hlinkCount)}
    destroy $w
}

proc doHelp {msgKey {w {}} {doFocus 1}} {
    global vsd vsdhelp vsdLinkVisited
    set doHistory 0
    if {[string equal $msgKey "back"]} {
	if {$vsd($w:helpHistoryIdx) == 0} {
	    setStatus "nothing to go back to."
	    bell
	    return
	}
	rememberPosition $w
	incr vsd($w:helpHistoryIdx) -1
	set doHistory 1
    } elseif {[string equal $msgKey "forward"]} {
	if {($vsd($w:helpHistoryIdx) + 1) == [llength $vsd($w:helpHistory)]} {
	    setStatus "nothing to go foward to."
	    bell
	    return
	}
	rememberPosition $w
	incr vsd($w:helpHistoryIdx)
	set doHistory 1
    } elseif {[string equal $msgKey "refresh"]} {
	set doHistory 1
    }
    if {$doHistory} {
	set msgKey [lindex $vsd($w:helpHistory) $vsd($w:helpHistoryIdx)]
    }
    if {![info exists vsdhelp($msgKey)]} {
	setStatus "no help for '$msgKey'."
	bell
	return
    }

    set vsdLinkVisited($msgKey) 1

    if {$w == {}} {
	# Look for a window that is already displaying this topic
	foreach w [allHelpWindows] {
	    set topic [lindex $vsd($w:helpHistory) $vsd($w:helpHistoryIdx)]
	    if {[string equal $topic $msgKey]} {
		# found an existing help window
		wm deiconify $w
		if {$doFocus} {
		    focus $w
		}
		raise $w
		return
	    }
	}
	if {$doFocus} {
	    # if doFocus is FALSE we end up using the last help window for this topic instead of always creating a new window. This the case for context sensitive help.
	    # if doFocus is TRUE then we need to clear $w so we will create a new window. This is the case of when a link was middle clicked on
	    set w {}
	}
    }
    
    if {$w != {} && [winfo exists $w]} {
	wm deiconify $w
	if {$doFocus} {
	    focus $w
	}
	raise $w
	set textw [$w.top.msg subwidget text]
	if {!$doHistory} {
	    set currentTopic [lindex $vsd($w:helpHistory) $vsd($w:helpHistoryIdx)]
	    if {[string equal $currentTopic $msgKey]} {
		# Window already contains requested topic
		return
	    }
	    set vsd($w:historyPositions) [lreplace $vsd($w:historyPositions) $vsd($w:helpHistoryIdx) $vsd($w:helpHistoryIdx) [lindex [$textw yview] 0]]
	    incr vsd($w:helpHistoryIdx)
	    if {$vsd($w:helpHistoryIdx) == [llength $vsd($w:helpHistory)]} {
		lappend vsd($w:helpHistory) $msgKey
		lappend vsd($w:historyPositions) 0
	    } else {
		set vsd($w:helpHistory) [lreplace $vsd($w:helpHistory) $vsd($w:helpHistoryIdx) end $msgKey]
		set vsd($w:historyPositions) [lreplace $vsd($w:historyPositions) $vsd($w:helpHistoryIdx) end 0]
	    }
	}
	$textw configure -state normal
	$textw configure -cursor $vsd($w:normalCursor)
	$textw delete "1.0" end
	$textw tag delete bulletItem bold fixed italic underline
	while {$vsd($w:hlinkCount) > 0} {
	    $textw tag delete "hlink$vsd($w:hlinkCount)"
	    incr vsd($w:hlinkCount) -1
	}
        foreach wn [$textw window names] {
	    destroy $wn
	}
    } else {
	incr vsd(helpIdx)
	set w ".help$vsd(helpIdx)"
	toplevel $w

	global widgetHelp
	set widgetHelp($w) {Help Window Features}

	frame $w.top -relief raised -bd 1

	tixScrolledText $w.top.msg -scrollbar y -width 400
	pack $w.top.msg -expand yes -fill both

	set textw [$w.top.msg subwidget text]
#	$textw -font normalTextFont
	bind $w <Control-s> \
	    [list startSearch $textw searchHelp 0 .vsdhelpsearch]

	bind $w <Control-b> "doHelp back $w; break"
	bind $w <Control-f> "doHelp forward $w; break"

	bind $w <Down>  "$textw yview scroll +1 units; break"
	bind $w <Up>    "$textw yview scroll -1 units; break"
	bind $w <Next>  "$textw yview scroll +1 pages; break"
	bind $w <Prior> "$textw yview scroll -1 pages; break"
	bind $w <Home>  "$textw yview moveto 0; break"
	bind $w <End>   "$textw yview moveto 1; break"
	if [wizardMode] {
	    bind $w <F4> [list helpRefresh $w]
	}

	tixButtonBox $w.box
	$w.box add back -text Back -width 6 -command "doHelp back $w"
	$w.box add forward -text Forward -width 6 -command "doHelp forward $w"
	$w.box add search -text Search... -width 6 \
	    -command [list startSearch $textw searchHelp 0 .vsdhelpsearch]
	$w.box add dismiss -text Dismiss -width 6 -command [list closeHelpWindow $w]
	set but [$w.box subwidget dismiss]
	wm protocol $w WM_DELETE_WINDOW [list closeHelpWindow $w]

	pack $w.box -fill x -side bottom
	pack $w.top -side top -fill both -expand yes

	set vsd($w:normalCursor) [$textw cget -cursor]
	
	set vsd($w:helpHistory) [list $msgKey]
	set vsd($w:historyPositions) {0}
	set vsd($w:helpHistoryIdx) 0
	set vsd($w:hlinkCount) 0
    }
    if {[string match "Help*" $msgKey]} {
	wm title $w $msgKey
    } else {
	wm title $w "Help: $msgKey"
    }

    set b [$w.box subwidget back]
    if {$vsd($w:helpHistoryIdx) == 0} {
	$b configure -state disabled
    } else {
	$b configure -state normal
    }
    set b [$w.box subwidget forward]
    if {($vsd($w:helpHistoryIdx) + 1) == [llength $vsd($w:helpHistory)]} {
	$b configure -state disabled
    } else {
	$b configure -state normal
    }

    $textw tag configure bold -font boldTextFont
    $textw tag configure italic -font italicTextFont
    $textw tag configure fixed -font fixedTextFont
    $textw tag configure underline -underline 1
    $textw tag configure bulletItem -lmargin1 10 -lmargin2 30
    $textw tag configure bulletItem2 -lmargin1 30 -lmargin2 50
    $textw tag configure bulletItem3 -lmargin1 50 -lmargin2 70

#     $textw insert 1.0 "    $msgKey\n"
#     $textw tag add bold 1.0 "1.0 lineend"

    $textw insert end [getHelpText $msgKey]
    
    # decorate headers
    set idx [$textw search -forwards -regexp -- {^!} "1.0" end]
    while {$idx != {}} {
	# get rid of the exclamation point
	$textw delete $idx
	$textw tag add bold $idx "$idx lineend"
	set idx [$textw search -forwards -regexp -- {^!} $idx end]
    }
    
    # decorate bullet list items
    set idx [$textw search -forwards -regexp -- {^   \* } "1.0" end]
    while {$idx != {}} {
	# get rid of the '   * ' marker
	$textw delete $idx "$idx +5c"
	set imageIdx [$textw image create $idx -image $vsd(bulletImage) -align center -padx 3]
	$textw tag add bulletItem $imageIdx "$idx lineend"
	set idx [$textw search -forwards -regexp -- {^   \* } $idx end]
    }

    # decorate bullet2 list items
    set idx [$textw search -forwards -regexp -- {^      \* } "1.0" end]
    while {$idx != {}} {
	# get rid of the '      * ' marker
	$textw delete $idx "$idx +8c"
	set imageIdx [$textw image create $idx -image $vsd(bulletImage) -align center -padx 3]
	$textw tag add bulletItem2 $imageIdx "$idx lineend"
	set idx [$textw search -forwards -regexp -- {^      \* } $idx end]
    }

    # decorate bullet3 list items
    set idx [$textw search -forwards -regexp -- {^         \* } "1.0" end]
    while {$idx != {}} {
	# get rid of the '         * ' marker
	$textw delete $idx "$idx +11c"
	set imageIdx [$textw image create $idx -image $vsd(bulletImage) -align center -padx 3]
	$textw tag add bulletItem3 $imageIdx "$idx lineend"
	set idx [$textw search -forwards -regexp -- {^         \* } $idx end]
    }

    # decorate numbered list items
    set idx [$textw search -forwards -regexp -- {^   1 } "1.0" end]
    while {$idx != {}} {
	set itemCount 0
	while {1} {
	    incr itemCount
	    # get rid of the '   1 ' marker
	    $textw delete $idx  "$idx +5c"
	    $textw insert $idx " ${itemCount}. "
	    $textw tag add bulletItem $idx "$idx lineend"
	    set idx [$textw index "$idx +1lines linestart"]
	    if {![string equal {   1 } [$textw get $idx "$idx +5c"]]} {
		break
	    }
	}
	set idx [$textw search -forwards -regexp -- {^   1 } $idx end]
    }

    # decorate numbered list items
    set idx [$textw search -forwards -regexp -- {^      1 } "1.0" end]
    while {$idx != {}} {
	set itemCount 0
	while {1} {
	    incr itemCount
	    # get rid of the '      1 ' marker
	    $textw delete $idx  "$idx +8c"
	    $textw insert $idx " ${itemCount}. "
	    $textw tag add bulletItem2 $idx "$idx lineend"
	    set idx [$textw index "$idx +1lines linestart"]
	    if {![string equal {      1 } [$textw get $idx "$idx +8c"]]} {
		break
	    }
	}
	set idx [$textw search -forwards -regexp -- {^      1 } $idx end]
    }

    # decorate <b>...</b> tags
    set idx [$textw search -forwards -exact -- {<b>} "1.0" end]
    while {$idx != {}} {
	# get rid of the '<b>' marker
	$textw delete $idx "$idx +3c"
	set idx2 [$textw search -forwards -exact -- {</b>} $idx "$idx lineend"]
	if {$idx2 == {}} {
	    setStatus "missing </b> in help"
	    bell
	    set idx [$textw index "$idx +1c"]
	} else {
	    # get rid of the '</b>' marker
	    $textw delete $idx2 "$idx2 +4c"
	    $textw tag add bold $idx $idx2
	    set idx $idx2
	}
	set idx [$textw search -forwards -exact -- {<b>} $idx end]
    }
    
    # decorate <u>...</u> tags
    set idx [$textw search -forwards -exact -- {<u>} "1.0" end]
    while {$idx != {}} {
	# get rid of the '<u>' marker
	$textw delete $idx "$idx +3c"
	set idx2 [$textw search -forwards -exact -- {</u>} $idx "$idx lineend"]
	if {$idx2 == {}} {
	    setStatus "missing </u> in help"
	    bell
	    set idx [$textw index "$idx +1c"]
	} else {
	    # get rid of the '</u>' marker
	    $textw delete $idx2 "$idx2 +4c"
	    $textw tag add underline $idx $idx2
	    set idx $idx2
	}
	set idx [$textw search -forwards -exact -- {<u>} $idx end]
    }
    
    # decorate <tt>...</tt> tags
    set idx [$textw search -forwards -exact -- {<tt>} "1.0" end]
    while {$idx != {}} {
	# get rid of the '<tt>' marker
	$textw delete $idx "$idx +4c"
	set idx2 [$textw search -forwards -exact -- {</tt>} $idx "$idx lineend"]
	if {$idx2 == {}} {
	    setStatus "missing </tt> in help"
	    bell
	    set idx [$textw index "$idx +1c"]
	} else {
	    # get rid of the '</tt>' marker
	    $textw delete $idx2 "$idx2 +5c"
	    $textw tag add fixed $idx $idx2
	    set idx $idx2
	}
	set idx [$textw search -forwards -exact -- {<tt>} $idx end]
    }
    
    # decorate <em>...</em> tags
    set idx [$textw search -forwards -exact -- {<em>} "1.0" end]
    while {$idx != {}} {
	# get rid of the '<em>' marker
	$textw delete $idx "$idx +4c"
	set idx2 [$textw search -forwards -exact -- {</em>} $idx "$idx lineend"]
	if {$idx2 == {}} {
	    setStatus "missing </em> in help"
	    bell
	    set idx [$textw index "$idx +1c"]
	} else {
	    # get rid of the '</em>' marker
	    $textw delete $idx2 "$idx2 +5c"
	    $textw tag add italic $idx $idx2
	    set idx $idx2
	}
	set idx [$textw search -forwards -exact -- {<em>} $idx end]
    }

    # decorate ----
    set idx [$textw search -forwards -regexp -- {^----} "1.0" end]
    while {$idx != {}} {
	# get rid of the '----' marker
	$textw delete $idx "$idx +4c"
	incr vsd(ruleCount)
	set fn "$textw.rule$vsd(ruleCount)"
	frame $fn -relief raised -borderwidth 3 -height 6 -width 300
	$textw window create $idx -window $fn -align center -padx 20 -pady 8
	set idx [$textw search -forwards -regexp -- {^----} $idx end]
    }
    
    # decorate hlinks
    set idx [$textw search -forwards -exact -- \[ "1.0" end]
    while {$idx != {}} {
	# get rid of the '[' marker
	$textw delete $idx
	if {[string equal [$textw get $idx] "\["]} {
	    # [[ escapes the bracket
	    set idx [$textw index "$idx +1c"]
	} else {
	    set idx2 [$textw search -forwards -exact -- \] $idx "$idx lineend"]
	    if {$idx2 == {}} {
		setStatus "missing ']' in help"
		bell
		set idx [$textw index "$idx +1c"]
	    } else {
		# get rid of the ']' marker
		$textw delete $idx2
		incr vsd($w:hlinkCount)
		set hlinkName "hlink$vsd($w:hlinkCount)"
		set hlinkText [$textw get $idx $idx2]
		if {[string first ">" $hlinkText] != -1} {
		    set hlinkList [split $hlinkText ">"]
		    set hlinkDisplay [string trim [lindex $hlinkList 0]]
		    set hlinkText [string trim [lindex $hlinkList 1]]
		    set newIdx2 [$textw index  "$idx +[string length $hlinkDisplay]c"]
		    $textw delete $newIdx2 $idx2
		    set idx2 $newIdx2
		}
		if {[info exists vsdhelp($hlinkText)]} {
		    set brokenLink 0
		} else {
		    set brokenLink 1
		}
		if {$brokenLink && [wizardMode]} {
		    puts "warning: help link '$hlinkText' does not exist."
		}
		$textw tag add $hlinkName $idx $idx2
		if {$brokenLink} {
		    $textw tag configure $hlinkName -underline 1 -foreground $vsd(brokenLinkColor)
		} elseif [info exists vsdLinkVisited($hlinkText)] {
		    $textw tag configure $hlinkName -underline 1 -foreground $vsd(visitedLinkColor)
		} else {
		    $textw tag configure $hlinkName -underline 1 -foreground $vsd(normalLinkColor)
		}
		$textw tag bind $hlinkName <1> [list followHelpLink $w $hlinkText]
		$textw tag bind $hlinkName <Control-1> [list followHelpLink {} $hlinkText]
		$textw tag bind $hlinkName <2> [list followHelpLink {} $hlinkText]
		$textw tag bind $hlinkName <3> [list followHelpLink {} $hlinkText]
		$textw tag bind $hlinkName <Enter> "$textw configure -cursor hand2"
		$textw tag bind $hlinkName <Leave> "$textw configure -cursor $vsd($w:normalCursor)"
		set idx $idx2
	    }
	}
	set idx [$textw search -forwards -exact -- \[ $idx end]
    }
    # do special character substitutions
    set idx [$textw search -forwards -exact -- {&#91;} "1.0" end]
    while {$idx != {}} {
	$textw insert "$idx" \[
	$textw delete "$idx +1c" "$idx +6c"
	set idx [$textw search -forwards -exact -- {&#91;} $idx end]
    }

    $textw configure -state disabled -wrap word
    if {$doHistory} {
	$textw yview moveto [lindex $vsd($w:historyPositions) $vsd($w:helpHistoryIdx)]
    }
}

event add <<Help>> <KeyPress-F1> <KeyPress-Help>
bind all <<Help>> {ContextSensitiveHelp %W}

proc ContextSensitiveHelp {w} {
    global widgetHelp
    while {$w != ""} {
	if [info exists widgetHelp($w)] {
	    doHelp $widgetHelp($w) {} 0
	    return
	}
	set w [winfo parent $w]
    }
    setStatus "no help available"
    bell
}

proc showChartHelp {} {
    doHelp "Chart Window Features"
}

proc showMainHelp {} {
    doHelp "Main Window Features"
}

proc HowToHelp {} {
    global vsdhelp
    set howtoTopic "How To Guide"
    if {![info exists vsdhelp($howtoTopic)]} {
	set help {}
	foreach topic [lsort [array names vsdhelp]] {
	    if [string match {*How to*} $topic] {
		append help "*\[$topic]\n"
	    }
	}
	set vsdhelp($howtoTopic) $help
    }
    doHelp $howtoTopic
}

proc wizardMode {} {
    global env vsd
    return [expr ([info exists env(VSD_WIZARD)] || [info exists vsd(wizard)])]
}

proc allHelp {} {
    global vsdhelp
    set allTopic "All Topics"
    if [wizardMode] {
	catch {unset vsdhelp($allTopic)}
    }
    if {![info exists vsdhelp($allTopic)]} {
	set help {}
	foreach topic [lsort [array names vsdhelp]] {
	    if [isHiddenTopic $topic] {
		continue
	    }
	    append help "*\[" $topic "]\n"
	}
	set vsdhelp($allTopic) $help
    }
    doHelp $allTopic
}

proc allFlatHelp {} {
    global vsdhelp
    set allTopic "All Help Text"
    if [wizardMode] {
	catch {unset vsdhelp($allTopic)}
    }
    if {![info exists vsdhelp($allTopic)]} {
	set help {}
	foreach topic [lsort [array names vsdhelp]] {
	    if [isHiddenTopic $topic] {
		continue
	    }
	    append help "----\n"
	    append help "!\t$topic\n"
	    append help [getHelpText $topic]
	}
	set vsdhelp($allTopic) $help
    }
    doHelp $allTopic
}

proc showNewFeatures {} {
    doHelp "Version History"
}

proc showAboutHelp {} {
    doHelp "About VSD"
}

proc UsageVSD {parent} {
    global vsd
    if {$vsd(warningGiven)} {
	return
    }
    set vsd(warningGiven) 1

    set usagevsd "VSD is an unsupported tool that is intended \
for use by GemStone Consulting Services only.
Problem reports and enhancement requests should be sent to $vsd(maintainer).
Please do not contact GemStone Technical Support for VSD support.
If you want to use VSD, even though it is unsupported, click 'Yes'.
If you want to quit now, click 'No'."

    if {[info commands tk_messageBox] != ""} {
	set response [tk_messageBox -title "VSD Usage Notice" \
			  -parent $parent -icon question -type yesno \
			  -default yes -message $usagevsd]
	if {[string equal $response "no"]} {
	    exit
	}
    } else {
	set w [tixDialogShell .usagevsd -parent $parent \
	       -title "VSD Usage Notice"]

	frame $w.top -relief raised -bd 1
	pack $w.top -side top -fill both -expand yes

	tixScrolledText $w.top.msg -scrollbar y -width 410 -height 150
	[$w.top.msg subwidget text] insert end $usagevsd
	[$w.top.msg subwidget text] configure -state disabled -wrap word
	pack $w.top.msg -expand yes -fill both

	tixButtonBox $w.box
	$w.box add continue -text "Yes" -width 4 \
	    -command "destroy $w"
	$w.box add quit -text "No" -width 4 \
	    -command "destroy $w; exit"
	pack $w.box -fill x -side bottom
	$w popup
    }
}

if {[info commands tk_messageBox] != ""} {
  # use tk_messageBox
  proc makeErrorDialog {w} {
    # do nothing
  }

  proc showError {msg} {
    global vsd
    tk_messageBox -icon error -parent $vsd(w) -title "Error" -message $msg \
	-type ok
  }

  proc fatalError {msg} {
    showError $msg
    exit
  }

} else {
  proc makeErrorDialog {w} {
    global vsd
    set d [tixDialogShell .vsderror -parent $w -title "Error"]
    set vsd(dlg:error) $d

    frame $d.top -relief raised -bd 1
    pack $d.top -side top -fill both

    label $d.top.msg -wraplength 3i -justify left -text "foo" \
	    -font -Adobe-Times-Medium-R-Normal--*-180-*-*-*-*-*-*
    pack $d.top.msg -side right -expand 1 -fill both -padx 3m -pady 3m
    label $d.top.bitmap -bitmap "error"
    pack $d.top.bitmap -side left -padx 3m -pady 3m

    tixButtonBox $d.box
    $d.box add dismiss -text Dismiss -width 6 -underline 0 \
	-command {$vsd(dlg:error) popdown; set vsd(fatalError) 1}
    set but [$d.box subwidget dismiss]
    bind $d <Alt-d> "$but invoke"
    pack $d.box -fill x -expand yes -side bottom
  }

  proc showError {msg} {
    global vsd
    set w $vsd(dlg:error)
    $w.top.msg configure -text $msg
    regexp {(.*x.*)(\+.*\+.*)} [wm geometry $vsd(w)] junk parentSize parentPosition
    wm geometry $w $parentPosition
    $w popup
  }

  proc fatalError {msg} {
    global vsd
    set vsd(fatalError) 0
    showError $msg
    tkwait variable vsd(fatalError)
    exit
  }
}

proc replayLog {str} {
    # NYI
}

proc writeTemplateFile {} {
   global vsd vsdtemplates

    if [catch {open "~/.vsdtemplates" w+} initFile] {
        showError "Notice: could not write '~/.vsdtemplates' because:\n$initFile"
	return
    }
    puts $initFile {
# See the vsd help section 'Template Syntax' for a guide to editing this file.
}

    foreach tn [lsort [array names vsdtemplates]] {
	puts $initFile "set vsdtemplates($tn) [list $vsdtemplates($tn)]"
    }

    close $initFile
}

proc addFileListMap {dfid} {
    global filelistMap
    set key [getFileInfoName $dfid]
    set filelistMap($key) $dfid
    return $key
}

proc getFullFileName {fi} {
    global filelistMap
    if [info exists filelistMap($fi)] {
	return [lindex [$filelistMap($fi) -info] 0]
    } else {
	return $fi
    }
}

proc writeStartupFile {} {
    global vsd vsdtemplates

    if [catch {open "~/.vsdrc_tmp" w+} initFile] {
        showError "Notice: could not write '~/.vsdrc' because:\n$initFile"
	return
    }
puts $initFile "\# .vsdrc is written whenever vsd exits normally.
\# Each time vsd is started it reads .vsdrc and will use the configuration
\# values in it. If you want to always have some other default put it
\# in .vsdconfig. Any user changes to .vsdrc will be lost the next time
\# vsd exits.
"
    puts $initFile "set vsd(confirmonexit) $vsd(confirmonexit)"
    puts $initFile "set vsd(warningGiven) $vsd(warningGiven)"
    if 0 {
	puts $initFile "set vsd(timesync) [list $vsd(timesync)]"
    }
    foreach cw $vsd(winnames) {
	if [winfo exists $cw] {
	    set vsd(geometry:$cw) [wm geometry $cw]
	}
	puts $initFile "set vsd(geometry:$cw) [list $vsd(geometry:$cw)]"
    }

    puts $initFile "set vsd(def:geometry) [wm geometry $vsd(w)]"
    puts $initFile "set vsd(autoUpdateTime) [list $vsd(autoUpdateTime)]"
    puts $initFile "set vsd(def:showlegend) [list $vsd(def:showlegend)]"
    puts $initFile "set vsd(def:xformat) [list $vsd(def:xformat)]"
    puts $initFile "set vsd(def:linestyle) [list $vsd(def:linestyle)]"
    puts $initFile "set vsd(def:xaxis:showtitle) [list $vsd(def:xaxis:showtitle)]"
    puts $initFile "set vsd(def:yaxis:showtitle) [list $vsd(def:yaxis:showtitle)]"
    puts $initFile "set vsd(def:y2axis:showtitle) [list $vsd(def:y2axis:showtitle)]"
    puts $initFile "set vsd(def:showcrosshairs) [list $vsd(def:showcrosshairs)]"
    puts $initFile "set vsd(def:showgridlines) [list $vsd(def:showgridlines)]"
    puts $initFile "set vsd(def:showcurxy) [list $vsd(def:showcurxy)]"
    puts $initFile "set vsd(def:showminmax) [list $vsd(def:showminmax)]"
    puts $initFile "set vsd(def:showlinestats) [list $vsd(def:showlinestats)]"
    puts $initFile "set vsd(def:sortbytype) [list $vsd(def:sortbytype)]"
    puts $initFile "set vsd(def:sortdecreasing) [list $vsd(def:sortdecreasing)]"

    puts $initFile "set vsd(showCtrInfo) [list $vsd(showCtrInfo)]"
    puts $initFile "set vsd(absoluteTSMode) [list $vsd(absoluteTSMode)]"
    puts $initFile "set vsd(copyChildren) [list $vsd(copyChildren)]"
    puts $initFile "set vsd(singleFileMode) [list $vsd(singleFileMode)]"
    puts $initFile "set vsd(templatesUseSelection) [list $vsd(templatesUseSelection)]"

    puts $initFile "set vsd(wv:statmoninterval) [list $vsd(wv:statmoninterval)]"
    puts $initFile "set vsd(wv:statmonflush) [list $vsd(wv:statmonflush)]"
    puts $initFile "set vsd(wv:statmonlevel) [list $vsd(wv:statmonlevel)]"
    puts $initFile "set vsd(wv:statmonappstats) [list $vsd(wv:statmonappstats)]"
    puts $initFile "set vsd(wv:statmonsessions) [list $vsd(wv:statmonsessions)]"
    puts $initFile "set vsd(wv:statmonpids) [list $vsd(wv:statmonpids)]"
    puts $initFile "set vsd(wv:statmoncompress) [list $vsd(wv:statmoncompress)]"

    puts $initFile "set vsd(activecolor) $vsd(activecolor)"
    puts $initFile "set vsd(combineInstances) $vsd(combineInstances)"
    puts $initFile "set vsd(combineFiles) $vsd(combineFiles)"
    puts $initFile "set vsd(noFlatlines) $vsd(noFlatlines)"
    puts $initFile "set vsd(traceAPICalls) $vsd(traceAPICalls)"

    if {![info exists vsd(lastVersionRun)] || ($vsd(lastVersionRun) < $vsd(version))} {
	puts $initFile "set vsd(lastVersionRun) $vsd(version)"
    } else {
	puts $initFile "set vsd(lastVersionRun) $vsd(lastVersionRun)"
    }

    puts $initFile "set vsd(instancePaneSize) [.vsd.mainPane panecget instances -size]"
    puts $initFile "set vsd(statisticPaneSize) [.vsd.mainPane panecget statistics -size]"


    foreach n [array names vsd *:geomid] {
	set w [lindex [split $n ":"] 0]
	if [winfo exists $w] {
	    rememberGraphGeometry $w
	}
    }
    foreach n [array names vsd *:graphgeometry] {
	set geom $vsd($n)
	# don't bother remembering funny geometries
	if {![string match "1x1+*" $geom]} {
	    puts $initFile "set vsd($n) [list $geom]"
	}
    }

    puts $initFile "set vsd(smallfont) [list [font actual vsdsf]]"
    puts $initFile "set vsd(textfont) [list [font actual normalTextFont]]"

    set tmplist {}
    foreach fi $vsd(filelist) {
	set f [getFullFileName $fi]
	if {[file exists $f]} {
	    lappend tmplist $f
	}
    }
    # We only want to remember the last 10 files loaded
    puts $initFile "set vsd(filelist) [list [lrange $tmplist 0 9]]"

    puts $initFile "sl_stat -level [sl_stat -level]"
    foreach level [array names vsd level:*] {
	puts $initFile "set vsd($level) $vsd($level)"
    }
    foreach filter [array names vsd filter:*] {
	puts $initFile "set vsd($filter) $vsd($filter)"
    }

    global ctrAliases
    if [info exists ctrAliases] {
	puts $initFile "global ctrAliases"
	puts $initFile "array set ctrAliases [list [array get ctrAliases]]"
    }
    
    puts $initFile {
# templates are now stored in ~/.vsdtemplates.
}
    if [catch {close $initFile} errStr] {
        showError "Notice: could not close '~/.vsdrc' because:\n$errStr"
	return
    }
    if [catch {file rename -force "~/.vsdrc_tmp"  "~/.vsdrc"} errStr] {
        showError "Notice: could not rename '~/.vsdrc_tmp' to '~/.vsdrc' because:\n$errStr"
	return
    }
}

proc fillCounters {force procs} {
    global vsd

    set objlist {}
    set instIdList {}
    if {$procs != {}} {
	foreach ientry $procs {
	    set entryData [$vsd(instanceList) info data $ientry]
	    set objset([lindex $entryData 1]) 1
	    lappend instIdList [lindex $entryData 6]
	}
	set objlist [lsort [array names objset]]
    }

    if {$force || ![string equal $instIdList $vsd(selectedInstIds)]} {
	set selCtr [getSelCtr]
	if {$selCtr != {}} {
	    set vsd(lastSelCtr) $selCtr
	}
	clearCounters
	set vsd(counterType) $objlist
	set vsd(selectedInstIds) $instIdList
	set tc ""
	if [info exists vsd(lastSelCtr)] {
	    set tc $vsd(lastSelCtr)
	}
	set ctrlist [lsort -dictionary [sl_stat -objctrs $objlist]]
	set cl $vsd(w:counterHList)
	set anchorSet 0
	foreach c $ctrlist {
	    set isZero [sl_stat -ctrzero $c $instIdList]
	    if {$vsd(noFlatlines) && $isZero} {
		lappend vsd(zeroCtrs) $c
		# Skip this counter
		continue
	    }
	    set entry [$cl addchild "" -data $c -itemtype text -text $c -style $vsd(ctr$isZero:s)]
	    if {[lsearch -exact $tc $c] != -1} {
		if {!$anchorSet} {
		    set anchorSet 1
		    $cl anchor set $entry
		    $cl see $entry
 		    showCounterInfo $c
		}
		$cl selection set $entry
	    }
	}
	updateDisabledItems
    }
}

proc updateDisabledItems {} {
    global vsd
    set newstate "normal"
    set procs [$vsd(instanceList) info selection]
    if {$procs == {} || [getSelCtr] == {}} {
	set newstate "disabled"
    }

    # newstate should be "normal" or "disabled"
#    $vsd(w:counterList) configure -state $newstate
    $vsd(w:addline) configure -state $newstate
    #$vsd(w:newchart) configure -state $newstate
    $vsd(w:chartmenu) entryconfigure "Add To Chart" -state $newstate
    #$vsd(w:chartmenu) entryconfigure "New Chart..." -state $newstate

    $vsd(w:mainmenu) entryconfigure "Copy Selection" -state $newstate

    return $procs
}

proc updateGraphWidgetState {} {
    global vsd

    $vsd(w:templatemenu) entryconfigure "New Template Chart" -state normal

    fillCounters 0 [updateDisabledItems]
}

proc showFileForAnchor {} {
    global vsd
    set anchor [$vsd(instanceList) info anchor]
    if {$anchor != {}} {
	set data [$vsd(instanceList) info data $anchor]
	set fd [lindex $data 5]
	if {![string equal $fd $vsd(statsrc)]} {
	    set vsd(statsrc) $fd
	    changeFile $fd
	}
    }
}

proc instanceBrowse {junk} {
    set t [tixEvent type]
    # fix for bug 22784
    set updateEvents {"<ButtonRelease-1>" "<Application>" "<Up>" "<Down>"
	"<Shift-Up>" "<Shift-Down>" "<Left>" "<Right>"}
    if {[lsearch -exact $updateEvents $t] != -1} {
	showFileForAnchor
	updateGraphWidgetState
    }
}

proc getSortedFiles {} {
    global vsd
    
    if {$vsd(def:sortdecreasing)} {
        return [lsort -decreasing -dictionary [sl_stat -enabledfiles]]
    } else {
	return [lsort -dictionary [sl_stat -enabledfiles]]
    }
}
    
proc sortWithKeys {l} {
    global vsd
    
    if {$vsd(def:sortdecreasing)} {
	return [lsort -decreasing -dictionary -index end $l]
    } else {
	return [lsort -dictionary -index end $l]
    }
}

proc instSort {l} {
    return [sortWithKeys [addSortKeysToList $l]]
}

proc instCompare {i1 i2} {
    global vsd
    set x1 0
    set x2 0
    switch -exact $vsd(def:sortbytype) {
	"Type" -
	"Name" {
	    # Use the sort key that was appended to the end
	    set x1 [lindex $i1 end]
	    set x2 [lindex $i2 end]
	    if {$vsd(def:sortdecreasing)} {
		return [string compare $x2 $x1]
	    } else {
		return [string compare $x1 $x2]
	    }
	}
	"Pid" -
	"Samples" {
	    # Use the sort key that was appended to the end
	    set x1 [lindex $i1 end]
	    set x2 [lindex $i2 end]
	}
	"StartTime" {
	    set x1 [lindex $i1 2]
	    set x2 [lindex $i2 2]
	}
	"File" {
	    set x1 [lindex $i1 5]
	    set x2 [lindex $i2 5]
	}
    }
    if {$x1 == $x2} {
	return 0
    }
    if {$vsd(def:sortdecreasing)} {
	if {$x1 > $x2} {
	    return -1
	} else {
	    return 1
	}
    } else {
	if {$x1 < $x2} {
	    return -1
	} else {
	    return 1
	}
    }
}

proc addInst {l inst {position ""}} {
    global vsd
    global vsdinstmap

    set needsPid 1
    set needsSession 0
    set obj [lindex $inst 1]
    # strip off any object version extension
    set obj [file rootname $obj]
    if {[string equal $obj "Gem"] ||
	[string equal $obj "Session"] ||
	[string equal $obj "Extent"] ||
	[string equal $obj "GcSession"]} {
	set needsSession 1
    } elseif {[string equal $obj "AppStat"] ||
        [string equal $obj "IOStat"]} {
	set needsPid 0
    }

    set instid [lindex $inst 6]
    set fullname [lindex $inst 0]
    set name [lindex $fullname 0]
    if {$needsSession} {
	set session [lindex $fullname 2]
	if {$session != 0 || [string equal $obj "Extent"]} {
	    append name "-$session"
	}
    }
    global vsdnametable
    if [info exists vsdnametable($name)] {
	incr vsdnametable($name)
    } else {
	set vsdnametable($name) 1
    }

    if {$position == ""} {
	set row [$l addchild "" -data $inst]
    } else {
	set row [$l addchild "" -at $position -data $inst]
    }
    set vsdinstmap($instid) $row
    
    # Start time
    $l item create $row $vsd(ilColumnIdx:StartTime) -itemtype text \
	-text [sl_stat -getdate [lindex $inst 2] "date"] -style $vsd(time:s)
    # File
    $l item create $row $vsd(ilColumnIdx:File) -itemtype text -text [getFileId [lindex $inst 5]] \
	-style $vsd(time:s)
    # Number of samples
    $l item create $row $vsd(ilColumnIdx:Samples) -itemtype text -text [lindex $inst 4] \
	-style $vsd(samples[lindex $inst 3]:s)
    # Pid
    if {$needsPid} {
	set pid [lindex $fullname 1]
	if {$pid != 0 && $pid != -1} {
	    $l item create $row $vsd(ilColumnIdx:Pid) -itemtype text -text $pid
	}
    }
    # Type
    $l item create $row $vsd(ilColumnIdx:Type) -itemtype text -text [lindex $inst 1]
    # Name
    $l item create $row $vsd(ilColumnIdx:Name) -itemtype text -text $name -style $vsd(name:s)
    return $row
}

proc setInstanceList {} {
    global vsd
    global vsdinstmap
    if {![info exists vsd(instanceList)]} {
	return
    }

    set l $vsd(instanceList)

    set selectedInstances {}
    foreach e [$l info selection] {
	set instid [lindex [$l info data $e] 6]
	lappend selectedInstances $instid
    }
    set oldAnchor [$l info anchor]
    if {$oldAnchor != {}} {
	set instid [lindex [$l info data $oldAnchor] 6]
	set oldAnchor $instid
    }
    
    $l delete all
    if [info exists vsdinstmap] {
	unset vsdinstmap
    }
    set instances [sl_stat -enabledinstances]
    if {$instances == {}} {
	return
    }
    global vsdnametable
    if [info exists vsdnametable] {
	unset vsdnametable
    }
#    set start [getMillis]
    set prevSortKey "PSI:$vsd(def:sortbytype):$vsd(def:sortdecreasing)"
    if {[info exists vsd($prevSortKey)] && [string equal $instances $vsd(previousUnsortedInstances)]} {
        set sortedInstances $vsd($prevSortKey)
    } else {
        set sortedInstances [instSort $instances]
        set vsd(previousUnsortedInstances) $instances
        set vsd($prevSortKey) $sortedInstances
    }
#     set end [getMillis]
#     puts "DEBUG: sorting took [expr {$end - $start}]"
#     set vsd(stats:addInst:count) 0
#     set start [getMillis]
    foreach i $sortedInstances {
#    incr vsd(stats:addInst:count)
	set e [addInst $l $i]
	set instid [lindex $i 6]
	if {$instid == $oldAnchor} {
	    $l anchor set $e
	    $l see $e
	}
	if {[lsearch -exact $selectedInstances $instid] != -1} {
	    $l selection set $e
	}
    }
#     set end [getMillis]
#     puts "DEBUG: process sortedInstances took [expr {$end - $start}]"
#     puts "DEBUG: addInst count $vsd(stats:addInst:count)"
}

proc getMillis {} {
    #  -milliseconds
    return [clock clicks]
}

proc instanceCommand {e} {
    global vsd

    doChart 0
}

proc getPrimTypeSortKey {inst} {
    return [string tolower [lindex $inst 1]]
}
proc getPrimStartTimeSortKey {inst} {
    return [lindex $inst 2]
}
proc getPrimPidSortKey {inst} {
    return [lindex [lindex $inst 0] 1]
}
proc getPrimFileSortKey {inst} {
    return [lindex $inst 5]
}
proc getPrimNameSortKey {inst} {
    set nameData [lindex $inst 0]
    set res [string tolower [lindex $nameData 0]]
    set nameId [lindex $nameData 2]
    if {$nameId != {}} {
        append res "_"
        append res $nameId
    }
    return $res
}

proc getTypeSortKey {inst} {
    set key [getPrimTypeSortKey $inst]
    append key "_"
    append key [getPrimNameSortKey $inst]
    append key "_"
    append key [getPrimFileSortKey $inst]
    append key "_"
    append key [getPrimPidSortKey $inst]
    append key "_"
    append key [getPrimStartTimeSortKey $inst]
    return $key
}

proc getNameSortKey {inst} {
    set key [getPrimNameSortKey $inst]
    append key "_"
    append key [getPrimTypeSortKey $inst]
    append key "_"
    append key [getPrimFileSortKey $inst]
    append key "_"
    append key [getPrimPidSortKey $inst]
    append key "_"
    append key [getPrimStartTimeSortKey $inst]
    return $key
}

proc getSamplesSortKey {inst} {
    set key [lindex $inst 4]
    if {[lindex $inst 3]} {
	set key [expr {$key ^ 0x04000000}]
    }
    append key "_"
    append key [getTypeSortKey $inst]
    return $key
}

proc getPidSortKey {inst} {
    set key [getPrimPidSortKey $inst]
    append key "_"
    append key [getPrimTypeSortKey $inst]
    append key "_"
    append key [getPrimNameSortKey $inst]
    append key "_"
    append key [getPrimFileSortKey $inst]
    append key "_"
    append key [getPrimStartTimeSortKey $inst]
    return $key
}

proc getFileSortKey {inst} {
    set key [getPrimFileSortKey $inst]
    append key "_"
    append key [getPrimTypeSortKey $inst]
    append key "_"
    append key [getPrimNameSortKey $inst]
    append key "_"
    append key [getPrimPidSortKey $inst]
    append key "_"
    append key [getPrimStartTimeSortKey $inst]
    return $key
}

proc getStartTimeSortKey {inst} {
    set key [getPrimStartTimeSortKey $inst]
    append key "_"
    append key [getPrimTypeSortKey $inst]
    append key "_"
    append key [getPrimNameSortKey $inst]
    append key "_"
    append key [getPrimFileSortKey $inst]
    append key "_"
    append key [getPrimPidSortKey $inst]
    return $key
}

proc addSortKeysToList {instlist} {
    global vsd
    set reslist {}
    switch -exact $vsd(def:sortbytype) {
	"Type" {
	    foreach inst $instlist {
		lappend inst [getTypeSortKey $inst]
		lappend reslist $inst
	    }
	}
	"Name" {
	    foreach inst $instlist {
		lappend inst [getNameSortKey $inst]
		lappend reslist $inst
	    }
	}
	"Samples" {
	    foreach inst $instlist {
		lappend inst [getSamplesSortKey $inst]
		lappend reslist $inst
	    }
	}
	"Pid" {
	    foreach inst $instlist {
		lappend inst [getPidSortKey $inst]
		lappend reslist $inst
	    }
	}
	"File" {
	    foreach inst $instlist {
		lappend inst [getFileSortKey $inst]
		lappend reslist $inst
	    }
	}
	"StartTime" {
	    foreach inst $instlist {
		lappend inst [getStartTimeSortKey $inst]
		lappend reslist $inst
	    }
	}
	default {
	    set reslist $instlist
	}
    }
    return $reslist
}

proc addSortKey {inst} {
    global vsd
    switch -exact $vsd(def:sortbytype) {
	"Type" {
	    lappend inst [getTypeSortKey $inst]
	}
	"Name" {
	    lappend inst [getNameSortKey $inst]
	}
	"Samples" {
	    lappend inst [getSamplesSortKey $inst]
	}
	"Pid" {
	    lappend inst [getPidSortKey $inst]
	}
	"File" {
	    lappend inst [getFileSortKey $inst]
	}
	"StartTime" {
	    lappend inst [getStartTimeSortKey $inst]
	}
    }
    return $inst
}

# insertInstance currently assumes that only a single copy needs
# to be inserted.
proc insertInstance {l inst} {
    global vsd
    set inst [addSortKey $inst]
    set sortList {}
    lappend sortList $inst
    foreach c [$l info children] {
	lappend sortList [$l info data $c]
    }
    set sortList [sortWithKeys $sortList]
    set idx [lsearch -exact $sortList $inst]
    return [addInst $l $inst $idx]
}

proc updateInstanceList {} {
    setInstanceList
    # The following code used to be used instead of setInstanceList.
    # It works well if the instance list is small but was became very
    # slow with large instance lists.
#     global vsd
#     global vsdinstmap
#     if {![info exists vsd(instanceList)]} {
# 	return
#     }
#     set instances [sl_stat -enabledinstances]
#     if {$instances == {}} {
# 	return
#     }
#     set l $vsd(instanceList)
#     foreach i $instances {
# 	set n [lindex $i 6]
# 	if {[info exists vsdinstmap($n)]} {
# 	    set e $vsdinstmap($n)
# 	    set edata [$l info data $e]
# 	    if {[lindex $edata 3] != [lindex $i 3]} {
# 		set setAnchor [string equal $e [$l info anchor]]
# 		set setSelect [$l selection includes $e]   
# 		$l delete entry $e
# 		set e [insertInstance $l $i]
# 		if {$setAnchor} {
# 		    $l anchor set $e
# 		    $l see $e
# 		}
# 		if {$setSelect} {
# 		    $l selection set $e
# 		}
# 	    } else {
# 		set iSamples [lindex $i 4]
# 		if {[lindex $edata 4] != $iSamples} {
# 		    $l entryconfigure $e -data [addSortKey $i]
# 		    $l item configure $e $vsd(ilColumnIdx:Samples) -text $iSamples
# 		}
# 	    }
# 	} else {
# 	    insertInstance $l $i
# 	}
#     }
}

proc destroyProgress {w} {
    global vsd
    
    catch {focus $vsd(progress_oldFocus)}
    unset vsd(progress_oldFocus)
    destroy $w
    if {$vsd(progress_oldGrab) != ""} {
	if {$vsd(progress_grabStatus) == "global"} {
	    grab -global $vsd(progress_oldGrab)
	} else {
	    grab $vsd(progress_oldGrab)
	}
	unset vsd(progress_oldGrab)
	unset vsd(progress_grabStatus)
    }
    update
}

proc showProgress {percentCompleted} {
    global vsd
    set parent $vsd(w)
    set w "$parent.progress"

    if {[winfo exists $w]} {
	if {$percentCompleted == 100} {
	    destroyProgress $w
	    return 1
	}
	update
	if {$vsd(progressCanceled)} {
	    destroyProgress $w
	    return 0
	}
    } else {
	set vsd(progressCanceled) 0
	toplevel $w -class Dialog
	wm title $w "Loading Data File"
	wm iconname $w Dialog
	wm protocol $w WM_DELETE_WINDOW { }
	wm transient $w $parent

	frame $w.bot -relief raised -bd 1
	pack $w.bot -side bottom -fill both
	frame $w.top -relief raised -bd 1
	pack $w.top -side top -fill both -expand 1

	label $w.top.title -text "Load in progress ...."
	pack $w.top.title -side top -expand 1 -fill x -padx 3m -pady 3m
	if {$vsd(hasMeter)} {
	    tixMeter $w.msg -value 0 -text "0%"
	} else {
	    label $w.msg -justify center -anchor center
	}
	pack $w.msg -in $w.top -side bottom -expand 1 -fill both -padx 3m -pady 3m -anchor c
	tixButtonBox $w.bot.box
	$w.bot.box add cancel -text "Interrupt" \
	    -command {set vsd(progressCanceled) 1}
	pack $w.bot.box -fill both -expand 1
	$vsd(balloon) bind $w.bot.box -msg "Interrupts can be continued later by doing a \"File|Update\""

	regexp {(.*x.*)(\+.*\+.*)} [wm geometry $parent] junk parentSize parentPosition
	wm geometry $w $parentPosition

	set vsd(progress_oldFocus) [focus]
	set vsd(progress_oldGrab) [grab current $w]
	if {$vsd(progress_oldGrab) != ""} {
	    set vsd(progress_grabStatus) [grab status $vsd(progress_oldGrab)]
	}
	grab $w
	focus $w
    }
    if {$vsd(hasMeter)} {
	$w.msg config -value [expr double($percentCompleted) / 100] \
	    -text "$percentCompleted%"
    } else {
	$w.msg configure -text "loaded $percentCompleted%"
    }
    update
    return 1
}

proc getLastDataFileName {} {
    global vsd
    return [getFullFileName $vsd(lastdatafile)]
}

proc updateFileTrimMenuItems {finfo} {
    global vsd

    set firstTS [lindex $finfo 9]
    set trimLeftTS [lindex $finfo 10]
    set trimRightTS [lindex $finfo 11]

    if {$firstTS != $trimLeftTS} {
	$vsd(w:filemenu) entryconfigure "Untrim Left" -state normal
    } else {
	$vsd(w:filemenu) entryconfigure "Untrim Left" -state disabled
    }
    if {$trimRightTS != -1} {
	$vsd(w:filemenu) entryconfigure "Untrim Right" -state normal
    } else {
	$vsd(w:filemenu) entryconfigure "Untrim Right" -state disabled
    }
    
}

proc changeFile {fd} {
    global vsd
    set vsd(autoUpdate) $vsd(autoUpdate:$fd)
	
    if {$vsd(updateok:$fd)} {
	$vsd(w:filemenu) entryconfigure "Update" -state normal
	$vsd(w:filemenu) entryconfigure "Auto Update" -state normal
    } else {
	$vsd(w:filemenu) entryconfigure "Update" -state disabled
	$vsd(w:filemenu) entryconfigure "Auto Update" -state disabled
    }
	
    set statsrcInfo [$fd -info]
    set vsd(file:isEnabled) [lindex $statsrcInfo 7]

    updateFileTrimMenuItems $statsrcInfo
    
    # If the file info window is up then update it
# BUG this was deadcoded because fileInfo currently always steal the focus
#     if [winfo exists .vsdfileinfo] {
# 	fileInfo
#     }
    set vsd(lastdatafile) [addFileListMap $fd]
    $vsd(w:filelist) configure -disablecallback true
    $vsd(w:filelist) configure -value $vsd(lastdatafile)
    $vsd(w:filelist) configure -disablecallback false
}

proc setDataFile {fname} {
    global vsd

    if {$fname != {} && [string equal "relative" [file pathtype $fname]]} {
	set fname [file join [pwd] $fname]
    }
    if {$fname != {} && $fname != [getLastDataFileName]} {
	replayLog "setDataFile $fname"
	if {$vsd(appendMode)} {
	    if [catch {$vsd(statsrc) -append $fname} result] {
		set msg "Could not append data file \'$fname\' because: "
		append msg $result
		showError $msg
	    } else {
		# NYI: Its not clear how much needs to be done after an append
		setInstanceList
		updateGraphWidgetState
	    }
	    set vsd(appendMode) 0
	    return
	}
	if [catch {sl_create -file $fname showProgress} result] {
	    set msg "Could not load data file \'$fname\' because: "
	    append msg $result
	    showError $msg
	    # set the w:filelist back to the lastdatfile loaded
	    $vsd(w:filelist) configure -disablecallback true
	    $vsd(w:filelist) configure -value $vsd(lastdatafile)
	    $vsd(w:filelist) configure -disablecallback false
	    return
	}
	    
	addUniqueFileName $result

	foreach type [lindex [$result -info] 8] {
	    generateTypeHelp $type
	}
	
	if {$vsd(singleFileMode)} {
	    if {$vsd(statsrc) != {}} {
		$vsd(statsrc) -disable
	    }
	    $result -enable
	}
	
	set vsd(statsrc) $result
	fillCounters 1 {}
	updateCounterList

	if {![info exists vsd(updateok:$result)]} {
	    set vsd(updateok:$result) 1
	    set vsd(autoUpdate:$result) 0
	}

	changeFile $result

	if {[$vsd(w:filemenu) entrycget "Info..." -state] == "disabled"} {
	    # We have a file loaded so enable the 'file' menu items
	    $vsd(w:filemenu) entryconfigure "Info..." -state normal
	    # $vsd(w:filemenu) entryconfigure "Absolute TimeStamps" -state normal
	    $vsd(w:filemenu) entryconfigure "Enabled" -state normal
	    if [wizardMode] {
		$vsd(w:filemenu) entryconfigure "Dump" -state normal
	    }
	}

	set ldfn [getLastDataFileName]
	set idx [lsearch -exact $vsd(filelist) $ldfn]
	if {$idx != -1} {
	    set vsd(filelist) [lreplace $vsd(filelist) $idx $idx]
	    set lb [$vsd(w:filelist) subwidget listbox]
	    set historyList [$lb get 0 end]
	    set idx [lsearch -exact $historyList $ldfn]
	    if {$idx != -1} {
		$lb delete $idx $idx
	    }
	}
	set idx [lsearch -exact $vsd(filelist) $vsd(lastdatafile)]
	if {$idx != -1} {
	    # Delete from the list; it will go on the front
	    set vsd(filelist) [lreplace $vsd(filelist) $idx $idx]
	    set lb [$vsd(w:filelist) subwidget listbox]
	    set historyList [$lb get 0 end]
	    set idx [lsearch -exact $historyList $vsd(lastdatafile)]
	    if {$idx != -1} {
		$lb delete $idx $idx
	    }
	}
	$vsd(w:filelist) insert 1 $vsd(lastdatafile)
	set vsd(filelist) [linsert $vsd(filelist) 0 $vsd(lastdatafile)]

	setInstanceList
	updateGraphWidgetState
    } else {
	# set the w:filelist back to the lastdatfile loaded
	$vsd(w:filelist) configure -disablecallback true
	$vsd(w:filelist) configure -value $vsd(lastdatafile)
	$vsd(w:filelist) configure -disablecallback false
    }
    set vsd(appendMode) 0
}

proc browseDataFile {} {
    global vsd
    if {$vsd(w:fileselector) != ""} {
	if 0 { # the -dir seems broken in Tix4.0.5
	    set fsbox [$vsd(w:fileselector) subwidget fsbox]
	    set lastfn [getLastDataFileName]
	    if {$lstfn != {}} {
		set dir [file dirname $lastfn]
		$fsbox configure -dir $dir
	    }
	}
	$vsd(w:fileselector) popup
    } else {
	set lastfn [getLastDataFileName]
	if {$lastfn != {}} {
	    set dir [file dirname $lastfn]
	    regsub -all "/" $dir "\\" dir
	} else {
	    set dir "."
	}
	set types {
	    {"All statistic data files" {.gfs .out .out.gz}}
	    {"Uncompressed GemFire archive files" {.gfs}}
	    {"Uncompressed StatMonitor data files" {.out}}
	    {"Compressed StatMonitor data files" {.out.gz}}
	    {"All files" {*}}
	}
	set fname [tk_getOpenFile -title "Open StatMonitor File" \
		       -parent $vsd(w) \
		       -initialdir $dir \
		       -filetypes $types]
	setDataFile $fname
    }
}

proc loadBrowsedDataFile {fname} {
    global vsd
    $vsd(w:fileselector) popdown 
    setDataFile $fname
}
    
proc chooseDataFile {fname} {
    if {$fname == "Browse For File..."} {
	global vsd
	$vsd(w:filelist) configure -disablecallback true
	$vsd(w:filelist) configure -value $vsd(lastdatafile)
	$vsd(w:filelist) configure -disablecallback false
	# Bring up a dialog that lets the user browse for a file
	browseDataFile
    } else {
	setDataFile [getFullFileName $fname]
    }
}

proc printGraph {graph name} {
    global vsd
    myBusyOn $graph
# NYI: BLT has special support for printing on NT. The graph widget has print1 and print2 commands. However 'blt::printer names' always returns empty list for me
    if [catch {$graph postscript output $name \
		   -landscape true -decorations false \
		   -colormode grey -padx .25i -pady .25i} result] {
	showError $result
    } elseif [catch {eval exec $vsd(exec:lpr) $name} result] {
	showError "$vsd(exec:lpr) $name failed: $result"
    } else {
	catch {file delete -force $name}
    }
    myBusyOff $graph
}

proc snapshotGraph {graph name} {
    global vsd
    set outputName "snapshot.gif"
    myBusyOn $graph
    set photo [image create photo -format gif]
    $graph snap $photo
    catch {file delete -force $outputName}
    $photo write $outputName -format gif
    image delete $photo
    myBusyOff $graph
}

# stripFloat removes a trailing .0 from a number
proc stripFloat {v} {
    set l [string length $v]
    incr l -1
    if {[string index $v $l] == "0"} {
	incr l -1
	if {[string index $v $l] == "."} {
	    incr l -1
	    return [string range $v 0 $l]
	}
    }
    return $v
}

proc updateAllLineTrimMenuItems {} {
    global bltActiveEntry
    global vsd

    foreach g [array names bltActiveEntry] {
	set e $bltActiveEntry($g)
	if {$e != -1} {
	    set mf "[winfo parent $g].mf"
	    set linfo [$vsd(ed:$e:$g) -info]
	    updateLineTrimMenuItems $mf.line.m [lindex $linfo 7]
	}
    }
}

proc updateLineTrimMenuItems {m datafiles} {
    set isTrimmedLeft 0
    set isTrimmedRight 0
    foreach dfid $datafiles {
	set dfinfo [$dfid -info]
	set firstTS [lindex $dfinfo 9]
	set trimLeftTS [lindex $dfinfo 10]
	set trimRightTS [lindex $dfinfo 11]
	if {$firstTS != $trimLeftTS} {
	    set isTrimmedLeft 1
	}
	if {$trimRightTS != -1} {
	    set isTrimmedRight 1
	}
	if {$isTrimmedLeft && $isTrimmedRight} {
	    break;
	}
    }
    if {$isTrimmedLeft} {
	$m entryconfigure "Untrim Left" -state normal
    } else {
	$m entryconfigure "Untrim Left" -state disabled
    }
    if {$isTrimmedRight} {
	$m entryconfigure "Untrim Right" -state normal
    } else {
	$m entryconfigure "Untrim Right" -state disabled
    }
}

proc showLineInfo {graph element} {
    global vsd
    set mf "[winfo parent $graph].mf"
    if {$element == {}} {
	$mf.line configure -state disabled
	set min ""
	set max ""
	set filter none
	set symbol none
	set style linear
	set counter ""
	hideMarker $graph triStart
	hideMarker $graph triEnd
	set isDerived 0
    } else {
	$mf.line configure -state normal
	if {[$graph element cget $element -mapy] == "y"} {
	    set vsd($graph:graphonleft) 1
	} else {
	    set vsd($graph:graphonleft) 0
	}
	set edata [$vsd(ed:$element:$graph) -info]
	set vsd($graph:normalized) [lindex $edata 11]
	set counter [lindex $edata 1]
	set yvname [lindex $edata 3]
        set scale [lindex $edata 4]
	#set filter [lindex $edata 5]
        set filter [getCommonFilter $graph [lindex $edata 5]]
#	set obj [lindex $edata 6]
#	set dfids [lindex $edata 7]
	if {[lindex $edata 9] == {}} {
	    set isDerived 0
	} else {
	    set isDerived 1
	}
	set symbol [$graph element cget $element -symbol]
	set style [$graph element cget $element -smooth]
	global $yvname
	set min [set ${yvname}(min)]
	if {$min == {}} {
	    set min 0.0
	}
	set max [set ${yvname}(max)]
	if {$max == {}} {
	    set max 0.0
	}
	if {$scale != 1} {
	    # Need to unscale min and max
	    set min [expr $min / $scale]
	    set max [expr $max / $scale]
	}
	updateLineTrimMenuItems $mf.line.m [lindex $edata 7]
	showCounterInfo $counter
    }
    set vsd($graph:linesym) $symbol
    set vsd($graph:linestyle) $style

    set f [$mf.min subwidget frame]
    $f.l configure -text [stripFloat $min]

    set f [$mf.max subwidget frame]
    $f.l configure -text [stripFloat $max]

    $mf.linef.counter configure -state normal
    $mf.linef.counter configure -disablecallback true
    # Note that the contents of the counter listbox is not computed
    # until the user drops it down. At that time chartComputeCounters
    # is called.
    if {$isDerived} {
	$mf.linef.counter configure -value [getCtrAlias $counter]
	$mf.linef.counter configure -state disabled
    } else {
	$mf.linef.counter configure -value $counter
	$mf.linef.counter configure -disablecallback false
    }
    if {$filter != {}} {
        $mf.linef.filtertype configure -state normal
        $mf.linef.filtertype configure -disablecallback true
        $mf.linef.filtertype configure -value $filter
        $mf.linef.filtertype configure -disablecallback false
    } else {
	$mf.linef.filtertype configure -state disabled
    }
    if {$element == {}} {
	$mf.linef.counter configure -state disabled
	$mf.linef.filtertype configure -state disabled
	$mf.linef.opMenu configure -state disabled
	$mf.linef.const configure -state disabled
    } else {
	$mf.linef.opMenu configure -state normal
	$mf.linef.const configure -state normal
	changeConstOp $graph {}
    }

    set f [$mf.curx subwidget frame]
    $f.l configure -text ""
    set f [$mf.cury subwidget frame]
    $f.l configure -text ""
}

proc lineIncrConst {newVal} {
    global vsd
    switch -exact $vsd(constOp) {
	"divide" -
	"multiply" -
	"scale" {
	    return [expr $newVal * 2.0]
	}
	"add" -
	"subtract" {
	    return [expr $newVal + 1]
	}
    }
}

proc lineDecrConst  {newVal} {
    global vsd
    switch -exact $vsd(constOp) {
	"divide" -
	"multiply" -
	"scale" {
	    return [expr $newVal / 2.0]
	}
	"add" -
	"subtract" {
	    return [expr $newVal - 1]
	}
    }
}

proc lineValidateConst {g newVal} {
    global vsd
    if [catch {expr double($newVal)} val] {
	setStatus "The string \"$newVal\" is not a valid number."
	bell
	return 1
    }
    switch -exact $vsd(constOp) {
	"scale" -
	"multiply" {
	    if {$val == 0} {
		setStatus "Can't multiply by zero."
		bell
		return 1
	    }
	}
	"divide" {
	    if {$val == 0} {
		setStatus "Can't divide by zero."
		bell
		return 1
	    }
	}
	"add" {
	    set e [getSelectedLine $g]
	    if {$e != {}} {
		set l $vsd(ed:$e:$g)
		set linfo [$l -info]
		set normalized [lindex $linfo 11]
		set offset [expr - [lindex $linfo 12]]
		if {$normalized && $offset != $val} {
		    # can't change adder/subtractor if line is normalized
		    setStatus "Can't add to normalized line."
		    bell
		    return $offset
		}
	    }
	}
	"subtract" {
	    set e [getSelectedLine $g]
	    if {$e != {}} {
		set l $vsd(ed:$e:$g)
		set linfo [$l -info]
		set normalized [lindex $linfo 11]
		set offset [lindex $linfo 12]
		if {$normalized && $offset != $val} {
		    # can't change subtractor if line is normalized
		    setStatus "Can't subtract from normalized line."
		    bell
		    return $offset
		}
	    }
	}
    }
    return $newVal
}

proc lineChangeConst {g newVal} {
    global vsd
    switch -exact $vsd(constOp) {
	"scale" {
	    lineChangeScale $g $newVal
	}
	"divide" {
	    lineDivideConst $g $newVal
	}
	"multiply" {
	    lineDivideConst $g [expr {1.0 / $newVal}]
	}
	"add" {
	    lineAddConst $g $newVal
	}
	"subtract" {
	    lineAddConst $g [expr - $newVal]
	}
    }
}

proc changeConstOp {g constOp} {
    global vsd
    set e [getSelectedLine $g]
    if {$e != {}} {
	set mf "[winfo parent $g].mf"
	set l $vsd(ed:$e:$g)
	set linfo [$l -info]
	set scale [lindex $linfo 4]
	set normalized [lindex $linfo 11]
	set offset [lindex $linfo 12]
	set divider [lindex $linfo 13]
	if {$constOp == {}} {
	    # pick the best one
	    set hasScale [expr {$scale != 1.0}]
	    set hasOffset [expr {$offset != 0.0}]
	    set hasDivider [expr {$divider != 1.0}]
	    # first check to see if constOp already set to something non-default for this line
	    switch -exact $vsd(constOp) {
		"scale" {
		    if {$hasScale} {
			set constOp $vsd(constOp)
		    }
		}
		"multiply" -
		"divide" {
		    if {$hasDivider} {
			set constOp $vsd(constOp)
		    }
		}
		"subtract" -
		"add" {
		    if {$hasOffset} {
			set constOp $vsd(constOp)
		    }
		}
	    }
	    if {$constOp == {}} {
		# still have not picked one so look for one for
		# which this line has a non-default value
		if {$hasDivider} {
		    # make it "divide" or "multiply"
		    if {[expr {abs($divider)}] >= 1.0} {
			set vsd(constOp) "divide"
		    } else {
			set vsd(constOp) "multiply"
		    }
		} elseif {$hasOffset} {
		    # make it "add" or "subtract"
		    if {$offset < 0} {
			set vsd(constOp) "add"
		    } else {
			set vsd(constOp) "subtract"
		    }
		} elseif {$hasScale} {
		    set vsd(constOp) "scale"
		}
		set constOp $vsd(constOp)
	    }
	}
	$mf.linef.const configure -disablecallback true
	switch -exact $constOp {
	    "scale" {
		$mf.linef.const configure -value $scale
	    }
	    "divide" {
		$mf.linef.const configure -value $divider
	    }
	    "multiply" {
		$mf.linef.const configure -value [expr {1.0 / $divider}]
	    }
	    "add" {
		if {$offset != 0} {
		    $mf.linef.const configure -value [expr {- $offset}]
		} else {
		    $mf.linef.const configure -value $offset
		}
	    }
	    "subtract" {
		$mf.linef.const configure -value $offset
	    }
	}
	$mf.linef.const configure -disablecallback false
    }
}

proc lineAddConst {g const} {
    global vsd
    set e [getSelectedLine $g]
    if {$e != {}} {
	set l $vsd(ed:$e:$g)
	$l -adder $const
	updateLineDataDisplay $g $e $l
    }
}

proc lineDivideConst {g const} {
    global vsd
    set e [getSelectedLine $g]
    if {$e != {}} {
	set l $vsd(ed:$e:$g)
	$l -divider $const
	updateLineDataDisplay $g $e $l
    }
}

proc lineChangeScale {g newVal} {
    global vsd
    set e [getSelectedLine $g]
    if {$e != {}} {
	set l $vsd(ed:$e:$g)
	$l -scale $newVal
	updateLineDataDisplay $g $e $l
    }
}

proc setCurXY {graph elem x y} {
    global vsd
    set mf "[winfo parent $graph].mf"

    set linfo [$vsd(ed:$elem:$graph) -info]
    set scale [lindex $linfo 4]
    if {$scale != 1} {
	# Need to remove the scale so that the Y value reported will be real
	set y [expr $y / $scale]
    }

    set f [$mf.curx subwidget frame]
    set xstr [sl_stat -getdate [expr int($x)] $vsd($graph:xformat)]
    $f.l configure -text $xstr
    set f [$mf.cury subwidget frame]
    $f.l configure -text [stripFloat $y]
}

proc closeAllCharts {} {
    global vsd
    foreach name [array names vsd  ct:*] {
	set w $vsd($name)
	set g $w.graph
	closeGraph $w $g
    }
}

proc getGraphGeometry {w} {
    global vsd
    if {$vsd(freeGeometryIds) == {}} {
	set geomid $vsd(graphcount)
	set vsd($w:geomid) $geomid
	if [info exists vsd($geomid:graphgeometry)] {
	    set result $vsd($geomid:graphgeometry)
	} else {
	    set result "600x300+1+1"
	    set vsd($geomid:graphgeometry) $result
	}
    } else {
	set geomid [lindex $vsd(freeGeometryIds) end]
	set vsd(freeGeometryIds) [lreplace $vsd(freeGeometryIds) end end]
	set vsd($w:geomid) $geomid
	set result $vsd($geomid:graphgeometry)
    }
    return $result
}

proc rememberGraphGeometry {w} {
    global vsd
    set geomid $vsd($w:geomid)
    lappend vsd(freeGeometryIds) $geomid
    set vsd($geomid:graphgeometry) [wm geometry $w]
}

proc closeGraph {w g} {
    global vsd
    global bltActiveGraph
    global bltActiveEntry

    incr vsd(graphcount) -1
    rememberGraphGeometry $w

    if {[string equal $vsd(longOpW) $w]} {
	cancelLongOp
    }
	
    update idletasks

    if {[info exists bltActiveGraph($g,alarmid)]} {
	after cancel $bltActiveGraph($g,alarmid)
	unset bltActiveGraph($g,alarmid)
	unset bltActiveGraph($g,x)
	unset bltActiveGraph($g,y)
    }

    if [info exists bltActiveEntry($g)] {
	unset bltActiveEntry($g)
    }
    if [info exists bltActiveGraph($g)] {
	unset bltActiveGraph($g)
    }
    if [info exists bltActiveGraph($g,closest)] {
	unset bltActiveGraph($g,closest)
    }
    if [info exists bltActiveGraph($g,oldSelectedLines)] {
	unset bltActiveGraph($g,oldSelectedLines)
    }

    foreach e [$g element names] {
	$vsd(ed:$e:$g) -free
	unset vsd(ed:$e:$g)
    }

    set title [wm title $w]
    unset vsd(ct:$title)
    set idx 0
    set listbox [$vsd(w:chartlist) subwidget listbox]
    foreach t [$listbox get 0 end] {
	if {[string equal $t $title]} {
	    $listbox delete $idx
	    if {$idx == 0} {
		set curwintitle [$listbox get 0]
		if [info exists vsd(ct:$curwintitle)] {
		    $vsd(w:chartlist) pick 0
		} else {
		    $vsd(w:chartlist) configure -disablecallback true
		    $vsd(w:chartlist) pick 0
		    $vsd(w:chartlist) configure -disablecallback false
		}
	    }
	    break
	}
	incr idx
    }
    destroy $w
}

proc chartFocus {w} {
    global vsd
    set title [wm title $w]
    if {![info exists vsd(ct:$title)]} {
	return
    }
    if {[string equal $vsd(ct:$title) $w]} {
        if {![string equal $vsd(curchart) $title]} {
	    $vsd(w:chartlist) configure -disablecallback true
	    $vsd(w:chartlist) addhistory $title
	    $vsd(w:chartlist) pick 0
	    $vsd(w:chartlist) configure -disablecallback false
	}
    }
}

proc getAxisTitle {g axis} {
    global vsd
    global bltActiveEntry

    if {[info exists bltActiveEntry($g)] && $bltActiveEntry($g) != -1} {
	set e $bltActiveEntry($g)
	if {[string equal $axis "xaxis"]} {
	    return [getElementXAxisTitle $g $e]
	} else {
	    set activeAxis [$g element cget $e -mapy]
	    append activeAxis "axis"
	    if {[string equal $activeAxis $axis]} {
		return [getElementYAxisTitle $g $e]
	    }
	}
    }
    return $vsd($axis:defaultTitle)
}

proc chartAxisTitle {g axis} {
    global vsd
    if {$vsd($g:$axis:showtitle)} {
	set title [getAxisTitle $g $axis]
    } else {
	set title ""
    }
    $g $axis configure -title $title
}

proc chartShowCrossHairs {g} {
    global vsd
    if {$vsd($g:showcrosshairs)} {
	Blt_CrosshairsOn $g
    } else {
	Blt_CrosshairsOff $g
    }
}

proc chartShowLegend {g} {
    global vsd
    mapLegend $g $vsd($g:showlegend)
}

proc chartShowGridLines {g} {
    global vsd
    if {$vsd($g:showgridlines)} {
	$g grid on 
    } else {
	$g grid off
    }
}

proc chartShowCurXY {w mf} {
    global vsd
    if {[lsearch -exact [pack slaves $mf] $mf.min] != -1} {
	set afterW $mf.min
    } else {
	set afterW $mf.linef
    }
    if {$vsd($w:showcurxy)} {
	pack $mf.cury $mf.curx -after $afterW -side right -padx 2
    } else {
	pack forget $mf.cury $mf.curx
    }
}

proc chartShowMinMax {w mf} {
    global vsd
    if {$vsd($w:showminmax)} {
	pack $mf.max $mf.min -after $mf.linef -side right -padx 2
    } else {
	pack forget $mf.max $mf.min
    }
}

proc chartCancelOp {g} {
    # default to zoom out
    chartCancelOpZoom $g
}

proc chartZoom {g} {
    global vsd

    if {$vsd($g:chartOp) != {}} {
	# do the above check so that default right click action not taken
	chartCancelOp$vsd($g:chartOp) $g
    }

    set vsd($g:chartOp) "Zoom"
    $g config -cursor top_left_corner
    hideMarker $g activeLine
    set title "Click to start zoom, right click to cancel"
    $g marker create text -name "bltZoom_title" -text $title \
	    -coords {-Inf Inf} -anchor nw -bg {} -font vsdsf
}

proc chartSetMinTime {g} {
    global vsd

    if {$vsd($g:chartOp) != {}} {
	# do the above check so that default right click action not taken
	chartCancelOp$vsd($g:chartOp) $g
    }

    set vsd($g:chartOp) "MinTime"
    $g config -cursor left_side
    set title "Click to set min time, right click to cancel"
    hideMarker $g activeLine
    $g marker create text -name "chartop_title" -text $title \
	    -coords {-Inf Inf} -anchor nw -bg {} -font vsdsf
}

proc chartSetMaxTime {g} {
    global vsd

    if {$vsd($g:chartOp) != {}} {
	# do the above check so that default right click action not taken
	chartCancelOp$vsd($g:chartOp) $g
    }

    set vsd($g:chartOp) "MaxTime"
    $g config -cursor right_side
    set title "Click to set max time, right click to cancel"
    hideMarker $g activeLine
    $g marker create text -name "chartop_title" -text $title \
	    -coords {-Inf Inf} -anchor nw -bg {} -font vsdsf
}

proc getTemplateProcName {pname ptype} {
    # added to fix bug 18996
    set res "*"
    switch -exact [string tolower $ptype] {
	disk -
	pgsvr -
        session -
        gcsession -
	gem {
	    # Need to strip unique id off end of name and replace with a *
	    regsub {[0-9]+$} $pname {*} res
	}
	vm {
	    switch -glob [string tolower $pname] {
		"gsjvm*" { set res "gsjVM*"}
		"gsvm*" { set res "gsVM*"}
		"gns*" { set res "gns*"}
		"*sap" { set res "*sap"}
		"*gc" { set res "*GC"}
		"*activator" { set res "*Activator"}
		"*otsagent" { set res "*OTSAgent"}
		"*rnsagent" { set res "*RNSAgent"}
	    }
	}
    }
    return $res
}

proc getTemplateLineSpec {li yaxis} {
    global vsd
    # proc-type proc-name stat-name scale filter axis
    set ptlist {}
    foreach pt [lindex $li 6] {
	# strip off any object type version
	lappend ptlist [file rootname $pt]
    }
    set procType $ptlist
    set instList [lindex $li 8]
    set operator [lindex $li 9]
    if {[llength $instList] > 1} {
	if {$operator != {}} {
	    set ls1 [getTemplateLineSpec [lindex $instList 0] $yaxis]
	    set ls2 [getTemplateLineSpec [lindex $instList 1] $yaxis]
	    switch -exact -- $operator {
		"+" {set opcode "plus"}
		"-" {set opcode "diff"}
		"/" {set opcode "divide"}
	    }
	    set lineSpec [list $opcode $ls1 $ls2 \
			      [lindex $li 4] [lindex $li 5] $yaxis \
			      [lindex $li 13] [lindex $li 12] [lindex $li 11]]
	    return $lineSpec
	} else {
	    append procType "+"
	    set procName "*"
	}
    } else {
	set procName [getTemplateProcName [lindex [lindex $li 0] 0] $procType]
    }
    set lineSpec [list $procType $procName [lindex $li 1] \
		      [lindex $li 4] [lindex $li 5] $yaxis \
		      [lindex $li 13] [lindex $li 12] [lindex $li 11]]
    return $lineSpec
}

proc getTemplateName {parent defaultName} {
    global vsd
    set vsd(template:tv) "$defaultName"
    update ;# allows startSearch to be called from popup menu
    set vsd(template:parent) $parent
    set vsd(template:oldfocus) [focus]
    set vsd(template:result) {}
    set w ".vsdtemplateName"
    set entry [$w.f.entry subwidget entry]
    
    set width [winfo width $parent]
    set x [winfo rootx $parent]
    set y [winfo rooty $parent]
    set dialogheight [winfo height $w]
    if {$dialogheight == 1} {
	set dialogheight [winfo reqheight $w]
	if {$dialogheight == 1} {
	    set dialogheight 32
	}
    }
    set y [expr $y - $dialogheight]
    wm deiconify $w
    raise $w
    wm geometry $w "${width}x$dialogheight+$x+$y"
    focus $entry
    tkwait variable vsd(template:result)
    return $vsd(template:result)
}

proc saveGraphTemplate {g n} {
    global vsd vsdtemplates
    set n [getTemplateName $g $n]
    if {![info exists vsdtemplates($n)]} {
	addTemplateMenu $vsd(w:templatecascade) $n
    }
    set vsdtemplates($n) {} ;# template line list
    foreach e [lsort -integer [$g element names]] {
	set yaxis [$g element cget $e -mapy]
	set li [$vsd(ed:$e:$g) -info]
	set lineSpec [getTemplateLineSpec $li $yaxis]
	if {[lsearch -exact $vsdtemplates($n) $lineSpec] == -1} {
	    lappend vsdtemplates($n) $lineSpec
	}
    }
    writeTemplateFile
}

proc lineUpdate {g} {
    global vsd
    set e [getSelectedLine $g]
    if {$e != {}} {
	set l $vsd(ed:$e:$g)
	foreach dfid [lindex [$l -info] 7] {
	    fileUpdate $dfid
	}
    }
}

proc getLineStyle {g e} {
    $g element cget $e -smooth
}

proc addLineToClipboard {l g e} {
    global vsd
    emptyClipboard
    lappend vsd(clipboard) "linecmd"
    lappend vsd(clipboard) [list $l [$g element cget $e -mapy] [$g element cget $e -symbol] [getLineStyle $g $e]]
    
}

proc lineCut {g} {
    global vsd
    set e [getSelectedLine $g]
    if {$e != {}} {
	addLineToClipboard $vsd(ed:$e:$g) $g $e
	deleteElement $g $e 0
    }
}

proc lineCopy {g} {
    global vsd
    set e [getSelectedLine $g]
    if {$e != {}} {
	addLineToClipboard [$vsd(ed:$e:$g) -copy] $g $e
    }
}


proc lineDelete {g} {
    global vsd
    foreach e [getSelectedLines $g] {
	deleteElement $g $e
    }
}

proc lineCombine {g op title} {
    global vsd

    set e [getSelectedLine $g]
    if {$e == {}} {
	return
    }
    if {$vsd($g:chartOp) != {}} {
	# do the above check so that default right click action not taken
	chartCancelOp$vsd($g:chartOp) $g
    }
    set vsd($g:combineData) [list $e $op]
    set vsd($g:chartOp) "Combine"
    $g config -cursor crosshair
    hideMarker $g activeLine
    append title ", right click to cancel"
    $g marker create text -name "chartop_title" -text $title \
	    -coords {-Inf Inf} -anchor nw -bg {} -font vsdsf
}

proc lineAdd {g} {
    lineCombine $g "+" "Select line to add with"
}
proc lineDivide {g} {
    lineCombine $g "/" "Select line to divide by"
}
proc lineDiff {g} {
    lineCombine $g "-" "Select line to diff with"
}

proc getLineInfoStr {linfo {indent ""}} {
    set nextindent "$indent  "
    foreach dfid [lindex $linfo 7] {
	lappend dfnames [lindex [$dfid -info] 0]
    }

    set ctrunits [getStatUnits [lindex $linfo 1]]
    set infoStr "${indent}Line: [lrange $linfo 0 1] "
    set subtractor [lindex $linfo 12]
    set divider [lindex $linfo 13]
    if {$divider != 1.0} {
	if {[expr {abs($divider)}] >= 1.0} {
	    append infoStr "/ $divider "
	} else {
	    append infoStr "* [expr {1.0 / $divider}] "
	}
    }
    if {$subtractor != 0} {
	if {$subtractor < 0} {
	    append infoStr "+ [expr {- $subtractor}] "
	} else {
	    append infoStr "- $subtractor "
	}
    }
    set ctr [lindex $linfo 1]
    set ctrAlias [getCtrAlias $ctr]
    if {![string equal $ctr $ctrAlias]} {
	append infoStr "alias: $ctrAlias "
    }
    append infoStr "filter: [lindex $linfo 5]  units: $ctrunits "
    if {[lindex $linfo 11] != 0} {
	append infoStr "normalized "
    }
    if {[llength $dfnames] > 1} {
	append infoStr "files: $dfnames"
    } else {
	append infoStr "file: $dfnames"
    }

    set instList [lindex $linfo 8]
    set operator [lindex $linfo 9]
    if {$operator != {}} {
	append infoStr "\n${indent}    derived using \"$operator\" from these two lines:"
	append infoStr "\n${indent}    [getLineInfoStr [lindex $instList 0] $nextindent]"
	append infoStr "\n${indent}    [getLineInfoStr [lindex $instList 1] $nextindent]"
    } elseif {[llength $instList] > 1} {
	append infoStr " dataSources:"
	foreach id $instList {
	    append infoStr "\n${indent}    [lindex [sl_stat -instinfo $id] 0]"
	}
    }
    return $infoStr
}

proc lineInfo {g} {
    global vsd

    set infoStr {}
    foreach e [getSelectedLines $g] {
        set l $vsd(ed:$e:$g)
        append infoStr [getLineInfoStr [$l -info]]

        set xStart [$g xaxis cget -min]
        set xEnd [$g xaxis cget -max]
        set lstats [$l -stats $xStart $xEnd]
        set samples [lindex $lstats 0]
        set min [lindex $lstats 1]
        set max [lindex $lstats 2]
        set ave [lindex $lstats 3]
        set stddev [lindex $lstats 4]
        set startString [xToStr $g [lindex $lstats 5]]
        set endString [xToStr $g [lindex $lstats 6]]
        append infoStr "\n  Starting at $startString and ending at $endString:"
        append infoStr "\n    sample count: $samples  min: $min  max: $max"
        append infoStr "\n    average: $ave  stddev: $stddev\n"
    }
    if {$infoStr != {}} {
        showData $infoStr
    }
}

proc lineDelta {g} {
    global vsd

    set e [getSelectedLine $g]
    if {$e == {}} {
	return
    }

    if {$vsd($g:chartOp) != {}} {
	# do the above check so that default right click action not taken
	chartCancelOp$vsd($g:chartOp) $g
    }

    set vsd($g:deltaLine) $e
    if [info exists vsd($g:deltapoint1)] {
	unset vsd($g:deltapoint1)
    }
    set vsd($g:chartOp) "Delta"
    $g config -cursor crosshair
    hideMarker $g activeLine
    set title "Click on first data point, right click to cancel"
    $g marker create text -name "chartop_title" -text $title \
	    -coords {-Inf Inf} -anchor nw -bg {} -font vsdsf
}

proc lineTrimLeft {g} {
    global vsd

    set e [getSelectedLine $g]
    if {$e == {}} {
	return
    }

    if {$vsd($g:chartOp) != {}} {
	# do the above check so that default right click action not taken
	chartCancelOp$vsd($g:chartOp) $g
    }

    set vsd($g:trimLine) $e
    set vsd($g:trimLeft) 1
    set vsd($g:chartOp) "Trim"
    $g config -cursor crosshair
    hideMarker $g activeLine
    set title "Click on first good data point, right click to cancel"
    $g marker create text -name "chartop_title" -text $title \
	    -coords {-Inf Inf} -anchor nw -bg {} -font vsdsf
}

proc lineTrimRight {g} {
    global vsd

    set e [getSelectedLine $g]
    if {$e == {}} {
	return
    }

    if {$vsd($g:chartOp) != {}} {
	# do the above check so that default right click action not taken
	chartCancelOp$vsd($g:chartOp) $g
    }

    set vsd($g:trimLine) $e
    set vsd($g:trimLeft) 0
    set vsd($g:chartOp) "Trim"
    $g config -cursor crosshair
    hideMarker $g activeLine
    set title "Click on last good data point, right click to cancel"
    $g marker create text -name "chartop_title" -text $title \
	    -coords {-Inf Inf} -anchor nw -bg {} -font vsdsf
}


proc lineUntrimLeft {g} {
    global vsd

    set e [getSelectedLine $g]
    if {$e == {}} {
	return
    }

    $vsd(ed:$e:$g) -trimleft 0
    trimUpdate $g $e
}

proc lineUntrimRight {g} {
    global vsd

    set e [getSelectedLine $g]
    if {$e == {}} {
	return
    }

    $vsd(ed:$e:$g) -trimright -1
    trimUpdate $g $e
}

proc lineNormalize {g} {
    global vsd

    set e [getSelectedLine $g]
    if {$e == {}} {
	return
    }

    set l $vsd(ed:$e:$g)
    if {$vsd($g:normalized)} {
	$l -normalize
    } else {
	$l -unnormalize
    }
    updateDerivedLines
}

proc trimUpdate {graph element} {
    global vsd

    updateFileTrimMenuItems [$vsd(statsrc) -info]
    updateAllLineTrimMenuItems
    setInstanceList
    updateGraphWidgetState
    updateAllActiveLines
}

proc chartCompare {g} {
    global vsd

    if {$vsd($g:chartOp) != {}} {
	# do the above check so that default right click action not taken
	chartCancelOp$vsd($g:chartOp) $g
    }

    if [info exists vsd($g:compareLine1)] {
	unset vsd($g:compareLine1)
    }
    if [info exists vsd($g:comparepoint1)] {
	unset vsd($g:comparepoint1)
    }
    set vsd($g:chartOp) "Compare"
    $g config -cursor crosshair
    hideMarker $g activeLine
    set title "Click on first data point, right click to cancel"
    $g marker create text -name "chartop_title" -text $title \
	    -coords {-Inf Inf} -anchor nw -bg {} -font vsdsf
}

proc emptyClipboard {} {
    global vsd
    foreach {type data} $vsd(clipboard) {
	switch -exact $type {
	    "linecmd" {
		[lindex $data 0] -free
	    }
	}
    }
    set vsd(clipboard) {}
}

proc chartPaste {w g} {
    global vsd
    foreach {type data} $vsd(clipboard) {
	switch -exact $type {
	    "linecmd" {
		set mapaxis [lindex $data 1]
		set symbol [lindex $data 2]
		set style [lindex $data 3]
		addLineToChart [lindex $data 0] 0 1 $mapaxis $symbol $style
	    }
	    "selection" {
		addToChart 0 [lindex $data 0] [lindex $data 1]
	    }
	}
    }
    set vsd(clipboard) {}
}

proc getCtrAlias {ctr} {
    global ctrAliases
    if [info exists ctrAliases($ctr)] {
	return $ctrAliases($ctr)
    } else {
	return $ctr
    }
}

proc getLineLegendLabel {i lineinfo} {
    global vsd
    set instinfo [lindex $lineinfo 0]
    set lineinst [lindex $instinfo 0]
    set obj [lindex $lineinfo 6]
    # strip off any object version extension
    set obj [file rootname $obj]
    if {[string equal $obj "Gem"] ||
        [string equal $obj "Session"] ||
	[string equal $obj "Extent"] ||
	[string equal $obj "GcSession"]} {
	# add session id on end of name
	set session [lindex $instinfo 2]
	if {$session != 0 || [string equal $obj "Extent"]} {
	    append lineinst "-$session"
	}
    }
    global vsdnametable
    if {[info exists vsdnametable($lineinst)] && $vsdnametable($lineinst) > 1} {
	set pid [lindex $instinfo 1]
	if {$pid != 0 && $pid != -1} {
	    append lineinst "_[lindex $instinfo 1]"
	}
	if {[string equal $lineinst "_Total"]} {
	    set lineinst "$obj$lineinst"
	}
    }
    
    set linectr [getCtrAlias [lindex $lineinfo 1]]
    set linefilter [lindex $lineinfo 5]

    if {[string equal $linefilter "none"]} {
	set label "$i.  $lineinst, $linectr"
    } elseif {[string equal $linefilter "aggregate"]} {
	set label "$i.  $lineinst, $linectr+"
    } elseif {[string equal $linefilter "smooth"]} {
	set label "$i.  $lineinst, $linectr~"
    } else {
	if {[string equal $linefilter "persecond"]} {
	    set label "$i.  $lineinst, $linectr/sec"
	} elseif {[string equal $linefilter "persample"]} {
	    set label "$i.  $lineinst, $linectr/sample"
	} else {
	    set label "$i.  $lineinst, $linectr, $linefilter"
	}
    }
}

proc lineFilter {g filter} {
    global vsd
    foreach e [getSelectedLines $g] {
	set line $vsd(ed:$e:$g)
	$line -refilter $filter
    }
    updateDerivedLines
}

proc lineSymbol {g symbol} {
    global vsd
    set e [getSelectedLine $g]
    if {$e != {}} {
	$g element configure $e -symbol $symbol
    }
}

proc lineMenuSymbol {g} {
    global vsd
    lineSymbol $g $vsd($g:linesym)
}

proc lineStyle {g style} {
    global vsd
    set e [getSelectedLine $g]
    if {$e != {}} {
	$g element configure $e -smooth $style
    }
}

proc lineMenuStyle {g} {
    global vsd
    lineStyle $g $vsd($g:linestyle)
}

proc lineGraphOnLeft {g} {
    global vsd
    set e [getSelectedLine $g]
    if {$e != {}} {
	if {$vsd($g:graphonleft)} {
	    set mapaxis "y"
	    set unmap "y2"
	} else {
	    set mapaxis "y2"
	    set unmap "y"
	}
	$g element configure $e -mapy $mapaxis
	deactivateAxis $g
	activateAxis $g $e

	showAxis $g ${mapaxis}axis
	if {[string equal $mapaxis "y"]} {
	    $g configure -leftmargin 0
	} else {
	    $g configure -rightmargin 0
	}

	foreach e [$g element names] {
	    if {[string equal $unmap [$g element cget $e -mapy]]} {
		return;
	    }
	}
	# No more lines using this axis so unmap it
	hideAxis $g ${unmap}axis
	if {[string equal $unmap "y"]} {
	    $g configure -leftmargin 2
	} else {
	    $g configure -rightmargin 2
	}
    }
}

proc updateLineDataDisplay {g e line} {
    $g marker configure activeLine -text [getLineLabel $g $e]
    set label [getLineLegendLabel $e [$line -info]]
    $g element configure $e -label $label
    chartAxisTitle $g [$g element cget $e -mapy]axis
    chartAxisTitle $g "xaxis"
    showLineInfo $g $e
}

proc chartChangeCounter {g newctr} {
    global vsd
    set e [getSelectedLine $g]
    if {$e != {}} {
	set line $vsd(ed:$e:$g)
	$line -changectr $newctr
	updateDerivedLines
    }
}

# call updateDerivedLines if a line has been changed in a way that can
# cause the info about a derived line to change.
proc updateDerivedLines {} {
    global bltActiveEntry
    global vsd

    # make sure every active line's info is correct
    foreach g [array names bltActiveEntry] {
	if {$bltActiveEntry($g) != -1} {
	    set e $bltActiveEntry($g)
	    set line $vsd(ed:$e:$g)
	    updateLineDataDisplay $g $e $line
	}
    }
    # make sure the names in the legend of each graph
    foreach n [array names vsd ed:*] {
	set nl [split $n ':']
	set e [lindex $nl 1]
	set g [lindex $nl 2]
	set line $vsd($n)
	set label [getLineLegendLabel $e [$line -info]]
	$g element configure $e -label $label
     }
}
    
proc chartBrowseCounters {c} {
    showCounterInfo $c
}

proc chartComputeCounters {g mf} {
    global vsd
    set e [getSelectedLine $g]
    if {$e != {}} {
	set linfo [$vsd(ed:$e:$g) -info]
	set obj [lindex $linfo 6]
	set instId [lindex $linfo 10]
	set counter [$mf.linef.counter cget -value]
	if {$vsd(noFlatlines)} {
	    set newctrlistid [list $obj $instId]
	} else {
	    set newctrlistid $obj
	}
	if {$vsd($g:ctrlistid) != {}} {
	    if {[string equal $newctrlistid $vsd($g:ctrlistid)]} {
		# the listbox already contains the right stuff
		set lb [$mf.linef.counter subwidget listbox]
		set endIdx [$lb size]
		set idx 0
		while {$idx < $endIdx} {
		    if {[string equal $counter [$lb get $idx]]} {
			$mf.linef.counter configure -disablecallback true
			$mf.linef.counter pick $idx
			$mf.linef.counter configure -disablecallback false
			break
		    }
		    incr idx
		}
		return
	    }
	}
	set vsd($g:ctrlistid) $newctrlistid
	set cb $mf.linef.counter
	set cl [$cb subwidget listbox]
	$cl delete 0 end
	set idx 0
	set fi -1
	set ctrlist [sl_stat -objctrs $obj]
	if {$vsd(noFlatlines)} {
	    if {$instId != -1} {
		set lineCtr [lindex $linfo 1]
		set newlist {}
		foreach ctr $ctrlist {
		    if [sl_stat -ctrzero $ctr $instId] {
			if {![string equal $ctr $lineCtr]} {
			    # dont add this guy
			    continue
			}
		    }
		    lappend newlist $ctr
		}
		set ctrlist $newlist
	    }
	}
	set ctrlist [lsort -dictionary $ctrlist]
	
	eval $cl insert end $ctrlist
	set fi [lsearch -exact $ctrlist $counter]
	if {$fi != -1} {
	    $cb configure -disablecallback true
	    $cb pick $fi
	    $cb configure -disablecallback false
	}
    }
}

proc searchHList {w str {next 0} {forwards 1}} {
    global vsd
    if {$str == ""} {
	return
    }
    set anchor [$w info anchor]
    set l [$w info children]
    if {$anchor != ""} {
        set idx [lsearch -exact $l $anchor]
	if {$idx != -1} {
	    set oldidx $idx
	    incr idx
	    if {$idx <= [llength $l]} {
		set l [concat [lrange $l $idx end] [lrange $l 0 $oldidx]]
	    }
	}
    }
    if [string is digit [string index $str 0]] {
	foreach e $l {
	    if [$w item exists $e $vsd(ilColumnIdx:Pid)] {
		if {[string equal $str [$w item cget $e $vsd(ilColumnIdx:Pid) -text]]} {
		    $w anchor set $e
		    $w see $e
		    showFileForAnchor
		    setStatus "Found Pid \"$str\"."
		    bell
		    return
		}
	    }
	}
    } else {
	set pattern "*$str*"
	foreach e $l {
	    if [string match -nocase $pattern [$w entrycget $e -data]] {
		$w anchor set $e
		$w see $e
		showFileForAnchor
		return
            }
	}
	setStatus "Nothing matches \"$pattern\"."
	bell
    }
}

proc searchCtrHList {w str {next 0} {forwards 1}} {
    global vsd
    if {$str == ""} {
	return
    }
    set anchor [$w info anchor]
    set l [$w info children]
    if {$anchor != ""} {
        set idx [lsearch -exact $l $anchor]
	if {$idx != -1} {
	    set oldidx $idx
	    incr idx
	    if {$idx <= [llength $l]} {
		set l [concat [lrange $l $idx end] [lrange $l 0 $oldidx]]
	    }
	}
    }
    set pattern "*$str*"
    foreach e $l {
	if [string match -nocase $pattern [$w entrycget $e -text]] {
	    $w selection clear
	    $w anchor set $e
	    $w selection set $e
	    $w see $e
	    return
	}
    }
    setStatus "Nothing matches \"$pattern\"."
    bell
}

proc searchComboBox {w str {next 0} {forwards 1}} {
    global vsd
    set lb [$w subwidget listbox]
    set curIdx [$lb index active]
    set pattern "*$str*"
    if {$curIdx == -1} {
	set curIdx 0
    } else {
	incr curIdx
    }
    set endIdx [$lb size]
    set idx $curIdx
    while {$idx < $endIdx} {
	set c [$lb get $idx]
	if [string match -nocase $pattern $c] {
	    $w configure -disablecallback true
	    $w pick $idx
	    $w configure -disablecallback false
	    set browsecmd [$w cget -browsecmd]
	    if {$browsecmd != {}} {
		$browsecmd $c
	    }
	    return
	}
	incr idx
    }
    if {$curIdx != 0} {
	set endIdx $curIdx
	set idx 0
	while {$idx < $endIdx} {
	    set c [$lb get $idx]
	    if [string match -nocase $pattern $c] {
		$w configure -disablecallback true
		$w pick $idx
		$w configure -disablecallback false
		set browsecmd [$w cget -browsecmd]
		if {$browsecmd != {}} {
		    $browsecmd $c
		}
		return
	    }
	    incr idx
	}
    }
    setStatus "Nothing matches \"$pattern\"."
    bell
}

proc searchTrace {n1 n2 op} {
    global vsd
    $vsd(search:func) $vsd(search:parent) $vsd($n2)
}

proc nextSearch {} {
    global vsd
    set p $vsd(search:parent)
    $vsd(search:func) $p $vsd($p:st) 1
}

proc prevSearch {} {
    global vsd
    set p $vsd(search:parent)
    $vsd(search:func) $p $vsd($p:st) 1 0
}

proc endSearch {w restoreFocus} {
    global vsd
    wm withdraw $w
    if {[info exists vsd(search:parent)]} {
	set p $vsd(search:parent)
	trace vdelete vsd($p:st) w searchTrace
	if {$vsd(search:oldfocus) != ""} {
	    focus $vsd(search:oldfocus)
	}
    }
}

proc createTemplateName {} {
    global vsd widgetHelp
    set w .vsdtemplateName
    toplevel $w
    wm withdraw $w
    wm overrideredirect $w 1
    frame $w.f -bd 3 -relief raised
    pack $w.f -fill both -expand yes
    tixLabelEntry $w.f.entry -label "Template Name:"

    set widgetHelp($w) {String Entry Editing}

    set entry [$w.f.entry subwidget entry]
    set vsd(template:tv) ""
    $entry config -textvariable vsd(template:tv)
    pack $w.f.entry -fill both -expand yes
    update
    bind $w <FocusOut>  [list endTemplateName $w $entry 0]
    bind $entry <Return> [list endTemplateName $w $entry 1]
}

proc endTemplateName {w entry restoreFocus} {
    global vsd
    wm withdraw $w
    if {[info exists vsd(template:parent)]} {
	set p $vsd(template:parent)
	if {$vsd(template:oldfocus) != ""} {
	    focus $vsd(template:oldfocus)
	}
        unset vsd(template:parent)
        set vsd(template:result) $vsd(template:tv)
    }
}


proc createSearch {} {
    global vsd widgetHelp
    set w .vsdsearch
    toplevel $w
    wm withdraw $w
    wm overrideredirect $w 1
    frame $w.f -bd 3 -relief raised
    pack $w.f -fill both -expand yes
    tixLabelEntry $w.f.entry -label "Search:"

    set widgetHelp($w) {String Entry Editing}

    set entry [$w.f.entry subwidget entry]
    pack $w.f.entry -fill both -expand yes
    update
    bind $w <FocusOut>  [list endSearch $w 0]
    bind $entry <Return> [list endSearch $w 1]
    bind $entry <Control-s> nextSearch
    bind $entry <Control-r> prevSearch
    bind $entry <Tab> {nextSearch; break}
}

proc createHelpSearch {} {
    global vsd widgetHelp
    set w .vsdhelpsearch
    toplevel $w
    wm withdraw $w
    wm overrideredirect $w 1

    set widgetHelp($w) {Help Search Control}

    frame $w.f -bd 3 -relief raised
    pack $w.f -fill both -expand yes
    tixLabelEntry $w.f.entry -label "Search:"

    set entry [$w.f.entry subwidget entry]
    pack $w.f.entry -fill both -expand yes -side left
    button $w.f.all -text "All Topics" -command searchAllTopics
    button $w.f.next -text "Next" -command nextSearch
    button $w.f.prev -text "Prev" -command prevSearch
    pack $w.f.all $w.f.next $w.f.prev -side right -expand no -fill none
    update
    bind $w <FocusOut>  [list endSearch $w 0]
    bind $entry <Return> [list endSearch $w 1]
    bind $entry <Control-s> nextSearch
    bind $entry <Control-r> prevSearch
    bind $entry <Tab> {nextSearch; break}
    bind $entry <Meta-s> searchAllTopics
}

proc extraStartSearch {parent searchFunc g mf} {
    chartComputeCounters $g $mf
    startSearch $parent $searchFunc
    [$parent subwidget entry] icursor 0 
}

proc startSearch {parent searchFunc {yoffset 0} {w .vsdsearch}} {
    global vsd
    update ;# allows startSearch to be called from popup menu
    set vsd(search:parent) $parent
    set vsd(search:func) $searchFunc
    set vsd(search:oldfocus) [focus]
    set vsd(search:unfound) {}
    if {! [info exists vsd($parent:st)]} {
	set vsd($parent:st) ""
    }
    set entry [$w.f.entry subwidget entry]
    $entry config -textvariable vsd($parent:st)
    trace variable vsd($parent:st) w searchTrace
    
    set width [winfo width $parent]
    set x [winfo rootx $parent]
    set y [winfo rooty $parent]
    set searchheight [winfo height $w]
    if {$searchheight == 1} {
	set searchheight [winfo reqheight $w]
	if {$searchheight == 1} {
	    set searchheight 32
	}
    }
    set y [expr $y - $searchheight - $yoffset]
    wm deiconify $w
    raise $w
    wm geometry $w "${width}x$searchheight+$x+$y"
    focus $entry
}

proc findByFirstLetter {cb letter iscombo} {
    global vsd
    if {$letter >= "A" && $letter <= "Z"} {
	set letter [string tolower $letter]
    }
    if {$letter >= "a" && $letter <= "z"} {
	set lb [$cb subwidget listbox]
	set curIdx [$lb index active]
	if {$curIdx == -1} {
	    set curIdx 0
	} else {
	    incr curIdx
	}
	set endIdx [$lb size]
	set idx $curIdx
	while {$idx < $endIdx} {
	    set c [$lb get $idx]
	    set fc [string tolower [string index $c 0]]
	    if {$fc == $letter} {
		if {$iscombo} {
		    $cb configure -disablecallback true
		    $cb pick $idx
		    $cb configure -disablecallback false
		    set browsecmd [$cb cget -browsecmd]
		    if {$browsecmd != {}} {
			$browsecmd $c
		    }
		} else {
		    $lb selection clear 0 end
		    $lb selection set $idx
		    $lb activate $idx
		    $lb see $idx
		    showCounterInfo $c
		}
		return
	    }
	    incr idx
	}
	if {$curIdx != 0} {
	    set endIdx $curIdx
	    set idx 0
	    while {$idx < $endIdx} {
		set c [$lb get $idx]
		set fc [string tolower [string index $c 0]]
		if {$fc == $letter} {
		    if {$iscombo} {
			$cb configure -disablecallback true
			$cb pick $idx
			$cb configure -disablecallback false
			set browsecmd [$cb cget -browsecmd]
			if {$browsecmd != {}} {
			    $browsecmd $c
			}
		    } else {
			$lb selection clear 0 end
			$lb selection set $idx
			$lb activate $idx
			$lb see $idx
			showCounterInfo $c
		    }
		    return
		}
		incr idx
	    }
	}
	setStatus "No statistic starts with \"$letter\"."
	bell
    }
}

proc HListPrefixClear {w} {
    global vsd
    set vsd(prefix:$w) {}
}

proc HListPrefixSearch {w letter} {
    global vsd
    if {$letter >= "A" && $letter <= "Z"} {
	set letter [string tolower $letter]
    }
    if {$letter >= "a" && $letter <= "z"} {
	if [info exists vsd(prefix:$w)] {
	    set prefix $vsd(prefix:$w)
	    append prefix $letter
	} else {
	    set prefix $letter
	}
	set vsd(prefix:$w) $prefix
	
	set l [$w info children]
	foreach e $l {
	    set ctr [string tolower [$w entrycget $e -text]]
	    if {[string first $prefix $ctr] == 0} {
		$w selection clear
		$w selection set $e
		$w anchor set $e
		$w see $e
		showCounterInfo $ctr
		return
	    }
	}
	setStatus "No statistic starts with \"$vsd(prefix:$w)\"."
	bell
    }
    HListPrefixClear $w
}

proc extraFindByFirstLetter {cb letter g mf} {
    if {$letter >= "A" && $letter <= "Z"} {
	set letter [string tolower $letter]
    }
    if {$letter >= "a" && $letter <= "z"} {
	chartComputeCounters $g $mf
	findByFirstLetter $cb $letter 1
	[$cb subwidget entry] icursor 0 
    }
}

proc showElapsedOnTicks {g x} {
    global vsd
    set x [expr int($x)]
    if [catch {sl_stat -getdate $x "elapsed"} result] {
	return $x
    } else {
	return $result
    }
}

proc showTimeOnTicks {g x} {
    global vsd
    set x [expr int($x)]
    if [catch {sl_stat -getdate $x "time"} result] {
	return $x
    } else {
	return $result
    }
}

proc showDateOnTicks {g x} {
    global vsd
    set x [expr int($x)]
    if [catch {sl_stat -getdate $x "date"} result] {
	return $x
    } else {
	return $result
    }
}

proc chartMenuTime {g} {
    global vsd
    chartAxisTitle $g xaxis
    if {[string equal $vsd($g:xformat) "elapsed"]} {
	$g xaxis configure -command showElapsedOnTicks
    } elseif {[string equal $vsd($g:xformat) "time"]} {
	$g xaxis configure -command showTimeOnTicks
    } else {
	$g xaxis configure -command showDateOnTicks
    }
}

proc computeScale {g e} {
    global vsd
    set l $vsd(ed:$e:$g)
    set yaxis [$g element cget $e -mapy]
    append yaxis "axis"
    scan [$g xaxis limits] "%s %s" xmin xmax
    scan [$g $yaxis limits] "%s %s" ymin ymax

    set edata [$l -info]
    set xvname [lindex $edata 2]
    set yvname [lindex $edata 3]
    set oldscale [lindex $edata 4]
    global $xvname
    set lxmin [set ${xvname}(min)]
    set lxmax [set ${xvname}(max)]
    if {$lxmin > $xmax || $lxmax < $xmin} {
	# No data points in current graph
	return
    }
    if {$lxmin < $xmin} {
	set lxmin $xmin
    }
    if {$lxmax > $xmax} {
	set lxmax $xmax
    }
    # calculate minidx
    set xvsize [$xvname length]
    incr xvsize -1
    set minidx 0
    set maxidx $xvsize
#     set dfid [lindex $edata 7]
#     set interval [lindex [$dfid -info] 6]
#     if {$interval != 0} {
# 	set minidx [expr int($lxmin / $interval)]
# 	if {$minidx > $xvsize} {
# 	    set minidx 0
# 	}
# 	set maxidx [expr int($lxmax / $interval)]
# 	if {$maxidx > $xvsize} {
# 	    set maxidx $xvsize
# 	}
#     }
#     while {[set ${xvname}($minidx)] > $lxmin} {
# 	if {$minidx == 0} {
# 	    break
# 	}
# 	incr minidx -1
#     }
    while {[set ${xvname}($minidx)] < $lxmin} {
	incr minidx
	if {$minidx > $xvsize} {
	    return
	}
    }
    while {[set ${xvname}($maxidx)] < $lxmax} {
	if {$maxidx == $xvsize} {
	    break
	}
	incr maxidx
    }
    while {[set ${xvname}($maxidx)] > $lxmax} {
	incr maxidx -1
	if {$maxidx <= $minidx} {
	    return
	}
    }
    # Need to unscale so that y values used will be correct
    vector create tmpy
    tmpy set [$yvname range $minidx $maxidx]
    set tmpyMax [vector expr max(tmpy)]
    vector destroy tmpy
    if {$tmpyMax == 0} {
	return
    }
    # NYI: Should handle negative numbers better.
    set newscale  [expr $ymax / $tmpyMax]
    if {$newscale >= 1.5} {
	set newscale [expr $newscale * $oldscale]
	$l -scale $newscale
	#updateLineDataDisplay $g $e $l
    }
}

proc lineComputeScale {g} {
    global vsd
    foreach e [getSelectedLines $g] {
	catch {computeScale $g $e} result
	if [wizardMode] {
	    if {$result != {}} {
		showError "computeScale: $result"
	    }
	}
        if {[string equal $e [getSelectedLine $g]]} {
            set l $vsd(ed:$e:$g)
            updateLineDataDisplay $g $e $l
        }
    }
}

proc lineUnscale {g} {
    lineChangeScale $g 1
    global vsd
    foreach e [getSelectedLines $g] {
	set l $vsd(ed:$e:$g)
	$l -scale 1
        if {[string equal $e [getSelectedLine $g]]} {
            updateLineDataDisplay $g $e $l
        }
    }
}

proc allComputeScale {g} {
    global vsd
    foreach e [$g element names] {
	catch {computeScale $g $e} result
	if [wizardMode] {
	    if {$result != {}} {
		showError "computeScale: $result"
	    }
	}
    }
    set e [getSelectedLine $g]
    if {$e != {}} {
	set l $vsd(ed:$e:$g)
	updateLineDataDisplay $g $e $l
    }
}

proc allUnscale {g} {
    global vsd
    foreach e [$g element names] {
	$vsd(ed:$e:$g) -scale 1
    }
    set e [getSelectedLine $g]
    if {$e != {}} {
	set l $vsd(ed:$e:$g)
	updateLineDataDisplay $g $e $l
    }
}

proc createGraphWindow {title} {
    global vsd isWindows widgetHelp
    global bltActiveEntry
    global bltActiveGraph
    

    set w ".chart$vsd(graphcreates)"
    set geom [getGraphGeometry $w]
    toplevel $w
    wm geometry $w $geom

    set widgetHelp($w) {Chart Window Features}

    if [info exists vsd(ct:$title)] {
	set title {}
    }
    if {$title == {}} {
	set title "Chart $vsd(graphcreates)"
	set templateName "chart$vsd(graphcreates)"
    } else {
	regsub -all { } $title {} templateName
    }

    incr vsd(graphcount)
    incr vsd(graphcreates)

    set vsd(ct:$title) $w
    $vsd(w:chartlist) configure -disablecallback true
    $vsd(w:chartlist) addhistory $title
    $vsd(w:chartlist) pick 0
    $vsd(w:chartlist) configure -disablecallback false
    set g $w.graph
    set bltActiveGraph($g) 0
    set bltActiveEntry($g) -1
    
    wm title $w $title

    set mf [frame $w.mf -bd 2 -relief raised]
    menubutton $mf.chart -menu $mf.chart.m -text "Chart" -underline 0 \
	-takefocus 0
    menu $mf.chart.m -tearoff 1

    set mftmp $mf.chart.m.templates
    set widgetHelp($mftmp) {Chart Menu Add From Template SubMenu}
    menu $mftmp -tearoff 1
    createGraphTemplateMenu $mftmp $title
    $mf.chart.m add cascade -label "Add From Template" \
	-menu $mftmp -underline 0

    $mf.chart.m add command -label "Save Template" -underline 0 \
	-command "saveGraphTemplate $g $templateName"
    $mf.chart.m add command -label "Paste" \
	-command [list chartPaste $w $g] \
	-accelerator "Ctrl+v"
    if {! $isWindows} {
 	$mf.chart.m add command -label "Print"  \
 	    -command "printGraph $g $w.ps" \
 	    -accelerator "Ctrl+p"
    }
    $mf.chart.m add command -label "Snapshot"  \
	-command "snapshotGraph $g $w.ps"
    $mf.chart.m add command -label "Help..." -underline 0 \
	-command {showChartHelp}
    $mf.chart.m add separator

    set vsd($g:chartOp) {}
    set vsd($g:showlegend) $vsd(def:showlegend)
    set vsd($g:xformat) $vsd(def:xformat)
    set vsd($g:xaxis:showtitle) $vsd(def:xaxis:showtitle)
    set vsd($g:yaxis:showtitle) $vsd(def:yaxis:showtitle)
    set vsd($g:y2axis:showtitle) $vsd(def:y2axis:showtitle)
    set vsd($g:showcrosshairs) $vsd(def:showcrosshairs)
    set vsd($g:showgridlines) $vsd(def:showgridlines)
    set vsd($w:showcurxy) $vsd(def:showcurxy)
    set vsd($w:showminmax) $vsd(def:showminmax)
    set vsd($w:showlinestats) $vsd(def:showlinestats)

    $mf.chart.m add command -label "Zoom In" \
	-command [list chartZoom $g] \
	-accelerator "Ctrl+z"
    $mf.chart.m add command -label "Zoom Out" \
	-command [list chartCancelOpZoom $g]
    $mf.chart.m add command -label "Compare Two Points" \
	-command [list chartCompare $g]
#	-accelerator "Ctrl+c"
    if 0 {
	$mf.chart.m add command -label "Set Min Time" \
	    -command [list chartSetMinTime $g]
	$mf.chart.m add command -label "Set Max Time" \
	    -command [list chartSetMaxTime $g]
    }
    $mf.chart.m add command -label "Compute Scale All" \
	-command [list allComputeScale $g] \
	-accelerator "Ctrl+S"
    $mf.chart.m add command -label "Unscale All" \
	-command [list allUnscale $g] \
	-accelerator "Ctrl+N"
    $mf.chart.m add separator

    set mtime $mf.chart.m.time
    set widgetHelp($mtime) {Chart Menu Time Format SubMenu}
    menu $mtime -tearoff 1
    $mtime add radio -label "Elapsed Time in Seconds" -value "elapsed" \
	-variable vsd($g:xformat) \
	-command [list chartMenuTime $g]
    $mtime add radio -label "Hour:Minute:Second" -value "time" \
	-variable vsd($g:xformat) \
	-command [list chartMenuTime $g]
    $mtime add radio -label "Month/Day Hour:Minute:Second" -value "date" \
	-variable vsd($g:xformat) \
	-command [list chartMenuTime $g]

    $mf.chart.m add check -label "Show Legend" \
	-command [list chartShowLegend $g] \
	-variable vsd($g:showlegend)
    $mf.chart.m add cascade -label "Time Format" -menu $mtime -underline 0
    $mf.chart.m add check -label "Show Time Axis Title" \
	-command [list chartAxisTitle $g "xaxis"] \
	-variable vsd($g:xaxis:showtitle)
    $mf.chart.m add check -label "Show Left Axis Title" \
	-command [list chartAxisTitle $g "yaxis"] \
	-variable vsd($g:yaxis:showtitle)
    $mf.chart.m add check -label "Show Right Axis Title" \
	-command [list chartAxisTitle $g "y2axis"] \
	-variable vsd($g:y2axis:showtitle)
    $mf.chart.m add check -label "Show Current Values" \
	-command [list chartShowCurXY $w $mf] \
	-variable vsd($w:showcurxy)
    $mf.chart.m add check -label "Show Min and Max" \
	-command [list chartShowMinMax $w $mf] \
	-variable vsd($w:showminmax)
    $mf.chart.m add check -label "Show Line Stats" \
	-variable vsd($w:showlinestats)
    $mf.chart.m add check -label "Show CrossHairs" \
	-command [list chartShowCrossHairs $g] \
	-variable vsd($g:showcrosshairs)
    $mf.chart.m add check -label "Show Grid Lines" \
	-command [list chartShowGridLines $g] \
	-variable vsd($g:showgridlines)
    $mf.chart.m add separator
    $mf.chart.m add command -label "Close   " -command "closeGraph $w $g"
    pack $mf.chart -side left
    set widgetHelp($mf.chart) {Chart Window Chart Menu}

    menubutton $mf.line -menu $mf.line.m -text "Line" -underline 0 \
	-takefocus 0 -state disabled
    menu $mf.line.m -tearoff 1
    $mf.line.m add command -label "Log Info" -underline 4 \
	-command [list lineInfo $g]
    $mf.line.m add command -label "Log Delta" \
	-command [list lineDelta $g] \
	-accelerator "Ctrl+d"
    $mf.line.m add command -label "Compute Scale" \
	-command [list lineComputeScale $g] \
	-accelerator "Ctrl+s"
    $mf.line.m add command -label "Unscale" \
	-command [list lineUnscale $g] \
	-accelerator "Ctrl+n"
    $mf.line.m add check -label "Graph on Left Axis" \
	-command [list lineGraphOnLeft $g] \
	-variable vsd($g:graphonleft) \
	-accelerator "Ctrl+a"

    set msym $mf.line.m.symbols
    set widgetHelp($msym) {Line Menu Symbol SubMenu}
    menu $msym -tearoff 1
    set vsd($g:linesym) none
    foreach s $vsd(symbollist) {
	$msym add radio -label $s -variable vsd($g:linesym) \
	    -command [list lineMenuSymbol $g]
    }
    $mf.line.m add cascade -label "Symbol" -menu $msym -underline 0
    set mstyle $mf.line.m.styles
    set widgetHelp($mstyle) {Line Menu Sytle SubMenu}
    menu $mstyle -tearoff 1
    set vsd($g:linestyle) linear
    foreach style {linear step natural quadratic} {
	$mstyle add radio -label $style -variable vsd($g:linestyle) \
	    -command [list lineMenuStyle $g]
    }
    $mf.line.m add cascade -label "Style" -menu $mstyle
    $mf.line.m add command -label "Update" \
	-command [list lineUpdate $g] \
	-accelerator "Ctrl+u"

    $mf.line.m add separator
    $mf.line.m add command -label "Add Lines" \
	-command [list lineAdd $g] \
	-accelerator "Ctrl++"
    $mf.line.m add command -label "Diff Lines" \
	-command [list lineDiff $g] \
	-accelerator "Ctrl+-"
    $mf.line.m add command -label "Divide Lines" \
	-command [list lineDivide $g] \
	-accelerator "Ctrl+/"

    $mf.line.m add separator
    $mf.line.m add check -label "Normalize" \
	-command [list lineNormalize $g] \
	-variable vsd($g:normalized)
    $mf.line.m add command -label "Trim Left" \
	-command [list lineTrimLeft $g]
    $mf.line.m add command -label "Trim Right" \
	-command [list lineTrimRight $g]
    $mf.line.m add command -label "Untrim Left" \
	-command [list lineUntrimLeft $g]
    $mf.line.m add command -label "Untrim Right" \
	-command [list lineUntrimRight $g]

    $mf.line.m add separator
    $mf.line.m add command -label "Copy" -command "lineCopy $g" \
	-accelerator "Ctrl+c"
    $mf.line.m add command -label "Cut" -command "lineCut $g" \
	-accelerator "Ctrl+x"
    $mf.line.m add command -label "Delete" -command "lineDelete $g" \
	-accelerator "Del"

    pack $mf.line -side left
    set widgetHelp($mf.line) {Chart Window Line Menu}

    tixLabelFrame $mf.curx -label "X:" -labelside left
    [$mf.curx subwidget label] configure -font vsdsf
    set f [$mf.curx subwidget frame]
    label $f.l -text "" -font vsdsf
    pack $f.l
    set widgetHelp($mf.curx) {Chart Window X: Display}
    $vsd(balloon) bind $mf.curx -msg "Show time offset of data at mouse pointer"

    tixLabelFrame $mf.cury -label "Y:" -labelside left
    [$mf.cury subwidget label] configure -font vsdsf
    set f [$mf.cury subwidget frame]
    label $f.l -text "" -font vsdsf
    pack $f.l
    set widgetHelp($mf.cury) {Chart Window Y: Display}
    $vsd(balloon) bind $mf.cury -msg "Show statistic value of data at mouse pointer"

    tixLabelFrame $mf.min -label "Min:" -labelside left
    [$mf.min subwidget label] configure -font vsdsf
    set f [$mf.min subwidget frame]
    label $f.l -text "" -font vsdsf
    set widgetHelp($mf.min) {Chart Window Min: Display}
    pack $f.l
    tixLabelFrame $mf.max -label "Max:" -labelside left
    [$mf.max subwidget label] configure -font vsdsf
    set f [$mf.max subwidget frame]
    label $f.l -text "" -font vsdsf
    set widgetHelp($mf.max) {Chart Window Max: Display}
    pack $f.l

    frame $mf.linef -bd 0

    set vsd($g:ctrlistid) {}

    tixComboBox $mf.linef.counter -dropdown true -editable false -value "" \
	-listcmd [list chartComputeCounters $g $mf] \
	-browsecmd chartBrowseCounters \
	-command [list chartChangeCounter $g] \
	-state disabled	-options {
	    entry.width 18
	    listbox.height 4
	    listbox.width 33
	}
    set widgetHelp($mf.linef.counter) {Chart Window Statistic ComboBox}
    [$mf.linef.counter subwidget entry] configure -font vsdsf
    [$mf.linef.counter subwidget listbox] configure -font vsdsf
    bind [$mf.linef.counter subwidget entry] <KeyPress> \
	[list extraFindByFirstLetter $mf.linef.counter %A $g $mf]
    bind [$mf.linef.counter subwidget entry] <Control-s> \
	[list extraStartSearch $mf.linef.counter searchComboBox $g $mf]
    $vsd(balloon) bind $mf.linef.counter -msg "Change the line's statistic"

    set fw $mf.linef.filtertype
    tixOptionMenu $fw -command [list lineFilter $g] \
	-state disabled -dynamicgeometry 1
    set widgetHelp($fw) {Chart Window Filter MenuButton}
    [$fw subwidget menubutton] configure -font vsdsf
    [$fw subwidget menu] configure -font vsdsf
    $fw configure -disablecallback true
    $fw add command none -label "No Filter"
    $fw add command persecond -label "PerSecond"
    $fw add command persample -label "PerSample"
#    $fw add command smooth -label "Smooth"
    $fw add command aggregate -label "Aggregate"
    $fw configure -disablecallback false
    $vsd(balloon) bind $fw -msg "Change the line's filter"

    
    set ow $mf.linef.opMenu
    tixOptionMenu $ow -command [list changeConstOp $g] -variable vsd(constOp) \
	-state disabled
    set widgetHelp($ow) {Chart Window Operator MenuButton}
    $vsd(balloon) bind $ow -msg "Select (S)cale, /, *, +, or -"
    [$ow subwidget menubutton] configure -font vsdsf -indicatoron 0 -padx 1
    [$ow subwidget menu] configure -font vsdsf
    $ow configure -disablecallback true
    $ow add command scale -label "S"
    $ow add command divide -label "/"
    $ow add command multiply -label "*"
    $ow add command add -label "+"
    $ow add command subtract -label "-"
    $ow configure -disablecallback false
    tixControl $mf.linef.const -label ":" -state disabled \
        -autorepeat false \
	-incrcmd lineIncrConst -decrcmd lineDecrConst \
	-validatecmd [list lineValidateConst $g] \
	-command [list lineChangeConst $g]
    set widgetHelp($mf.linef.const) {Chart Window Number Entry}
    [$mf.linef.const subwidget label] configure -font vsdsf
    [$mf.linef.const subwidget entry] configure -font vsdsf -width 7

    $vsd(balloon) bind $mf.linef.const -msg "Change the constant the line is modified with"

    pack $mf.linef.counter $fw $ow $mf.linef.const -side left ;# -padx 2
    pack $mf.linef -side right
    if {$vsd($w:showcurxy)} {
	pack $mf.cury $mf.curx -after $mf.linef -side right -padx 2
    }
    if {$vsd($w:showminmax)} {
	pack $mf.max $mf.min -after $mf.linef -side right -padx 2
    }

    graph $g -title "" -topmargin 3 -leftmargin 2 -rightmargin 2 -takefocus 1 \
	-plotbackground white 	-cursor $vsd(graphcursor)
    $g pen configure "activeLine" -color $vsd(activecolor) -fill "" -symbol ""
    #      -outline [lindex $vsd(colorlist) $cidx]
    set widgetHelp($g) {Chart Window Graph}
    hideAxis $g yaxis
    hideAxis $g y2axis

    if {! $isWindows} {
	bind $g <Control-p> [list $mf.chart.m invoke "Print"]
    }
    bind $g <Control-z> [list $mf.chart.m invoke "Zoom In"]
    bind $g <Control-S> [list $mf.chart.m invoke "Compute Scale All"]
#    bind $g <Control-c> [list $mf.chart.m invoke "Compare Two Points"]
    bind $g <Control-N> [list $mf.chart.m invoke "Unscale All"]
    bind $g <Control-plus> [list $mf.line.m invoke "Add Lines"]
    bind $g <Control-minus> [list $mf.line.m invoke "Diff Lines"]
    bind $g <Control-slash> [list $mf.line.m invoke "Divide Lines"]
    bind $g <Control-d> [list $mf.line.m invoke "Log Delta"]
    bind $g <Control-s> [list $mf.line.m invoke "Compute Scale"]
    bind $g <Control-n> [list $mf.line.m invoke "Unscale"]
    bind $g <Control-a> [list $mf.line.m invoke "Graph on Left Axis"]
    bind $g <Control-u> [list $mf.line.m invoke "Update"]
    bind $g <Delete> [list $mf.line.m invoke "Delete"]
    bind $g <Left> [list ZoomHorizontal $g -2]
    bind $g <Right> [list ZoomHorizontal $g +2]
    bind $g <Control-Left> [list ZoomHorizontalPage $g -1]
    bind $g <Control-Right> [list ZoomHorizontalPage $g +1]
#    bind $g <Up> [list ZoomVertical $g +1]
#    bind $g <Down> [list ZoomVertical $g -1]
    bind $g <<Paste>> [list $mf.chart.m invoke "Paste"]
    bind $g <<Copy>> [list $mf.line.m invoke "Copy"]
    bind $g <<Cut>> [list $mf.line.m invoke "Cut"]

    if {1} {
	$g configure -font vsdsf
        $g xaxis configure -tickfont vsdsf -titlefont vsdsf
        $g yaxis configure -tickfont vsdsf -titlefont vsdsf
        $g y2axis configure -tickfont vsdsf -titlefont vsdsf
    }
    chartMenuTime $g
    chartAxisTitle $g yaxis
    chartAxisTitle $g y2axis
    
    $g legend configure -position bottom -anchor w -font vsdsf -activeforeground $vsd(activecolor) -activerelief raised
    mapLegend $g $vsd($g:showlegend)

    if {$vsd($g:showcrosshairs)} {
	Blt_CrosshairsOn $g
    }
    $g grid configure -dashes {4 6}
    if {$vsd($g:showgridlines)} {
	$g grid on
    }
    Blt_ZoomStack $g
    Blt_ActiveGraph $g

    pack $mf -side top -fill x
    pack $g -side bottom -fill both -expand yes
    wm protocol $w WM_DELETE_WINDOW "closeGraph $w $g"

    $g marker create text -name activeLine -text "" \
	-coords {-Inf Inf} -anchor nw -bg {} -under 0 -font vsdsf
    $g marker create bitmap -name triStart -under 1 \
        -bitmap $vsd(triBitMapName) -fg $vsd(activecolor) \
	-fill "" -yoffset 6
    $g marker create bitmap -name triEnd -under 1 \
        -bitmap $vsd(triBitMapName) -fg $vsd(activecolor) \
	-fill "" -yoffset 6

    # The <Configure> type can be used to get resize and window move notification
    # bind $w <Configure> {+puts "Configure %W %R %S [wm geometry %W]"}

    return $w
}

proc getFreeGraphSlot {gw} {
    set elements [$gw.graph element names]
    if {[llength $elements] == 0} {
        return 1
    } else {
        set slot [lindex $elements 0]
        foreach e $elements {
            if {$e > $slot} {
                set slot $e
            }
        }
        incr slot
        return $slot
    }
}

# statFilter returns 1 if the line is ok, 0 if the filter does not want it
proc statFilter {line filter} {
    global vsd
    set stats [$line -stats {} {}]
    #stats = {count min max average stddev}
    set fcount [lindex $filter 0]
    if {$fcount != {}} {
	if {[llength $fcount] == 2} {
	    # we only wants lines who have the number of samples in the range
	    set actualCount [lindex $stats 0]
	    if {$actualCount < [lindex $fcount 0] ||
		$actualCount > [lindex $fcount 1]} {
		return 0
	    }
	} elseif {$fcount < 0} {
	    # we only wants lines who have less samples than the filter
	    set fcount [expr (- $fcount)]
	    if {[lindex $stats 0] > $fcount} {
		# to many samples so reject it
		return 0
	    }
	} else {
	    # we only wants lines who have more samples than the filter
	    if {[lindex $stats 0] < $fcount} {
		# not enough samples so reject it
		return 0
	    }
	}
    }
    set fmin [lindex $filter 1]
    if {$fmin != {}} {
	if {[llength $fmin] == 2} {
	    # we only wants lines who have a min in the range
	    set actualMin [lindex $stats 1]
	    if {$actualMin < [lindex $fmin 0] ||
		$actualMin > [lindex $fmin 1]} {
		return 0
	    }
	} elseif {$fmin < 0} {
	    # we only wants lines whose min is less than the filter
	    if {[lindex $stats 1] > $fmin} {
		# smallest item is larger than the min filter
		return 0
	    }
	} else {
	    # we only wants lines whose min is greater than the filter
	    if {[lindex $stats 1] < $fmin} {
		# smallest item is less than the min filter
		return 0
	    }
	}
    }
    set fmax [lindex $filter 2]
    if {$fmax != {}} {
	if {[llength $fmax] == 2} {
	    # we only wants lines who have a max in the range
	    set actualMax [lindex $stats 2]
	    if {$actualMax < [lindex $fmax 0] ||
		$actualMax > [lindex $fmax 1]} {
		return 0
	    }
	} elseif {$fmax < 0} {
	    set fmax [expr (- $fmax)]
	    # we only wants lines whose max is less than the filter
	    if {[lindex $stats 2] > $fmax} {
		# largest item is greater than the max filter
		return 0
	    }
	} else {
	    # we only wants lines whose max is greater than the filter
	    if {[lindex $stats 2] < $fmax} {
		# largest item is less than the max filter
		return 0
	    }
	}
    }
    set fmean [lindex $filter 3]
    if {$fmean != {}} {
	if {[llength $fmean] == 2} {
	    # we only wants lines who have a mean in the range
	    set actualMean [lindex $stats 3]
	    if {$actualMean < [lindex $fmean 0] ||
		$actualMean > [lindex $fmean 1]} {
		return 0
	    }
	} elseif {$fmean < 0} {
	    set fmean [expr (- $fmean)]
	    # we only wants lines whose mean is less than the filter
	    if {[lindex $stats 3] > $fmean} {
		# average item is greater than the mean filter
		return 0
	    }
	} else {
	    # we only wants lines whose mean is greater than the filter
	    if {[lindex $stats 3] < $fmean} {
		# average item is less than the mean filter
		return 0
	    }
	}
    }
    set fstddev [lindex $filter 4]
    if {$fstddev != {}} {
	if {[llength $fstddev] == 2} {
	    # we only wants lines who have a stddev in the range
	    set actualSd [lindex $stats 3]
	    if {$actualSd < [lindex $fstddev 0] ||
		$actualSd > [lindex $fstddev 1]} {
		return 0
	    }
	} elseif {$fstddev < 0} {
	    set fstddev [expr (- $fstddev)]
	    # we only wants lines whose stddev is less than the filter
	    if {[lindex $stats 4] > $fstddev} {
		# line stddev is greater than the stddev filter
		return 0
	    }
	} else {
	    # we only wants lines whose stddev is greater than the filter
	    if {[lindex $stats 4] < $fstddev} {
		# line stdev is less than the stddev filter
		return 0
	    }
	}
    }
    return 1
}

proc lineMin {l} {
    set yvec [lindex [$l -info] 3]
    global $yvec
    return [set ${yvec}(min)]
}

proc lineMax {l} {
    set yvec [lindex [$l -info] 3]
    global $yvec
    return [set ${yvec}(max)]
}

proc addLineToChart {line new activate mapaxis symbol {style {}}} {
    global vsd
    
    if {! $new} {
	if {![info exists vsd(ct:$vsd(curchart))]} {
	    setStatus "no title for $vsd(curchart)"
	    bell
	    return
#	    set new 1
	}
    }
    set lineinfo [$line -info]
    set lineyv [lindex $lineinfo 3]
    global $lineyv
    set linexv [lindex $lineinfo 2]
    global $linexv

    if {$new} {
	set gw [createGraphWindow $vsd(curchart)]
	if {$new == 2} {
	    startLongOp $gw
	}
    } else {
	set gw $vsd(ct:$vsd(curchart))
	if {![winfo exists $gw]} {
	    if {$vsd(longOpW) != ""} {
		cancelLongOp
	    } else {
		setStatus "missing chart window $gw"
		bell
	    }
	    return
	}
    }
    raise $gw

    set numColors [llength $vsd(colorlist)]
    set i [getFreeGraphSlot $gw]
    set cidx [expr ($i - 1) % $numColors]
    set dashes [expr (($i - 1) / $numColors) * 2]
    if {$cidx >= $numColors} {
	set cidx 0
	incr dashes 2
    }
    set g $gw.graph
    set vsd(ed:$i:$g) $line
    showAxis $g ${mapaxis}axis
    if {[string equal $mapaxis "y"]} {
	$g configure -leftmargin 0
    } else { ;# y2 axis
	$g configure -rightmargin 0
    }
    set label [getLineLegendLabel $i $lineinfo]
    if {$style == {}} {
	set style $vsd(def:linestyle)
    }
    $g element create $i -label $label -mapy $mapaxis -symbol $symbol \
	-xdata $linexv -ydata $lineyv -dashes $dashes \
	-color [lindex $vsd(colorlist) $cidx] \
	-outline [lindex $vsd(colorlist) $cidx] \
	-pixels 2 -fill "" -smooth $style

    # The following is done to get the graph to redraw.
#    puts "DEBUG: [lsort -integer [$g element names]]"
#    $g element show [lsort -integer [$g element names]]
    if {$activate} {
	activateElement $g $i 0
    }
}

proc createOperatorLine {lineList op copyChildren {filter "default"} {scale 1}
			 {divider 1} {offset 0} {normalized 0}
			 {statFilter {}}} {
    global vsd
    if [catch {sl_create -derivedline $lineList $op $filter $copyChildren} line] {
	setStatus $line
	bell
	return {}
    }
    if {$scale != 1} {
	$line -scale $scale
    }
    if {$divider != 1} {
	$line -divider $divider
    }
    if {$normalized} {
	$line -normalize
    } elseif {$offset != 0} {
	$line -adder [expr {- $offset}]
    }
    if {$statFilter != {}} {
	if {! [statFilter $line $statFilter]} {
	    $line -free
	    return {}
	}
    }
    return $line
}

proc addDerivedLine {lineList op {filter "default"} {scale 1} {mapaxis "y"}} {
    global vsd
    replayLog "addDerivedLine $lineList $op $filter $scale $mapaxis"
    set line [createOperatorLine $lineList $op $vsd(copyChildren) $filter $scale]
    if {$line != {}} {
	addLineToChart $line 0 1 $mapaxis "none"
    }
}

proc createSimpleLine {instList counter
	       {filter "default"} {scale 1}
		       {divider 1} {offset 0} {normalized 0}
		       {statFilter {}}} {
    global vsd

    set line [sl_create -line $instList $counter $filter $vsd(absoluteTSMode)]
    if {$vsd(noFlatlines)} {
	if {[lineMax $line] == 0 && [lineMin $line] == 0} {
	    $line -free
	    return {}
	}
    }
    if {$scale != 1} {
	$line -scale $scale
    }
    if {$divider != 1} {
	$line -divider $divider
    }
    if {$normalized} {
	$line -normalize
    } elseif {$offset != 0} {
	$line -adder [expr {- $offset}]
    }
    if {$statFilter != {}} {
	if {! [statFilter $line $statFilter]} {
	    $line -free
	    return {}
	}
    }
    return $line
}

proc doOneCounter {new instList activate counter
                   {filter "default"} {scale 1} {mapaxis "y"}
		   {divider 1} {offset 0} {normalized 0}
                   {statFilter {}}} {
    global vsd

    replayLog "doOneCounter $new $instList $activate $counter $filter $scale $mapaxis $divider $offset $normalized $statFilter"
    set line [createSimpleLine $instList $counter $filter $scale $divider $offset $normalized $statFilter]
    if {$line != {}} {
	addLineToChart $line $new $activate $mapaxis "none"
	return 1
    } else {
	return 0
    }
}

# proc doTemplateCounter {new instList templateInfo} {
#     global vsd
#     set counter [lindex $templateInfo 2]
#     set scale [lindex $templateInfo 3]
#     set filter [lindex $templateInfo 4]
#     set mapaxis [lindex $templateInfo 5]
#     set infoArgs [llength $templateInfo]
#     if {$infoArgs <= 7} {
# 	# old style with default divider, offset, and normalize
# 	set divider 1
# 	set offset 0
# 	set normalized 0
# 	set statFilter [lindex $templateInfo 6]
#     } else {
# 	set divider [lindex $templateInfo 6]
# 	set offset [lindex $templateInfo 7]
# 	set normalized [lindex $templateInfo 8]
# 	set statFilter [lindex $templateInfo 9]
#     }
#     if {$vsd(combineFiles) || [llength $instList] == 1} {
# 	set result [doOneCounter $new $instList 0 $counter $filter $scale $mapaxis \
# 			$divider $offset $normalized $statFilter]
#     } else {
# 	set result 0
# 	foreach df [sl_stat -enabledfiles] {
# 	    set dfInstList {}
# 	    foreach inst $instList {
# 		set instData [sl_stat -instinfo $inst]
# 		if {[string equal $df [lindex $instData 5]]} {
# 		    lappend dfInstList $inst
# 		}
# 	    }
# 	    if {$dfInstList != {}} {
# 		if {[doOneCounter $new $dfInstList 0 $counter $filter $scale $mapaxis \
# 			$divider $offset $normalized $statFilter]} {
# 		    set result 1
# 		    set new 0
# 		    update
# 		}
# 	    }
# 	}
#     }
#     return $result
# }


proc addToChart {new procs ctrs} {
    global vsd

    set count 0
    disableAutoUpdates
    set fileCount [llength [sl_stat -enabledfiles]]
    if {[llength $ctrs] == 1 && ([llength $procs] == 1 ||
				 ($vsd(combineInstances) && ($vsd(combineFiles) || $fileCount == 1)))} {
	set activate 1
    } else {
	set activate 0
    }
	
    set chartname [$vsd(w:chartlist) cget -selection]
    if {![string equal $chartname $vsd(curchart)]} {
	set vsd(curchart) $chartname
    }
    if {!$activate} {
	if {$new} {
	    # Setting new to 2 means that startLongOp should be done when
	    # a window is created
	    set new 2
	} else {
	    set gw $vsd(ct:$vsd(curchart))
	    startLongOp $gw
	}
    }
    if {$vsd(combineInstances)} {
	if {$vsd(combineFiles)} {
            if {$vsd(combineFilePattern) == ""} {
                set instList {}
                foreach ientry $procs {
                    set instData [$vsd(instanceList) info data $ientry]
                    lappend instList [lindex $instData 6]
                }
                foreach ctr $ctrs {
                    if {[doOneCounter $new $instList $activate $ctr]} {
                        incr count
                        set new 0
                        update
                        if {$vsd(longOpCancel)} {break}
                    }
                }
            } else {
                # Use combineFilePattern to group files
                global patternMap
                foreach fGroupName [getSortedGroupNames] {
                    set fGroupIds $patternMap($fGroupName);
                    set instList {}
                    foreach ientry $procs {
                        set instData [$vsd(instanceList) info data $ientry]
                        if {[lsearch -exact $fGroupIds [lindex $instData 5]] != -1} {
                            lappend instList [lindex $instData 6]
                        }
                    }
                    if {$instList != {}} {
                        foreach ctr $ctrs {
                            if {[doOneCounter $new $instList $activate $ctr]} {
                                incr count
                                set new 0
                                update
                                if {$vsd(longOpCancel)} {break}
                            }
                        }
                    }
                    if {$vsd(longOpCancel)} {break}
                }
            }
	} else {
	    foreach df [getSortedFiles] {
		set instList {}
		foreach ientry $procs {
		    set instData [$vsd(instanceList) info data $ientry]
		    if {[string equal $df [lindex $instData 5]]} {
			lappend instList [lindex $instData 6]
		    }
		}
		if {$instList != {}} {
		    foreach ctr $ctrs {
			if {[doOneCounter $new $instList $activate $ctr]} {
			    incr count
			    set new 0
			    update
			    if {$vsd(longOpCancel)} {break}
			}
		    }
		}
		if {$vsd(longOpCancel)} {break}
	    }
	}
    } else {
	foreach ientry $procs {
	    set instData [$vsd(instanceList) info data $ientry]
	    set instId [lindex $instData 6]
	    foreach ctr $ctrs {
		if {[doOneCounter $new [list $instId] $activate $ctr]} {
		    incr count
		    set new 0
		    update
		    if {$vsd(longOpCancel)} {break}
		}
	    }
	    if {$vsd(longOpCancel)} {break}
	}
    }
    if {$count == 0} {
	if {$vsd(noFlatlines) && !$vsd(longOpCancel)} {
	    # ring the bell since no lines were added due to flatlines
	    setStatus "Line was not created because \"No Flatlines\" is enabled."
	    bell
	}
    }
    enableAutoUpdates
    endLongOp
}

proc doChart {new} {
    global vsd

    set procs [$vsd(instanceList) info selection]
    set ctrs [getSelCtr]
    if {$procs == {} || $ctrs == {}} {
	if {$new} {
	    createGraphWindow {}
	}
    } else {
	if {!$new && $vsd(curchart) == {}} {
	    set new 1
	}
	addToChart $new $procs $ctrs
    }
}

proc doExitVSD {} {
    global vsd
    writeStartupFile
    foreach smon [array names vsd statmonpid:*] {
	catch {sl_kill $vsd($smon) 2}
    }
    destroy $vsd(w)
    exit
}

proc ExitVSD {} {
    global vsd

    if {! $vsd(confirmonexit)} {
	doExitVSD
    }

    set msgtext "Are you sure you want to exit?"

    if {[info commands tk_messageBox] != ""} {
	set response [tk_messageBox -title "Confirm Exit" \
			  -parent $vsd(w) -icon question -type yesno \
			  -default yes -message $msgtext]
	if {[string equal $response "yes"]} {
	    doExitVSD
	}
    } else {
	set d [tixDialogShell .vsdexit -parent $vsd(w) -title "Confirm Exit"]

	frame $d.top -relief raised -bd 1
	pack $d.top -side top -fill both

	label $d.top.msg -text $msgtext
	pack $d.top.msg -side right -expand 1 -fill both -padx 3m -pady 3m
	label $d.top.bitmap -bitmap "question"
	pack $d.top.bitmap -side left -padx 3m -pady 3m
	

	tixButtonBox $d.box
	$d.box add yes -text Yes -command doExitVSD
	$d.box add no -text No -command {destroy .vsdexit}

	pack $d.box -fill x -expand yes

	$d popup
	focus [$d.box subwidget yes]
    }
}

proc ChangeXAuto {w} {
    global vsd

    if {$vsd(xautoscale)} {
	$w.min configure -state disabled
	$w.max configure -state disabled
    } else {
	$w.min configure -state normal
	$w.max configure -state normal
    }
}

proc ChangeYAuto {w} {
    global vsd

    if {$vsd(yautoscale)} {
	$w.min configure -state disabled
	$w.max configure -state disabled
    } else {
	$w.min configure -state normal
	$w.max configure -state normal
    }
}

proc getSelCtr {} {
    global vsd
    set res {}
    foreach i [$vsd(w:counterHList) info selection] {
	lappend res [$vsd(w:counterHList) info data $i]
    }
    return $res
}

proc clearCounters {} {
    global vsd
    set selCtr [getSelCtr]
    if {$selCtr != {}} {
	set vsd(lastSelCtr) $selCtr
    }
    $vsd(w:counterHList) delete all
    set vsd(selectedCtr) {}
    set vsd(counterType) {}
    set vsd(selectedInstIds) {}
    set vsd(zeroCtrs) {}
}

proc showCounter {c} {
    global vsd

    if {$c == {}} {
	return
    }
    set vsd(lastctr) $c
    $vsd(doctext:w) configure -state normal
    $vsd(doctext:w) delete 1.0 end

    set ctype [getStatType $c]
    if {[string equal $ctype "uvalue"]} {
	set ctype "unsigned value"
    } elseif {[string equal $ctype "svalue"]} {
	set ctype "signed value"
    }
    $vsd(ctrtype:w) configure -text $ctype
    $vsd(ctrunits:w) configure -text [getStatUnits $c]
    set objList [getStatObjList $c]
    if {[string length $objList] == 0} {
	$vsd(ctrobjs:w) configure -text "unknown"
    } else {
	$vsd(ctrobjs:w) configure -text $objList
    }

    $vsd(ctrfilter:w) configure -disablecallback true -state normal
    set vsd(ctrfilter) [getStatFilter $c]
    $vsd(ctrfilter:w) configure -disablecallback false
    $vsd(ctrlevel:w) configure -disablecallback true -state normal
    set vsd(ctrlevel) [getStatLevel $c]
    $vsd(ctrlevel:w) configure -disablecallback false
    set counterDoc [getPlainStatDescription $c]
    if {$counterDoc != {}} {
	$vsd(doctext:w) insert 1.0 $counterDoc
    }
    $vsd(doctext:w) configure -state disabled
}

proc showCounterInfo {c} {
    global vsd
    
    if {$c == {}} {
	return
    }


    set oldctr $vsd(lastctr)
    if {[string equal $c $vsd(lastctr)]} {
	return
    }
    set vsd(lastctr) $c
    if {![string equal withdrawn [wm state .ctrinfo]]} {
	if {[info exists vsd(ctrbox:w)] && [winfo exists $vsd(ctrbox:w)]} {
	    set lb [$vsd(ctrbox:w) subwidget listbox]
	    set idx 0
	    foreach ctr [$lb get 0 end] {
		if {[string equal $c $ctr]} {
		    $vsd(ctrbox:w) pick $idx
		    break
		}
		incr idx
	    }
	}
    }
}

proc fileLogInfo {} {
    global vsd
    if {$vsd(statsrc) == {}} {
	return
    }

    set info [$vsd(statsrc) -info]
    set filename [file tail [lindex $info 0]]
    set gsver "[lindex $info 3] for [lindex $info 2]"
    set machine [lindex $info 4]
    set interval [lindex $info 6]
    set date "[lindex $info 5] in $interval second intervals"
    set firstTS [lindex $info 9]
    set trimLeftTS [lindex $info 10]
    set trimRightTS [lindex $info 11]

    set fileData "\nFile: [lindex $info 0]\n  Gemstone Version: $gsver\n  Machine: $machine\n  Time: $date"

    if {$firstTS != $trimLeftTS} {
	append fileData "\n  TrimLeft: [sl_stat -getdate $trimLeftTS date]"
    }
    if {$trimRightTS != -1} {
	append fileData "\n  TrimRight: [sl_stat -getdate $trimRightTS date]"
    }
    
    showData $fileData
}

proc appendDataFile {} {
    global vsd
    if {$vsd(statsrc) == {}} {
	return
    }
    set vsd(appendMode) 1
    browseDataFile
}

proc fileInfo {} {
    global vsd widgetHelp
    if {$vsd(statsrc) == {}} {
	return
    }

    set info [$vsd(statsrc) -info]
    set filename [file tail [lindex $info 0]]
    set gsver "[lindex $info 3] for [lindex $info 2]"
    set machine [lindex $info 4]
    set interval [lindex $info 6]
    set date "timestamps since [lindex $info 5] in $interval second intervals"

    set w .vsdfileinfo
    if [winfo exists $w] {
	regexp {(.*x.*)(\+.*\+.*)} [wm geometry $w] junk parentSize position
	destroy $w
    } else {
	regexp {(.*x.*)(\+.*\+.*)} [wm geometry $vsd(w)] junk parentSize position
    }
	
    set widgetHelp($w) {File Information Window}
    toplevel $w
    wm geometry $w $position
    wm title $w "info on $filename"

    frame $w.top -relief raised -bd 1

    tixLabelFrame $w.top.gsver -label "GemStone Version"
    set f [$w.top.gsver subwidget frame]
    label $f.l -text $gsver
    pack $f.l
    pack $w.top.gsver -fill x -expand yes

    tixLabelFrame $w.top.machine -label "Machine Information"
    set f [$w.top.machine subwidget frame]
    label $f.l -text $machine
    pack $f.l
    pack $w.top.machine -fill x -expand yes

    tixLabelFrame $w.top.time -label "Time Information"
    set f [$w.top.time subwidget frame]
    label $f.l -text $date
    pack $f.l
    pack $w.top.time -fill x -expand yes

    pack $w.top -side top -fill both -expand yes

    tixButtonBox $w.box
    $w.box add dismiss -text Dismiss -width 6 -command "destroy $w"
    $w.box add log -text "Log..." -width 6 -command fileLogInfo
    set but [$w.box subwidget dismiss]
    pack $w.box -fill x -side bottom
}

proc fileDump {} {
    global vsd
    if {$vsd(statsrc) != {}} {
	# NYI: hack implementation
	$vsd(statsrc) -dump
    }
}

proc singleFileMode {} {
    global vsd
    if {$vsd(singleFileMode)} {
	set vsd(lastEnabledFiles) [sl_stat -enabledfiles]
	foreach f $vsd(lastEnabledFiles) {
	    if {![string equal $f $vsd(statsrc)]} {
		$f -disable
	    }
	}
    } else {
	set files $vsd(lastEnabledFiles)
	if {$files == {}} {
	    # enable them all
	    set files [sl_stat -allfiles]
	} else {
	    if {$vsd(statsrc) != {}} {
		lappend files $vsd(statsrc)
	    }
	}
	foreach f $files {
	    $f -enable
	}
    }
    setInstanceList
    updateGraphWidgetState
}

proc fileEnableMode {} {
    global vsd
    if {$vsd(statsrc) != {}} {
	if {$vsd(file:isEnabled)} {
	    $vsd(statsrc) -enable
	} else {
	    $vsd(statsrc) -disable
	}
	setInstanceList
	updateGraphWidgetState
    }
}

proc fileUntrimLeft {f} {
    if {$f != {}} {
	$f -trimleft 0
    }
    updateFileTrimMenuItems [$f -info]
    updateAllLineTrimMenuItems
}

proc fileUntrimRight {f} {
    if {$f != {}} {
	$f -trimright -1
    }
    updateFileTrimMenuItems [$f -info]
    updateAllLineTrimMenuItems
}

proc fileUpdateAll {} {
    global vsd
    foreach f [sl_stat -enabledfiles] {
        fileUpdate $f
    }
}

proc fileUpdate {f} {
    global vsd
    if {$f != {} && $vsd(updateok:$f)} {
	if [catch {$f -update} updateCount] {
	    set vsd(updateok:$f) 0
	    set vsd(autoUpdate:$f) 0
	    if [info exists vsd(autoUpdateId:$f)] {
		after cancel $vsd(autoUpdateId:$f)
		unset vsd(autoUpdateId:$f)
	    }
	    if {$f == $vsd(statsrc)} {
		$vsd(w:filemenu) entryconfigure "Update" -state disabled
		$vsd(w:filemenu) entryconfigure "Auto Update" -state disabled
		set vsd(autoUpdate) 0
	    }
	    showError "Update failed because: $updateCount"
	}
	if {$updateCount != 0} {
	    if {$vsd(noFlatlines)} {
		# NYI optimize this so it doesn't unconditionally zap everyone
		foreach idx [array names vsd {*:ctrlistid}] {
		    set vsd($idx) {}
		}
	    }
	    set isEnabled [lindex [$f -info] 7]
	    if {$isEnabled} {
		foreach c $vsd(zeroCtrs) {
		    if {![sl_stat -ctrzero $c $vsd(selectedInstIds)]} {
			fillCounters 1 [$vsd(instanceList) info selection]
			break
		    }
		}
		updateInstanceList
	    }
	}
    }
}

proc doAutoUpdate {f t} {
    global vsd
    if {!$vsd(autoUpdatesDisabled)} {
	fileUpdate $f
    }
    set vsd(autoUpdateId:$f) [after $t [list doAutoUpdate $f $t]]
}

proc disableAutoUpdates {} {
    global vsd
    set vsd(autoUpdatesDisabled) 1
}

proc enableAutoUpdates {} {
    global vsd
    set vsd(autoUpdatesDisabled) 0
}

proc clearStatus {} {
    global vsd
    set vsd(status) ""
}

proc setStatus {msg} {
    global vsd
    if [info exists vsd(statusTimeout)] {
	after cancel $vsd(statusTimeout)
	unset vsd(statusTimeout)
    }
    set vsd(status) $msg
    set vsd(statusTimeout) [after 10000 clearStatus]
}

proc autoUpdate {} {
    global vsd
    set f $vsd(statsrc)

    if {$f == {}} {
	return
    }
    
    if [info exists vsd(autoUpdateId:$f)] {
	after cancel $vsd(autoUpdateId:$f)
	unset vsd(autoUpdateId:$f)
    }

    set vsd(autoUpdate:$f) $vsd(autoUpdate)

    if {$vsd(autoUpdate)} {
	set interval [expr [lindex [$f -info] 6] * 1000]
	if {$interval == 0} {
	    set interval $vsd(autoUpdateTime)
	}
	doAutoUpdate $f $interval
    }
}

proc monitorBrowse {e} {
    global vsd
    set w .monitors
    if {![winfo exists $w]} {
	return
    }
    set l [$w.top.monlist subwidget hlist]

    set data [$l info data $e]
    set name [lindex $data 0]
    set version [lindex $data 1]
    set gemstone [lindex $data 3]
    if [info exists vsd(statmonpid:$name)] {
	[$w.box subwidget start] configure -state disabled
	[$w.box subwidget status] configure -state normal
	[$w.box subwidget stop] configure -state normal

	if [info exists vsd(statmonoutput:$name)] {
	    $w.statmonfile configure -state normal
	    set vsd(wv:statmonfile) $vsd(statmonoutput:$name)
	}
	$w.statmonfile configure -state disabled

	if [info exists vsd(statmoninterval:$name)] {
	    $w.ctr.statmoninterval configure -state normal
	    set vsd(wv:statmoninterval) $vsd(statmoninterval:$name)
	}
	$w.ctr.statmoninterval configure -state disabled
	if [info exists vsd(statmonflush:$name)] {
	    $w.ctr.statmonflush configure -state normal
	    set vsd(wv:statmonflush) $vsd(statmonflush:$name)
	}
	$w.ctr.statmonflush configure -state disabled
	if [info exists vsd(statmonlevel:$name)] {
	    $w.ctr.statmonlevel configure -state normal
	    set vsd(wv:statmonlevel) $vsd(statmonlevel:$name)
	}
	$w.ctr.statmonlevel configure -state disabled
	if [info exists vsd(statmonappstats:$name)] {
	    $w.ctr.statmonappstats configure -state normal
	    set vsd(wv:statmonappstats) $vsd(statmonappstats:$name)
	}
	$w.ctr.statmonappstats configure -state disabled
	if [info exists vsd(statmoncompress:$name)] {
	    $w.ctr2.compress configure -state normal
	    set vsd(wv:statmoncompress) $vsd(statmoncompress:$name)
	}
	$w.ctr2.compress configure -state disabled
	if [info exists vsd(statmonsessions:$name)] {
	    $w.ctr2.statmonsessions configure -state normal
	    set vsd(wv:statmonsessions) $vsd(statmonsessions:$name)
	}
	$w.ctr2.statmonsessions configure -state disabled
	if [info exists vsd(statmonpids:$name)] {
	    $w.ctr2.statmonpids configure -state normal
	    set vsd(wv:statmonpids) $vsd(statmonpids:$name)
	}
	$w.ctr2.statmonpids configure -state disabled
    } else {
	set statmonlist {}
	[$w.box subwidget start] configure -state normal
	[$w.box subwidget status] configure -state disabled
	[$w.box subwidget stop] configure -state disabled
	set vsd(wv:statmonfile) ""
	$w.statmonfile configure -state normal
	$w.ctr.statmoninterval configure -state normal
	$w.ctr.statmonflush configure -state normal
	$w.ctr.statmonlevel configure -state normal
	$w.ctr.statmonappstats configure -state normal
	$w.ctr2.statmonsessions configure -state normal
	$w.ctr2.statmonpids configure -state normal
	set compressState "normal"
	if {[string equal $compressState "disabled"]} {
	    set vsd(wv:statmoncompress) 0
	}
	$w.ctr2.compress configure -state $compressState
    }
}

proc updateMonitorState {name updatelist} {
    global vsd
    set w .monitors
    if {![winfo exists $w]} {
	return
    }
    set l [$w.top.monlist subwidget hlist]
    set e [$l info selection]
    if {$e == {}} {
	return
    }
    set data [$l info data $e]
    if {[string equal $name [lindex $data 0]]} {
	monitorBrowse $e
    }
    if {$updatelist} {
	foreach e [$l info children] {
	    set data [$l info data $e]
	    if {[string equal $name [lindex $data 0]]} {
		if [info exists vsd(statmonpid:$name)] {
		    $l item create $e 1 -itemtype text \
			-text [lindex $vsd(statmonpid:$name) 0]
		} else {
		    $l item create $e 1 -itemtype text -text "<none>"
		}
	    }
	}
    }
}

proc showMonitorStatus {name} {
    global vsd
    set w .monstatus
    set exists [winfo exists $w]
    if $exists {
	wm deiconify $w
	raise $w
	[$w.top.msg subwidget text] delete 1.0 end
    } else {
	toplevel $w
	wm title $w "Monitor Status"
	if {$vsd(geometry:$w) != {}} {
	    wm geometry $w $vsd(geometry:$w)
	}
	frame $w.top -relief raised -bd 1
	tixScrolledText $w.top.msg -width 500 -height 100
	[$w.top.msg subwidget text] configure -wrap none -font fixedTextFont
	pack $w.top.msg -expand yes -fill both
	pack $w.top -side top -fill both -expand yes
	tixButtonBox $w.box
	$w.box add dismiss -text Dismiss -width 6 \
	    -command "dismissWindow $w"
	pack $w.box -fill x -side bottom
    }

    [$w.top.msg subwidget text] insert end $vsd(statmoncmd:$name)
    [$w.top.msg subwidget text] insert end "\n"
    [$w.top.msg subwidget text] insert end $vsd(statmonstatus:$name)
}

proc readMonitorOutput {f name} {
    global vsd
    if [eof $f] {
	catch {close $f}
	showMonitorStatus $name
	unset vsd(statmoncmd:$name)
	unset vsd(statmonpid:$name)
	unset vsd(statmonoutput:$name)
	unset vsd(statmoninterval:$name)
	unset vsd(statmonflush:$name)
	unset vsd(statmonstatus:$name)
	unset vsd(statmonsessions:$name)
	unset vsd(statmonpids:$name)
	unset vsd(statmoncompress:$name)
	unset vsd(statmonlevel:$name)
	unset vsd(statmonappstats:$name)
	updateMonitorState $name true
    } else {
	gets $f line
	append vsd(statmonstatus:$name) $line
	append vsd(statmonstatus:$name) "\n"
	if {$vsd(statmonoutput:$name) == {}} {
	    if [regexp {Output file is:[ ]+(.+)$} $line match file] {
		set vsd(statmonoutput:$name) $file
		updateMonitorState $name false
	    }
	} elseif {$vsd(statmoninterval:$name) == {}} {
	    if [regexp {Sample Interval .+is:[ ]+([0-9.]+)} $line match interval] {
		set vsd(statmoninterval:$name) $interval
		updateMonitorState $name false
	    }
	} elseif {$vsd(statmonflush:$name) == {}} {
	    if [regexp {Write Interval .+is:[ ]+([0-9.]+)} $line match flushinterval] {
		set vsd(statmonflush:$name) $flushinterval
		updateMonitorState $name false
		if {$flushinterval == 0} {
		    set i $vsd(statmoninterval:$name)
		} else {
		    set i $flushinterval
		}
		after [expr int(($i + 3) * 1000)] [list loadStatmonFile $name]
	    }
	}
    }
}

proc loadStatmonFile {name} {
    global vsd
    if [info exists vsd(statmonoutput:$name)] {
	setDataFile $vsd(statmonoutput:$name)
	# file from statmonitors started by vsd default to auto update
	set vsd(autoUpdate) 1
	autoUpdate
    }
}

proc statusMonitor {} {
    global vsd
    set w .monitors
    if {![winfo exists $w]} {
	return
    }
    set l [$w.top.monlist subwidget hlist]
    set e [$l info selection]
    if {$e == {}} {
	return
    }
    set data [$l info data $e]
    set name [lindex $data 0]
    showMonitorStatus $name
}

proc stopMonitor {} {
    global vsd
    set w .monitors
    if {![winfo exists $w]} {
	return
    }
    set l [$w.top.monlist subwidget hlist]
    set e [$l info selection]
    if {$e == {}} {
	return
    }
    set data [$l info data $e]
    set name [lindex $data 0]
    if [info exists vsd(statmonpid:$name)] {
	sl_kill $vsd(statmonpid:$name) 2
    }
}

proc stashStatmonUsage {exe} {
    global vsd
    if [info exists vsd(usage:$exe)] {
	return
    }
    catch {exec $exe} vsd(usage:$exe)
}

proc checkStatmonUsage {exe switch} {
    global vsd
    if {![info exists vsd(usage:$exe)]} {
	return 0
    }
    if {[string first " $switch " $vsd(usage:$exe)] == -1} {
	return 0
    } else {
	return 1
    }
}

proc startMonitor {} {
    global vsd isWindows env
    set w .monitors
    if {![winfo exists $w]} {
	return
    }
    set l [$w.top.monlist subwidget hlist]
    set e [$l info selection]
    if {$e == {}} {
	return
    }
    set data [$l info data $e]
    set name [lindex $data 0]
    set version [lindex $data 1]
    set gemstone [lindex $data 3]

    if [info exists vsd(statmonpid:$name)] {
	showError "StatMon is already running on cache $name."
	return
    }

    if {![string equal $name "none"]} {
	if {$version == ""} {
	    showError "No support for starting statmonitor on GemStone/S versions 4.1.3 and earlier."
	    return
	}
    }

    if [info exists vsd(statmonexe)] {
	set statmonexe $vsd(statmonexe)
    } else {
	set statmonexe ""
    }
    if {$statmonexe == {} || ![file exists $statmonexe]} {
	set statmonbase "statmonitor"
	if {$isWindows} {
	    append statmonbase ".exe"
	}
	set statmonexe [file join $gemstone bin $statmonbase]
	if {$gemstone == {} || ![file exists $statmonexe]} {
	    set statmondir [file join [file dirname [file dirname [file dirname [info nameofexecutable]]]] bin]
	    set statmonexe [file join $statmondir $statmonbase]
	    if {![file exists $statmonexe]} {
		global env
		set loaded 0
		if [info exists env(GEMSTONE)] {
		    set statmonexe [file join $env(GEMSTONE) bin $statmonbase]
		    if [file exists $statmonexe] {
			set gemstone {}
			set loaded 1
		    }
		}
		if {! $loaded} {
		    showError "Could not find statmonitor executable."
		    return
		}
	    } else {
		set gemstone [file dirname $statmondir]
	    }
	}
    }

    $vsd(w:statmoninterval) update
    $vsd(w:statmonflush) update

    stashStatmonUsage $statmonexe
    
    set statmoncmdline "$statmonexe $name"
    if {$vsd(wv:statmonfile) != {}} {
	if {[string equal ".out" [file extension $vsd(wv:statmonfile)]]} {
	    append statmoncmdline " -f [file rootname $vsd(wv:statmonfile)]"
	} else {
	    append statmoncmdline " -f $vsd(wv:statmonfile)"
	}
    }
    if {$vsd(wv:statmoninterval) != {}} {
	append statmoncmdline " -i $vsd(wv:statmoninterval)"
    }
    if {$vsd(wv:statmonflush) != {}} {
	append statmoncmdline " -u $vsd(wv:statmonflush)"
    } else {
	append statmoncmdline " -u 0"
    }
    $vsd(w:statmonlevel) update
    if {$vsd(wv:statmonlevel) != 1} {
	append statmoncmdline " -s $vsd(wv:statmonlevel)"
    }
    $vsd(w:statmonappstats) update
    if {$vsd(wv:statmonappstats) != 0} {
	append statmoncmdline " -n $vsd(wv:statmonappstats)"
    }
    if {$vsd(wv:statmonsessions) != {}} {
	foreach id $vsd(wv:statmonsessions) {
	    append statmoncmdline " -p $id"
	}
    }
    if [checkStatmonUsage $statmonexe "-P"] {
	if {$vsd(wv:statmonpids) != {}} {
	    foreach id $vsd(wv:statmonpids) {
		append statmoncmdline " -P $id"
	    }
	}
    }
    if {$vsd(wv:statmoncompress)} {
	append statmoncmdline " -z"
    }
    if [checkStatmonUsage $statmonexe "-v"] {
	append statmoncmdline " -v [pid]"
    }
    set oldGemstone {}
    if {$gemstone != {}} {
	if [info exists env(GEMSTONE)] {
	    set oldGemstone $env(GEMSTONE)
	}
	set env(GEMSTONE) $gemstone
    }
    set cmdstr "|$statmoncmdline 2>@stdout"
    if [catch {open $cmdstr r} result] {
	showError "The command '$statmoncmdline'\nfailed with: $result"
	if {$oldGemstone != {}} {
	    set env(GEMSTONE) $oldGemstone
	}
	return
    }
    if {$oldGemstone != {}} {
	set env(GEMSTONE) $oldGemstone
    }
    set vsd(statmoncmd:$name) $statmoncmdline
    set vsd(statmonpid:$name) [lindex [pid $result] 0]
    set vsd(statmonoutput:$name) ""
    set vsd(statmoninterval:$name) ""
    set vsd(statmonflush:$name) ""
    set vsd(statmonstatus:$name) ""
    set vsd(statmonsessions:$name) $vsd(wv:statmonsessions)
    set vsd(statmonpids:$name) $vsd(wv:statmonpids)
    set vsd(statmoncompress:$name) $vsd(wv:statmoncompress)
    set vsd(statmonlevel:$name) $vsd(wv:statmonlevel)
    if {$vsd(wv:statmonappstats) != 0} {
	set vsd(statmonappstats:$name) $vsd(wv:statmonappstats)
    } else {
	set vsd(statmonappstats:$name) ""
    }
    updateMonitorState $name true
    fileevent $result readable [list readMonitorOutput $result $name]
}

proc sl_caches {} {
    set result {}
    if [catch {exec gslist -x} gslistOutput] {
	# something went wrong. Probably no gslist.
    } else {
	# parse the result
	set matchData [regexp -all -inline {([^\n]+)\s+status=[^\n]+\s+type=\s+([^\n]+)\s+version=\s+([^\n]+)\s+owner=\s+([^\n]+)\s+(?:\S+=[^\n]+\s+){3,7}(GEMSTONE|product)=\s*([^\n]+)\s*} $gslistOutput]
	foreach {junk name type version owner junk2 dir} $matchData {
	    if {[string equal $type "SAP"] || [string equal $type "cache"]} {
		lappend result [list $name $version $owner $dir]
	    }
	}
    }
    return $result
}

proc getMonitorTargets {} {
    global tcl_platform
    set res [sl_caches]
    lappend res [list none $tcl_platform(osVersion) [info hostname] [file dirname [file dirname [info nameofexecutable]]]]
    return $res
}
proc refreshMonitors {} {
    global vsd
    set w .monitors
    if {![winfo exists $w]} {
	return
    }
    set l [$w.top.monlist subwidget hlist]
    $l delete all
    [$w.box subwidget start] configure -state disabled
    [$w.box subwidget status] configure -state disabled
    [$w.box subwidget stop] configure -state disabled
    foreach c [getMonitorTargets] {
	set name [lindex $c 0]
	set row [$l addchild "" -data $c -itemtype text -text $name]
	if [info exists vsd(statmonpid:$name)] {
	    $l item create $row 1 -itemtype text \
		-text [lindex $vsd(statmonpid:$name) 0]
	} else {
	    $l item create $row 1 -itemtype text -text "<none>"
	}
	$l item create $row 2 -itemtype text -text [lindex $c 1]
	$l item create $row 3 -itemtype text -text [lindex $c 2]
    }
}

proc dismissWindow {w} {
    global vsd
    set vsd(geometry:$w) [wm geometry $w]
    destroy $w
}

proc changeCtrFilter {newFilter} {
    global vsd
    set ctr $vsd(lastctr)
    set curfilter [getStatFilter $ctr]
    if {[string equal $curfilter $newFilter]} {
	return
    } else {
	setStatFilter $ctr $newFilter
    }
}

proc showStatisticInfoHelp {} {
    global vsd
    set topic "$vsd(lastctr) Statistic"
    doHelp $topic
}

proc changeCtrLevel {newLevel} {
    global vsd
    set ctr $vsd(lastctr)
    if {[string equal [getStatLevel $ctr] $newLevel]} {
	return
    } else {
	setStatLevel $ctr $newLevel
    }
}

proc getUsedStatNames {} {
    if {[llength [sl_stat -allfiles]] > 0} {
	return [sl_stat -objctrs {}]
    } else {
	return [sl_stat -names]
    }
}

proc updateCounterList {} {
    global vsd
    set ctrnames [getUsedStatNames]
    set newStatNameCount [llength $ctrnames]
    if {$vsd(statNameCount) != $newStatNameCount} {
	set vsd(statNameCount) $newStatNameCount
	if {[info exists vsd(ctrbox:w)] && [winfo exists $vsd(ctrbox:w)]} {
	    set w $vsd(ctrbox:w)
	    [$w subwidget listbox] delete 0 end
	    foreach c [lsort -dictionary $ctrnames] {
		$w insert end $c
	    }
	    set c $vsd(lastctr)
	    set vsd(lastctr) {}
	    showCounterInfo $c
	}
    }
}

proc destroyCtrInfo {w} {
    global vsd
    set vsd(showCtrInfo) 0
    wm withdraw $w
}

proc createCtrInfo {w} {
    global vsd widgetHelp

    toplevel $w
    wm protocol $w WM_DELETE_WINDOW "destroyCtrInfo $w"

    if {$vsd(geometry:$w) != {}} {
	wm geometry $w $vsd(geometry:$w)
    }
    set widgetHelp($w) {Statistic Information Window}
    wm title $w "Statistic Information"

    set vsd(ctrbox:w) $w.counters
    tixComboBox $w.counters -dropdown true -editable false -value "" \
	-command showCounter
    $vsd(balloon) bind $w.counters -msg "Selects statistic to display/modify information on"
    bind [$w.counters subwidget entry] <KeyPress> \
	[list findByFirstLetter $w.counters %A 1]
    bind [$w.counters subwidget entry] <Control-s> \
	[list startSearch $w.counters  searchComboBox]
    set ctrlist [lsort -dictionary [getUsedStatNames]]
    if {$vsd(lastctr) == {}} {
	set vsd(lastctr) [lindex $ctrlist 0]
    }
    set vsd(statNameCount) [llength $ctrlist]
    foreach c $ctrlist {
	$w.counters insert end $c
    }
    pack $w.counters -fill x -padx 3 -pady 3

    frame $w.top
    tixLabelFrame $w.top.type -labelside left -label "Kind:"
    set f [$w.top.type subwidget frame]
    label $f.l -text "none"
    set vsd(ctrtype:w) $f.l
    pack $f.l
    pack $w.top.type -fill x -side left
    $vsd(balloon) bind $w.top.type -msg "Shows the statistic's kind"

    tixLabelFrame $w.top.units -labelside left -label "Units:"
    set f [$w.top.units subwidget frame]
    label $f.l -text "none"
    set vsd(ctrunits:w) $f.l
    pack $f.l
    pack $w.top.units -fill x -side right
    $vsd(balloon) bind $w.top.units -msg "Shows the units that the statistic measures"

    pack $w.top -fill x -padx 3 -pady 3
    
    tixLabelFrame $w.ctrobjs -labelside left -label "Types:"
    set f [$w.ctrobjs subwidget frame]
    label $f.l -text "none"
    set vsd(ctrobjs:w) $f.l
    pack $f.l
    pack $w.ctrobjs -padx 3 -pady 3 -anchor w
    $vsd(balloon) bind $w.ctrobjs -msg "Shows all instance types that have this statistic"

    tixOptionMenu $w.filtertype -label "Default Filter:" -variable vsd(ctrfilter) \
	-state disabled -command changeCtrFilter \
	-options {
	    label.width 12
	}
    $vsd(balloon) bind $w.filtertype -msg "Click to change statistic's default filter"
    set vsd(ctrfilter:w) $w.filtertype
    $vsd(ctrfilter:w) configure -disablecallback true
    $w.filtertype add command default -label "Default"
    $w.filtertype add command none -label "None"
    $w.filtertype add command persecond -label "PerSecond"
    $w.filtertype add command persample -label "PerSample"
#    $w.filtertype add command smooth -label "Smooth"
    $w.filtertype add command aggregate -label "Aggregate"
    set vsd(ctrfilter) default
    $vsd(ctrfilter:w) configure -disablecallback false
    pack $w.filtertype -padx 3 -pady 3 -anchor w

    tixOptionMenu $w.level -label "Level:" -variable vsd(ctrlevel) \
	-state disabled -command changeCtrLevel \
	-options {
	    label.width 12
	}
    $vsd(balloon) bind $w.level -msg "Click to change statistic's level"
    set vsd(ctrlevel:w) $w.level
    $vsd(ctrlevel:w) configure -disablecallback true
    $w.level add command common
    $w.level add command advanced
    $w.level add command wizard
    set vsd(ctrlevel) common
    $vsd(ctrlevel:w) configure -disablecallback false
    pack $w.level -padx 3 -pady 3 -anchor w

    button $w.help -text "Statistic Help" -command {showStatisticInfoHelp}
    pack $w.help -padx 3 -pady 3
    $vsd(balloon) bind $w.help -msg "Click to see statistic's help topic"

    tixLabelFrame $w.fdoc -label "Statistic Description"
    set fdoc [$w.fdoc subwidget frame]
    tixScrolledText $fdoc.doc -scrollbar y -width 250 -height 120
    set vsd(doctext:w) [$fdoc.doc subwidget text]
    $vsd(doctext:w) configure -wrap word -takefocus 0 -state disabled
    $vsd(balloon) bind $w.fdoc -msg "Describes the current statistic"

    pack $fdoc.doc -fill both -expand yes
    pack $w.fdoc -fill both -expand yes
}

proc dumpCtrInfo {} {
    global vsd

    set str {}
    foreach c [lsort -dictionary [sl_stat -names]] {
	append str "\n" $c
	append str "\n  type: " [getStatType $c] "  level: " [getStatLevel $c] "  units: " [getStatLevel $c] "  filter: " [getStatFilter $c] "\n" [getPlainStatDescription $c] "\n  os: " [isOSStat $c] "  objects: " [getStatObjList $c] "\n"
    }
    showData $str 1
}

proc doCtrInfo {} {
    global vsd
    set w .ctrinfo
    if {$vsd(showCtrInfo)} {
	if [winfo exists $w] {
	    wm deiconify $w
	    raise $w
	} else {
	    createCtrInfo $w
	}
	set c $vsd(lastctr)
	set vsd(lastctr) {}
	showCounterInfo $c
    } else {
	if {![winfo exists $w]} {
	    createCtrInfo $w
	    set vsd(lastctr) {}
	}
	wm withdraw $w
    }
}

proc doCopySelection {} {
    global vsd
    set procs [$vsd(instanceList) info selection]
    if {$procs == {}} {
	return
    }
    set ctrs [getSelCtr]
    if {$ctrs == {}} {
	return
    }
    set vsd(clipboard) {}
    lappend vsd(clipboard) "selection"
    lappend vsd(clipboard) [list $procs $ctrs]
}

# Added to fix bug 27336
proc doChangeDirectory {} {
    global vsd
    set newDir [tk_chooseDirectory -parent $vsd(w) -mustexist true -title "VSD Working Directory"]
    if {$newDir != {}} {
	cd $newDir
    }
}

proc doMonitor {} {
    global vsd widgetHelp
    set w .monitors
    if [winfo exists $w] {
	wm deiconify $w
	focus $w
	raise $w
	refreshMonitors
	return
    }

    set widgetHelp($w) {Monitor Window}

    toplevel $w
    wm protocol $w WM_DELETE_WINDOW "wm withdraw $w"
    wm title $w "Monitor"
    if {$vsd(geometry:$w) != {}} {
	wm geometry $w $vsd(geometry:$w)
    }
    frame $w.top -relief raised -bd 1

    tixScrolledHList $w.top.monlist -width 300 -options {
	hlist.columns 4
	hlist.header true
	hlist.height 3
	hlist.selectMode single
	hlist.BrowseCmd monitorBrowse
    }
    set l [$w.top.monlist subwidget hlist]
#     global isWindows
#     if {$isWindows} {
# 	$l configure -font [tix option get font] \
# 	    -selectbackground SystemHighlight \
# 	    -selectforeground SystemHighlightText \
#     }

    # First some styles for the headers
    set vsd(header:s) [tixDisplayStyle text -fg black \
			   -anchor c -padx 8 -pady 2 \
			   -font [tix option get bold_font]]

    $l header create 0 -itemtype text -text "Cache Name" \
	-style $vsd(header:s)
    $l header create 1 -itemtype text -text "StatMon" \
	-style $vsd(header:s)
    $l header create 2 -itemtype text -text "Version" \
	-style $vsd(header:s)
    $l header create 3 -itemtype text -text "Creator" \
	-style $vsd(header:s)
    pack $w.top.monlist -expand yes -fill both
    $vsd(balloon) bind $w.top.monlist -msg "Lists/Selects statistic sources and monitor processes"

    set vsd(wv:statmonfile) ""
    tixLabelEntry $w.statmonfile -label "StatMon Output:" -state disabled \
	-options {
	    entry.textVariable vsd(wv:statmonfile)
	}
    $vsd(balloon) bind $w.statmonfile -msg "Click to enter file name that monitor will write to"

    frame $w.ctr -relief flat -bd 0
    set vsd(w:statmoninterval) $w.ctr.statmoninterval
    tixControl $w.ctr.statmoninterval -label "Sample Interval:" -state disabled \
	-integer 1 -min 1 -autorepeat false -variable vsd(wv:statmoninterval) \
	-value $vsd(wv:statmoninterval) \
	-options {
	    entry.width 3
	}
    $vsd(balloon) bind $w.ctr.statmoninterval -msg "How often, in seconds, monitor should sample"

    set vsd(w:statmonflush) $w.ctr.statmonflush
    tixControl $w.ctr.statmonflush -label "Write Interval:" -state disabled \
	-integer 1 -min -1 -autorepeat false -variable vsd(wv:statmonflush) \
	-value $vsd(wv:statmonflush) \
	-options {
	    entry.width 3
	}
    $vsd(balloon) bind $w.ctr.statmonflush -msg "How often, in seconds, monitor should flush collected data to disk"

    set vsd(w:statmonlevel) $w.ctr.statmonlevel
    tixControl $w.ctr.statmonlevel -label "Level:" -state disabled \
	-integer 1 -min 0 -max 4 -autorepeat false \
	-variable vsd(wv:statmonlevel) \
	-value $vsd(wv:statmonlevel) \
	-options {
	    entry.width 1
	}
    $vsd(balloon) bind $w.ctr.statmonlevel -msg "Controls the operating system statistics that are collected"

    set vsd(w:statmonappstats) $w.ctr.statmonappstats
    tixControl $w.ctr.statmonappstats -label "AppStat Count:" -state disabled \
	-integer 1 -min 0 -max 2048 -autorepeat false \
	-variable vsd(wv:statmonappstats) \
	-value $vsd(wv:statmonappstats) \
	-options {
	    entry.width 4
	}
    $vsd(balloon) bind $w.ctr.statmonappstats -msg "Controls how many shared counters are collected"

    pack $w.ctr.statmoninterval $w.ctr.statmonflush $w.ctr.statmonlevel $w.ctr.statmonappstats -side left
    
    frame $w.ctr2 -relief flat -bd 0
    checkbutton $w.ctr2.compress -text "Compress" \
	-variable vsd(wv:statmoncompress) -state disabled
    pack $w.ctr2.compress -expand no -side left
    tixLabelEntry $w.ctr2.statmonpids -label "Pids:" \
        -state disabled \
	-options {
	    entry.textVariable vsd(wv:statmonpids)
	}
    $vsd(balloon) bind $w.ctr2.compress -msg "Check if output should be compressed"
    pack $w.ctr2.statmonpids -expand yes -fill x -side left
    $vsd(balloon) bind $w.ctr2.statmonpids -msg "List of extra process ids to collect OS stats on"
    tixLabelEntry $w.ctr2.statmonsessions -label "Sessions:" \
        -state disabled \
	-options {
	    entry.textVariable vsd(wv:statmonsessions)
	    entry.width 4
	}
    pack $w.ctr2.statmonsessions -side left
    $vsd(balloon) bind $w.ctr2.statmonsessions -msg "Restricts session statistic collection to this list of ids"

    tixButtonBox $w.box
    $w.box add refresh -text Refresh -width 6 \
      -command refreshMonitors
    $vsd(balloon) bind [$w.box subwidget refresh] -msg "Update display of statistic sources that can be monitored"
    $w.box add start -text Start -width 6 -state disabled \
      -command startMonitor
    $vsd(balloon) bind [$w.box subwidget start] -msg "Start monitoring the select statistic source"
    $w.box add status -text Status -width 6 -state disabled \
      -command statusMonitor
    $vsd(balloon) bind [$w.box subwidget status] -msg "Show the status of the selected monitor task"
    $w.box add stop -text Stop -width 6 -state disabled \
      -command stopMonitor
    $vsd(balloon) bind [$w.box subwidget stop] -msg "Stop the selected monitor task"
    $w.box add dismiss -text Dismiss -width 6 \
      -command "wm withdraw $w"
    set but [$w.box subwidget dismiss]
    $vsd(balloon) bind $but -msg "Close the monitor window"


    pack $w.box -fill x -side bottom
    pack $w.ctr2 -expand no -fill x -side bottom
    pack $w.ctr -fill x -side bottom
    pack $w.statmonfile -expand no -fill x -side bottom
    pack $w.top -side top -fill both -expand yes

    refreshMonitors
}

proc createVsdConfig {fname} {
    global vsd

    if [catch {open $fname w+} f] {
        showError "Notice: could not write $fname because:\n$f"
	return
    }
puts $f "\# .vsdconfig is never changed by vsd. If the user deletes it then
\# the next time vsd is started it will be recreated with default values.
\# Users can configure vsd by setting default values in this file.
\# Any value set in .vsdconfig will override the same definition in .vsdrc.
\# Make sure and put braces around the value if it contains whitespace.
\# For example: set vsd(exec:lpr) {lpr -h}
"

    puts $f "\# vsd(exec:lpr) is the name of the command used to print.
\# It is called with one argument; the name of the file to be printed."
    puts $f "set vsd(exec:lpr) [list $vsd(exec:lpr)]"

    puts $f "\n\# vsd(exec:mail) is the name of the command used to send mail.
\# It is called with one argument; the name of the user to send mail to.
\# It also expects the message to mail from stdin."
    puts $f "set vsd(exec:mail) [list $vsd(exec:mail)]"

    puts $f "\n\# vsd(exec:date) is the name of the command used to get the date.
\# It is called with no arguments."
    puts $f "set vsd(exec:date) [list $vsd(exec:date)]"

    puts $f "\n\# vsd(exec:uname) is the name of the command used to get system info.
\# It is called with no arguments."
    puts $f "set vsd(exec:uname) [list $vsd(exec:uname)]"

    puts $f "\n\# Uncomment the next line if you do not want the cursor to blink.
\# set vsd(cursorblink) 0"

puts $f {
# See the vsd help section "Statistic Definitions" for a guide to adding
# your own definitions to this file.
#
# See the vsd help section "Statistic Aliases" for a guide to adding
# your own aliases to this file.
}
    catch {close $f}
}

proc chooseChart {title} {
    global vsd
    if [info exists vsd(ct:$title)] {
	set w $vsd(ct:$title)
	if [winfo exists $w] {
	    wm deiconify $w
	    raise $w
	}
    }
}

proc changeNoFlatlines {} {
    global vsd

    foreach idx [array names vsd {*:ctrlistid}] {
	set vsd($idx) {}
    }
    fillCounters 1 [$vsd(instanceList) info selection]
}

proc changeLevel {} {
    global vsd
    if {[string equal [sl_stat -level] $vsd(statlevel)]} {
	return
    }
    sl_stat -level $vsd(statlevel)
    # Cause each chart windows counter listbox to be recalculated
    foreach i [array names vsd *:ctrlistid] {
	set vsd($i) {}
    }
    # fix for bug 26924
    updateCounterList
    # Make sure main window statistic list updated
    fillCounters 1 [$vsd(instanceList) info selection]
}

proc traceAPICalls {} {
    global vsd
    sl_stat -trace $vsd(traceAPICalls)
}

proc ctrHlistBrowse {junk} {
    global vsd
    set te [tixEvent type]
    if {![string equal $te "<ButtonRelease-1>"]} {
	set lb $vsd(w:counterHList)
	if {![string equal $te "<Up>"] &&
	    ![string equal $te "<Down>"] &&
	    ![string equal $te "<Application>"]} {
	    set i [$lb nearest [tixEvent flag y]]
	} else {
	    set i [$lb info anchor]
	}
	if {$i != {} && [$lb selection includes $i]} {
	    set itext [$lb entrycget $i -text]
	    showCounterInfo $itext
	}
	updateDisabledItems
    }
}

proc ctrHlistCommand {e} {
    global vsd

    doChart 0
}

proc setActiveColor {} {
    global vsd
    set color [tk_chooseColor -initialcolor $vsd(activecolor) \
                   -parent $vsd(w) -title "Choose Selected Line Color"]
    if {$color != ""} {
        set vsd(activecolor) $color
	foreach name [array names vsd  ct:*] {
	    set g $vsd($name).graph
	    $g pen configure "activeLine" -color $vsd(activecolor)
	    $g marker configure triStart -fg $vsd(activecolor)
	    $g marker configure triEnd -fg $vsd(activecolor)
	}
    }
}

proc applyChartFont {res} {
    font delete vsdsf
    eval font create vsdsf $res
}

proc setChartFont {} {
    set res [Font_Select "Chart Font" applyChartFont [font actual vsdsf]]
    if {[string length $res] != 0} {
	applyChartFont $res
    }
}

proc createTextFonts {} {
    global vsd
    eval font create normalTextFont $vsd(textfont)
    eval font create boldTextFont $vsd(textfont) -weight bold
    eval font create italicTextFont $vsd(textfont) -slant italic
    eval font create boldItalicTextFont $vsd(textfont) -weight bold -slant italic
    eval font create fixedTextFont $vsd(textfont) -family Courier -weight bold
}

proc applyTextFont {res} {
    global vsd
    set vsd(textfont) $res
    font delete normalTextFont boldTextFont italicTextFont boldItalicTextFont fixedTextFont
    createTextFonts
}
proc setTextFont {} {
    set res [Font_Select "Help Font" applyTextFont [font actual normalTextFont]]
    if {[string length $res] != 0} {
	applyTextFont $res
    }
}

proc Font_Select {title applyCmd {defaults {}}} {
    global font widgetHelp

    set font(applyCalled) 0
    set font(applyCmd) $applyCmd
    set font(defaults) $defaults
    set font(otherSize) 0
    set top .fontsel
    set widgetHelp($top) {Font Window}
	# Create the menus for the menu bar

	toplevel $top -class Fontsel -bd 10
        wm title $top $title
	set menubar [menu $top.menubar]
	$top config -menu $menubar
	foreach x {File Font Size Format} {
		set menu [menu $menubar.[string tolower $x]]
		$menubar add cascade -menu $menu -label $x
	}
        $menubar.file configure -tearoff 0
	$menubar.file add command -label Reset -command FontReset
	$menubar.file add command -label Apply -command FontApply
	$menubar.file add command -label OK \
		-command {set font(ok) 1}
	$menubar.file add command -label Cancel \
		-command {set font(ok) 0}

	# Build a cascaded family menu if there are lots of fonts

	set allfonts [lsort [font families]]
	set numfonts [llength $allfonts]
	set i 0
	foreach family $allfonts {
	    incr i
	    set cb 0
	    if {($i % 15) == 0} {
		set cb 1
	    }
	    $menubar.font add radio -label $family \
		-variable font(-family) \
		-value $family \
		-columnbreak $cb \
		-command FontUpdate
	}

	# Complete the other menus

	foreach size {6 7 8 10 12 14 18 24} {
		$menubar.size add radio -label $size \
			-variable font(-size) \
			-value $size \
			-command FontUpdate
	}
	$menubar.size add command -label Other... \
			-command [list FontSetSize $top]
	$menubar.format add check -label Bold \
			-variable font(-weight) \
			-onvalue bold -offvalue normal \
			-command FontUpdate
	$menubar.format add check -label Italic \
			-variable font(-slant) \
			-onvalue italic -offvalue roman \
			-command FontUpdate
	$menubar.format add check -label Underline \
		-variable font(-underline) \
		-command FontUpdate
	$menubar.format add check -label Overstrike \
		-variable font(-overstrike) \
		-command FontUpdate

	FontReset

	# This label displays the current font
	label $top.font -textvar font(name) -bd 5

	# A message displays a string in the font.
	message $top.msg -aspect 1000 \
					-borderwidth 10 -font fontsel \
					-text  "
ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
0123456789
!@#$%^&*()_+-=[]{};:\"'` ~,.<>/?\\|
"

	# Lay out the dialog

	pack $top.font $top.msg  -side top
	set f [frame $top.buttons]
	button $f.ok -text Ok -command {set font(ok) 1}
        button $f.apply -text Apply -command FontApply
	button $f.cancel -text Cancel -command {set font(ok) 0}
	pack $f.ok $f.apply $f.cancel -padx 10 -side left
	pack $f -side top

    set font(ok) -1
	Dialog_Wait $top
	destroy $top
	if {$font(ok)} {
		return [array get font -*]
	} else {
	        FontReset
		return {}
	}
}
proc FontApply {} {
    global font

    set font(applyCalled) 1
    $font(applyCmd) [array get font -*]
}

proc FontUpdate { } {
	global font

	# The elements of font that have a leading - are
	# used directly in the font configuration command.

	eval {font configure fontsel} [array get font -*]
	FontSet
}
proc FontReset {} {
        global font
	catch {font delete fontsel}
	eval font create fontsel $font(defaults)
	FontSet
        if {$font(applyCalled)} {
	    FontApply
	    set font(applyCalled) 0
	}
}
proc FontSet {} {
	global font

	# The name is the font configuration information
	# with a line break so it looks nicer

	set font(name) [font actual fontsel]
	regsub -- "-slant" $font(name) "\n-slant" font(name)

	# Save the actual parameters after any font substitutions

	array set font [font actual fontsel]
}
proc FontSetSize {top} {
        global font

    if {$font(otherSize)} {
	return
    }
	# Add an entry to enter a specific size.

        set font(otherSize) 1
	set f [frame $top.size -borderwidth 10]
	pack $f -side top -fill x
	label $f.msg -text "Size:"
	entry $f.entry -textvariable font(-size)
	bind $f.entry <Return> FontUpdate
	pack $f.msg -side left
	pack $f.entry -side top -fill x
}
proc Dialog_Wait {top {focus {}}} {
    global font

	# Poke the variable if the user nukes the window
        bind $top <Destroy> {if {$font(ok) == -1} {set font(ok) 0}}

	# Grab focus for the dialog
	if {[string length $focus] == 0} {
		set focus $top
	}
	set old [focus -displayof $top]
	focus $focus
	catch {tkwait visibility $top}
	catch {grab $top}

	# Wait for the dialog to complete
	tkwait variable font(ok)
	catch {grab release $top}
	focus $old
}

proc isCombineTemplate {tl} {
    string match {*+} [lindex $tl 0]
}
proc isOperatorTemplate {tl} {
    expr {[lsearch -exact {"plus" "diff" "divide"} [lindex $tl 0]] != -1}
}

proc fileMatches {mf df fids} {
    if {[llength $fids] > 0} {
        expr {[lsearch -exact $fids [getFileId $mf]] != -1}
    } else {
        expr {$df == {} || [string equal $df $mf]}
    }
}

proc findTemplateMatch {tl {df {}}} {
    global vsd
    set instList {}

    set typeList [string trimright [lindex $tl 0] "+"]
    set objs {}
    set fids {}
    foreach t $typeList {
        if {[string is integer -strict $t]} {
            lappend fids $t
        } else {
            lappend objs $t
        }
    }
    set name [lindex $tl 1]
    set ctr [lindex $tl 2]

    if [catch {getStatObjList $ctr} statObjList] {
	setStatus "Unknown statistic \"$ctr\"."
	bell
	return {}
    }

    if {$objs != {}} {
	set ctrobjs {}
	foreach co $statObjList {
	    set noverco [file rootname $co]
	    if {[lsearch -exact $objs $noverco] != -1} {
		lappend ctrobjs $co
	    }
	}
    } else {
	set ctrobjs $statObjList
    }
    if {$ctrobjs == {}} {
	# We don't have any instances of the target objects
	return {}
    }

    if {$vsd(templatesUseSelection)} {
	set procs [$vsd(instanceList) info selection]
	if {$procs != {}} {
	    # if some procs are selected restrict the template to them
	    foreach i $procs {
		set data [$vsd(instanceList) info data $i]
		set iobj [lindex $data 1]
		if {[lsearch -exact $ctrobjs $iobj] != -1} {
		    set fullname [lindex $data 0]
		    if {[string match $name [lindex $fullname 0]]} {
			if {[fileMatches [lindex $data 5] $df $fids]} {
			    lappend instList [lindex $data 6]
			}
		    }
		}
	    }
	    # Only return the matched selected instances if at least
	    # one of the selected types was the kind this template
	    # was trying to match.
	    if {$instList != {}} {
		return $instList
	    }
	}
    }

    set instList {}
    foreach i [instSort [sl_stat -enabledobjinstances $ctrobjs]] {
	set fullname [lindex $i 0]
	if {[string match $name [lindex $fullname 0]]} {
            if {[fileMatches [lindex $i 5] $df $fids]} {
		lappend instList [lindex $i 6]
	    }
	}
    }

    return $instList
}

proc createLinesFromTemplate {tl {df {}}} {
    global vsd
    set result {}
    set scale [lindex $tl 3]
    set filter [lindex $tl 4]
    set infoArgs [llength $tl]
    if {$infoArgs <= 7} {
	# old style with default divider, offset, and normalize
	set divider 1
	set offset 0
	set normalized 0
	set statFilter [lindex $tl 6]
    } else {
	set divider [lindex $tl 6]
	set offset [lindex $tl 7]
	set normalized [lindex $tl 8]
	set statFilter [lindex $tl 9]
    }
    if {[isOperatorTemplate $tl]} {
	set childLines {}
	foreach childSpec [lrange $tl 1 2] {
	    set isChildOp [isOperatorTemplate $childSpec]
	    lappend childLines [createLinesFromTemplate $childSpec $df]
	}
	set lines1 [lindex $childLines 0]
	set lines2 [lindex $childLines 1]
	if {[llength $lines1] > 0 && [llength $lines2] > 0} {
	    set opcode [lindex $tl 0]
	    switch -exact $opcode {
		"plus" {set operator "+"}
		"diff" {set operator "-"}
		"divide" {set operator "/"}
	    }
	    while {[llength $lines1] < [llength $lines2]} {
		lappend lines1 [lindex $lines1 end]
	    }
	    while {[llength $lines2] < [llength $lines1]} {
		lappend lines2 [lindex $lines2 end]
	    }
	    foreach l1 $lines1 l2 $lines2 {
		set line [createOperatorLine [list $l1 $l2] $operator 0 $filter $scale $divider $offset $normalized $statFilter]
		if {$line != {}} {
		    lappend result $line
		}
	    }
	}
	
	foreach tmp $childLines {
	    foreach l $tmp {
		$l -free
	    }
	}
    } else {
	set instList [findTemplateMatch $tl $df]
	if {$instList == {}} {
	    return {}
	}
	set counter [lindex $tl 2]
	if {[isCombineTemplate $tl]} {
	    if {$vsd(combineFiles) || [llength $instList] == 1} {
                if {$vsd(combineFilePattern) == "" || [llength $instList] == 1} {
                    set line [createSimpleLine $instList $counter $filter $scale $divider $offset $normalized $statFilter]
                    if {$line != {}} {
                        lappend result $line
                    }
                } else {
                    # Use combineFilePattern to group files
                    global patternMap
                    foreach fGroupName [getSortedGroupNames] {
                        set fGroupIds $patternMap($fGroupName);
                        set dfInstList {}
                        foreach inst $instList {
                            set instData [sl_stat -instinfo $inst]
                            if {[lsearch -exact $fGroupIds [lindex $instData 5]] != -1} {
                                lappend dfInstList $inst
                            }
                        }
                        if {$dfInstList != {}} {
                            set line [createSimpleLine $dfInstList $counter $filter $scale $divider $offset $normalized $statFilter]
                            if {$line != {}} {
                                lappend result $line
                            }
                        }
                    }
                }
	    } else {
		foreach fIt [getSortedFiles] {
		    set dfInstList {}
		    foreach inst $instList {
			set instData [sl_stat -instinfo $inst]
			if {[string equal $fIt [lindex $instData 5]]} {
			    lappend dfInstList $inst
			}
		    }
		    if {$dfInstList != {}} {
			set line [createSimpleLine $dfInstList $counter $filter $scale $divider $offset $normalized $statFilter]
			if {$line != {}} {
			    lappend result $line
			}
		    }
		}
	    }
	} else {
	    foreach fn $instList {
		set line [createSimpleLine [list $fn] $counter $filter $scale $divider $offset $normalized $statFilter]
		if {$line != {}} {
		    lappend result $line
		}
	    }
	}
    }
    return $result
}

proc startLongOp {w} {
    global vsd
    set w [winfo toplevel $w]
    set vsd(longOpW) $w
    set vsd(longOpCancel) 0
    myBusyOn $w
    set busyWin ${w}._Busy
    focus $busyWin
    bind $busyWin <Escape> {cancelLongOp}
    bind $busyWin <Control-g> {cancelLongOp}
}

proc cancelLongOp {} {
    global vsd
    set vsd(longOpCancel) 1
    setStatus "Cancelled operation"
    bell
}

proc endLongOp {} {
    global vsd
    if {$vsd(longOpW) != ""} {
	myBusyOff $vsd(longOpW)
	set vsd(longOpW) ""
    }
    set vsd(longOpCancel) 0
}

proc newFromTemplate {t} {
    global vsd vsdtemplates
    if {[info exists vsdtemplates($t)]} {
	if {[string equal "@" [lindex $vsdtemplates($t) 0]]} {
	    foreach tn [lrange $vsdtemplates($t) 1 end] {
		newFromTemplate $tn
	    }
	    return
	}
	disableAutoUpdates
	foreach f [getSortedFiles] {
	    set new 1
	    set w ""
	    foreach tl $vsdtemplates($t) {
		set lineList [createLinesFromTemplate $tl $f]
		if {$lineList != {}} {
		    set mapaxis [lindex $tl 5]
		    if {$new} {
			set vsd(curchart) "$t $vsd(graphcreates)"
			set w [createGraphWindow $vsd(curchart)]
			startLongOp $w
			set new 0
		    }
		    foreach line $lineList {
			if {$w != "" && ![winfo exists $w]} {set vsd(longOpCancel) 1; break}
			addLineToChart $line 0 0 $mapaxis "none"
			update
			if {$vsd(longOpCancel)} {break}
		    }
		}
		if {$vsd(longOpCancel)} {break}
	    }
	    if {$vsd(longOpCancel)} {break}
	    endLongOp
	}
	enableAutoUpdates
	endLongOp
    }
}

proc addFromTemplate {t title} {
    global vsd vsdtemplates
    if {[info exists vsdtemplates($t)]} {
	if {[string equal "@" [lindex $vsdtemplates($t) 0]]} {
	    foreach tn [lrange $vsdtemplates($t) 1 end] {
		addFromTemplate $tn $title
	    }
	    return
	}
	set w $vsd(ct:$title)
	startLongOp $w
	set vsd(curchart) $title
	disableAutoUpdates
	foreach tl $vsdtemplates($t) {
	    set lineList [createLinesFromTemplate $tl]
	    set mapaxis [lindex $tl 5]
	    foreach line $lineList {
		if {![winfo exists $w]} {set vsd(longOpCancel) 1; break}
		addLineToChart $line 0 0 $mapaxis "none"
		update
		if {$vsd(longOpCancel)} {break}
	    }
	    if {$vsd(longOpCancel)} {break}
	}
	enableAutoUpdates
	endLongOp
    }
}

proc createGraphTemplateMenu {m title} {
    global vsd vsdtemplates
    foreach t [lsort [array names vsdtemplates]] {
	$m add command -label $t -command [list addFromTemplate $t $title]
    }
}

proc reloadTemplates {m} {
    global vsd vsdtemplates

    if [file exists "~/.vsdtemplates"] {
	if [catch {source "~/.vsdtemplates"} msg] {
	    showError "Notice: could not read '~/.vsdtemplates' because:\n$msg"
	} else {
	    $m delete 0 end
	    createTemplateMenu $m
	}
    } else {
	showError "Notice: could not read '~/.vsdtemplates' because:\nfile does not exist"
    }
}

proc createTemplateMenu {m} {
    global vsd vsdtemplates
    foreach t [lsort [array names vsdtemplates]] {
	addTemplateMenu $m $t
    }
}

proc addTemplateMenu {m t} {
    $m add command -label $t -command [list newFromTemplate $t]
}

proc defaultTemplates {} {
    global vsdtemplates
    set vsdtemplates(CacheMix) {
        {Shrpc {*} FreeFrameCount 1 none y2}
        {Shrpc {*} LocalDirtyPageCount 1 none y}
        {Shrpc {*} FreeFrameLimit 1 none y}
        {Shrpc {*} BitlistPagesWrittenByGem 1 none y}
        {Shrpc {*} BitlistPagesWrittenByStone 1 none y}
        {Shrpc {*} BmInternalPagesWrittenByGem 1 none y}
        {Shrpc {*} BmInternalPagesWrittenByStone 1 none y}
        {Shrpc {*} BmLeafPagesWrittenByGem 1 none y}
        {Shrpc {*} BmLeafPagesWrittenByStone 1 none y}
        {Shrpc {*} CommitRecordPagesWrittenByGem 1 none y}
        {Shrpc {*} CommitRecordPagesWrittenByStone 1 none y}
        {Shrpc {*} DataPagesWrittenByGem 1 none y}
        {Shrpc {*} OtInternalPagesWrittenByGem 1 none y}
        {Shrpc {*} OtInternalPagesWrittenByStone 1 none y}
        {Shrpc {*} OtLeafPagesWrittenByGem 1 none y}
        {Shrpc {*} OtLeafPagesWrittenByStone 1 none y}
    }
    set vsdtemplates(CacheTooSmall) {
	{Shrpc ShrPcMonitor FreeFrameCount 1 none y2}
	{+ {*} FramesFromFreeList 1 persecond y}
	{+ {*} FramesFromFindFree 1 persecond y}
    }
    set vsdtemplates(CommitInfo) {
	{Stn {*} TotalCommits 1 persecond y}
	{Stn {*} CommitRecordCount 1 none y2}
	{Stn {*} CommitQueueSize 1 none y2}
    }
    set vsdtemplates(CPU) {
	{+ {*} UserTime 1 persecond y}
	{SolarisSystem {*} PercentCpuActive 1 none y2}
	{SolarisSystem {*} PercentCpuWaiting 1 none y2}
	{+ {*} SysTime 1 persecond y}
	{NtSystem {*} TotalProcessorTime 1 persecond y}
	{NtSystem {*} ProcessorQueueLength 1 none y2}
    }
    set vsdtemplates(CRBacklog) {
	{Stn {*} TotalCommits 1 persecond y2}
	{Stn {*} CommitRecordCount 1 none y2}
	{Stn {*} CommitQueueSize 1 none y2}
	{Stn {*} OldestCrSession 1 none y}
    }
    set vsdtemplates(EpochSweeps) {
	{Stn {*} EpochGcCount 1 persecond y}
	{Stn {*} EpochScannedObjs 1 none y2}
	{Stn {*} EpochNewObjsSize 1 none y2}
	{Stn {*} EpochPossibleDeadSize 1 none y2}
	{Stn {*} PossibleDeadSize 1 none y2}
    }
    set vsdtemplates(Garbage) {
        {Stn {*} PagesNeedReclaimSize 1 none y2}
        {Stn {*} ReclaimedPagesCount 1 none y2}
        {Stn {*} EpochGcCount 1 persecond y}
        {Stn {*} ReclaimCount 1 persecond y}
        {Gem+ {*Gc*} CommitCount 1 persecond y}
    }
    set vsdtemplates(PageServer) {
	{Pgsvr+ {*} AioDirtyCount 1 persecond y}
	{Pgsvr+ {*} AioCkptCount 1 persecond y}
	{Shrpc {*} LocalDirtyPageCount 1 none y}
    }
    set vsdtemplates(SpaceFree) {
        {Shrpc {*} FreeFrameCount 1 none y}
        {Stn {*} FreePages 1 none y2}
    }
}
proc getStatType {s} {
    return [lindex [sl_stat -info $s] 0]
}
proc getStatLevel {s} {
    return [lindex [sl_stat -info $s] 1]
}
proc getStatFilter {s} {
    return [lindex [sl_stat -info $s] 2]
}
proc setStatFilter {s f} {
    global vsd
    sl_stat -info $s [list {} {} $f]
    set vsd(filter:$s) $f
    if {[string equal $f "Default"]} {
	unset vsd(filter:$s)
    }
}
proc setStatLevel {s l} {
    global vsd
    sl_stat -info $s [list {} $l]
    set vsd(level:$s) $l
}
proc getStatObjList {s} {
    return [lindex [sl_stat -info $s] 3]
}
proc getPlainStatDescription {s} {
    set txt [getStatDescription $s]
    regsub -all {\[(\w+) > \w+ Statistic\]} $txt {\1} res
    return $res
}

proc getStatDescription {s} {
    global statDocs
    if [info exists statDocs($s)] {
	return $statDocs($s)
    } else {
	if {[string equal -length 13 $s "sharedCounter"]} {
	    return $statDocs(sharedCounter)
	} else {
            if [fetchStatDef $s] {
                return $statDocs($s)
            } else {
                return ""
            }
	}
    }
}

proc isOSStat {s} {
    global statDefinitions
    if [info exists statDefinitions($s)] {
	return [lindex $statDefinitions($s) 3]
    } else {
        if [fetchStatDef $s] {
            return [lindex $statDefinitions($s) 3]
        } else {
            return false
        }
    }
}

proc getStatUnits {s} {
    global statDefinitions
    if [info exists statDefinitions($s)] {
	return [lindex $statDefinitions($s) 2]
    } else {
        if [fetchStatDef $s] {
            return [lindex $statDefinitions($s) 2]
        } else {
            return none
        }
    }
}

proc fetchStatDef {s} {
    if [catch {sl_stat -info $s} statDef] {
        return 0
    } else {
        set kind [lindex $statDef 0]
        set level [lindex $statDef 1]
        # 2 is filter
        # 3 is object list
        set isOSStat [lindex $statDef 4]
        set units [lindex $statDef 5]
        set docs [lindex $statDef 6]

        global statDefinitions statDocs
	set statDefinitions($s) [list $kind $level $units $isOSStat]
        set statDocs($s) $docs
        return 1
    }
}

proc selectByStatistic {} {
    global vsd
    set selCtr [getSelCtr]
    if {$selCtr != {}} {
	foreach ctr $selCtr {
	    set objlist [getStatObjList $ctr]
	    foreach obj $objlist {
		set objset($obj) 1
	    }
	}
	set objnames [lsort [array names objset]]
	if {$objnames != {}} {
	    foreach i [$vsd(instanceList) info children] {
		set iobj [lindex [$vsd(instanceList) info data $i] 1]
		if {[lsearch -exact $objnames $iobj] != -1} {
		    $vsd(instanceList) selection set $i
		}
	    }
	}
    }
    updateGraphWidgetState
}

proc selectAllInstances {} {
    global vsd
    foreach i [$vsd(instanceList) info children] {
	$vsd(instanceList) selection set $i
    }
    updateGraphWidgetState
#    set il [$vsd(instanceList) info children]
#    if {[llength $il] > 1} {
#	$vsd(instanceList) selection set [lindex $il 0] [lindex $il end]
#	updateGraphWidgetState
#    }
}

proc selectByType {} {
    global vsd
    set typeList {}
    foreach i [$vsd(instanceList) info selection] {
	set data [$vsd(instanceList) info data $i]
	set iobj [lindex $data 1]
	if {[lsearch -exact $typeList $iobj] == -1} {
	    lappend typeList $iobj
	}
    }
    if {$typeList != {}} {
	foreach i [$vsd(instanceList) info children] {
	    set iobj [lindex [$vsd(instanceList) info data $i] 1]
	    if {[lsearch -exact $typeList $iobj] != -1} {
		$vsd(instanceList) selection set $i
	    }
	}
	updateGraphWidgetState
    }
}

proc doPopup {w m x y} {
    global vsd
    if {[string equal $w [winfo containing $x $y]]} {
	tk_popup $m $x $y
    }
}

proc setHdrSortHighlight {} {
    global vsd
    set type $vsd(def:sortbytype)
    if {$vsd(def:sortdecreasing)} {
	set relief groove
    } else {
	set relief ridge
    }
    $vsd(instanceList).hdrBut$type configure -relief $relief
    return
}

proc sortInstances {type} {
    global vsd
    set oldtype $vsd(def:sortbytype)
    if {[string equal $type $oldtype]} {
	set vsd(def:sortdecreasing) [expr !$vsd(def:sortdecreasing)]
    } else {
	set oldw $vsd(instanceList).hdrBut$oldtype
	if {[winfo exists $oldw]} {
	    $oldw configure -relief flat
	}
	set vsd(def:sortbytype) $type
	set vsd(def:sortdecreasing) 1
    }
    setHdrSortHighlight
    setInstanceList
    return
}

proc getScriptName {} {
    global vsd
    set result $vsd(infoScript)
    if {$result == {}} {
	set exe [info nameofexecutable]
	set result [file join [file dirname $exe] "vsd"]
    }
    return $result
}

proc restartVsd {} {
    global vsd
    set vsd(restarting) 1
    uplevel #0 {source [getScriptName]}
}

proc RunVSD {w} {
    global vsd vsdtemplates isWindows widgetHelp env

    set widgetHelp($w) {Main Window Features}
    
    if {[info exists env(GEMSTONE_LANG)]} {
	unset env(GEMSTONE_LANG)
    }

    set vsd(maintainer) "vsd@gemstone.com"

    set vsd(triBitMapName) "triImage"
    bitmap define "triImage" {{9 8} {
	0x10, 0x00, 0x38, 0x00, 0x38, 0x00, 0x7c, 0x00,
	0x7c, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xff, 0x01
    }}

    set vsd(helpIdx) 0
    set vsd(bulletImage) [image create photo -data "R0lGODlhEAAFAID/AMDAwAAAACH5BAEAAAAALAAAAAAQAAUAAAINhA+hyKff2FvRzYogKwA7"]
    
    set vsd(version) "207.06"
    set vsd(exec:lpr) "lpr"
    set vsd(exec:mail) "/usr/lib/sendmail"
    set vsd(exec:date) "date"
    set vsd(exec:uname) "uname -a"
    set vsd(symbollist) {none scross splus square triangle circle diamond plus cross}

    bind Toplevel <FocusIn> {+ chartFocus %W}
    set vsd(w) $w
    set vsd(confirmonexit) 1
    set vsd(traceAPICalls) 0
    set vsd(warningGiven) 0
    set vsd(sdtrace) 0
    set vsd(xcount) 0
    set vsd(ycount) 0
    set vsd(lastdatafile) {}
    set vsd(lastctr) {}
    set vsd(counterType) {}
    set vsd(selectedInstIds) {}
    set vsd(zeroCtrs) {}
    set vsd(autoUpdatesDisabled) 0
    if {$isWindows} {
	set vsd(graphcursor) arrow
    } else {
	set vsd(graphcursor) top_left_arrow
    }
    set vsd(xaxis:defaultTitle) "Time Axis"
    set vsd(yaxis:defaultTitle) "Left  Axis"
    set vsd(y2axis:defaultTitle) "Right  Axis"
    set vsd(obsoleteCounters) "StatTypeNum Time ProcessName ProcessNumber ProcessId SessionId Offset DeviceNumber"
    if {[winfo depth .] == 1} {
	set vsd(colorlist) {black}
	set vsd(activecolor) black
    } else {
	set vsd(colorlist) {blue cyan brown green \
			    purple pink magenta black \
			    PeachPuff SeaGreen DodgerBlue orchid }
	set vsd(activecolor) red
    }

    set vsd(brokenLinkColor) red
    set vsd(normalLinkColor) blue
    set vsd(visitedLinkColor) brown
    
    set vsd(freeGeometryIds) {}
    set vsd(graphcount) 0
    set vsd(graphcreates) 0

    set vsd(winnames) {.monitors .monstatus .ctrinfo .datawin}
    foreach cw $vsd(winnames) {
	set vsd(geometry:$cw) {}
    }
    set vsd(def:geometry) {}
    set vsd(def:xformat) "time"
    set vsd(def:linestyle) "linear"
    set vsd(def:xaxis:showtitle) 1
    set vsd(def:yaxis:showtitle) 1
    set vsd(def:y2axis:showtitle) 1
    set vsd(def:showcurxy) 1
    set vsd(def:showminmax) 0
    set vsd(def:showlinestats) 1
    set vsd(def:showcrosshairs) 0
    set vsd(def:showlegend) 1
    set vsd(def:showgridlines) 0
    set vsd(def:sortbytype) Type
    set vsd(def:sortdecreasing) 1
    set vsd(filelist) {}
    set vsd(statsrc) {}
    set vsd(appendMode) 0
    set vsd(autoUpdate) 0
    set vsd(autoUpdateTime) 10000
    set vsd(showCtrInfo) 0
    set vsd(absoluteTSMode) 1
    set vsd(copyChildren) 1
    set vsd(singleFileMode) 1
    set vsd(lastEnabledFiles) {}
    set vsd(templatesUseSelection) 0
    set vsd(file:isEnabled) 1
    set vsd(cursorblink) 1
    auto_load tk_chooseColor    
    auto_load tk_messageBox    
    auto_load tk_getOpenFile    
    auto_load tixMeter
    set vsd(hasMeter) [expr {[info commands tixMeter] != ""}]

    set vsd(wv:statmoninterval) 20
    set vsd(wv:statmonflush) 0
    set vsd(wv:statmonlevel) 1
    set vsd(wv:statmonappstats) 0
    set vsd(wv:statmonsessions) ""
    set vsd(wv:statmonpids) ""
    set vsd(wv:statmoncompress) 0
    set vsd(combineInstances) 0
    set vsd(combineFiles) 0
    set vsd(combineFilePattern) ""
    set vsd(sortedGroupNames) {}
    set vsd(noFlatlines) 0
    set vsd(clipboard) {}
    set vsd(ruleCount) 0
    set vsd(longOpCancel) 0
    set vsd(longOpW) ""

    set vsd(instancePaneSize) 115
    set vsd(statisticPaneSize) 50
    

    defaultTemplates

    makeErrorDialog $w

    loadStatisticAliases

    if [file exists "~/.vsdrc"] {
	if [catch {source "~/.vsdrc"} msg] {
	    showError "Notice: could not read '~/.vsdrc' because:\n$msg"
	}
	if {[string equal $vsd(def:sortbytype) "Start Time"]} {
	    set vsd(def:sortbytype) "StartTime"
	}
    }
    if [file exists "~/.vsdtemplates"] {
	if [catch {source "~/.vsdtemplates"} msg] {
	    showError "Notice: could not read '~/.vsdtemplates' because:\n$msg"
	}
    } else {
	writeTemplateFile
    }
    if [file exists "~/.vsdconfig"] {
	global statdef
	if [catch {source "~/.vsdconfig"} msg] {
	    showError "Notice: could not read '~/.vsdconfig' because:\n$msg"
	}
    } else {
	createVsdConfig "~/.vsdconfig"
    }

    loadStatisticDefinitions ;# do this after reading .vsdconfig and .vsdrc

    if {![info exists vsd(smallfont)]} {
	if {$isWindows} {
#        set vsd(smallfont) [lreplace [tix option get font] 1 1 "8"]
#        set vsd(smallfont) "-Adobe-Helvetica-Bold-R-Normal--*-120-*"
	    set vsd(smallfont) {-family Helvetica -size 8}
	} else {
	    set vsd(smallfont) {-family lucida -size 8}
	}
    }
    eval font create vsdsf $vsd(smallfont)

    if {![info exists vsd(textfont)]} {
	# does a better way of getting default text font exist?
	set tmptextw [text .foobar]
	set vsd(textfont) [font actual [$tmptextw cget -font]]
	destroy $tmptextw
    }
    createTextFonts
    
    if {! $vsd(cursorblink)} {
	option add *insertOffTime 0
    }
    
    # Sometimes the geometry gets saved with a strange value
    if {[string match "1x1+*" $vsd(def:geometry)]} {
	set vsd(def:geometry) ""
    }
    foreach cw $vsd(winnames) {
	if {[string match "1x1+*" $vsd(geometry:$cw)]} {
	    set vsd(geometry:$cw) ""
	}
    }

    if {$vsd(def:geometry) != {}} {
	wm geometry $vsd(w) $vsd(def:geometry)
    }

    set sltclVer "12.0.0"
    set vsdExeName [info nameofexecutable]
    if {[lsearch -exact [package names] SlTcl] == -1} {
	# This vsd executable is an old one that did not provide a package
	fatalError "The $vsdExeName is out of date with the '[getScriptName]' file.
You need $vsdExeName version '$sltclVer'."
    } elseif [catch {package require SlTcl $sltclVer} vsd(sltclVer)] {
	fatalError "The $vsdExeName is out of date with the '[getScriptName]' file.
You need $vsdExeName version '$sltclVer'.
Tcl error message: '$vsd(sltclVer)'."
    }

    set mf [frame $w.mf -bd 2 -relief raised]
    
    menubutton $mf.main -menu $mf.main.m -text "Main" -underline 0 \
	-takefocus 0
    menu $mf.main.m -tearoff 0
    set vsd(w:mainmenu) $mf.main.m
    $mf.main.m add command -label "Load Data File..." -underline 0 \
	-command browseDataFile
    if {$isWindows} {
        # fix for bug 27746
        $mf.main.m add command -label "Monitor..." -command {doMonitor} \
            -accelerator "Ctrl+m" -state disabled
    } else {
        $mf.main.m add command -label "Monitor..." -command {doMonitor} \
            -accelerator "Ctrl+m"
    }
    $mf.main.m add command -label "Change Directory..." -command {doChangeDirectory}
    $mf.main.m add command -label "Copy Selection" -command {doCopySelection} \
	-accelerator "Ctrl+c"
    bind $vsd(w) <Control-m> [list $mf.main.m invoke "Monitor..."]
    bind $vsd(w) <<Copy>> [list $mf.main.m invoke "Copy Selection"]
    $mf.main.m add check -label "Show Statistic Info" -underline 0 \
	-variable vsd(showCtrInfo) \
	-command {doCtrInfo}
    $mf.main.m add check -label "Combine" \
	-variable vsd(combineInstances)
    $mf.main.m add check -label "Combine Across Files" \
	-variable vsd(combineFiles)
    $mf.main.m add check -label "No Flatlines" \
	-variable vsd(noFlatlines) -command changeNoFlatlines
    $mf.main.m add check -label "Single File Mode" \
	-variable vsd(singleFileMode) -command singleFileMode
    $mf.main.m add check -label "Absolute TimeStamps" \
	-variable vsd(absoluteTSMode)
    $mf.main.m add check -label "Copy Referenced Lines" \
	-variable vsd(copyChildren)
    set mclevel $mf.main.m.clevel
    menu $mclevel -tearoff 0
    set vsd(statlevel) [sl_stat -level]
    $mclevel add radio -label "Common Statistics Only" -value "common" \
	-variable vsd(statlevel) \
	-command changeLevel
    $mclevel add radio -label "Advanced & Common Statistics" -value "advanced" \
	-variable vsd(statlevel) \
	-command changeLevel
    $mclevel add radio -label "All Statistics" -value "wizard" \
	-variable vsd(statlevel) \
	-command changeLevel

    $mf.main.m add cascade -label "Statistic Level" -menu $mclevel

    if [wizardMode] {
	$mf.main.m add command -label "Dump Statistic Info"  -command dumpCtrInfo
	$mf.main.m add check -label "Trace API Calls" \
	    -variable vsd(traceAPICalls) -command traceAPICalls
	$mf.main.m add command -label "ForceError"  -command {forcedError }
	$mf.main.m add command -label "Restart" \
	    -command {restartVsd}
	$mf.main.m add command -label "Debug" \
	    -command {source "~/tkcon.tcl"}
    }
    $mf.main.m add separator
    $mf.main.m add check -label "Confirm Exit" \
	-variable vsd(confirmonexit)
    $mf.main.m add separator
    $mf.main.m add command -label "Exit     " -underline 1 -command ExitVSD
    pack $mf.main -side left

    set widgetHelp($mf.main) {Main Window Main Menu}

    menubutton $mf.file -menu $mf.file.m -text "File" -underline 0 \
	-takefocus 0
    menu $mf.file.m -tearoff 0
    set vsd(w:filemenu) $mf.file.m
    $mf.file.m add command -label "Append Data File..." \
	-command appendDataFile
    $mf.file.m add command -label "Info..." -underline 0 -state disabled \
	-command fileInfo
    $mf.file.m add command -label "Update" -state disabled \
	-command {fileUpdate $vsd(statsrc)} \
	-accelerator "Ctrl+u"
    $mf.file.m add command -label "Update All" \
	-command {fileUpdateAll} \
	-accelerator "Ctrl+U"
    bind $vsd(w) <Control-u> [list $mf.file.m invoke "Update"]
    bind $vsd(w) <Control-U> [list $mf.file.m invoke "Update All"]
    $mf.file.m add check -label "Auto Update" -state disabled \
	-command autoUpdate -variable vsd(autoUpdate)
    $mf.file.m add check -label "Enabled" -state disabled \
	-command fileEnableMode -variable vsd(file:isEnabled)
    $mf.file.m add command -label "Untrim Left" -state disabled \
	-command {fileUntrimLeft $vsd(statsrc)}
    $mf.file.m add command -label "Untrim Right" -state disabled \
	-command {fileUntrimRight $vsd(statsrc)}
    if [wizardMode] {
	$mf.file.m add command -label "Dump" -state disabled -command fileDump
    }
    pack $mf.file -side left
    set widgetHelp($mf.file) {Main Window File Menu}

    menubutton $mf.chart -menu $mf.chart.m -text "Chart" -underline 0 \
	-takefocus 0
    menu $mf.chart.m -tearoff 1
    set vsd(w:chartmenu) $mf.chart.m
    $mf.chart.m add command -label "Add To Chart" \
	-command {doChart 0} -accelerator "Ctrl+a" -state disabled
    bind $vsd(w) <Control-a> [list $vsd(w:chartmenu) invoke "Add To Chart"]
    $mf.chart.m add command -label "New Chart..." \
	-command {doChart 1} -accelerator "Ctrl+n" -state normal
    bind $vsd(w) <Control-n> [list $vsd(w:chartmenu) invoke "New Chart..."]

    $mf.chart.m add separator
    $mf.chart.m add check -label "Show Legend" \
	-variable vsd(def:showlegend)

    set mtime $mf.chart.m.time
    set widgetHelp($mtime) {Main Chart Menu Time Format SubMenu}
    menu $mtime -tearoff 0
    $mtime add radio -label "Elapsed Time in Seconds" -value "elapsed" \
	-variable vsd(def:xformat)
    $mtime add radio -label "Hour:Minute:Second" -value "time" \
	-variable vsd(def:xformat)
    $mtime add radio -label "Month/Day Hour:Minute:Second" -value "date" \
	-variable vsd(def:xformat)

    $mf.chart.m add cascade -label "Time Format" -menu $mtime -underline 0

    set mstyle $mf.chart.m.styles
    set widgetHelp($mstyle) {Main Chart Menu Default Line Style SubMenu}
    menu $mstyle -tearoff 1
    foreach style {linear step natural quadratic} {
	$mstyle add radio -label $style -variable vsd(def:linestyle)
    }
    $mf.chart.m add cascade -label "Default Line Style" -menu $mstyle

    $mf.chart.m add check -label "Show Time Axis Title" \
	-variable vsd(def:xaxis:showtitle)
    $mf.chart.m add check -label "Show Left Axis Title" \
	-variable vsd(def:yaxis:showtitle)
    $mf.chart.m add check -label "Show Right Axis Title" \
	-variable vsd(def:y2axis:showtitle)
    $mf.chart.m add check -label "Show Current Values" \
	-variable vsd(def:showcurxy)
    $mf.chart.m add check -label "Show Min and Max" \
	-variable vsd(def:showminmax)
    $mf.chart.m add check -label "Show Line Stats" \
	-variable vsd(def:showlinestats)
    $mf.chart.m add check -label "Show CrossHairs" \
	-variable vsd(def:showcrosshairs)
    $mf.chart.m add check -label "Show Grid Lines" \
	-variable vsd(def:showgridlines)
    if {[info commands tk_chooseColor] != ""} {
        $mf.chart.m add command -label "Selected Line Color..." \
            -command setActiveColor
    }
    $mf.chart.m add command -label "Choose Chart Font..." \
            -command setChartFont
    $mf.chart.m add separator
    $mf.chart.m add command -label "Close All Charts" -command {closeAllCharts}
    pack $mf.chart -side left
    set widgetHelp($mf.chart) {Main Window Chart Menu}

    menubutton $mf.template -menu $mf.template.m -text "Template" -underline 0 \
	-takefocus 0
    menu $mf.template.m -tearoff 1
    set vsd(w:templatemenu) $mf.template.m
    set vsd(w:templatecascade) $mf.template.m.templates

    $mf.template.m add command -label "Reload Template File" \
	-command "reloadTemplates $vsd(w:templatecascade)" -underline 0

    set widgetHelp($vsd(w:templatecascade)) {Template Menu New Template Chart SubMenu}
    menu $vsd(w:templatecascade) -tearoff 1
    createTemplateMenu $vsd(w:templatecascade)
    $mf.template.m add cascade -label "New Template Chart" \
	-menu $vsd(w:templatecascade) -underline 0 -state disabled
    $mf.template.m add check -label "Templates Use Selection" \
	-variable vsd(templatesUseSelection)

    pack $mf.template -side left
    set widgetHelp($mf.template) {Main Window Template Menu}

    menubutton $mf.help -menu $mf.help.m -text "Help" -underline 0 \
	-takefocus 0
    menu $mf.help.m -tearoff 0
    $mf.help.m add command -label "How to..." -underline 0 -command HowToHelp
    $mf.help.m add command -label "Main Window..." -command {showMainHelp}
    $mf.help.m add command -label "Chart Window..." -command {showChartHelp}
    $mf.help.m add command -label "All Topics..." -command {allHelp}
    $mf.help.m add command -label "All Help Text..." -command {allFlatHelp}
    $mf.help.m add separator
    $mf.help.m add command -label "Choose Text Font..." -command setTextFont
    $mf.help.m add separator
    $mf.help.m add command -label "About VSD..." -underline 0 -command {showAboutHelp}
    pack $mf.help -side right
    set widgetHelp($mf.help) {Main Window Help Menu}

    pack $mf -side top -fill x

    # We create the frame and the ScrolledHList widget
    # at the top of the dialog box
    #
    tixComboBox $w.filelist -label "File:" -anchor e \
	-editable true -command chooseDataFile -options {
	    listbox.height 6
	}
    set vsd(w:filelist) $w.filelist
    $vsd(w:filelist) appendhistory "Browse For File..."
    set dirlist {}
    set tmplist {}
    foreach f $vsd(filelist) {
        if {[file exists $f]} {
	    if {[lsearch -exact $tmplist $f] == -1} {
		lappend tmplist $f
	    }
        }
    }
    set vsd(filelist) $tmplist
    foreach f $vsd(filelist) {
	$vsd(w:filelist) appendhistory $f
	set dir [file dirname $f]
	if {[lsearch -exact $dirlist $dir] == -1} {
	    lappend dirlist $dir
	}
    }

    set xpad 3
    set ypad 3

    set widgetHelp($w.filelist) {Main Window File ComboBox}

    pack $vsd(w:filelist) -side top -fill x -padx $xpad -pady $ypad
    update ;# so that winfo height will work

    set filelistHeight [winfo height $vsd(w:filelist)]
    if {$filelistHeight == 1} {
	set filelistHeight [winfo reqheight $vsd(w:filelist)]
	if {$filelistHeight == 1} {
	    set filelistHeight 24
	}
    }
    incr filelistHeight $ypad
    incr filelistHeight $ypad
    incr filelistHeight $ypad

    if {$isWindows} {
        # info commands tk_getOpenFile
	# use tk_getOpenFile
        set vsd(w:fileselector) ""
    } else {
	tixExFileSelectDialog .fileselector -command loadBrowsedDataFile
	set vsd(w:fileselector) .fileselector
	set fsbox [$vsd(w:fileselector) subwidget fsbox]
	$fsbox configure -filetypes {
	    {{*} "All files"}
	    {{*.gfs *.out *.out.gz} "All statistic data files"}
	    {{*.gfs} "Uncompressed GemFire archive files"}
	    {{*.out} "Uncompressed StatMonitor data files"}
	    {{*.out.gz} "Compressed StatMonitor data files"}
	} -pattern {*.gfs *.out *.out.gz}
	if {[llength $dirlist] > 0} {
	    set fsboxdir [$fsbox subwidget dir]
	    foreach d $dirlist {
		$fsboxdir appendhistory $d
	    }
	}
    }

    tixPanedWindow $w.mainPane -orient vertical
    set p1 [$w.mainPane add instances -min 115 -size $vsd(instancePaneSize) -expand 3]
    set p2 [$w.mainPane add statistics -min 50 -size $vsd(statisticPaneSize) -expand 1]

    tixScrolledHList $p1.instanceList -options {
	hlist.columns 6
	hlist.header true
	hlist.selectMode extended
	hlist.command instanceCommand
	hlist.BrowseCmd instanceBrowse
    }
    set vsd(instanceList) [$p1.instanceList subwidget hlist]

#     if {$isWindows} {
# 	$vsd(instanceList) configure -font [tix option get font] \
# 	    -selectbackground SystemHighlight \
# 	    -selectforeground SystemHighlightText \
#     }
    
    set vsd(buthdr:s) [tixDisplayStyle window -padx 0 -pady 0]
    set i 0
    set instList {StartTime File Samples Pid Type Name}
    foreach n $instList {
	set buttonName "$vsd(instanceList).hdrBut$n"
        set vsd(ilColumnIdx:$n) $i
	button $buttonName -text $n -relief flat \
	    -font [tix option get bold_font] -takefocus 0 -padx 0 -pady 0 \
	    -command [list sortInstances $n] -anchor w
	$vsd(instanceList) header create $i -itemtype window \
	    -window $buttonName -style $vsd(buthdr:s)
	incr i
    }
    setHdrSortHighlight
    set sfg [$vsd(instanceList) cget -selectforeground]
    set vsd(name:s) [tixItemStyle text -refwindow $vsd(instanceList) \
			 -font [tix option get bold_font] \
			 -selectforeground $sfg]
    set vsd(time:s) [tixItemStyle text -refwindow $vsd(instanceList) \
			 -font [tix option get font] -padx 8 \
			 -selectforeground $sfg]
    set vsd(samples0:s) [tixItemStyle text -refwindow $vsd(instanceList) \
			     -font [tix option get font] \
			     -selectforeground $sfg]
    set vsd(samples1:s) [tixItemStyle text -refwindow $vsd(instanceList) \
			  -fg green \
			  -selectforeground $sfg \
			  -font [tix option get bold_font]]

    pack $p1.instanceList -expand yes -fill both
    set widgetHelp($p1.instanceList) {Main Window Instance Table}

    bind $vsd(instanceList) <Control-s> \
	[list startSearch $vsd(instanceList) searchHList $filelistHeight]

    if 0 {
	tixPopupMenu $w.instanceMenu -title "Process Menu"
	$w.instanceMenu bind 
	$w.instanceMenu bind $vsd(instanceList).tixsw:header
	set m [$w.instanceMenu subwidget menu]
    } else {
	set m [menu $w.processmenu]
	set bindcmd [list doPopup %W $m %X %Y]
	bind $vsd(instanceList) <ButtonRelease-3> $bindcmd
	bind $vsd(instanceList).tixsw:header <ButtonRelease-3> $bindcmd
	set widgetHelp($w.processmenu) {Instance List PopupMenu}
    }
#     if 0 {
# 	$m add cascade -label "Hide" -menu $m.hb
# 	menu $m.hb
# 	$m.hb add check -label "Inactive" \
# 	    -variable vsd(def:hideInactive) -command setInstanceList
#     }
    $m add command -label "Search..." -accelerator "Ctrl+s" \
	-command [list startSearch $vsd(instanceList) searchHList $filelistHeight] 

#     $m add cascade -label "Sort By" -menu $m.sb
#     menu $m.sb -tearoff 1
#     foreach {n v} [concat $instList {Activity activity}] {
# 	$m.sb add radio -label $n -value $v \
# 	    -variable vsd(def:sortbytype) -command setInstanceList
#     }

    $m add cascade -label "Select" -menu $m.select
    menu $m.select -tearoff 1
    $m.select add command -label "Clear" \
	-command {$vsd(instanceList) selection clear; updateGraphWidgetState}
    $m.select add command -label "by Statistic" \
	-command {selectByStatistic}
    $m.select add command -label "by Type" \
	-command {selectByType}
    $m.select add command -label "All" \
	-command {selectAllInstances}
    $m add check -label "Combine" \
	-variable vsd(combineInstances)
    $m add check -label "Combine Across Files" \
	-variable vsd(combineFiles)
    $m add check -label "No Flatlines" \
	-variable vsd(noFlatlines) -command changeNoFlatlines
    $m add check -label "Single File Mode" \
	-variable vsd(singleFileMode) -command singleFileMode
    $m add check -label "Absolute TimeStamps" \
	-variable vsd(absoluteTSMode)

    set vsd(selectedCtr) ""

    tixScrolledHList $p2.counterHList -options {
	hlist.columns 1
	hlist.header false
	hlist.selectMode extended
	hlist.command ctrHlistCommand
	hlist.BrowseCmd ctrHlistBrowse
	hlist.exportSelection 0
	hlist.takeFocus 1
    }
    set vsd(w:counterHList) [$p2.counterHList subwidget hlist]
    bind $vsd(w:counterHList) <KeyPress> \
	[list HListPrefixSearch $vsd(w:counterHList) %A]
    bind $vsd(w:counterHList) <Control-s> \
	[list startSearch $vsd(w:counterHList) searchCtrHList]
    event add <<ClearSearch>> <Up> <Down> <Shift-Up> <Shift-Down> <Left> <Right> \
	<Prior> <Next> <Return> <space> <Double-1> <1> <Shift-1> <Control-1> \
	<FocusOut>
    bind $vsd(w:counterHList) <<ClearSearch>> "+[list HListPrefixClear $vsd(w:counterHList)]"
    set sfg [$vsd(w:counterHList) cget -selectforeground]
    # the font for normal stats
    set vsd(ctr0:s) [tixItemStyle text -refwindow $vsd(w:counterHList) \
			 -font [tix option get bold_font] \
			 -selectforeground $sfg]
    # the font for zero stats
    set vsd(ctr1:s) [tixItemStyle text -refwindow $vsd(w:counterHList) \
			 -font [tix option get font] \
			 -selectforeground $sfg]
#			     -font [tix option get italic_font]

    pack $p2.counterHList -fill both -expand yes
    set widgetHelp($p2.counterHList) {Main Window Statistic List}

    set vsd(curchart) {}
    tixComboBox $w.chartlist -label "Chart:" -dropdown true \
	-command chooseChart -history true -prunehistory true \
        -editable false -variable vsd(curchart) -options {
          listbox.height 4
	}

    set vsd(w:chartlist) $w.chartlist
    set widgetHelp($w.chartlist) {Main Window Chart ComboBox}

    tixButtonBox $w.box -padx $xpad -pady $ypad
    $w.box add additem -text "Add Line" -command {doChart 0} -state disabled
    set vsd(w:addline) [$w.box subwidget additem]
    $w.box add newchart -text "New Chart" -command {doChart 1} -state normal
    set vsd(w:newchart) [$w.box subwidget newchart]
    set widgetHelp($vsd(w:addline)) {Main Window Add Line Button}
    set widgetHelp($vsd(w:newchart)) {Main Window New Chart Button}

    set sf [frame $w.statusFrame -relief raised -bd 1]
    set vsd(status) ""
    label $sf.status -relief sunken -bd 1 -textvariable vsd(status) -padx 2
    pack $sf.status -fill x
    pack $sf -fill x -side bottom -padx $xpad -pady $ypad

    pack $w.box -fill x -side bottom -padx $xpad -pady $ypad

    pack $w.chartlist -side bottom -padx $xpad -pady $ypad -fill x

    pack $w.mainPane -side top -expand yes -fill both -padx $xpad -pady $ypad

    set widgetHelp($w.box) {Main Window Status Display}

    set vsd(balloon) [tixBalloon .vsd_balloon -statusbar $sf.status -state status]
    $vsd(balloon) bind $vsd(w:filelist) -msg "Show/Select/Load current statmonitor file"
    foreach n $instList {
	$vsd(balloon) bind "$vsd(instanceList).hdrBut$n" -msg "Click to sort by \"$n\""
    }
    $vsd(balloon) bind $vsd(w:chartlist) -msg "Show/Select/Name current chart"
    $vsd(balloon) bind $vsd(w:addline) -msg "Add selected stats to current chart"
    $vsd(balloon) bind $vsd(w:newchart) -msg "Creates a new chart window and add selected stats to it"

    wm protocol $w WM_DELETE_WINDOW ExitVSD

    patchTix

    createSearch
    createTemplateName
    createHelpSearch
    createAboutHelp
    #UsageVSD $w
    doCtrInfo

    traceAPICalls

    set appendIt 0
    global argv
    foreach f $argv {
	switch -exact -- $f {
	    "-n" {set appendIt 0; set vsd(appendMode) 0}
	    "-a" {set appendIt 1}
	    "-u" {set vsd(autoUpdate) 1; autoUpdate}
	    default {
		if {$appendIt} {
		    if {$vsd(statsrc) != {}} {
			set vsd(appendMode) 1
		    } else {
			set vsd(appendMode) 0
		    }
		}
		setDataFile $f
	    }
	}
    }
    set vsd(appendMode) 0
    set vsd(autoUpdate) 0

    if {![info exists vsd(lastVersionRun)] || ($vsd(lastVersionRun) < $vsd(version))} {
	showNewFeatures
    }
}

proc loadStatisticDefinitions {} {
    global statDefinitions vsd
    foreach s [array names statDefinitions] {
	set statAttributes $statDefinitions($s)
	set type [lindex $statAttributes 0]
	set level [lindex $statAttributes 1]
	set filter {}
	if [info exists vsd(filter:$s)] {
	    set filter $vsd(filter:$s)
	}
	if [info exists vsd(level:$s)] {
	    if {[string equal $level $vsd(level:$s)]} {
		unset vsd(level:$s)
	    } else {
		set level $vsd(level:$s)
	    }
	}
	sl_stat -info $s [list $type $level]
    }
    # convert old vsd(ctr:*) definitions
    foreach ctr [array names vsd ctr:*] {
	set statname [string range $ctr 4 end]
	set ctrlist $vsd($ctr)
	set level [lindex $ctrlist 1]
	set filter [lindex $ctrlist 3]
	if {$level != {}} {
	    setStatLevel $statname $level
	}
	if {$filter != {}} {
	    setStatFilter $statname $filter
	}
	unset vsd($ctr)
    }
    processUserStatDefs
    generateAllStatHelp
}

proc processUserStatDefs {} {
    global statdef statDefinitions statDocs
    foreach name [array names statdef] {
	set attributes $statdef($name)
	if {[llength $attributes] != 6} {
	    fatalError "The statistic definition for $name does not have six attributes. Check ~/.vsdconfig for a line that sets statdef($name) and correct it. To learn more about statistic definitions see the vsd help section entitled \"Statistic Definitions\"."
	}
	set kind [lindex $attributes 0]
	set level [lindex $attributes 1]
	set units [lindex $attributes 2]
	set isOSStat [lindex $attributes 3]
	set filter [lindex $attributes 4]
	set docs [lindex $attributes 5]
	if {$kind != {}} {
	    if [catch {sl_stat -info $name [list $kind]} err] {
		fatalError "The statistic definition for $name does not have a valid value for the kind attribute. The illegal value found is: \"$kind\". The problem is: \"$err\". Check ~/.vsdconfig for a line that sets statdef($name) and correct it. To learn more about statistic definitions see the vsd help section entitled \"Statistic Definitions\"."
	    }
	} else {
	    set kind "uvalue"
	}
	if {$level != {}} {
	    if [catch {sl_stat -info $name [list {} $level]} err] {
		fatalError "The statistic definition for $name does not have a valid value for the level attribute. The illegal value found is: \"$level\". The problem is: \"$err\". Check ~/.vsdconfig for a line that sets statdef($name) and correct it. To learn more about statistic definitions see the vsd help section entitled \"Statistic Definitions\"."
	    }
	} else {
	    set level "common"
	}
	if {$filter != {}} {
	    if [catch {sl_stat -info $name [list {} {} $filter]} err] {
		fatalError "The statistic definition for $name does not have a valid value for the filter attribute. The illegal value found is: \"$filter\". The problem is: \"$err\". Check ~/.vsdconfig for a line that sets statdef($name) and correct it. To learn more about statistic definitions see the vsd help section entitled \"Statistic Definitions\"."
	    }
	} else {
	    set filter "default"
	}
	if {$isOSStat != {}} {
	    if {![string is boolean $isOSStat]} {
		fatalError "The statistic definition for $name does not have a valid boolean value for the isOSStat attribute. The illegal value found is: \"$isOSStat\". Check ~/.vsdconfig for a line that sets statdef($name) and correct it. To learn more about statistic definitions see the vsd help section entitled \"Statistic Definitions\"."
	    }
	} else {
	    set isOSStat false
	}
	if {$units == {}} {
	    set units "none"
	}
	sl_stat -info $name {} ;# make sure it gets pushed to lower level
	set statDefinitions($name) [list $kind $level $units $isOSStat]
	if {$docs != {}} {
	    set statDocs($name) $docs
	}
    }
}

proc debugvar {varname} {
    upvar $varname var
    puts "$varname is: '$var'"
    return
}

# The stathelp array contains extra information about statistics that
# needs to be added to the standard information from 'sl_stat -info'.
array set stathelp {
{FreeFrameCount} {
In the [shrpc > Shrpc Type], the FreeFrameCount displays the current number of free frames available in the [Shared Page Cache]. The cache is considered full as this count approaches zero.

See also: [FramesAddedToFreeList > FramesAddedToFreeList Statistic],\
[PagesPreempted > PagesPreempted Statistic],\
[PagesRemovedForStone > PagesRemovedForStone Statistic],\
and [Shared Page Cache Health].
}

{IVolCSW} {
A large number of [involuntary context switches > Context Switch] indicates contention for the cpu. 
}
{VolCSW} {
A large number of [voluntary context switches > Context Switch] indicates an increase in non-cpu resources.
}
{LocalPageCacheMisses} {
NOTE: prior to 4.6, the LocalPageCacheMisses statistic was grossly overstated. You can sum the extent stat [ExtentReadKBytes > ExtentReadKBytes Statistic] to approximate LocalPageCacheMisses.
}

{PrivatePageCacheSize} {
The private page cache is used by a session to cache freshly written temporary pages. If a session is writing a large number of objects, the number of temporary pages needed may exceed the default size of the private page cache. If the private page cache is large enough, you will see the stat [FramesAddedToFreeList > FramesAddedToFreeList Statistic] flat-lined at zero. 

!How big should I make the private page cache?
You can tell you need a larger private page cache if:
   * The session is doing [FramesAddedToFreeList > FramesAddedToFreeList Statistic]. Optimally a session's [FramesAddedToFreeList > FramesAddedToFreeList Statistic] will be flat-lined at zero.

<b>Problem:</b> you can't set the private page cache size on activated VM's that use session pools!
}

{FramesAddedToFreeList} {
In the [shrpc > Shrpc Type], the FramesAddedToFreeList stat is a summary of all such activity in the system.

There are two active sources of FramesAddedToFreeList in the system; either a [session > Session Type] or the [AIO page servers]. 

The page server named <b>pageService</b> is implemented with a thread in the [SAP] vm. This particular thread is removing pages from the shared page cache that are ready to be re-used by the stone. These [removed pages > PagesRemovedForStone Statistic] are the residue of commit record disposal and reclaim activity. The <b>pageService</b> thread also performs [page preemption > PagesPreempted Statistic], which adds frames to the free list.

Optimally, a [session > Session Type] will have no FramesAddedToFreeList activity. Excessive activity of this stat for a [session > Session Type] indicates that the [private page cache > PrivatePageCacheSize Statistic] for the [session > Session Type] is too small. Thousands of FramesAddedToFreeList per second for a session is a significant performance degradation. You will also notice that [FramesFromFindFree > FramesFromFindFree Statistic] will dramatically increase when a [session > Session Type] has non-zero FramesAddedToFreeList.

See also: [FreeFrameCount > FreeFrameCount Statistic]
}
}

proc initStatHelp {name} {
    global vsdhelp
    set topic "$name Statistic"
    set vsdhelp($topic) [list TCLEVAL generateStatHelp $name]
}

proc generateStatHelp {name} {
    global stathelp vsdhelp
    set type [getStatType $name]
    set level [getStatLevel $name]
    set units [getStatUnits $name]
    set filter [getStatFilter $name]
    set description [getStatDescription $name]
    set isOS [isOSStat $name]
    set objects [getStatObjList $name]

    set help ""
    append help $description
    append help "\n\n"
    append help "   * <b>Kind:</b>      $type\n"
    append help "   * <b>Units:</b>     $units\n"
    append help "   * <b>Level:</b>     $level\n"
    if {![string equal $filter "default"]} {
	append help "   * <b>Filter:</b>    $filter\n"
    }
    append help "   * <b>Source:</b> "
    if {$isOS} {
	append help "operating system\n"
    } else {
	append help "product\n"
    }
    if {$objects != {}} {
	append help "   * <b>Types:</b>   "
	foreach obj $objects {
	    set typeName [file rootname $obj]
	    set typeVersion [file extension $obj]
	    if {$typeVersion == {}} {
		set typeVersion ".1"
	    }
	    set versionNumber [string trimleft $typeVersion "."]
	    set topicName "$typeName Type Version $versionNumber"
	    if [info exists vsdhelp($topicName)] {
		append help { [} $obj " > $topicName]"
	    } else {
		append help " " $obj 
	    }
	}
	append help "\n"
    }
    if [info exists stathelp($name)] {
	append help "----\n"
	append help $stathelp($name)
    }
    return $help
}

proc loadStatisticAliases {} {
    sl_stat -alias "numberattached" "AttachedCount"
    sl_stat -alias "numberoffreeframes" "FreeFrameCount"
    sl_stat -alias "numberofcommitrecords" "CommitRecordCount"
    sl_stat -alias "asynchwritesinprogress" "AsyncWritesInProgress"
    sl_stat -alias "aynschwritesiocount" "AsyncWritesCount"
    sl_stat -alias "messagestostn" "MessagesToStone"
    sl_stat -alias "numincommitqueue" "CommitQueueSize"
    sl_stat -alias "numinlockreqqueue" "LockReqQueueSize"
    sl_stat -alias "numinnotifyqueue" "NotifyQueueSize"
    sl_stat -alias "numinloginwaitqueue" "LoginQueueSize"
    sl_stat -alias "numinrunqueue" "RunQueueSize"
    sl_stat -alias "numinsymbolcreatequeue" "SymbolCreationQueueSize"
    sl_stat -alias "numberofscavenges" "ScavengeCount"
    sl_stat -alias "numberofdeadobjs" "DeadObjCount"
    sl_stat -alias "numberofmakeroominoldspace" "MakeRoomInOldSpaceCount"
    sl_stat -alias "numberofgcnotconnected" "GcNotConnectedCount"
    sl_stat -alias "numberofgcnotconnecteddead" "GcNotConnectedDeadCount"
    sl_stat -alias "norollbacksize" "NoRollbackSetSize"
    sl_stat -alias "notconnectedobjssize" "NotConnectedObjsSetSize"
    sl_stat -alias "numberofsigabort" "SigAbortCount"
    sl_stat -alias "numberofsiglostot" "SigLostOtCount"
    sl_stat -alias "numberofreads" "ReadCount"
    sl_stat -alias "numberofwrites" "WriteCount"
    sl_stat -alias "numberofseeks" "SeekCount"
    sl_stat -alias "numberoftransfers" "TransferCount"
    sl_stat -alias "numswaps" "SwapCount"
    sl_stat -alias "epochgccount" "EpochGcCount"
    sl_stat -alias "localdirtypagecount" "LocalDirtyPageCount"
    sl_stat -alias "globaldirtypagecount" "GlobalDirtyPageCount"
    sl_stat -alias "pagereads" "PageReads"
    sl_stat -alias "pagewrites" "PageWrites"
    sl_stat -alias "deadobjscount" "DeadObjsCount"
    sl_stat -alias "reclaimcount" "ReclaimCount"
    sl_stat -alias "reclaimedpagescount" "ReclaimedPagesCount"
    sl_stat -alias "checkpointcount" "CheckpointCount"
    sl_stat -alias "pagesneedreclaimsize" "PagesNeedReclaimSize"
    sl_stat -alias "possdeadsize" "PossibleDeadSize"
    sl_stat -alias "deadnotreclaimedsize" "DeadNotReclaimedSize"
    sl_stat -alias "pgsvraiodirtycount" "AioDirtyCount"
    sl_stat -alias "pgsvraiockptcount" "AioCkptCount"
    sl_stat -alias "numberofcommits" "CommitCount"
    sl_stat -alias "numberoffailedcommits" "FailedCommitCount"
    sl_stat -alias "numberofaborts" "AbortCount"
    # The following old names only existed for a 5.0 alpha
    sl_stat -alias "vccachenumscavenges" "VcCacheScavengesCount"
    sl_stat -alias "vccachesizebytes" "VcCacheSizeBytes"
    sl_stat -alias "codecachesizebytes" "CodeCacheSizeBytes"
    sl_stat -alias "codecachenumentries" "CodeCacheEntries"
    sl_stat -alias "codecachenumstaleentries" "CodeCacheStaleEntries"
    sl_stat -alias "codecachenumscavenges" "CodeCacheScavengesCount"
    sl_stat -alias "datepageswrittenbygem" "DataPagesWrittenByGem"
    sl_stat -alias "datepageswrittenbystone" "DataPagesWrittenByStone"
    # Names changed after gsj 3.0
    set i 0
    while {$i < 48} {
	sl_stat -alias "sessionstat$i" "SessionStat$i"
	incr i
    }

    # Names changed in gsj fiji (4.0)
    sl_stat -alias "sweepcount" "RGCSweepCount"
    sl_stat -alias "possibledeadwsunionsize" "RGCPossibleDeadWsUnionSize"
    sl_stat -alias "pagesneedreclaiming" "RGCPagesNeedReclaiming"
    sl_stat -alias "reclaimnewdatapagescount" "RGCReclaimNewDataPagesCount"
    # Names changed in gsj guatamala (4.6)
    sl_stat -alias "jdbcconnectionsreturned" "JDBCConnectionsAcquired"
    sl_stat -alias "webrequestcount" "WebRequestsReceived"
}
	
proc generateTypeHelp {name} {
    global vsdhelp

    set typeName [file rootname $name]
    set typeVersion [file extension $name]
    if {$typeVersion == {}} {
	set typeVersion ".1"
    }
    set versionNumber [string trimleft $typeVersion "."]
    set topicName "$typeName Type Version $versionNumber"
    if [info exists vsdhelp($topicName)] {
	# Already Done
	return
    }
    set help ""
    set strippedType "$typeName Type"
    if [info exists vsdhelp($strippedType)] {
	append help  "This is version $versionNumber of the \[$typeName > $strippedType\] instance type.\n\n"
	append vsdhelp($strippedType) "   * \[$topicName\]\n"
    }


    # add statistic links; make sure all level documented
    set saveLevel [sl_stat -level]
    sl_stat -level "wizard"
    append help "\n!Statistics\n"
    foreach s [lsort -dictionary [sl_stat -objctrs $name]] {
	if {![isOSStat $s]} {
	    append help "   * \[$s > $s Statistic\]\n"
	}
    }
    append help "\n!Operating System Statistics\n"
    foreach s [lsort -dictionary [sl_stat -objctrs $name]] {
	if {[isOSStat $s]} {
	    append help "   * \[$s > $s Statistic\]\n"
	}
    }
    sl_stat -level $saveLevel

    set vsdhelp($topicName) $help
}

proc generateAllStatHelp {} {
    global vsdhelp
    set topic "All Statistics"
    set help ""
    foreach n [lsort [sl_stat -names]] {
	append help {*[} "$n > $n Statistic" {]} "\n"
	initStatHelp $n
    }
    set vsdhelp($topic) $help
}

proc createAboutHelp {} {
    global vsd tk_version env blt_version tix_version isWindows vsdhelp
    set topic {About VSD}
    if [info exists vsdhelp($topic)] {
	return
    }
    set vsdhelp($topic) \
"<b>VSD:</b>          Visual Statistic Display
<b>Versions:</b>  vsd=$vsd(version),  sltcl=$vsd(sltclVer)
<b>Author:</b>    Darrel Schneider
<b>Support:</b>  send mail to $vsd(maintainer)
<b>Home Page:</b> http://www.gemstone.com/Customers/Downloads/Unsupported/vsd
<b>Purpose:</b>   To display GemStone statistics. Currently the statistics must come from a \[statmonitor] output file.
<b>Credits:</b>  Tcl[info tclversion],  Tk$tk_version,  Tix$tix_version,  and BLT$blt_version.
<b>Platforms:</b>    Solaris, HPUX, AIX, Linux, and Windows NT/98/Me.
\[<b>Files:</b> > VSD Files]
   * <tt>$env(HOME)/.vsdrc</tt>
   * <tt>$env(HOME)/.vsdconfig</tt>
   * <tt>$env(HOME)/.vsdtemplates</tt>
   * <tt>[getScriptName]</tt> contains VSD's \[Tcl > Tcl Language] source code implementation.
   * <tt>[info nameofexecutable]</tt> contains VSD's binary virtual machine.

See \[New Features > Version History] to learn about whats new in this version.
"
}

# Every statDocs entry should also have a matching statDefinitions entry.
# Each statDocs entry must have the following form:
#  {STATNAME} DESCRIPTION
#  where:
#    STATNAME is a string that names the statistic
#    DESCRIPTION is a string that desribes the statistic.
#      The description can contain hyper links to other statistics
#      by inserting text of this form in the string:
#        \[STATNAME > STATNAME Statistic]
#      You can also have hyper links to other help sections
#      using the same form. The text before the ">" is whats
#      displayed as the hyperlink. The text after the ">" must
#      be the actual name of the help section.
#      If you need a left bracket "[" to be displayed in the description
#      then use this text "&#91;".
array set statDocs {
{sharedCounter}
"Computed by user code to define statistics associated with a shared cache. They are called shared because any VM attached to the cache can modify them.

Use the method initSharedCounter() in gemstone.services.StatisticAccess to set one to an explicit value, and the method incrementSharedCounter() to change one.

Smalltalk: The value of a shared counter can be set using 'System|_sharedCounter:setValue:' and 'System|_sharedCounter:incrementBy:'. If you want a user defined counter that is private for each session see 'System|_sessionCacheStatAt:put:'.

Note: statmonitor must be told how many AppStats to collect with the -n switch."
{SessionStat0}
"Computed by user code to define statistics associated with a session.

Java: See methods myApplicationStat(), putMyApplicationStat(), applicationStat() in gemstone.services.GsSystemAdminService for Java access to SessionStats.

The value of a sessionStat can be set from Smalltalk using 
'System|_sessionCacheStatAt:put:'. If you want a user defined counter that can be set by more than one session then see 'System|_sharedCounter:incrementBy:'."
{VMStat0}
"Computed by user code to define statistics associated with a virtual machine.
Use the set and change methods for VMStats in the VMStatisticWriter interface to compute the value of this statistic."
{AioRateLimit}
"AioRateLimit is the current IO rate being used by the page server 
expressed in IO operations per second.  The page server will do no more 
than this number of IO operations per second on average."
{AsyncWritesCount}
"The number of asynchronous writes performed since the process started."
{AsyncWritesInProgress}
"Is zero or one for an aio page server. It is one when the aiopgsvr is doing checkpoint io.
Always zero for a stone and a page server that is not an aio page server."
{AsyncFlushesInProgress}
"AsyncFlushesInProgress is the number of pending extent flush operations."
{AttachDelta}
"Calculated by the cache monitor (shrpcmonitor) process and read by other processes. This value controls the number of data pages that the process is allowed to attach in the shared page cache. It is used to control the sharing of the cache resources among multiple processes using the cache.
The attach delta can be either a positive or negative value. If the value is positive, the process may attach that many more pages before it must give up an existing attached page. If the value is negative then the process must give up, that is, release that many pages before it can attach another page.
The value for AttachDelta is periodically recalculated by the cache monitor process. Similar (but not necessarily constant) values for active processes performing similar tasks is an indicator that the cache is being shared and that the page cache monitor process is working properly. A process that is idle may have a negative value, or a small positive value quite different from other sessions. 
Java: Obsolete since GSJ4.0."
{CheckpointCount}
"The number of checkpoints that have been written since the stone was last started. Writing a checkpoint implies that all of the data and meta information needed to recover the data corresponding to the commit record associated with the checkpoint has been written to the disk(s) containing the extent(s) that make up the repository. Thus, the last checkpoint in the transaction log determines how much data in the log must be recovered when there is a system crash.
In full logging mode, the checkpoints are controlled completely by the stone's checkpointInterval property (Java) or the STN_CHECKPOINT_INTERVAL configuration parameter(Smalltalk). In partial logging mode, a checkpoint may be written more often if the size of the transaction exceeds the value set by the stone's tranLogLimitObjs property (Java) or the configuration parameter STN_TRAN_LOG_LIMIT (Smalltalk). If partial logging is in use, a rapidly increasing value indicates that tranLogLimitObjs or STN_TRAN_LOG_LIMIT may be set too small."
{Offset}
"Obsolete."
{IntSendCount}
"Obsolete and always returns 0."
{ClassCacheCount}
"Obsolete and always returns 0."
{MethodCacheCount}
"Obsolete and always returns 0."
{TotalObjsCommitted}
"Obsolete and always returns 0."
{TotalNewObjsCommitted}
"TotalNewObjsCommitted is the total number of new objects committed by all gems."
{timeCommitTokenHeld}
"Obsolete."
{DeadNotReclaimedSize}
"DeadNotReclaimedSize is the number of objects that have been determined to be dead (current sessions have indicated they do not have a reference to the objects) but have not yet been reclaimed."
{RGCDeadNotReclaimedSize}
"The number of repository objects that have been determined to be dead (current sessions have indicated they do not have a reference to the objects) but have not yet been reclaimed."
{DetachAllPagesCount}
"DetachAllPagesCount is the number of times the gem has detached all pages in the shared cache."
{DeadObjsCount}
"DeadObjsCount is the total number of dead objects reclaimed since the Stone repository monitor process was last started. For a system in 'steady state' for a particular application, look for a uniform discovery rate per garbage collection epoch. Increasing the duration of the epoch should increase this value, but that could also cause larger swings in the amount of free space in the repository."
{DeadObjsReclaimedCount} 
"DeadObjsReclaimedCount is the total number of dead objects reclaimed since the Stone repository monitor process was last started."
{RGCDeadObjsCount}
"The total number of dead objects reclaimed by the repository garbage collector. For a system in 'steady state' for a particular application, look for a uniform discovery rate per garbage collection epoch. Increasing the duration of the epoch should increase this value, but that could also cause larger swings in the amount of free space in the repository."
{RGCEpochCount}
"The total number of times that the repository garbage collector has started an epoch garbage collection. For a system in steady state, look for uniform periods between runs or a uniform run rate."
{ExportedSetSize}
"The number of objects in the ExportSet. The ExportSet is a collection of objects for which the Gem process has handed out its Oop to one of the interfaces (GCI, GBS, objects returned from topaz run commands). Objects in the ExportSet are prevented from being garbage collected by any of the garbage collection processes (that is, by a Gem's in-memory collection of temporary objects, or the epoch garbage collection). The ExportSet is used to guarantee referential integrity for objects only referenced by an application, that is, objects that ave no references to them within the Gem."
{TrackedSetSize}
"The number of objects in the Tracked Objects Set, as defined by the GCI."
{DirtyListSize}
"The number of modified committed objects in the temporary object memory dirty list."
{ExtentFlushCount}
"ExtentFlushCount is the cumulative number of file flush operations performed on any extent by the process.  Note that extents residing on raw partitions do not require flushing.  On UNIX systems, file flushes are performed by calling the fsync() function. During a checkpoint, each extent will be flushed once, except for the primary extent which is flushed twice.  Most extent flushes are performed by the AIO page servers."
{FreeFrameCacheSize}
"FreeFrameCacheSize is the number of frames the process will add or remove from the shared free frame list in a single operation.  A value of zero indicates free frames are not cached and will be added or removed from the shared free frame list one at a time."
{FreeFrameCacheNumFrames}
"FreeFrameCacheNumFrames is the number of free frames currently in the free frame cache of the process."
{GlobalDirtyPageCount}
"The total number of pages in the shared cache that are dirty but not yet eligible for asynchronous writing to the disk because they have not yet been committed. If this value is very large, then very large transactions may be filling the cache. Otherwise, if the stone is running on this cache, the Stone's private page cache size may be too small.
This statistic may not be the actual number of dirty pages in the cache at the time the statistic is viewed because its value is not updated each time a dirty page is added or removed.

Java: Obsolete since GSJ 3.1 and later. Its value will always be zero."
{LastWakeupInterval}
"The average number of milliseconds that the cache stats thread in the system agent is pausing between recalculations.  If this value is low, the cache stats thread is very busy. If it is large (1500 ms), the cache stats thread is relatively quiescent.

Smalltalk: the average number of milliseconds that the shrpcmonitor is pausing between recalculations.  If this value is low, the shrpcmonitor is very busy. If it is large (500 ms), the shrpcmonitor is relatively quiescent."
{SpinLockSmcQSleepCount}
"Number of times a session was forced to sleep on a semaphore waiting for the Smc spinLock. The SMC queue allows sessions to communicate with the stone via shared memory."
{SpinLockFreePceSleepCount}
"Number of times a thread or process was forced to sleep on a semaphore waiting for a FreePce spinLock."
{SpinLockFreeFrameSleepCount}
"Number of times a thread or process was forced to sleep on a semaphore waiting for a FreeFrame spinLock."
{SpinLockHashTableSleepCount}
"Number of times a thread or process was forced to sleep on a semaphore waiting for a HashTable spinLock."
{SpinLockPageFrameSleepCount}
"Number of times a thread was forced to sleep on a semaphore waiting for a PageFrame spinLock."
{SpinLockSmuSleepCount}
"Number of times a thread was forced to sleep on a semaphore waiting for a Smu spinLock."
{SpinLockSharedCtrSleepCount}
"Number of times a thread was forced to sleep on a semaphore waiting for a SharedCounter spinLock."
{SpinLockOtherSleepCount}
"Java: Number of times a thread was forced to sleep on a semaphore waiting for a RecoveryWorkspace, PreparedCommit or LockState spinLock.
Smalltalk: Total number of times a process was forced to sleep on a semaphore while attempting to acquire a shared counter spin lock."
{SpinLockNewSymSleepCount}
"Total number of times a process was forced to sleep on a semaphore while attempting to acquire the new symbols spin lock.  The new symbols spin lock is only used on HPUX versions of GemStone64 and is only used by the stone and the symbol gem."
{PinnedDataPagesCount}
"Number of pinned data pages found in the cache."
{PinnedSharedCount}
"Total number of pages pinned by more than one process."
{PinnedOtPagesCount}
"Number of pinned object table pages found in the cache."
{PinnedTotalCount}
"Total number of pinned pages found in the cache."
{ActiveProcessCount}
"The number of active processes attached to the shared cache, computed by the shrpcmonitor.  This has a slow decay.

Java: Obsolete since GSJ 4.0."
{RecentActiveProcessCount}
"The number of active processes attached to the shared cache, computed by the shrpcmonitor.  This is recomputed every half second and has a fast decay.

Java: Obsolete since GSJ 4.0."
{InTransaction}
"Will be 1 if the session is in a transaction. "
{LocalDirtyPageCount}
"The current number of pages in the shared cache that are dirty and eligible for asynchronous writing to the disk. The Stone's AIO page server will write these pages to the disk.
This statistic may not be the actual number of dirty pages in the cache at the time the statistic is viewed because its value is not updated each time a dirty page is added or removed."
{LocalCacheOverflowCount}
"LocalCacheOverflowCount is the number of times a page was moved from private cache to the shared cache because the private cache was full."
{LocalCacheFreeFrameCount}
"LocalCacheFreeFrameCount is the number of frames in the private page cache that are free."  
{LocalPageCacheHits}
"The number of times a page lookup found the page in either the private or shared page cache. No I/O was required to access the page."
{LocalPageCacheMisses}
"The number of times a page was not found in either the private or shared cache. A miss does not always result in a disk read."
{LocalPageCacheWrites}
"The number of times a page had to be written. With the shared page cache enabled, this counts the writes from the private cache to the shared cache. If the shared page cache is disabled, it counts the pages written to disk."
{LogRecordsIoCount}
"The number of physical write operations performed on the transaction logs since the stone was last started. The minimum write to a transaction log is 512 bytes (one log record). The maximum number of bytes written in a single I/O to the transaction log is 64K. The implication for performance tuning is that to achieve the best throughput (in transactions per second) you would like to have as few as possible writes to the transaction logs. The technique for achieving this is to tune the size of the transactions so that each transaction writes one or more completely filled 64K records."
{LogRecordsWritten}
"The number of log records that have been written to the transaction logs since the stone was last started. The size of a log record is 512 bytes."
{NewObjsCommitted}
"Total number of new objects successfully committed by this session."
{ObjectsRead}
"Number of committed objects copied into VM memory since start of session."
{ClassesRead}
"Number of Classes copied into VM memory since start of session"
{MethodsRead}
"Number of GsMethods copied into VM memory since start of session"
{ObjectsRefreshed}
"Number of committed objects in VM memory that have been re-read from
pagecache after transaction boundaries, since start of session."
{NoRollbackSetSize}
"The number of objects in the NoRollbackSet. The NoRollbackSet is used to provide different abort behavior for committed objects. Normal behavior for committed objects is that their state is 'rolled back,' that is, the modifications to the object made by the transaction are rolled back (removed) by the abort. Objects in the NoRollBackSet do not have this behavior for aborts. Instead, the state of the object is preserved across the abort. This is the kind of behavior desired for 'temporary' objects even if they happen to get committed. This feature is used by GeODE for objects that manage the location of windows on the screen. It is obvious that we do not want these objects to lose the changes made by the current transaction!

Objects are not automatically added or removed from the set by the system. Instead the application has sole responsibility for adding/removing objects to/from the NoRollbackSet. The contents of the NoRollbackSet can be examined or modified using hidden set methods defined in class System. There are no known limits on this although it is probably best to keep its size under 2K Oops.
Always zero in a Java system."
{NotConnectedObjsSetSize}
"The number of objects in the notConnectedObjsSet. This set is used to provide abort behavior for temporary objects, that is, objects which have not been connected to one of the permanent root objects in the repository. (Root objects are kernel classes and predefined objects like Globals, AllUsers, and so forth.) A large value sometimes indicates that the GEM_TEMPOBJ_CACHE_SIZE configuration parameter set is too small.
This set is updated during commit processing to remove objects that have become connected to permanent objects by the commit. New objects are added to this set when objects move to disk because GEM_TEMPOBJ_CACHE_SIZE overflowed, or because an object already on disk references an object in GEM_TEMPOBJ_CACHE_SIZE at commit. The contents of the NotConnectedObjsSet can be examined using the hidden set methods defined in class System. There are a couple of implications for performance tuning. First, if the size of the set is monotonically increasing, it is an indication of garbage objects leaking out of the temporary object space to disk. Second, like the ExportSet, the performance of the system is improved if the size of the set is under 2K objects.
Always zero in a Java system."
{AttachedCount}
"The number of data pages that the process currently has attached in the shared page cache. It indicates how much of a load the application is putting on the cache for resources."
{AbortCount}
"The total number of aborts done by a session."
{CommitRecordCount}
"The number of outstanding commit records that are currently being maintained by the system. A number larger than the stone's signalAbortCrBacklog property (Java) or STN_SIGNAL_ABORT_CR_BACKLOG configuration option (Smalltalk) indicates that there is a process in a transaction that is preventing the stone from reclaiming (garbage collecting) the resources associated with those commit records. Large values are usually accompanied by continuing growth in the size of the repository."
{CommitCount}
"The total number of commits, including read-only commits, done by a session."
{CommitRecordsDisposedCount}
"CommitRecordsDisposedCount is the total number of commit records disposed by the stone."
{DeadObjCount}
"The number of dead objects that have been garbage collected by the by the in-memory garbage collection of temporary objects since the process started.
Always zero in a Java system."
{FailedAioCount}
"The number of Asynchronous I/O operations that failed since the stone was last started."
{FailedCommitCount}
"The number of attempts to commit that failed to succeed due to concurrency conflicts."
{TargetFreeFrameCount}
"TargetFreeFrameCount is minimum number of unused page frames the free frame page server(s) will attempt to keep in the cache.  The free frame count can still fall below this value if the cache contains mostly dirty pages, which free frame page servers cannot preempt."
{PagesRemovedForStone}
"The number of pages removed from the Shared Page Cache by the System Agent on behalf of the stone. After this operation, the stone is free to add the pages to the free page list."
{PagesNotRemovedForStone}
"The number of pages that could not be removed from the Shared Page Cache by the System Agent. Page removal will be attempted again."
{PagesWaitingForRemovalInSap}
"The number of pages in the System Agent that are waiting to be removed from the Shared Page Cache."
{PagesWaitingForRemovalInStoneCount}
"The number of pages in the Stone that are waiting to be removed from the Shared Page Cache by the Page Manager (Smalltalk) or the System Agent (Java)."
{RemoteCachesNeedServiceCount}
"RemoteCachesNeedServiceCount is the number of outstanding requests to start or stop a remote shared page cache.  Requests are initiated by the stone and executed by the Page Manager session." 
{PagesPreempted}
"The number of pages that were preempted from the Shared Page Cache in an attempt to replenish the free frame list."
{PagesNotPreempted}
"The number of pages that were candidates for preemption, but could not be removed from the Shared Page Cache (i.e., the page was locked, pinned, etc.)."
{InUseByStoneTest}
"The count of the number of InUseByStoneTests performed by the System Agent in response to vms going off-line."
{RecoveredSlots}
"The count of the number of process slots that had to be recovered by the System Agent in response to vms going off-line."
{SapServiceQueueSize}
"The number of entries in the System Agents service queue."
{FreeFrameCount}
"The number of unused page frames in the shared page cache. It gives some indication of the utilization of the cache, but it is not tunable."
{AvgPercentShared}
"The percentage of shared attached pages that are attached by the average process.

Java: Obsolete since GSJ 4.0."
{GcNotConnectedCount}
"The number of times the notConnected objects were garbage collected since the process started.
Always zero in a Java system."
{GcNotConnectedDeadCount}
"The number of dead objects found during the garbage collection of the notConnected objects.
Always zero in a Java system."
{GcNotConnectedDeadCommittedCount}
"The number of dead objects found during the garbage collection of the notConnected objects that were previously committed.
Always zero in a Java system."
{MakeRoomInOldSpaceCount}
"The number of times the oldest temporary object generation filled up. Large values are okay for a large data load session; otherwise, the GEM_TEMPOBJ_CACHE_SIZE configuration option may be too small. We suggest comparing this statistic with \[NotConnectedObjsSetSize > NotConnectedObjsSetSize Statistic] to see if both are growing. Another useful comparison is that this statistics value should be less than one-third the size of \[ScavengeCount > ScavengeCount Statistic]; larger ratios indicate that the cache is too small.
Always zero in a Java system."
{ScavengeCount}
"Its the number of times that the in-memory temporary object garbage collector was executed since the process started.
Always zero in a Java system."
{CommitQueueSize}
"Shows the number of sessions waiting for the commit token. "
{LockReqQueueSize}
"Shows the number of sessions waiting for a commit to complete so that their lock request can be serviced. "
{LoginQueueSize}
"Shows the number of sessions waiting for login completion."
{NotifyQueueSize}
"Shows the number of sessions using notifiers."
{RunQueueSize}
"Shows the number of sessions waiting for service from the stone."
{SmcQueueSize}
"Shows the number of sessions in the SMC (shared memory communication) queue waiting to be added to the run queue by stone."
{ObjsCommitted}
"Total number of new and modified objects successfully committed by this session."
{PagesNeedReclaimSize}
"The number of pages of reclamation work that is pending, that is, the backlog waiting for the GcSession (Java) or GcGem (Smalltalk) reclaim task."
{TimeWaitingForIo}
"The total real time in milliseconds the process has spent waiting for I/O calls that read or write pages to complete.  Only page I/O is included in this statistic.  Other types of I/O such as tranlog writes by the stone process are not included."
{PageIoTimeOverallAvg}
"The average duration of a page I/O (page read or page write) call in microseconds."
{PageIoTime10SampleAvg}
"The average duration of a page I/O (page read or page write) call in microseconds.  The average is computed for the last 10 I/O operations and is updated every 10 I/O operations."
{PageIoTime100SampleAvg}
"The average duration of an I/O call (page read or page write) in microseconds.  The average is computed for the last 100 I/O operations and is updated every 10 I/O operations."
{PersistentPagesCommittedCount}
"Total number of pages made persistent (committed) by the session.  This statistic is updated during commit processing."
{SleepDuringDisposeTempPageCount}
"Total number of times the gem slept while waiting to dispose a temp page. 5ms sleep for each tick of counter. Excessive counts should be reported to Tech Support."
{PageIoCount}
"The number of page I/O (page read or page write) calls done by the process since it was last started.  Each I/O call may read or write more than 1 page."
{PageReads}
"The number of page read operations done by the process since it was last started. These operations involve actual disk reads and not reads from the shared page cache.
Note that a single operation may read more than one page."
{DataPageReads}
"The number of data pages read by the process since it was last started.

Smalltalk: These page reads are actual disk reads and not reads from the shared page cache."
{ObjTablePageReads}
"The number of object table pages read by the process since it was last started."
{ObjectTablePageReads}
"The number of object table pages read by the process since it was last started. These page reads are actual disk reads and not reads from the shared page cache."
{BitmapPageReads}
"The number of bitmap pages read by the process since it was last started. These page reads are actual disk reads and not reads from the shared page cache."
{BitMapPageReads}
"The number of bit map pages read by the process since it was last started."
{PreemptedDataPages}
"PreemptedDataPages is the number of data pages removed from the shared page cache by this page server."
{PreemptedObjectTablePages}
"PreemptedObjectTablePages is the number of object table pages removed from the shared page cache by this page server."
{PreemptedBitmapPages}
"PreemptedBitmapPages is the number of bitmap removed from the shared page cache by this page server."
{PreemptedCommitRecordPages}
"PreemptedCommitRecordPages is the number of commit record pages removed from the shared page cache by this page server."
{PreemptedOtherPages}
"PreemptedOtherPages is the number of pages removed from the shared cache by this page server which were not data, object table, commit record, or bitmap pages."
{ClockHandFrameId}
"ClockHandFrameId is the shared page cache frame ID the page server clock hand currently references."
{PostCheckpointPages}
"PostCheckpointPages is the count of pages written out by the page server during post checkpoint processing."
{ObjectTableLookups}
"The number of times an oop was looked up in the object table."
{PageSetDirtyCount}
"The number of times a page was marked dirty by the session."
{PageWrites}
"The number of pages written by the process since it was last started. These page writes are actual disk writes and not just writes into the shared page cache. Unless a large data load is in process, the number should be low for all processes except the Stone's AIO page server process."
{AioCkptCount}
"The number of dirty pages written from the shared page cache to disk to satisfy a checkpoint. "
{AioDirtyCount}
"The number of dirty pages written from the shared page cache to disk by Stone's AIO page server during normal operation."

{AioWakeupInterval}
"The average number of milliseconds that the aio server thread in the system agent is pausing between recalculations.  If this value is low, the shrpcmonitor thread is very busy. If it is large (1000 ms), the aio server is relatively quiescent."
{PreemptedPagesCount}
"The number of pages preempted from the shared page by the pgsvr. "
{PossibleDeadSize}
"The number of objects previously marked as dereferenced in the repository but for which sessions currently in a transaction might have created a reference in their object space. The object is not declared ('promoted to') dead until each active session verifies the absence of such references."
{ProcessId}
"The operating system processId for the process."
{ProcessName}
"ProcessName identifies the process kind (vm, gem, stone, page server, or shared page cache monitor)."
{ReclaimCount}
"ReclaimCount is the number of reclaims performed by a GcGem process since the Stone repository monitor was last started."
{ReclaimedPagesCount}
"ReclaimedPagesCount is the number of pages reclaimed by a GcGem reclaim process since the Stone repository monitor process was last started.  The count indicates the number of pages that have been or will soon be placed back into the free pool of pages in the repository."
{RGCReclaimCount}
"The total number of reclaims performed by the repository garbage collector."
{RGCReclaimedPagesCount}
"The total number of pages reclaimed by the repository garbage collector. The count indicates the number of pages that have been or will soon be placed back into the free pool of pages in the repository."
{RepositorySize}
"The size of the stone's repository in pages."
{SessionId}
"The GemStone sessionId associated with this client."
{SessionWithOldestCr}
"A session that is in a transaction that is currently referencing the oldest commit record, which may be preventing it from being reclaimed."
{SessionWithOldestCrNotInTrans}
"A session that is not in a transaction that is currently referencing the oldest commit record, which may be preventing it from being reclaimed."
{OldestCrSessNotInTrans}
"The session ID of the oldest session that is not in a transaction that is currently referencing the oldest commit record.  This session may be preventing the commit record from being disposed."
{SessionWithGcLock}
"A session that is holding the Gc Lock because it is executing a markForCollection or an epochGC. Zero if the lock is not held."
{CheckpointIoRatio} "Multipler for MaxAioRate during checkpoint writing."
{Spare2} "Undefined"
{Spare3} "Undefined"
{Spare4} "Undefined"
{Spare5} "Undefined"

{SharedAttached}
"The number of data pages in the shared page cache that are attached by more than one process. A large value indicates that processes may be accessing the same objects, while a small value indicates that processes are mostly accessing different objects.

Java: Obsolete since GSJ 4.0."
{TimeInScavenges}
"Real time in milliseconds spent in in-memory garbage collector scavenges."
{MarkSweepCount}
"MarkSweepCount is the number of mark/sweep operations performed in the gem's object memory.  Mark/sweep operations are more expensive than scavenge operations."
{TimeInMarkSweep}
"Real time in milliseconds spent in in-memory garbage collector mark/sweeps."
{TimeProcessingCommit}
"Shows the cumulative amount of real time in milliseconds that the session has spent doing the processing for commits while it has the commit token. "
{TimeStoneCommit}
"Shows the cumulative amount of real time in milliseconds that the session has waited for the stone to complete commits by this session. "
{TimeWaitingForCommit}
"Shows the cumulative amount of real time in milliseconds that the session has spent waiting for its turn to commit, that is, the time waiting for the commit token and the Stone's processing time for serialization. "
{TotalAttached}
"The total number of data pages attached in the cache (the sum of the \[AttachedCount > AttachedCount Statistic] for all processes).

Java: Obsolete since GSJ 4.0."
{TotalAborts}
"The total number of aborts, including read-only commits, performed by all sessions since the stone was last started."
{TotalCommits}
"The total number of commits, excluding read-only commits, performed by all sessions since the stone was last started."
{UserTime}
"The number of milliseconds the process has been using the CPU to execute user code."
{SysTime}
"The number of milliseconds the process has been using the CPU to execute system calls."
{MaxRSS}
"The high water mark of the processes resident set size.
Note that this counter is always 0 on Solaris."
{MajFlt}
"The number of times the process has had a page fault that needed disk access."
{MinorFaults}
"The number of times the process has had a page fault that did not need disk access."
{SwapCount}
"The number of times the process swapped out of memory to disk."
{MsgSent}
"The number of messages sent by the process."
{MsgRecv}
"The number of messages received by the process."
{VolCSW}
"The number of voluntary context switches done by the process.
Note that this counter is always 0 on HP-UX."
{IVolCSW}
"The number of times the process was forced to do a context switch.
Note that this counter is always 0 on HP-UX."
{SignalsReceived}
"The total number of operating system signals this process has received."
{InputBlocks}
"The number of input blocks."
{OutputBlocks}
"The number of output blocks."
{CharacterIO}
"The number of characters read and written."
{SharedMemorySize}
"The integral size of shared memory."
{UnsharedDataSize}
"The integral operating system unshared data size."
{UnsharedStackSize}
"The integral unshared stack size."
{DataRSS}
"The data resident set size."
{TextRSS}
"The text resident set size."
{DataVmSize}
"The data virtual memory size."
{PercentMemoryUsed}
"The percentage of real memory used by the process.
Java: On Solaris it is only collected if 'statmonitor -s 2' or greater is used."
{PercentCpuUsed}
"The percentage of recent cpu time used by the process.
It is only collected if 'statmonitor -s 2' or greater is used."
{LwpTotalCount}
"The total number of light weight processes that have ever contributed to the process's statistics."
{LwpCount}
"The total number of light weight processes that have ever contributed to the process's statistics."
{LwpCurCount}
"The current number of light weight processes that exist in the process."
{StackKBytes}
"The size of the process's stack in kilobytes."
{HeapKBytes}
"The size of the process's heap in kilobytes."
{ImageKBytes}
"The size of the process's image in kilobytes.
It is only collected if 'statmonitor -s 2' or greater is used."
{RSSKBytes}
"The size of the process's resident set size in kilobytes.
It is only collected if 'statmonitor -s 2' or greater is used."
{TrapTime}
"The number of milliseconds the process has been in system traps."
{TextFaultSleepTime}
"The number of milliseconds the process has been faulting in text pages."
{DataFaultSleepTime}
"The number of milliseconds the process has been faulting in data pages."
{KernelFaultSleepTime}
"The number of milliseconds the process has been faulting in kernel pages."
{LockWaitSleepTime}
"The number of milliseconds the process has been waiting for a user lock.
Java: Note that all lwp's contribute to this stat's value so check \[LwpCurCount > LwpCurCount Statistic] to understand large values."
{AllOtherSleepTime}
"The number of milliseconds the process has been sleeping for some reason not tracked by any other stat.
Java: Note that all lwp's contribute to this stat's value so check \[LwpCurCount > LwpCurCount Statistic] to understand large values."
{WaitCpuTime}
"The number of milliseconds the process has been waiting for a CPU due to latency."
{StoppedTime}
"The number of milliseconds the process has been stopped."
{SystemCalls}
"The total number system calls."
{DataSize}
"The number of real pages used for data."
{TextSize}
"The number of real pages used for text."
{StackSize}
"The number of real pages used for stack."
{DataPages}
"The number of pages of operating system real memory used for data."
{TextPages}
"The number of pages of operating system real memory used for text."
{StackPages}
"The number of pages of operating system real memory used for stack."
{InOsWait}
"Will be 1 if the process is waiting for some OS resource. "
{PrivatePages}
"The operating system resident set size (i.e. private pages) for the process."
{RealSharedMemoryPages}
"The number of operating system real pages used for shared memory."
{RealMMFPages}
"The number of operating system real pages used for memory mapped files."
{RealUandKPages}
"The number of operating system real pages used for U-Area and k_Stack."
{RealDevIoPages}
"The number of operating system real pages used for I/O device mapping."
{VirtualTextPages}
"The number of operating system virtual pages used for text."
{VirtualDataPages}
"The number of operating system virtual pages used for data."
{VirtualStackPages}
"The number of operating system virtual pages used for stack."
{VirtualSharedMemoryPages}
"The number of operating system virtual pages used for shared memory."
{VirtualMMFPages}
"The number of operating system virtual pages used for memory mapped files."
{VirtualUandKPages}
"The number of operating system virtual pages used for U-Area and k_Stack."
{VirtualDevIoPages}
"The number of operating system virtual pages used for I/O device mapping."
{MaxOpenFd}
"The highest file descriptor currently opened by the process."
{SigAbortCount}
"The number of abort signals that have been sent by the stone to a particular session.

Note that this counter is incremented whenever the stone sends an abort, even if the session ignores the signal."
{SigLostOtCount}
"The number of lost object table signals that have been sent by the stone to a particular session."
{AbortSignalsSent}
"The total number of abort signals that have been sent by the stone to a particular session.
Note that this counter is incremented whenever the stone sends an abort signal, even if the session ignores the signal.
It will always be zero for sessions whose vm is not on the same host as the stone."
{ForcedAbortSignalsSent}
"The total number of forced abort signals that have been sent by the stone to a particular session.
Note that a forced abort used to be called a lostOt.
It will always be zero for sessions whose vm is not on the same host as the stone."
{AbortSignalsReceived}
"The total number of abort signals that a particular session has received from the stone."
{ForcedAbortSignalsReceived}
"The total number of forced abort signals that a particular session has received from the stone.
Note that a forced abort means that the session has lost its object table."
{TotalSignalsSent}
"The total number of signals that have been sent by the stone to a session or vm since the stone started. The signal types include: abort, forced abort, changed object notification,transaction log full, and stop session."
{TotalAbortSignalsSent}
"The total number of abort signals that have been sent by the stone since it started."
{TotalForcedAbortSignalsSent}
"The total number of forced abort signals that have been sent by the stone since it started."
{ProgressCount}
"Can be used to monitor the progress of certain Repository methods that may run for extended periods.
During markForCollection, ProgressCount for that session's cache slot first indicates the number of objects swept during the mark-sweep (transitive closure) phase. The transition to the second phase is marked by ProgressCount being reset to zero. During the second phase, it indicates the number of possible dead objects identified by taking the difference between the universe and those objects found during the mark-sweep phase.

During backup and restore ProgressCount for that session's cache slot is the number of objects written to or restored from the backup file.

During object audit Progress count for that session's cache slot is the number of objects audited."
{MessagesToStone}
"The number of messages sent from a session to the stone."
{NewSymbolsCount}
"The number of new symbols created by a session."
{BytesCommittedCount}
"Total number of bytes written to new Pom Data Pages by this session during commit attempts."
{OmBytesFlushed}
"Total number of temporary object memory bytes flushed to Pom during commit attempts for this session."
{AllSymbolsQueueSize}
"The number of sessions waiting for a lock on the global object AllSymbols. Because symbols are canonical (that is, there is only a single instance of each in the system), transactions that create a new symbol must write AllSymbols during commit processing.

If the queue typically contains several sessions, you should examine the number of symbols the application creates.

Always zero in a Gemstone/J system."
{PageWaitQueueSize}
"The number of sessions waiting for new pages."
{LogWaitQueueSize}
"The number of sessions waiting for transaction log space."
{NumInSetLostOtQueue}
"The number of sessions waiting for set lostOt in shared caches."
{ReclaimQueueSize}
"The size of the queue that holds sessions waiting for a reclaimAll operation to
 complete"
{ReclaimWaitQueueSize}
"The number of sessions waiting for a reclaimAll operation to complete"
{NetWriteQueueSize}
"The number of sessions waiting for the JavaVm client to clear the network (sessions blocked on output).
Obsolete after GSJ 4.1."
{TempPagesDisposed}
"The number of temporary pages (pages allocated since the last checkpoint) that have been disposed."
{PersistentPagesDisposed}
"The number of persistent pages that have been disposed of while in the stone's private cache."
{PageDisposesDeferred}
"The number of times a page disposal had to be deferred. The can be caused by a asynchronous operation being in progress on the page or it being attached or locked."
{FreePages}
"For the stone is the size of the free page pool for the repository.  For a VM or gem, it indicates the number of free pages that the VM or gem has aquired but not yet used."
{ClientPageReads}
"The number of pages that have been transmitted by the page server to the client."
{ClientPageWrites}
"The number of pages that have been transmitted by the client to the page server."
{VcCacheScavengesCount}
"The number of garbage collections of the VC space. VC space is a memory region private to the virtual machine.

Always zero in a Java system."
{VcCacheSizeBytes}
"The total size in bytes of the VC space. This is the private heap memory of the gem.

Always zero in a Java system."
{CodeCacheSizeBytes}
"Total size in bytes of copies of GsMethod's that are in the code generation area and ready for execution, as of the end of mark/sweep."
{CodeCacheEntries}
"The number of methods in the code cache.

Always zero for Java."
{CodeCacheStaleEntries}
"The number of stale methods in the code cache.

Always zero for Java."
{CodeCacheScavengesCount}
"The number of garbage collections of the code cache.

Always zero for Java."
{FramesFromFreeList}
"A count of the number of times the process acquired a shared page cache frame from the free list."
{FramesAddedToFreeList}
"Number of frames the process added to the free frame list."
{FramesFromFindFree}
"A count of the number of times the process acquired a shared page cache frame by scanning cache entries."
{NonSharedAttached}
"Calculated by the cache monitor (shrpcmonitor) each time the \[AttachDelta > AttachDelta Statistic] is recomputed for this process. The value represents the number of pages that were attached by only this process. 

Java: Obsolete since GSJ 4.0."

{PrivateAttachLimit}
"Calculated by the cache monitor (shrpcmonitor) each time the \[AttachDelta > AttachDelta Statistic] is recomputed for this process. This value is reserved for future use."
{FreeFrameLimit}
"When the number of free frames in the shared page cache is less than this limit the process will scan the cache for a free frame rather than use one from the free frame list (to allow the stone to use the remaining free frames)."
{ReadCount}
"A count of the read operations done by an operating system IO device."
{WriteCount}
"A count of the write operations done by an operating system IO device."
{KBytesRead}
"The number of kilobytes read by an operating system IO device."
{KBytesWritten}
"The number of kilobytes written by an operating system IO device."
{SeekCount}
"A count of the seek operations done by an operating system IO device."
{TransferCount}
"A count of the read and write operations done by an operating system IO device."
{KBytesTransferred}
"The number of kilobytes read and written by an operating system IO device."
{InvalidPagesWrittenByGem}
"The number of invalid (i.e. empty) pages in the cache because of a write done by a gem."
{InvalidPagesWrittenByStone}
"The number of invalid (i.e. empty) pages in the cache because of a write done by the stone."
{RootPagesWrittenByGem}
"The number of root pages in the cache because of a write done by a gem."
{RootPagesWrittenByStone}
"The number of root pages in the cache because of a write done by the stone."
{FragmentBmPagesWrittenByGem}
"The number of bitmap fragment pages in the cache because of a write done by a gem."
{FragmentBmPagesWrittenByStone}
"The number of bitmap fragment pages in the cache because of a write done by the stone."
{OldFragmentBmPagesWrittenByGem}
"The number of old bitmap fragment pages in the cache because of a write done by a gem.
An old FragementBm page is an obsolete fragment bitmap page from a release prior to GemStone64."
{OldFragmentBmPagesWrittenByStone}
"The number of old bitmap fragment pages in the cache because of a write done by the stone.
An old FragementBm page is an obsolete fragment bitmap page from a release prior to GemStone64."
{CommitRecordPagesWrittenByGem}
"The number of commit record pages in the cache because of a write done by a gem."
{CommitRecordPagesWrittenByStone}
"The number of commit record pages in the cache because of a write done by the stone."
{OldCommitRecordPagesWrittenByGem}
"The number of old commit record pages in the cache because of a write done by a gem.
An old CommitRecord page is an obsolete commit record from a prior release of GemStone."
{OldCommitRecordPagesWrittenByStone}
"The number of old commit record pages in the cache because of a write done by the stone.
An old CommitRecord page is an obsolete commit record from a release prior to GemStone64."
{DataPagesWrittenByGem}
"The number of data pages in the cache because of a write done by a gem."
{DataPagesWrittenByStone}
"The number of data pages in the cache because of a write done by the stone."
{OtInternalPagesWrittenByGem}
"The number of object table internal pages in the cache because of a write done by a gem."
{OtInternalPagesWrittenByStone}
"The number of object table internal pages in the cache because of a write done by the stone."
{OtLeafPagesWrittenByGem}
"The number of object table leaf pages in the cache because of a write done by a gem."
{OtLeafPagesWrittenByStone}
"The number of object table leaf pages in the cache because of a write done by the stone."
{BmInternalPagesWrittenByGem}
"The number of bitmap internal pages in the cache because of a write done by a gem."
{BmInternalPagesWrittenByStone}
"The number of bitmap internal pages in the cache because of a write done by the stone."
{OldBmInternalPagesWrittenByGem}
"The number of old bitmap internal pages in the cache because of a write done by a gem.
An old BmInternal page is an obsolete internal bitmap page from a release prior to GemStone64."
{OldBmInternalPagesWrittenByStone}
"The number of bitmap internal pages in the cache because of a write done by the stone.
An old BmInternal page is an obsolete internal bitmap page from a release prior to GemStone64."
{BmLeafPagesWrittenByGem}
"The number of bitmap leaf pages in the cache because of a write done by a gem."
{BmLeafPagesWrittenByStone}
"The number of bitmap leaf pages in the cache because of a write done by the stone."
{OldBmLeafPagesWrittenByGem}
"The number of old bitmap leaf pages in the cache because of a write done by a gem.
An old BmLeaf page is an obsolete bitmap leaf page from a release prior to GemStone64."
{OldBmLeafPagesWrittenByStone}
"The number of old bitmap leaf pages in the cache because of a write done by the stone.
An old BmLeaf page is an obsolete bitmap leaf page from a release prior to GemStone64."
{EmptyBmLeafPagesWrittenByGem}
"The number of empty bitmap leaf pages in the cache because of a write done by a gem."
{EmptyBmLeafPagesWrittenByStone}
"The number of empty bitmap leaf pages in the cache because of a write done by the stone."
{MultObjPagesWrittenByGem}
"The number of multiple object pages in the cache because of a write done by a gem."
{MultObjPagesWrittenByStone}
"The number of multiple object pages in the cache because of a write done by the stone."
{RepBkupRestPagesWrittenByGem}
"This page kind is no longer used."
{RepBkupRestPagesWrittenByStone}
"This page kind is no longer used."
{CountBagLeafPagesWrittenByGem}
"The number of count bag leaf pages in the cache because of a write done by a gem."
{CountBagLeafPagesWrittenByStone}
"The number of count bag leaf pages in the cache because of a write done by the stone."
{BitlistPagesWrittenByGem}
"The number of bitlist pages in the cache because of a write done by a gem.
A bitlist page is a form of a bit array."
{BitlistPagesWrittenByStone}
"The number of bitlist pages in the cache because of a write done by the stone.
A bitlist page is a form of a bit array."
{OldBitlistPagesWrittenByGem}
"The number of old bitlist pages in the cache because of a write done by a gem.
An old bitlist page is an obsolete bitlist page from a release prior to GemStone64."
{OldBitlistPagesWrittenByStone}
"The number of bitlist pages in the cache because of a write done by the stone.
An old bitlist page is an obsolete bitlist page from a release prior to GemStone64."
{DeadDataPagesWrittenByGem}
"The number of dead data pages in the cache because of a write done by a gem.
Dead data pages are intended for disposal."
{DeadDataPagesWrittenByStone}
"The number of dead data pages in the cache because of a write done by the stone.
Dead data pages are intended for disposal."
{CountMapLeafPagesWrittenByGem}
"This page kind is no longer used."
{CountMapLeafPagesWrittenByStone}
"This page kind is no longer used."
{CountBagInteriorPagesWrittenByGem}
"The number of count bag interior pages in the cache because of a write done by a gem."
{CountBagInteriorPagesWrittenByStone}
"The number of count bag interior pages in the cache because of a write done by the stone."
{LogRecordPagesWrittenByGem}
"The number of transaction log record pages in the cache because of a write done by a gem."
{LogRecordPagesWrittenByStone}
"The number of transaction log record pages in the cache because of a write done by the stone."
{Root40PagesWrittenByGem}
"The number of root 4.0 pages in the cache because of a write done by a gem."
{Root40PagesWrittenByStone}
"The number of root 4.0 pages in the cache because of a write done by the stone."
{BackupRecordPagesWrittenByGem}
"The number of backup record pages in the cache because of a write done by a gem."
{BackupRecordPagesWrittenByStone}
"The number of backup record pages in the cache because of a write done by the stone."
{LostOtPagesWrittenByGem}
"The number of lost ot pages in the cache because of a write done by a gem."
{LostOtPagesWrittenByStone}
"The number of lost ot pages in the cache because of a write done by the stone."
{StonePidPagesWrittenByGem}
"The number of pid pages in the cache because of a write done by the gem."
{StonePidPagesWrittenByStone}
"The number of pid pages in the cache because of a write done by the stone."
{MilliSecPerIoSample}
"Used as a parameter to implement the configurable I/O limit for GemStone processes. Because a process's I/O rate currently is sampled every 5 I/Os, MilliSecPerIoSample is computed as 1000/(ioLimit * 5). A value of 1 means that the process has no I/O limit. If the time in milliseconds since the last sample equals or exceeds MilliSecPerIoSample, the process can perform another I/O operation; if not, the process sleeps.

MilliSecPerIoSample is particularly useful in limiting I/O rate of a process that is executing a long-running primitive. For information about setting this value, see the discussion in chapter two of the 'GemStone Administration Guide'. If you want to calculate the current I/O limit, it is given by 1000/(MilliSecPerIoSample * 5)."
{GcPromoteDeadCount}
"The total number of objects that the garbage collector has promoted to dead."
{GcSweepCount}
"The total number of sweeps of the possible dead write set union that have been done by the GcGem since it started."
{GcWsUnionSweepCount}
"The total number of sweeps of the possible dead write set union that have been done by the Admin since it started."
{GcPossibleDeadSize}
"The number of possibleDead objects waiting to be promoted to dead by the GcGem.  Initially, it is the size of the possibleDeadSet received from Stone.  Each time a group of objects is promoted to dead, this value is decremented by the size of that group."
{GcPossibleDeadWsUnionSize}
"The size of the possible dead write set union if a sweep is in progress.  It is zero if a sweep is not in progress.  The progress count during a GcGem sweep may reach this as its maximum value so this stat can be used to figure out when a GcGem sweep will complete."
{GcPagesNeedReclaiming}
"The number of pages that need reclaiming.  This value controls if promotes and/or epochs will be defered.  If this value is greater than GcDeferPromoteDeadThreshold then promotes are defered.  If this value is greater than GcDeferEpochThreshold then epochs are defered."
{RGCSweepCount}
"The total number of sweeps of the possible dead write set union that have been done by the repository garbage collector."
{RGCSweepThreadsActive}
"The current number of threads that are being used by the repository garbage collector to sweep the write set union."
{RGCSweepThreadsLimit}
"The maximum number of threads that can be used by the repository garbage 
collector to sweep the write set unions.  Defaults to 2 times the number of 
cpu's on the system."
{RGCAuditThreadsActive}
"The current number of threads that are being used by an parallel type audit."
{RGCAuditThreadsLimit}
"The maximum number of threads that can be used by the process running a 
typeAudit.  Defaults to 2 times the number of cpu's on the system."
{RGCPossibleDeadSize}
"The number of objects previously marked as dereferenced in the repository but for which sessions currently in a transaction might have created a reference in their object space. The object is not declared ('promoted to') dead until each active session verifies the absence of such references."
{RGCPossibleDeadWsUnionSize}
"The size of the possible dead write set union if a repository garbage collector sweep is in progress. It is zero if a sweep is not in progress. The progress count during a RGC sweep may reach this as its maximum value so this stat can be used to figure out when a RGC sweep will complete."
{RGCPagesNeedReclaiming}
"The number of repository pages that need reclaiming. This value controls if repository epochs will be deferred. If this value is greater than \[RGCEpochThreshold > RGCEpochThreshold Statistic] then epochs are deferred."
{GcDeferPromoteDeadThreshold}
"The value of the GcUser deferPromoteDeadReclaimThreshold parameter that the garbage collector is currently using."
{GcDeferEpochThreshold}
"The value of the GcUser deferEpochReclaimThreshold parameter that the GcGem is currently using."
{DeferEpochThreshold}
"The value of the deferEpochReclaimThreshold parameter that the GcSession is currently using."
{GcReclaimMaxPages}
"The value of the reclaimMaxPages parameter that the GcSession (Java) or GcGem (Smalltalk) is currently using."
{GcReclaimNewDataPagesCount}
"GcReclaimNewDataPagesCount is the number of new data pages that the GcGem had to allocate during reclaims since the Stone process was started."
{RGCReclaimNewDataPagesCount}
"The total number of new data pages allocated by the repository garbage collector during reclaims."
{TransactionLevel}
"Indicates if the session is in a transaction. Possible values are:
-1 indicates that the session is in a transactionless state.

0 indicates that the session is not in a transaction, but allows a consistent view for reads.  Session is subject to sigAbort or lostOT (Smalltalk)
1 indicates the session is in a transaction."
{TimeInPgsvrNetReads}
"Shows the cumulative amount of real time in milliseconds that a session or stone has spent reading network data from a page server."
{TimeInPgsvrNetWrites}
"Shows the cumulative amount of real time in milliseconds that a session or stone has spent writing network data to a page server."
{GsMsgCount}
"The number of messages processed by Stone."
{GsMsgSessionId}
"Identifies the session that sent the message being processed."
{GsMsgKind}
"The command identifier for the message being executed."
{StnLoopState}
"An indicator of where in the stone control loop the process is executing. 

Smalltalk: For state definitions, see the comments in the code.

Java: Possible values and their meanings:
0:  Checking if license has expired.
1:  Polling the network for an event.
2:  Getting messages from shared memory.
3:  Servicing first active task.
4:  Servicing all other active tasks.
6:  Checking for stale attach deltas.
7:  Dispose stale commit records.
8:  Handle free psace threshold.
9:  Checking for full tranlogs or checking if checkpoint needed.
10: Doing a checkpoint.
11: Check for session timeouts. Obsolete after the Facets 1.1 release.
12: Check for failed logins or stopped sessions.
13: Check for completion of async tranlog writes.
14: Check for completion of async checkpoint writes.
15: Check for events before sleeping.
16: Wait for an event.
19: Disposing of temporary pages.
2x: Disposing of temporary pages in extent X.
40: Finish remote checkpoint async io for checkpoint.
41: Flush non-primary extents for checkpoint.
42: Write primary root page for checkpoint.
43: Flush primary extent for checkpoint.
44: Write tranlog record for checkpoint.
50: Do synchronous tranlog write.
"
{DeferCkptCompleteCount}
"The number of commits that have happened since completion of the current checkpoint has been deferred."
{TimeWritingStats}
"The elapsed time in milliseconds that the statmonitor spent collecting and writing the statistics."
{UserTimeNT}
"The elapsed time in milliseconds that this process's threads have spent executing code in user mode. Applications, environment subsystems, and integral subsystems execute in user mode. Code executing in User Mode cannot damage the integrity of the Windows NT Executive, Kernel, and device drivers. Unlike some early operating systems, Windows NT uses process boundaries for subsystem protection in addition to the traditional protection of user and privileged modes. These subsystem processes provide additional protection. Therefore, some work done by Windows NT on behalf of your application might appear in other subsystem processes in addition to the privileged time in your process."
{PrivilegedTime}
"The elapsed time in milliseconds that the threads of the process have spent executing code in privileged mode. When a Windows NT system service is called, the service will often run in Privileged Mode to gain access to system-private data. Such data is protected from access by threads executing in user mode. Calls to the system can be explicit or implicit, such as page faults or interrupts. Unlike some early operating systems, Windows NT uses process boundaries for subsystem protection in addition to the traditional protection of user and privileged modes. These subsystem processes provide additional protection. Therefore, some work done by Windows NT on behalf of your application might appear in other subsystem processes in addition to the privileged time in your process."
{ProcessorTime}
"The elapsed time in milliseconds that all of the threads of this process used the processor to execute instructions. An instruction is the basic unit of execution in a computer, a thread is the object that executes instructions, and a process is the object created when a program is run. Code executed to handle some hardware interrupts and trap conditions are included in this count."
{VirtualBytesPeak}
"The maximum number of bytes of virtual address space the process has used at any one time. Use of virtual address space does not necessarily imply corresponding use of either disk or main memory pages. Virtual space is however finite, and by using too much, the process might limit its ability to load libraries."
{VirtualBytes}
"Virtual Bytes is the current size in bytes of the virtual address space the process is using. Use of virtual address space does not necessarily imply corresponding use of either disk or main memory pages. Virtual space is finite, and by using too much, the process can limit its ability to load libraries."
{PageFaults}
"The total number of Page Faults by the threads executing in this process. A page fault occurs when a thread refers to a virtual memory page that is not in its working set in main memory. This will not cause the page to be fetched from disk if it is on the standby list and hence already in main memory, or if it is in use by another process with whom the page is shared."
{WorkingSetPeak}
"The maximum number of bytes in the Working Set of this process at any point in time. The Working Set is the set of memory pages touched recently by the threads in the process. If free memory in the computer is above a threshold, pages are left in the Working Set of a process even if they are not in use. When free memory falls below a threshold, pages are trimmed from Working Sets. If they are needed they will then be soft-faulted back into the Working Set before they leave main memory."
{WorkingSet}
"The current number of bytes in the Working Set of this process. The Working Set is the set of memory pages touched recently by the threads in the process. If free memory in the computer is above a threshold, pages are left in the Working Set of a process even if they are not in use. When free memory falls below a threshold, pages are trimmed from Working Sets. If they are needed they will then be soft-faulted back into the Working Set before they are paged out out to disk."
{PageFileBytesPeak}
"The maximum number of bytes this process has used in the paging file(s). Paging files are used to store pages of memory used by the process that are not contained in other files. Paging files are shared by all processes, and lack of space in paging files can prevent other processes from allocating memory."
{PageFileBytes}
"The current number of bytes this process has used in the paging file(s). Paging files are used to store pages of memory used by the process that are not contained in other files. Paging files are shared by all processes, and lack of space in paging files can prevent other processes from allocating memory. "
{PrivateBytes}
"The current number of bytes this process has allocated that cannot be shared with other processes."
{ThreadCount}
"Number of threads currently active in this process. An instruction is the basic unit of execution in a processor, and a thread is the object that executes instructions. Every running process has at least one thread."
{PriorityBase}
"The current base priority of the process. Threads within a process can raise and lower their own base priority relative to the process's base priority.
A higher priority make it more likely a process's threads will get scheduled to run.
The base priority of a process establishes a range within which the dynamic priorities of its threads vary. The system schedules ready threads for the processor in order of their dynamic priority."
{PoolPagedBytes}
"The number of bytes in the Paged Pool, a system memory area where space is acquired by operating system components as they accomplish their appointed tasks. Paged Pool pages can be paged out to the paging file when not accessed by the system for sustained periods of time."
{PoolNonpagedBytes}
"The number of bytes in the nonpaged pool, a system memory area where space is acquired by operating system components as they accomplish their appointed tasks. Nonpaged pool pages cannot be paged out to the paging file, but instead remain in main memory as long as they are allocated."
{HandleCount}
"The total number of handles currently open by this process. This number is the sum of the handles currently open by each thread in this process."
{EpochGcCount}
"The number of times that the epoch garbage collection process was run by the GcGem since the GcGem was started.  For a system in steady state, look for uniform periods between runs or a uniform run rate."
{EpochNewObjsSize}
"The number of new objects that were created during the last epoch."
{EpochScannedObjs}
"The number of objects scanned by the last epoch garbage collection."
{EpochPossibleDeadSize}
"The number of possible dead objects found by the last epoch garbage collection."
{TotalFileReadOps}
"An aggregate of all the file system read operations on the computer."
{TotalFileWriteOps}
"An aggregate of all the file system write operations on the computer."
{TotalFileControlOps}
"An aggregate of all the file system operations that are neither reads nor writes on the computer. These operations usually include file system control requests or requests for information about device characteristics or status."
{TotalFileDataOps}
"An aggregate of all the file system read and write operations on the computer."
{TotalFileReadKBytes}
"An aggregate of the kilobytes transferred for all the file system read operations on the computer."
{TotalFileWriteKBytes}
"An aggregate of the kilobytes transferred for all the file system write operations on the computer."
{TotalFileControlKBytes}
"An aggregate of the kilobytes transferred for all the file system operations that are neither reads nor writes on the computer. These operations usually include file system control requests or requests for information about device characteristics or status."
{TotalContextSwitches}
"The total number of switches from one thread to another on the computer.  Thread switches can occur either inside of a single process or across processes.  A thread switch may be caused either by one thread asking another for information, or by a thread being preempted by another, higher priority thread becoming ready to run.  Unlike some early operating systems, Windows NT uses process boundaries for subsystem protection in addition to the traditional protection of User and Privileged modes. These subsystem processes provide additional protection. Therefore, some work done by Windows NT on behalf of an application may appear in other subsystem processes in addition to the Privileged Time in the application. Switching to the subsystem process causes one Context Switch in the application thread.  Switching back causes another Context Switch in the subsystem thread."
{TotalSystemCalls}
"The total number of calls to Windows NT system service routines on the computer.  These routines perform all of the basic scheduling and synchronization of activities on the computer, and provide access to non-graphical devices, memory management, and name space management."
{TotalProcessorTime}
"The elapsed time in milliseconds spent doing useful work by all processors.  On a multi-processor system, if all processors are always busy this is 1000/sec, if all processors are 50% busy then this is 500/sec and if 1/4th of the processors are busy this is 250/sec."
{TotalUserTime}
"The elapsed time in milliseconds spent in User mode by all processors.  On a multi-processor system, if all processors are always in User mode this is 1000/sec, if all processors are 50% in User mode this is 500/sec and if 1/4th of the processors are in User mode this is 250/sec.  Applications execute in User Mode, as do subsystems like the window manager and the graphics engine. Code executing in User Mode cannot damage the integrity of the Windows NT Executive, Kernel, and device drivers. Unlike some early operating systems, Windows NT uses process boundaries for subsystem protection in addition to the traditional protection of User and Privileged modes.  These subsystem processes provide additional protection.  Therefore, some work done by Windows NT on behalf of an application may appear in other subsystem processes in addition to the Privileged Time in the application process."
{TotalPrivilegedTime}
"The elapsed time in milliseconds spent in Privileged mode by all processors.  On a multi-processor system, if all processors are always in Privileged mode this is 1000/sec, and if 1/4th of the processors are in Privileged mode this is 250/sec.  When a Windows NT system service is called, the service will often run in Privileged Mode in order to gain access to system-private data.  Such data is protected from access by threads executing in User Mode.  Calls to the system may be explicit, or they may be implicit such as when a page fault or an interrupt occurs.  Unlike some early operating systems, Windows NT uses process boundaries for subsystem protection in addition to the traditional protection of User and Privileged modes. These subsystem processes provide additional protection. Therefore, some work done by Windows NT on behalf of an application may appear in other subsystem processes in addition to the Privileged Time in the application process."
{TotalInterrupts}
"The total number of harware interrupts on the computer. Some devices that may generate interrupts are the system timer, the mouse, data communication lines, network interface cards and other peripheral devices.  This counter provides an indication of how busy these devices are on a computer-wide basis."
{ProcessorQueueLength}
"The instantaneous length of the processor queue in units of threads. All processors use a single queue in which threads wait for processor cycles.  This length does not include the threads that are currently executing.  A sustained processor queue length greater than two generally indicates processor congestion.  This is an instantaneous count, not an average over the time interval.
Unlike disk queue counters, it counts only waiting threads, not those being serviced.
This counter is on the System object because there is a single queue even when there are multiple processors on the computer."
{AlignmentFixups}
"The total number of alignment faults fixed by the system."
{ExceptionDispatches}
"The total number of exceptions dispatched by the system."
{FloatingEmulations}
"The total number of floating point arithmetic emulations performed by the system."
{TotalDPCTime}
"The sum of DPC Time in milliseconds of all processors divided by the number of processors in the system."
{TotalInterruptTime}
"The sum of Interrupt Time in milliseconds of all processors divided by the number of processors in the system."
{TotalDPCsQueued}
"The total number of DPC objects being queued to all processors DPC queues."
{TotalDPCRate}
"The average rate DPC objects are queued to all processors DPC queue per clock tick."
{TotalDPCBypasses}
"The total number of times Dispatch interrupts were short-circuited across all processors."
{TotalAPCBypasses}
"The total number of times kernel APC interrupts were short-circuited across all processors."
{RegistryQuotaInUse}
"The percentage of the Total Registry Quota Allowed currently in use by the system."
{AvailableBytes}
"The size of the virtual memory currently on the Zeroed, Free, and Standby lists.  Zeroed and Free memory is ready for use, with Zeroed memory cleared to zeros.  Standby memory is memory removed from a process's Working Set but still available.  Notice that this is an instantaneous count, not an average over the time interval."
{CommittedBytes}
"The size of virtual memory (in bytes) that has been Committed (as opposed to simply reserved).  Committed memory must have backing (i.e., disk) storage available, or must be assured never to need disk storage (because main memory is large enough to hold it.)  Notice that this is an instantaneous count, not an average over the time interval."

{CommitLimit}
"The size (in bytes) of virtual memory that can be committed without having to extend the paging file(s).  If the paging file(s) can be extended, this is a soft limit."

{TotalPageFaults}
"A count of the total number of Page Faults in the system.  A page fault occurs when a process refers to a virtual memory page that is not in its Working Set in main memory.  A Page Fault will not cause the page to be fetched from disk if that page is on the standby list, and hence already in main memory, or if it is in use by another process with whom the page is shared.
If requested code or data is repeatedly not found, theprocess's working set is probably too small because memory is limited."
{WriteCopies}
"The total number of page faults that have been satisfied by making a copy of a page when an attempt to write to that page is made."
{TransitionFaults}
"The total number of page faults resolved by recovering pages that were in transition, i.e., being written to disk at the time of the page fault.  The pages were recovered without additional disk activity."
{CacheFaults}
"Incremented whenever the Cache manager does not find a file's page in the immediate Cache and must ask the memory manager to locate the page elsewhere in memory or on the disk so that it can be loaded into the immediate Cache."
{DemandZeroFaults}
"The total number of page faults for pages that must be filled with zeros before the fault is satisfied.  If the Zeroed list is not empty, the fault can be resolved by removing a page from the Zeroed list."
{Pages}
"The total number of pages read from the disk or written to the disk to resolve memory references to pages that were not in memory at the time of the reference. This is the sum of \[PagesInput > PagesInput Statistic] and the \[PagesOutput > PagesOutput Statistic]. This counter includes paging traffic on behalf of the system Cache to access file data for applications.  This value also includes the pages to/from non-cached mapped memory files.  This is the primary counter to observe if you are concerned about excessive memory pressure (that is, thrashing), and the excessive paging that may result."
{PagesInput}
"The total number of pages read from the disk to resolve memory references to pages that were not in memory at the time of the reference.  This counter includes paging traffic on behalf of the system Cache to access file data for applications.  This is an important counter to observe if you are concerned about excessive memory pressure (that is, thrashing), and the excessive paging that may result.
Compare with \[PageFaults > PageFaults Statistic] to see how many faults are satisfied by readingfrom disk, and how many come from somewhere else."
{NtPageReads}
"The total number of times the disk was read to retrieve pages of virtual memory necessary to resolve page faults.  Multiple pages can be read during a disk read operation.
This is the primary indicator of a memory shortage. Some pagereads are expected, but a sustained rate of 5 pages persecond or more indicates a memory shortage."
{PagesOutput}
"A count of the total number of pages that are written to disk because the pages have been modified in main memory.
A high rate indicates that most faulting is data pages and that memory is becoming scarce. If memory is available, changed pages are retained in a list in memory and written to disk in batches."
{NtPageWrites}
"A count of the total number of times pages have been written to the disk because they were changed since last retrieved.  Each such write operation may transfer a number of pages.
This counter is another good indicator of the effect of paging on the disk."
{TotalPoolPagedBytes}
"The number of bytes in the Paged Pool, a system memory area where space is acquired by operating system components as they accomplish their appointed tasks.  Paged Pool pages can be paged out to the paging file when not accessed by the system for sustained periods of time."
{TotalPoolNonpagedBytes}
"The number of bytes in the Nonpaged Pool, a system memory area where space is acquired by operating system components as they accomplish their appointed tasks.  Nonpaged Pool pages cannot be paged out to the paging file, but instead remain in main memory as long as they are allocated."
{PoolPagedAllocs}
"The total number of calls to allocate space in the system Paged Pool.  Paged Pool is a system memory area where space is acquired by operating system components as they accomplish their appointed tasks. Paged Pool pages can be paged out to the paging file when not accessed by the system for sustained periods of time."
{PoolNonpagedAllocs}
"The total number of calls to allocate space in the system Nonpaged Pool.  Nonpaged Pool is a system memory area where space is acquired by operating system components as they accomplish their appointed tasks.  Nonpaged Pool pages cannot be paged out to the paging file, but instead remain in main memory as long as they are allocated."
{FreeSystemPageTableEntries}
"The number of Page Table Entries not currently in use by the system."
{CacheBytes}
"Measures the number of bytes currently in use by the system Cache.  The system Cache is used to buffer data retrieved from disk or LAN.  The system Cache uses memory not in use by active processes in the computer."
{CacheBytesPeak}
"Measures the maximum number of bytes used by the system Cache.  The system Cache is used to buffer data retrieved from disk or LAN.  The system Cache uses memory not in use by active processes in the computer."
{PoolPagedResidentBytes}
"The size of paged Pool resident in core memory.  This is the actual cost of the paged Pool allocation, since this is actively in use and using real physical memory."
{SystemCodeTotalBytes}
"The number of bytes of pagable pages in ntoskrnl.exe, hal.dll, and the boot drivers and file systems loaded by ntldr/osloader."
{SystemCodeResidentBytes}
"The number of bytes of \[SystemCodeTotalBytes > SystemCodeTotalBytes Statistic] currently resident in core memory. This is the code working set of the pagable executive. In addition to this, there is another ~300k bytes of non-paged kernel code."
{SystemDriverTotalBytes}
"The number of bytes of pagable pages in all other loaded device drivers."
{SystemDriverResidentBytes}
"The number of bytes of \[SystemDriverTotalBytes > SystemDriverTotalBytes Statistic] currently resident in core memory.  This number is the code working set of the pagable drivers.  In addition to this, there is another ~700k bytes of non-paged driver code."
{SystemCacheResidentBytes}
"The number of bytes currently resident in the global disk cache."
{CommittedBytesInUse}
"The ratio of the \[CommittedBytes > CommittedBytes Statistic] to the \[CommitLimit > CommitLimit Statistic]. This represents the percentage of available virtual memory in use. Note that the \[CommitLimit > CommitLimit Statistic] may change if the paging file is extended. This is an instantaneous value, not an average."
{Processes}
"The number of processes in the computer at the time of data collection.  Notice that this is an instantaneous count, not an average over the time interval.  Each process represents the running of a program."
{Threads}
"The number of threads in the computer at the time of data collection.  Notice that this is an instantaneous count, not an average over the time interval.  A thread is the basic executable entity that can execute instructions in a processor."
{Events}
"The number of events in the computer at the time of data collection.  Notice that this is an instantaneous count, not an average over the time interval.  An event is used when two or more threads wish to synchronize execution."
{Semaphores}
"The number of semaphores in the computer at the time of data collection.  Notice that this is an instantaneous count, not an average over the time interval.  Threads use semaphores to obtain exclusive access to data structures that they share with other threads."
{Mutexes}
"The number of mutexes in the computer at the time of data collection.  This is an instantaneous count, not an average over the time interval.  Mutexes are used by threads to assure only one thread is executing some section of code."
{Sections}
"The number of sections in the computer at the time of data collection.  Notice that this is an instantaneous count, not an average over the time interval. A section is a portion of virtual memory created by a process for storing data.  A process may share sections with other processes."
{Usage}
"The amount of the Page File instance in use in percent.
See also \[PageFileBytes > PageFileBytes Statistic]."
{UsagePeak}
"The peak usage of the Page File instance in percent.
See also \[PageFileBytesPeak > PageFileBytesPeak Statistic]."
{FreeSpace}
"The percentage of the free space available on the logical disk unit to the total usable space provided by the selected logical disk drive."
{FreeMegabytes}
"The unallocated space on the logical disk in megabytes. One megabyte = 1,048,576 bytes."
{CurrentDiskQueueLength}
"The number of requests outstanding on the disk at the time the performance data is collected. It includes requests in service at the time of the snapshot. This is an instantaneous length, not an average over the time interval.  Multi-spindle disk devices can have multiple requests active at one time, but other concurrent requests are awaiting service.  This counter may reflect a transitory high or low queue length, but if there is a sustained load on the disk drive, it is likely that this will be consistently high.  Requests are experiencing delays proportional to the length of this queue minus the number of spindles on the disks.  This difference should average less than 2 for good performance.
If more than two requests are waiting over time, the disk may be a bottleneck.
Unlike the other queue measures, this one measures requests, not time. It includes the request being serviced as well as those waiting and is an instantaneous value, not an average.
If this counter is always 0 then 'diskperf -y' needs to be run."
{DiskTime}
"The total number of milliseconds that the selected disk drive has been busy servicing read or write requests.
If it is busy almost all of the time, and there is a large queue, the disk might be a bottleneck.
If this counter is always 0 then 'diskperf -y' needs to be run."
{DiskReadTime}
"The total number of milliseconds that the selected disk drive has been busy servicing read requests.
If this counter is always 0 then 'diskperf -y' needs to be run."
{DiskWriteTime}
"The total number of milliseconds that the selected disk drive has been busy servicing write requests.
If this counter is always 0 then 'diskperf -y' needs to be run."
{DiskTransfers}
"The total number of read and write operations on the disk.
When filtered persecond tells how fast data requests are being serviced.
If this counter is always 0 then 'diskperf -y' needs to be run."
{DiskReads}
"The total number of read operations on the disk.
If this counter is always 0 then 'diskperf -y' needs to be run."
{DiskWrites}
"The total number of write operations on the disk.
If this counter is always 0 then 'diskperf -y' needs to be run."
{DiskKbytes}
"The total kilobytes that have been transferred to or from the disk during write or read operations.
When filtered persecond tells how fast is data being moved in kilobytes.
This is the primary measure of disk throughput.
If this counter is always 0 then 'diskperf -y' needs to be run."
{DiskReadKbytes}
"The total kilobytes that have been transferred from the disk during read operations.
If this counter is always 0 then 'diskperf -y' needs to be run."
{DiskWriteKbytes}
"The total kilobytes that have been transferred to the disk during write operations.
If this counter is always 0 then 'diskperf -y' needs to be run."
{BytesTotal}
"The number of bytes sent and received on the network interface, including framing characters."
{Packets}
"The number of packets sent and received on the network interface."
{PacketsReceived}
"The number of packets received on the network interface."
{PacketsSent}
"The number of packets sent on the network interface."
{CurrentBandwidth}
"An estimate of the network interface's current bandwidth in bits per second (bps). For interfaces that do not vary in bandwidth or for those where no accurate estimation can be made, this value is the nominal bandwidth."
{BytesReceived}
"The number of bytes received on the network interface, including framing characters."
{PacketsReceivedUnicast}
"The number of (subnet) unicast packets delivered to a higher-layer protocol."
{PacketsReceivedNonUnicast}
"The number of  non-unicast (i.e., subnet broadcast or subnet multicast) packets delivered to a higher-layer protocol."
{PacketsReceivedDiscarded}
"The number of inbound packets that were chosen to be discarded even though no errors had been detected to prevent their being deliverable to a higher-layer protocol. One possible reason for discarding such a packet could be to free up buffer space."
{PacketsReceivedErrors}
"The number of inbound packets that contained errors preventing them from being deliverable to a higher-layer protocol."
{PacketsReceivedUnknown}
"The number of packets received via the interface that were discarded because of an unknown or unsupported protocol."
{BytesSent}
"The number of bytes sent on the network interface, including framing characters."
{PacketsSentUnicast}
"The number of packets requested to be transmitted to subnet-unicast addresses by higher-level protocols.  The includes the packets that were discarded or not sent."
{PacketsSentNonUnicast}
"The number of packets requested to be transmitted to non-unicast (i.e., subnet broadcast or subnet multicast) addresses by higher-level protocols.  This includes the packets that were discarded or not sent."
{PacketsOutboundDiscarded}
"The number of outbound packets that were chosen to be discarded even though no errors had been detected to prevent their being transmitted. One possible reason for discarding such a packet could be to free up buffer space."
{PacketsOutboundErrors}
"The number of outbound packets that could not be transmitted because of errors."
{OutputQueueLength}
"The length of the output packet queue (in packets.)  If this is longer than 2, delays are being experienced and the bottleneck should be found and eliminated if possible.  Since the requests are queued by NDIS in this implementations, this will always be 0."
{Segments}
"The total number of TCP segments that have been  sent or received using the TCP protocol."
{ConnectionsEstablished}
"Current number of established TCP socket connections on the machine.
At the lowest leve this means that a socket's current state is either ESTABLISHED or CLOSE-WAIT."
{ConnectionsActive}
"The total number of times a client socket has explicitly connected to a listening server socket.
At the lowest level this means that a socket has made a direct transition to the SYN-SENT state from the CLOSED state."
{ConnectionsPassive}
"The total number of times a listening server socket has accepted a connection from a client.
At the lowest level this means that a socket has made a direct transition to the SYN-RCVD state from the LISTEN state."
{ConnectionFailures}
"The total number of times TCP connections failed to be established.
At the lowest level this means that they have made a direct transition to the CLOSED state from the SYN-SENT state or the SYN-RCVD state, or a direct transition to the LISTEN state from the SYN-RCVD state."
{ConnectionsReset}
"The total number of times established TCP connections have been closed.
At the lowest level this means a direct transition to the CLOSED state from either the ESTABLISHED state or the CLOSE-WAIT state."
{SegmentsReceived}
"The total number of TCP segments that have been received, including those received in error.  This count includes segments received on currently established connections."
{SegmentsSent}
"The total number of TCP segments that are sent, including those on current connections, but excluding those containing only retransmitted bytes."
{SegmentsRetransmitted}
"The total number of retransmitted TCP segments,  that is, segments transmitted containing one or more previously transmitted bytes.
If this value is more than 30% of \[SegmentsSent > SegmentsSent Statistic] you may have some bad network hardware, a congested route that is dropping packets, or and operating system that needs a patch."
{ThreadProcessorTime}
"The elapsed time in milliseconds that this thread used the processor to execute instructions. An instruction is the basic unit of execution in a processor, and a thread is the object that executes instructions. Code executed to handle certain hardware interrupts or trap conditions may be counted for this thread."
{ThreadUserTimeNT}
"The elapsed time in milliseconds that this thread has spent executing code in User Mode.  Applications execute in User Mode, as do subsystems like the window manager and the graphics engine.  Code executing in User Mode cannot damage the integrity of the Windows NT Executive, Kernel, and device drivers.  Unlike some early operating systems, Windows NT uses process boundaries for subsystem protection in addition to the traditional protection of User and Privileged modes.  These subsystem processes provide additional protection.  Therefore, some work done by Windows NT on behalf of your application may appear in other subsystem processes in addition to the Privileged Time in your process."
{ThreadPrivilegedTime}
"The elapsed time in milliseconds that this thread has spent executing code in Privileged Mode. When a Windows NT system service is called, the service will often run in Privileged Mode in order to gain access to system-private data.  Such data is protected from access by threads executing in User Mode.  Calls to the system may be explicit, or they may be implicit such as when a page fault or an interrupt occurs.  Unlike some early operating systems, Windows NT uses process boundaries for subsystem protection in addition to the traditional protection of User and Privileged modes. These subsystem processes provide additional protection. Therefore, some work done by Windows NT on behalf of your application may appear in other subsystem processes in addition to the Privileged Time in your process."
{ContextSwitches}
"The number of times this thread has lost the cpu to another thread.  Thread switches can occur either inside of a single process or across processes.  A thread switch may be caused either by one thread asking another for information, or by a thread being preempted by another, higher priority thread becoming ready to run.  Unlike some early operating systems, Windows NT uses process boundaries for subsystem protection in addition to the traditional protection of User and Privileged modes. These subsystem processes provide additional protection. Therefore, some work done by Windows NT on behalf of an application may appear in other subsystem processes in addition to the Privileged Time in the application. Switching to the subsystem process causes one Context Switch in the application thread.  Switching back causes another Context Switch in the subsystem thread."
{PriorityCurrent}
"The current dynamic priority of this thread.  The system may raise the thread's dynamic priority above the base priority if the thread is handling user input, or lower it towards the base priority if the thread becomes compute bound.
The microkernel schedules thread for the processor in order of their priority. The system adjusts the dynamic priority of threads within the range of the base priority of the process to optimize the response of processes interacting with the user."
{ThreadPriorityBase}
"The current base priority of this thread.  The system may raise the thread's dynamic priority above the base priority if the thread is handling user input, or lower it towards the base priority if the thread becomes compute bound.
The base priority of a thread is determined by the base priority of the process in which it runs. Except for Idle and Real-time threads, the base priority of a thread varies only +/-2 from the base priority of its process."
{StartAddress}
"Starting virtual address for this thread."
{ThreadState}
"An instantaneous indicator of the dispatcher thread state, which represents the current status of a thread with regard to the processor:
0 Initialized.  The thread is recognized as an object by the microkernel.
1 Ready.  The thread is in the processor queue and is prepared to run on the next free processor as soon as the processor is available.
2 Running.  The thread is executing on a processor.
3 Standby.  The thread is assigned to a processor and is about to run. Only one thread can be in the Standby state at a time, regardless of the number of processors.
4 Terminated.  The thread is finished executing.
5 Waiting.  The thread is not ready for the processor because it is waiting for a peripheral operation to complete or a resource to become free. When it is ready, it will have to be rescheduled.
6 Transition.  The thread is ready but waiting for resources other than the processor to become available, such as waiting for its execution stack to be paged in from disk.
7 Unknown.  The thread state is unknown."
{ThreadWaitReason}
"Only applicable when the thread is in the Wait state (see Thread State.)  It is:
0 or 7 when the thread is waiting for the Executive,
1 or 8 for a Free Page,
2 or 9 for a Page In,
3 or 10 for a Pool Allocation,
4 or 11 for an Execution Delay,
5 or 12 for a Suspended condition,
6 or 13 for a User Request,
14 for an Event Pair High,
15 for an Event Pair Low,
16 for an LPC Receive,
17 for an LPC Reply,
18 for Virtual Memory,
19 for a Page Out,
20 and higher are not assigned at the time of this writing.
Event Pairs are used to communicate with protected subsystems (see \[ContextSwitches > ContextSwitches Statistic])."
{Sessions}
"The number of sessions that a Virtual Machine has logged into a stone."
{Classes}
"The number of classes loaded by the Virtual Machine since it started. Not maintained by HotSpot VM.
Obsolete since GSJ 4.0."
{ClassesFreed}
"The number of classes that have been freed by the Virtual Machine. Not maintained by HotSpot VM.
Obsolete since GSJ 4.0."
{ClassesReadFromRepository}
"The number of classes that the Virtual Machine has read from the repository since the Vm was started." 
{JHandleMemSize}
"The amount of memory that the Classic Virtual Machine has allocated for JHandles (subset of \[ObjMemSize > ObjMemSize Statistic]).
Always zero in Hotspot Java VM.
Obsolete since GSJ 4.0."
{FreeJHandleMemSize}
"The amount of Classic VM handle memory that is currently not being used to store any handles.
Always zero in Hotspot Java VM.
Obsolete since GSJ 4.0."
{InUseJHandleMemSize}
"The amount of Classic VM handle memory that is currently being used to store handles.
Always zero in Hotspot Java VM.
Obsolete since GSJ 4.0."
{ObjMemSize}
"The amount of memory that the Virtual Machine has allocated for object memory. Hotspot updates this stat only at each fullGc . "
{FreeObjMemSize}
"The amount of vm object memory that is currently not being used to store any objects.
The Hotspot Java VM updates this stat only at each fullGc."
{InUseObjMemSize}
"The amount of vm object memory that is currently being used to store objects. Hotspot updates this stat only at each fullGc. "
{ObjCount}
"The total number of objects allocated in the Classic VM Java Object Memory since the Virtual Machine was started.
Always zero in Hotspot Java VM.
Obsolete since GSJ4.0."
{NeedFinalizationCount}
"The number of objects allocated since the Virtual Machine was started that need to have finalization performed on them."
{FinalizedCount}
"The number of objects that the Virtual Machine has finalized since it was started."
{GcObjCount}
"The number of objects that were garbage collected since the Classic Virtual Machine was started.
Always zero in Hotspot Java VM.
Obsolete since GSJ 4.0."
{GcCount}
"The total number of times that the Hotspot incremental garbage collector was run since the VM was started."
{GcTime}
"The total amount of time in milliseconds spent in Hotspot incremental garbage collection operations since the VM was started."
{FullGcCount}
"The number of times that the HotSpot markSweep garbage collector was run since the Virtual Machine was started."
{FullGcTime}
"The amount of time in milliseconds spent in the HotSpot markSweep garbage collector since the Virtual Machine was started."
{MethodsCompiled}
"The number of methods that have been compiled or recompiled by the HotSpot virtual machine."
{PomObjsCount}
"The number of objects in the HotSpot Virtual Machine's object memory that are copies of permanent objects."
{DirtyObjsSize}
"The number of objects in the workingSet which are dirty."
{FlushCount}
"The number of times that dirty POM objects have been flushed from Java Object Memory into Pom."
{FlushedObjsCount}
"The total number of Objects that have been flushed from Java Object Memory into Pom."
{PomMapCollisions}
"The number of collisions in the Pom to JHandle Map."
{PomMapEntries}
"The number of objects that are currently in the Pom to JHandle Map."
{CanonPomMapCollisions}
"The number of collisions in the Canonical Pom to JHandle Map."
{CanonPomMapEntries}
"The number of canonical objects that are currently in the Canonical Pom to JHandle Map."
{ClassMapEntries}
"The number of class objects that are currently in the Class Map."
{DeadNotReclaimed}
"The number of objects found in one Classic VM garbage collection that were not able to be added to the deadHandlesList because all of the buffers in the pool were full.  Reset to zero every time the java garbage collector is run.
Always zero in Hotspot Java VM.
Obsolete since GSJ 4.0."
{DeadHandlesBufPoolSize}
"The number of empty buffers in the Classic VM deadHandlesBufPool.
Always zero in Hotspot Java VM.
Obsolete since GSJ 4.0."
{DeadPomHandleCount}
"The number of Classic VM JHandles for Pom objects that were added to the deadHandles buffers.
Always zero in Hotspot Java VM.
Obsolete since GSJ 4.0."
{VmUserThreads}
"The number of user threads in this virtual machine.
This stat is only updated when the vm's gargage collector runs."
{PreparedCommits}
"The number of sessions that are in the two phase commit prepared state and waiting for a final commit."
{PomObjMapSize}
"The size of the Pom Object Map.  The PomObjMap is used to convert a Pom objectId (oop) to a JHandle.  Each entry is 4 bytes in size."
{PomClassMapSize}
"The size of the Pom Class Map."
{PrivatePageCacheSize}
"The size of the private page cache in kilobytes."
{WorkOopMapSize}
"The number of entries in the OopMap used to translate Pom oops to memory addresses.
Obsolete after GSJ 4.1."
{HighWaterOop}
"The largest oop given to a session."
{RGCEpochNewObjsSize}
"The number of new objects that were created in the last epoch repository garbage collection."
{RGCEpochScannedObjs}
"The number of objects scanned by the last epoch repository garbage collection."
{RGCEpochPossibleDeadSize}
"The number of possible dead objects found by the last epoch repository garbage collection."
{RGCEpochThreadsActive}
"The current number of threads that are being used by the repository garbage collector to do epochGc."
{RGCEpochThreadsLimit}
"The maximum number of threads that can be used by the repository garbage 
collector to do reclaims. Defaults to 2 times the number of cpu's on the system."
{RGCMaintThreadsActive}
"The current number of threads that are being used by a repository maintenance 
operation (listInstances, listReferences, etc)."
{RGCMaintThreadsLimit}
"The maximum number of threads that can be used by a repository maintence
operation. Defaults to 2 times the number of cpu's on the system."
{RGCMfcThreadsActive}
"The current number of threads that are being used by a markForCollection
operation"
{RGCMfcThreadsLimit}
"The maximum number of threads that can be used by a markForCollection
operation. Defaults to 2 times the number of cpu's on the system."
{VoteNotDead}
"Java: The number of possible dead objects the session found in its working set.

Smalltalk: The number of objects that the gem process removed from the possibleDead set the last time that it voted on the possibleDead."
{VoteNotDeadSize}
"The number of objects that the gem process removed from the possibleDead set the last time that it voted on the possibleDead.
For the Admin GC session, the number of objects removed from the possible dead set by the write set union sweep."

{ObjsReadWithTransientFields}
"The total number of objects read by this session from Permanent Object Memory (POM) into the Java Object Memory (JOM) that had transient fields.  If this value is large it may be an indicator of poor working set and performance may be improved if the application can be redesigned to use fewer objects with transient fields."
{NativeThreadId}
"The last native thread used to access this session."
{SessionCount}
"The number of sessions currently logged into stone."
{VmCount}
"The number of Java Virtual Machines currently connected to stone."
{VoteSeqNumber}
"The request for voting on possible dead sequence number.It is basically an indicator of how many votes the virtual machine has participated in."
{AllocatedPages}
"The number of temporary pages allocated to the vm, maintained by stone.  Only implemented in slows for VMs on stone's machine to help detect page leaks."
{PomScavCount}
"The number of scavenges of the PomGeneration performed by the vm."
{Spare}
"An unused stat for the vm."
{ExtentCount}
"The number of extents the stone has online."
{TranLogObjectLimit}
"The minimum number of new or modified objects a transaction must contain to cause it to be promoted to a checkpoint when stone's startup config tranFullLogging is false."
{ConcurrencyMode}
"Controls what checking is done when a transaction is committed. It is 0 if both read/write and write/write conflicts will be detected. It is 1 if only write/write checks are detected."
{CheckpointInterval}
"The maximum number of seconds between checkpoints. Checkpoints may be written more often."
{HaltOnFatalError}
"1 if the stone will halt if a session died with a fatal internal error. It is 0 if the stone attempt to keep running if a session has a fatal error."
{SessionTimeout}
"The number of minutes that the stone will wait for an idle session to have some kind of interaction with stone. A session which has not had any interaction with stone for this amount of time will be terminated by the Stone. If non-zero this timeout is also the maximum time allowed for a session to complete processing of its login to stone.If this timeout is 0, session do not timeout and the maximum time for session to stone login processing is set to 5 minutes.
Obsolete after Facets 1.1."
{TransactionTimeout}
"The number of minutes that the stone will wait for a session to commit or abort.  Any session that does not commit in this time interval has the transaction disabled and a ForcedAbort is executed.  Application objects should be aborted to prevent inconsistent views."
{SessionAbortTimeout}
"The number of seconds that the stone will wait for a session running outside of a transaction to abort after stone has signaled the session that it should abort. If the time expires before the session aborts, it is forcibly aborted by stone. Forcible abort means that the session will receive the forcedAbort error, and will have to completely reinitialize its object caches."
{SignalAbortCrBacklog}
"The number of old transactions, above which the stone will start to signal a session that is running outside of a transaction to abort. This option should not exceed the value of maxSessions."
{MaxAioRate}
"The maximum number of dirty page writes per second a pgsvr thread will do."
{TargetPercentDirty}
"The percent of dirty pages that AIO page servers try to maintain in the shared cache. If the dirty pages are below this target then the io rate will be limited on the next scan. If the dirty pages are above this target then the io rate will be set to AioRateMax."
{FreeSpaceThreshold}
"The minimum number of free megabytes to be available in the repository. A value of zero indicates no threshold. If stone cannot maintain this level by growing an extent, it begins to take the following actions to prevent shutdown of the system:
Divides \[SignalAbortCrBacklog > SignalAbortCrBacklog Statistic] in half. If free space remains below this level for more than diskFullTerminationInterval minutes then it sets \[SignalAbortCrBacklog > SignalAbortCrBacklog Statistic] to two.Once enough space becomes free the \[SignalAbortCrBacklog > SignalAbortCrBacklog Statistic] is set back to its original value.
Becomes more aggressive about disposing commit records.
Writes message to the stone log.
Send each virtual machine a signal to give up all except five unused pages.
Writes a checkpoint if there isn't one in progress.Does this every three minutes that free space remains below this threshold."
{DiskFullTerminationInterval}
"The number of minutes the stone will wait after the \[FreeSpaceThreshold > FreeSpaceThreshold Statistic] is hit before setting \[SignalAbortCrBacklog > SignalAbortCrBacklog Statistic] to two."
{MaxSessions}
"The maximum number of sessions that can be logged in at the same time to the stone. This includes system sessions such as the garbage collector. This value might be limited by the site's GemStone license."
{OldestTranLogIdForRecovery}
"The sequence number of the oldest transaction log needed to recover if the system failed now. Will be -1 if a transaction log is not be needed."
{CurrentTranLogDirId}
"The identity of the directory used by the current transaction log file. The directory identity is an offset that can be used as an index into the array that is the value of the tranLogDirs property on the stone's startup configuration."
{CurrentTranLogId}
"The sequence number of the current transaction log."
{CurrentTranLogMaxSize}
"The maximum number of transaction log records that the current transaction log can contain. The size of a log record is 512 bytes."
{CurrentTranLogSize}
"The number of transaction log records that have been written to the current transaction log. The size of a log record is 512 bytes."
{ExtentSize}
"The size of an extent's file in kilobytes."
{ExtentFreeSpace}
"The amount of free space in an extent in kilobytes."
{ExtentWeight}
"The number of pages that will be allocated from an extent before allocation moves to the next extent. If the value is zero then the stone is sequentially allocating pages."
{ExtentReadOperations}
"The number of read operations performed on the extent since the stone started."  
{ExtentReadKBytes}
"The number of kilobytes read from the extent since the stone started."
{ExtentWriteOperations}
"The number of write operations performed on the extent since the stone started."  
{ExtentWriteKBytes}
"The number of kilobytes written to the extent since the stone started."
{TotalPagesAllocated}
"The total number of pages allocated since the stone started."
{ExtentPagesAllocated}
"The total number of pages allocated from an extent since the stone started."
{TotalLocksGranted}
"The total number of object lock requests that succeeded since the stone started."
{TotalLocksDenied}
"The total number of object lock requests that failed since the stone started."
{CuQueueSize}
"Shows the number of sessions in the cuQueue waiting for cuLock  serialization. The first one is either committing or in the CommitQueue."
{WaitingForSessionToVote}
"Shows the sessionId of a session which the system is waiting for to complete the voting on possible dead objects.A zero value indicates that it is not waiting."
{CPUs}
"The number of online cpus on the local machine."
{LoadAverage1}
"The average number of threads ready to run over the last minute."
{LoadAverage5}
"The average number of threads ready to run over the last five minutes."
{LoadAverage15}
"The average number of threads ready to run over the last fifteen minutes."
{PhysicalMemory}
"The amount of physical memory on the machine in megabytes."
{SchedulerRunCount}
"The total number of times the system scheduler has put a thread in its run queue."
{SchedulerSwapCount}
"The total number of times the system scheduler has swapped out an idle process."
{SchedulerWaitCount}
"The total number of times the system scheduler has removed a thread from the run queue because it was waiting for a resource."
{FreeMemory}
"The number of megabytes of memory in the free list."
{ReservedSwap}
"The number of megabytes of swap space reserved for allocation by a particular process."
{AllocatedSwap}
"The number of megabytes of swap space have actually been written to. Swap space must be reserved before it can be allocated."
{UnreservedSwap}
"The number of megabytes of swap space that are free. If this value goes to zero new processes can no longer be created."
{UnallocatedSwap}
"The number of megabytes of swap space that have not been allocated."
{PercentCpuActive}
"The percentage of the total available time that has been used to execute user or system code."
{PercentCpuWaiting}
"The percentage of the total available time that has been spent waiting for io, paging, or swapping."
{PercentCpuIdle}
"The percentage of the total available time that has been spent sleeping."
{PercentCpuUser}
"The percentage of the total available time that has been used to execute user code."
{PercentCpuSystem}
"The percentage of the total available time that has been used to execute system (i.e. kernel) code."
{PercentCpuIOWait}
"The percentage of the total available time that has been spent waiting for disk io to complete."
{PercentCpuSwapWait}
"The percentage of the total available time that has been spent waiting for paging and swapping to complete."
{PhysicalBlockReads}
"The total number of physical block I/O read operations."
{PhysicalBlockWrites}
"The total number of physical block I/O write operations, both synchronous and asynchronous."
{LogicalBlockReads}
"The total number of logical block I/O read operations."
{LogicalBlockWrites}
"The total number of logical block I/O write operations."
{RawIOReads}
"The total number of raw I/O read operations."
{RawIOWrites}
"The total number of raw I/O read operations."
{TotalCSW}
"The total number of context switches from one thread to another on the computer.  Thread switches can occur either inside of a single process or across processes.  A thread switch may be caused either by one thread asking another for information, or by a thread being preempted by another, higher priority thread becoming ready to run."
{Traps}
"The total number of traps that have occurred on the computer."
{Interrupts}
"The total number of interrupts that have occurred on the computer."
{SystemReads}
"The total number of read() and readv() system calls."
{SystemWrites}
"The total number of write() and writev() system calls."
{SystemForks}
"The total number of fork() system calls."
{SystemVForks}
"The total number of vfork() system calls."
{SystemExecs}
"The total number of exec() system calls."
{SystemSelects}
"The total number of select() system calls."
{SystemFsReads}
"The total number of file system reads."
{SystemFsWrites}
"The total number of file system writes."
{SystemNfsReads}
"The total number of network file system (NFS) reads."
{SystemNfsWrites}
"The total number of network file system (NFS) writes."
{SystemNfsBytesRead}
"The total number of bytes read in network file system (NFS) reads."
{SystemNfsBytesWriten}
"The total number of bytes written in network file system (NFS) writes."
{MessageCount}
"The total number of msgrcv() and msgsnd() system calls."
{SemaphoreOps}
"The total number of semaphore operations."
{PathnameLookups}
"The total number of pathname lookups."
{InterruptsAsThreads}
"The total number of interrupts as threads. This does not include clock interrupts."
{InterruptsBlocked}
"The total number of interrupts blocked/preempted/released."
{IdleThread}
"The total number of times the idle thread has been scheduled to run."
{TotalIVolCSW}
"The total number of times a thread was forced to give up the cpu even though it was still ready to run."
{ThreadCreates}
"The total number of times a thread has been created."
{ThreadMigrates}
"The total number of times a thread (lwp) has migrated from one CPU to another."
{CrossCalls}
"The total number of inter-cpu cross-calls."
{FailedMutexEnters}
"The total number of times a thread entering a mutex had to wait for the mutex to be unlocked."
{FailedReaderLocks}
"The total number of times readers failed to obtain a readers/writer locks on their first try. When this happens the reader has to wait for the current writer to release the lock."
{FailedWriterLocks}
"The total number of times writers failed to obtain a readers/writer locks on their first try. When this happens the writer has to wait for all the current readers or the single writer to release the lock."
{PhysicalAsyncBlockWrites}
"The total number of physical asynchronous block I/O write operations."
{ProcsInIOWait}
"The number of processes waiting for block I/O at this instant in time."
{PageReclaims}
"The total number of page reclaims; both from the free list and from disk.
Page reclaims are caused by a reference to a page that has been stolen from a process by the page daemon."
{PageFreeReclaims}
"The total number of page reclaims done from the free list. These reclaims are much cheaper than those that need to go to disk."
{PageIns}
"The total number of times pages have been brought into memory from disk by the operating system's memory manager."
{PagesPagedIn}
"The total number of pages that have been brought into memory from disk by the operating system's memory manager."
{PageOuts}
"The total number of times pages have been flushed from memory to disk by the operating system's memory manager."
{PagesPagedOut}
"The total number of pages that have been flushed from memory to disk by the operating system's memory manager."
{SwapIns}
"The total number of times a process that had been swapped out to disk is brought back into memory."
{PagesSwappedIn}
"The total number of swapped out pages that have been brought back into memory from disk."
{SwapOuts}
"The total number of times an idle process has been swapped out from memory to disk. If this ever happens its a sign that free memory stayed low long enough to trigger swapping."
{PagesSwappedOut}
"The total number of pages that have been moved from memory to disk due to a swap out operation."
{ZeroFilledPages}
"The total number of pages have been block-cleared to contain all zeros."
{PagesFreedAutomatically}
"The total number of pages that have been added to the free list be either the pager daemon or automatically."
{PagesScanned}
"The total number pages examined by the pageout daemon. When the amount of free memory gets below a certain size, the daemon start to look for inactive memory pages to steal from processes. So I high scan rate is a good indication of needing more memory."
{PageDemonCycles}
"The total number of revolutions of the page daemon's scan \"clock hand\"."
{HATMinorFaults}
"The total number of hat faults. You only get these on systems with software memory management units."
{UserMinorFaults}
"The total number of minor page faults in non-kernel code. Minor page faults do not require disk access."
{MajorPageFaults}
"The total number of times a page fault required disk io to get the page.
A page fault occurs when a process refers to a virtual memory page that has been paged out."
{CopyOnWriteFaults}
"The total number of times a private copy of a shared page needed to be made due to a write to the shared page."
{ProtectionFaults}
"The total number of times memory has been accessed in a way that was not allowed. This results in a segementation violation and in most cases a core dump."
{SoftwareLockFaults}
"The total number of faults caused by software locks held on memory pages."
{SystemMinorFaults}
"The total number of minor page faults in kernel code. Minor page faults do not require disk access."
{PagerRuns}
"The total number of times the pager daemon has been scheduled to run."
{ExecPagesPagedIn}
"The total number readonly pages that contain code or data that have been copied from disk to memory."
{ExecPagesPagedOut}
"The total number readonly pages that contain code or data that have been removed from memory and will need to be paged in when used again."
{ExecPagesFreed}
"The total number readonly pages that contain code or data that have been removed from memory and returned to the free list."
{AnonymousPagesPagedIn}
"The total number pages that contain heap, stack, or other changeable data that have been allocated in memory and possibly copied from disk."
{AnonymousPagesPagedOut}
"The total number pages that contain heap, stack, or other changeable data that have been removed from memory and copied to disk."
{AnonymousPagesFreed}
"The total number pages that contain heap, stack, or other changeable data that have been removed from memory and added to the free list."
{FileSystemPagesPagedIn}
"The total number of pages that contain the contents of a file due to the file being read from a file system."
{FileSystemPagesPagedOut}
"The total number of pages, that contained the contents of a file due to the file being read from a file system, that   have been removed from memory and copied to disk."
{FileSystemPagesFreed}
"The total number of pages, that contained the contents of a file due to the file being read from a file system, that   have been removed from memory and put on the free list."
{InputPackets}
"The total number of packets read from the network interface."
{InputErrors}
"The total number of errors associated with read operations on the network interface."
{OutputPackets}
"The total number of packets written to the network interface."
{OutputErrors}
"The total number of errors associated with write operations on the network interface."
{Collisions}
"The total number of packet collisions that have happened on the network interface."
{InputBytes}
"The total number of bytes read from the network interface."
{OutputBytes}
"The total number of bytes written to the network interface."
{MulticastInputPackets}
"The total number of multicast packets read from the network interface."
{MulticastOutputPackets}
"The total number of multicast packets written to the network interface."
{BroadcastInputPackets}
"The total number of broadcast packets read from the network interface."
{BroadcastOutputPackets}
"The total number of broadcast packets written to the network interface."
{InputPacketsDiscarded}
"The total number of input packets discarded."
{OutputPacketsDiscarded}
"The total number of output packets discarded."
{ReadKBytes}
"The total number of kilobytes read from the operating system I/O device."
{WriteKBytes}
"The total number of kilobytes written to the operating system I/O device."
{ReadOperations}
"The total number of read operations done on the operating system I/O device."
{WriteOperations}
"The total number of write operations done on the operating system I/O device."
{WaitQueueLength}
"The average number of operations in the driver's wait queue for a system I/O device.
Operations go into the wait queue when they are performed on the I/O device and leave it when both the system bus and device are ready to activate the operation."
{WaitQueueResponseTime}
"The average milliseconds and operation stays in the queue. Its calculated by dividing the queue length by total number of operations taken out of the queue.
Operations go into the wait queue when they are performed on the I/O device and leave it when both the system bus and device are ready to activate the operation."
{WaitQueueServiceTime}
"The average wait queue service time in milliseconds. Its calculated by dividing the time the queue was busy by total number of operations taken out of the queue.
Operations go into the wait queue when they are performed on the I/O device and leave it when both the system bus and device are ready to activate the operation."
{WaitQueueUtilization}
"A percentage that represents how much of the queue is being used. Its calculated by dividing the time the queue was busy by the total time available.
Operations go into the wait queue when they are performed on the I/O device and leave it when both the system bus and device are ready to activate the operation."
{ActiveQueueLength}
"The average number of operations being performed on  a system I/O device.
Operations go into the active queue when they are taken from the wait queue because the system bus and device are ready. They leave it when the device completes the operation."
{ActiveQueueResponseTime}
"The average milliseconds and operation stays in the queue. Its calculated by dividing the queue length by total number of operations taken out of the queue.
Operations go into the active queue when they are taken from the wait queue because the system bus and device are ready. They leave it when the device completes the operation."
{ActiveQueueServiceTime}
"The average active queue service time in milliseconds. Its calculated by dividing the time the queue was busy by total number of operations taken out of the queue.
Operations go into the active queue when they are taken from the wait queue because the system bus and device are ready. They leave it when the device completes the operation."
{ActiveQueueUtilization}
"A percentage that represents how much of the queue is being used. Its calculated by dividing the time the queue was busy by the total time available.
Operations go into the active queue when they are taken from the wait queue because the system bus and device are ready. They leave it when the device completes the operation."
{SoftErrors}
"The total number of soft errors that have occured on the I/O device."
{HardErrors}
"The total number of hard errors that have occured on the I/O device."
{TransportErrors}
"The total number of transport errors that have occured on the I/O device."
{MediaErrors}
"The total number of media errors that have occured on the I/O device."
{DeviceNotReady}
"The total number of errors that have occured due to the device not being ready."
{NoDevice}
"The total number of errors that have occured due to a device not being available."
{Recoverable}
"The total number of errors that have occured on the I/O device that are recoverable."
{IllegalRequest}
"The total number of illegal request errors that have occured on the I/O device."
{PredictiveFailureAnalysis}
"A metric that can be used to predict the next failure on the I/O device."
{UnswappableMemory}
"The amount of allocated memory, in megabytes, that can not be swapped out."
{LockedPages}
"The current number of physical memory pages on the machine that are locked."
{IOPages}
"The current number of physical memory pages on the machine that are being input or output from disk."
{TotalPages}
"The current number of physical memory pages on the machine."
{SentTcpBytes}
"The total number of bytes sent in TCP data segments."
{RetransmittedTcpBytes}
"The total number of bytes resent in TCP data segments.
If this value is more than 30% of \[SentTcpBytes > SentTcpBytes Statistic] you may have some bad network hardware, a congested route that is dropping packets, or and operating system that needs a patch."
{AcksSent}
"The total number of acknowledgment TCP segments sent."
{DelayedAcksSent}
"The total number of delayed acknowledgment TCP segments sent."
{ControlSegmentsSent}
"The total number of control (syn, fin, rst) TCP segments sent."
{AcksReceived}
"The total number of acknowledgment TCP segments received."
{AckedBytes}
"The total number of bytes acknowledged by received TCP ack segments."
{DuplicateAcks}
"The total number of duplicate acknowledgment TCP segments received."
{AcksForUnsentData}
"The total number of acknowledgment TCP segments received for unsent data."
{ReceivedInorderBytes}
"The total number of TCP data bytes received in the correct order."
{ReceivedOutOfOrderBytes}
"The total number of TCP data bytes received in the wrong order.
If this value is high compared to \[ReceivedInorderBytes > ReceivedInorderBytes Statistic] then it could be a sign of routing problems."

{ReceivedDuplicateBytes}
"The total number of TCP data bytes received in duplicate segments.
Incoming data may be duplicated when an acknowledgment is lost or delayed and the other end retransmits a segment that actually arrived correctly the first time. This situation can be a sign that the remote systems are retransmitting too quickly and needs tuning or a patch."
{ReceivedPartialDuplicateBytes}
"The total number of TCP data bytes received in partially duplicated segments.
Incoming data may be duplicated when an acknowledgment is lost or delayed and the other end retransmits a segment that actually arrived correctly the first time. This situation can be a sign that the remote systems are retransmitting too quickly and needs tuning or a patch."

{RetransmitTimeouts}
"The total number of TCP retransmit timeouts."
{RetransmitTimeoutDrops}
"The total number of connections dropped due to a retransmit timeout."
{KeepAliveTimeouts}
"The total number of keep alive timeouts."
{KeepAliveProbes}
"The total number of times a probe needed to be sent out due to a keep alive timer expiring."
{KeepAliveDrops}
"The connections dropped due to the failure of a keep alive probe."
{ListenQueueFull}
"The total number of connections refused due to a listen queue being full."
{HalfOpenQueueFull}
"The total number of connection refused due to the help open listen queue (q0) being full."
{HalfOpenDrops}
"The total number of half open connections dropped. Non-zero values usually indicate a SYN fload attack."
{EJBHomesActivated}
"The number of EJB homes activated."
{EJBInstancesAddedToPool}
"The number of bean instances put in the pool. This statistic is applicable only if beans are pooled."
{EJBInstancesTakenFromPool}
"The number of bean instances taken from the pool. This statistic is applicable only if beans are pooled."
{EJBInstancesCreated}
"The number of session and entity bean instances created, via ejbCreate(args)."
{EJBInstancesPostCreated}
"The number of ejbPostCreate methods invoked.  ejbPostCreate is called only for entity beans, after ejbCreate completes and after the primary key for the bean has been set."
{EJBInstancesRemoved}
"The number of session and entity bean instances removed via ejbRemove()."
{EJBInstancesTimedOut}
"The number of stateful session beans timed out."
{EJBInstancesDiscarded}
"The number of beans discarded during exception handling."
{EJBInstancesActivated}
"The number of session and entity bean instances activated via ejbActivate()."
{EJBInstancesPassivated}
"The number of session and entity bean instances passivated via ejbPassivate()."
{EJBFinderInstancesCreated}
"The number of entity bean finder instances created.  Finder instances are used only to execute ejbFind methods."
{EJBFindersInvoked}
"The number of ejbFind methods invoked.  This includes ejbFindByPrimaryKey and all custom ejbFind<method>(args) methods."
{EJBFinderInstancesDestroyed}
"The number of entity bean finder instances destroyed.  Finder instances are used only to execute ejbFind methods."
{EJBSessionHandlesAcquired}
"The number of session bean handles acquired via getHandle()."
{EJBSessionHandleActivations}
"The number of session beans acquired via handle.getEJBObject()."
{EJBEntityHandlesAcquired}
"The number of entity bean handles acquired via getHandle()."
{EJBEntityHandlesActivations}
"The number of and entity beans  acquired via handle.getEJBObject()."
{EJBBusinessMethodInvocations}
"The number of entity and session bean business methods invoked."
{EJBEntityContextsSet}
"The number of setEntityContext methods invoked for entity beans.  setEntityContext is called on each entity bean when created and for each finder instance created and used to execute an ejbFind method."
{EJBEntityContextsUnset}
"The number of unsetEntityContext methods invoked for entity beans.  unsetEntityContext is called for each entity bean when removed; it is not called for finder instances."
{EJBSessionContextsSet}
"The number of setSessionContext methods invoked for session beans."
{EJBEntityLoads}
"The number of ejbLoad methods called for entity beans."
{EJBEntityStores}
"The number of ejbStore methods called for entity beans."
{EJBSessionTxnAfterBegins}
"The number of afterBegin methods called for session beans that implement transaction synchronization."
{EJBSessionTxnBeforeCompletions}
"The number of beforeCompletion methods called for session beans that implement transaction synchronization."
{EJBSessionTxnAfterCompletions}
"The number of afterCompletion methods called for session beans that implement transaction synchronization."
{EJBGsSessionsCreated}
"The total number of sessions created by the EJB session pool manager."
{EJBGsSessionsTerminated}
"The total number of sessions terminated by the EJB session pool manager.
This happens when the number of inactive sessions exceeds the optimal pool size. If its consistently happening the optimal pool size should be increased or a different vm should be used."
{EJBGsSessionPoolSize}
"The current number of active and inactive session in the EJB session pool."
{EJBFreeGsSessionCount}
"The total number of times a session obtained be calling GSJEJBContext.getGsSession() has been freed."
{EJBFreeGsSessionTime}
"The total number of milliseconds spent freeing sessions obtained by calling GSJEJBContext.getGsSession()."
{EJBGetGsSessionCount}
"The total number of times GSJEJBContext.getGsSession() has been called."
{EJBGetGsSessionTime}
"The total number of milliseconds spent acquiring sessions via calls to GSJEJBContext.getGsSession()."
{EJBGsSessionsHandedOut}
"The total number of times EJB pool sessions have changed status from inactive to active. This happens when a session is requested by EJB applications and when a session is used internally by the EJB server."
{EJBGsSessionsReturned}
"The total number of times EJB pool sessions have changed status from active to inactive. A GsSession is returned either at the end of the transaction or at the end of the non-transactional method in which it was acquired."
{EJBTransactionsSuspended}
"The number of OTS transactions suspended by a bean method."
{EJBTransactionsResumed}
"The number of OTS transactions resumed by a bean method."
{EJBBeansDeployed}
"The number of beans deployed during EJB and DJB application installation.  DJB apps typically have just one bean, DJBSession."
{EJBStubsServantsDeployed}
"The number of stubs and servants deployed during EJB and DJB application installation."
{EJBApplicationImportTime}
"The time spent importing EJB and DJB applications.  This corresponds to the total time spent in methods EJBApplication.importProviderJar(..) and EJBApplication.mergeProviderJar(..)."
{EJBApplicationArtifactGenerationTime}
"The time spent generating artifact source code for EJB and DJB applications, not including stubs and servants.  This is part of the time spent in the method EJBApplication.enable(session)."
{EJBApplicationArtifactCompilationTime}
"The time spent compiling artifact source code for EJB and DJB applications, not including stubs and servants.  This is part of the time spent in the method EJBApplication.enable(session)."
{EJBApplicationStubServantGenerationTime}
"The time spent generating stub and servant source code for EJB and DJB applications.  This is part of the time spent in the method EJBApplication.enable(session)."
{EJBApplicationStubServantCompilationTime}
"The time spent compiling stub and servant source code for EJB and DJB applications. This is part of the time spent in the method EJBApplication.enable(session)."
{EJBPreDispatchTime}
"The total number of milliseconds spent predispatching an EJB business method invocation."
{EJBPostDispatchTime}
"The total number of milliseconds spent postdispatching an EJB business method invocation."
{JNDILookupTime}
"The time spent doing JNDI lookups.  Note that this refers to time spend doing lookups in this VM only."
{JNDILookups}
"The number of JNDI lookups attempted."
{POACreateCount}
"The total number of Portable Object Adapters created since the VM was started."
{POADeleteCount}
"The total number of Portable Object Adapters destroyed since the VM was started."
{ORBServantCount}
"The current number of servants activated in the ORB, either explicitly or implicitly. In other words the current number of objects exported from all POAs."
{ORBCurrentConnections}
"The number of current connections to clients and/or servers.  Each connection may reserve resources such as sockets and/or threads."
{ORBUpcallCount}
"The current number of server requests being processed."
{ORBRequestsSent}
"The total number of ORB requests sent."
{ORBRequestsReceived}
"The total number of ORB requests received."
{ORBRequestsCompleted}
"The total number of received ORB requests that have completed."
{ORBRequestBytesSent}
"The total number of bytes sent in the form of ORB requests."
{ORBRequestDurationTime}
"The total duration, in milliseconds,  of all received ORB requests. Time is measured from when a request  is received and until that request completes."
{ORBRequestBytesReceived}
"The total number of bytes received in the form of ORB requests."
{ORBRootPOAServantCount}
"The current number of servants that have been activated in the Root POA.
Increase in the size of the root POA servant count can indicate a memory leak in the EJB architecture."
{EJBSerializationTime}
"The total number of milliseconds spent in serialization when transporting ORB request arguments and replies."
{ORBResponseWaitTime}
"The total number of milliseconds client has waited for a response to an ORB request it has sent."
{ORBResponseBytesSent}
"The total number of bytes sent to clients in the form of responses to their requests."
{ORBResponseBytesReceived}
"The total number of bytes received from a server in the form of responses to a a sent request."
{ORBQueuedRequests}
"The current number of client requests that are waiting for a thread. If this number if consistently high then the system property \"com.gemstone.CORBA.ThreadHighWaterMark\" should be set to a higher number or an additional vm should be used."
{ActivationInitializers}
"The total number of CORBA activation initializers executed."
{ActivationInitializerTime}
"The total time spent executing all CORBA activation initializers."
{VMInitializers}
"The total number of VM initializers executed."
{VMInitializerTime}
"The total time spent executing all VM initializers."
{OTSTransactionsBegun}
"The number of OTS transactions begun.  All processing for a transaction occurs the VM in which the transaction begins."
{OTSTransactionsCommitted}
"The number of OTS transactions committed.  All processing for a transaction occurs the VM in which the transaction begins."
{OTSTransactionsRolledBack}
"The number of OTS transactions rolled back.  All processing for a transaction occurs the VM in which the transaction begins."
{OTSTransactionCommitTime}
"The total number of milliseconds spent committing OTS transactions."
{OTSTransactionTime}
"The total OTS transaction time.  This is the time between beginning a transaction and ending it, either via commit or rollback.  All processing for a transaction occurs the VM in which the transaction begins."
{OTSResourcesRegistered}
"The number of resources registered with a transaction coordinator.  All processing for a transaction occurs the VM in which the transaction begins."
{OTSSynchronizersRegistered}
"The number of synchronizers registered with a transaction coordinator.  All processing for a transaction occurs the VM in which the transaction begins."
{OTSReplayCompletionsIssued}
"The number of replay_completion commands sent by resources to a transaction recovery coordinator. All processing for a transaction occurs the VM in which the transaction begins."
{OTSResourcesTimedOut}
"The number of resources timed out.  All processing for a transaction occurs the VM in which the transaction begins."
{JDBCConnectionPools}
"The number of JDBC connection pools created."
{JDBCPooledConnections}
"The number of JDBC connections existing in all connection pools.  These connections may or may not be in use."
{JDBCPooledConnectionsInUse}
"The number of JDBC connections in use across all connection pools."
{JDBCGetConnectionTime}
"The total number of milliseconds spent acquiring JDBC connections via calls to aDataSource.getConnection or DriverManager.getConnection.  Specifically, this statistic applies to connections that are acquired from a GsXADataSource or are acquired from DriverManager in JDBCResource-initialized VMs (includes activated VMs). Use with \[JDBCGetConnectionCount > JDBCGetConnectionCount Statistic] to determine average time."
{JDBCConnectionsRequested}
"The number of requests to get a JDBC connection via calls to aDataSource.getConnection or DriverManager.getConnection.  Use this with \[JDBCConnectionsAcquired > JDBCConnectionsAcquired Statistic] to determine the number of open requests.  Specifically, this statistic applies to connections that are acquired from a GsXADataSource or are acquired from DriverManager in JDBCResource-initialized VMs (includes activated VMs)."
{JDBCConnectionsAcquired}
"The number of JDBC connections returned to the caller from a request to get a connection via aDataSource.getConnection or DriverManager.getConnection.  Use this with \[JDBCConnectionsRequested > JDBCConnectionsRequested Statistic] to determine the number of open requests.  Specifically, this statistic applies to connections that are acquired from a GsXADataSource or are acquired from DriverManager in JDBCResource-initialized VMs (includes activated VMs)."
{JDBCCloseConnectionTime}
"The total number of milliseconds spent closing JDBC connections via calls to connection.close(). Specifically, this statistic applies to connections that are acquired from a GsXADataSource or are acquired from DriverManager in JDBCResource-initialized VMs (includes activated VMs).  Use with \[JDBCCloseConnectionCount > JDBCCloseConnectionCount Statistic] to determine average time."
{JDBCExecuteQueryTime}
"The total number of milliseconds spent executing SQL statements via calls to executeQuery(String sql) or executeQuery().  This includes executeQuery calls on Statement, PreparedStatement, and CallableStatement instances.  Specifically, this statistic applies to statements created on connections that are acquired from a GsXADataSource or are acquired from DriverManager in JDBCResource-initialized VMs (includes activated VMs).  Use with \[JDBCExecuteQueryCount > JDBCExecuteQueryCount Statistic] to determine average time."
{JDBCExecuteUpdateTime}
"The total number of milliseconds spent executing SQL statements via calls to executeUpdate(String sql) or executeUpdate().  This includes executeUpdate calls on Statement, PreparedStatement, and CallableStatement instances.  Specifically, this statistic applies to statements created on connections that are acquired from a GsXADataSource or are acquired from DriverManager in JDBCResource-initialized VMs (includes activated VMs).  Use with \[JDBCExecuteUpdateCount > JDBCExecuteUpdateCount Statistic] to determine average time."
{JDBCExecuteBatchTime}
"The total number of milliseconds spent executing SQL statements via calls to executeBatch().  This includes executeBatch calls on Statement, PreparedStatement, and CallableStatement instances.  Specifically, this statistic applies to statements created on connections that are acquired from a GsXADataSource or are acquired from DriverManager in JDBCResource-initialized VMs (includes activated VMs).  Use with \[JDBCExecuteBatchCount > JDBCExecuteBatchCount Statistic] to determine average time."
{JDBCExecuteTime}
"The total number of milliseconds spent executing SQL statements via calls to execute(String sql) or execute().  This includes execute calls on Statement, PreparedStatement, and CallableStatement instances.  Specifically, this statistic applies to statements created on connections that are acquired from a GsXADataSource or are acquired from DriverManager in JDBCResource-initialized VMs (includes activated VMs).  Use with \[JDBCExecuteCount > JDBCExecuteCount Statistic] to determine average time."
{JDBCConnectionsShared}
"The number of connections which have been modified to point to other connections to achieve connection sharing.  For example, if there are two shared connection requests to the same resource, this number will be incremented by one.  Use with \[JDBCConnectionsUnshared > JDBCConnectionsUnshared Statistic] to determine the current number of shared connections.  Specifically, this statistic applies to connections that are acquired from a GsXADataSource using pseudo-XA mode or are acquired from DriverManager in JDBCResource-initialized VMs (includes activated VMs)."
{JDBCConnectionsUnshared}
"The number of connections which had been modified to point to other connections but are now being closed or unshared.  Use with \[JDBCConnectionsShared > JDBCConnectionsShared Statistic] to determine the current number of shared connections.  Specifically, this statistic applies to connections that are acquired from a GsXADataSource using pseudo-XA mode or are acquired from DriverManager in JDBCResource-initialized VMs (includes activated VMs)."
{JDBCGetConnectionCount}
"The total number of JDBC connections acquired via calls to aDataSource.getConnection or DriverManager.getConnection.  Specifically, this statistic applies to connections that are acquired from a GsXADataSource or are acquired from DriverManager in JDBCResource-initialized VMs (includes activated VMs)."
{JDBCCloseConnectionCount}
"The total number of JDBC connections closed via calls to connection.close().  Specifically, this statistic applies to connections that are acquired from a GsXADataSource or are acquired from DriverManager in JDBCResource-initialized VMs (includes activated VMs)."
{JDBCExecuteQueryCount}
"The total number of JDBC calls to executeQuery(String sql) or executeQuery().  This includes executeQuery calls on Statement, PreparedStatement, and CallableStatement instances.  Specifically, this statistic applies to statements created on connections that are acquired from a GsXADataSource or are acquired from DriverManager in JDBCResource-initialized VMs (includes activated VMs)."
{JDBCExecuteUpdateCount}
"The total number of JDBC calls to executeUpdate(String sql) or executeUpdate().  This includes executeUpdate calls on Statement, PreparedStatement, and CallableStatement instances.  Specifically, this statistic applies to statements created on connections that are acquired from a GsXADataSource or are acquired from DriverManager in JDBCResource-initialized VMs (includes activated VMs)."
{JDBCExecuteBatchCount}
"The total number of JDBC calls to executeBatch().  This includes executeBatch calls on Statement, PreparedStatement, and CallableStatement instances.  Specifically, this statistic applies to statements created on connections that are acquired from a GsXADataSource or are acquired from DriverManager in JDBCResource-initialized VMs (includes activated VMs)."
{JDBCExecuteCount}
"The total number of JDBC calls to execute(String sql) or execute().  This includes execute calls on Statement, PreparedStatement, and CallableStatement instances. Specifically, this statistic applies to statements created on connections that are acquired from a GsXADataSource or are acquired from DriverManager in JDBCResource-initialized VMs (includes activated VMs)."
{DependencyListCallbackCount}
"The total the number of times a callback is made to potentially update indexes when an object is modified."

{DGCServantCount}
"The total number of servants that have been disconnected as a result of distributed garbage collection."
{DGCServantTime}
"The total number of milliseconds spent doing distributed garbage collection of servants."
{DGCStubCount}
"The total number of stubs that have been disconnected as a result of distributed garbage collection."
{DGCStubTime}
"The total number of milliseconds spent doing distributed garbage collection of stubs."
{RGCEpochThreshold}
"Can be used to defer epoch repository garbage collection. If \[RGCPagesNeedReclaiming > RGCPagesNeedReclaiming Statistic] exceeds this threshold then epochs are not done."
{RGCEpochTime}
"The number of seconds to wait between epoch repository garbage collections. A value of -1 disables epochs."
{RGCEpochScheduledTime1}
"The number of seconds after midnight to begin an epochGc."
{RGCEpochScheduledTime2}
"The number of seconds after midnight to begin an epochGc."
{RGCEpochScheduledTime3}
"The number of seconds after midnight to begin an epochGc."
{RGCEpochScheduledTime4}
"The number of seconds after midnight to begin an epochGc."
{RGCReclaimPagesMax}
"The maximum number of pages to reclaim at one time."
{RGCReclaimPagesMin}
"The minimum number of pages needed to cause the repository garbage collector to do a reclaim."
{RGCReclaimSleepTime}
"The number of seconds to wait between repository garbage collector reclaims. A value of -1 disables reclaims."
{RGCReclaimThreadsActive}
"The current number of threads that are being used by the repository garbage collector to do reclaims."
{RGCReclaimThreadsLimit}
"The maximum number of threads that can be used by the repository garbage 
collector to do reclaims. Defaults to 2 times the number of cpu's on the system."
{RGCStatsPrintTime}
"The number of seconds to wait between logging statistics to the repository garbage collector's log file."
{ResponseTimeAverage}
"The average number of milliseconds the VM takes to complete a client's request.
By default the value of this statistic will be computed every second. By default the average computation ignores values older than 60 seconds.
In systems with an activator this stat is used by its load balancer to select the best VM."
{RequestLoadAverage}
"The average number of client requests that the VM has not completed.
By default the value of this statistic will be computed every second. By default the average computation ignores values older than 10 seconds.
In systems with an activator this stat is used by its load balancer to decide if a VM is a valid activation target."
{WebAdapterConnectionCloseCount}
"The total number of connections that have been closed between the web adapter and the web engine."
{WebAdapterConnectionCurrentCount}
"The number of connections that are currently open between the web adapter and the web engine."
{WebAdapterConnectionOpenCount}
"The total number of connections that have been opened between the web adapter and the web engine."
{WebHttpSessionCreateCount}
"The total number of HttpSessions that the web engine has created."
{WebHttpSessionCurrentCount}
"The number of HttpSessions that the web engine is currently managing."
{WebHttpSessionExpiredCount}
"The total number of HttpSessions that the web engine has removed because the HttpSession timed out.  The HttpSession's web application deployment descriptor defines the timeout interval using the <session-timeout=\"minutes\"> tag."
{WebHttpSessionInvalidatedCount}
"The total number of HttpSessions that the web engine has removed because the servlet explicitly sent an invalidate message."
{WebHttpSessionReapTime}
"The total number of milliseconds that the web engine has spent reaping expired HttpSessions."
{WebHttpSessionRemoveCount}
"The total number of HttpSessions that the web engine has removed for any reason.
See also: \[WebHttpSessionExpiredCount > WebHttpSessionExpiredCount Statistic], \[WebHttpSessionInvalidatedCount > WebHttpSessionInvalidatedCount Statistic]."
{WebJSPCompileCount}
"The total number of JSPs that the web engine has parsed and compiled.  A JSP is automatically reparsed and recompiled whenever it has changed."
{WebJSPCompileTime}
"The total number of milliseconds that the web engine has spent compiling JSPs."
{WebJSPParseTime}
"The total number of milliseconds that the web engine has spent parsing JSPs."
{WebRequestAbortedCount}
"The total number of web requests that have been aborted before the full response was sent.  The abort may have been triggered by the web adapter, web engine or some other source."
{WebRequestsReceived}
"The total number of web requests that the web engine has received.  The web engine may or may not have been able to successfully send a response."
{WebRequestsCompleted}
"The total number of received web requests that have completed.  The web engine may or may not have been able to successfully send a response."
{WebRequestCurrentCount}
"The number of web requests that the web engine is currently processing.  The web engine is considered to be processing a request until the response is fully sent."
{WebRequestDurationTime}
"The total number of milliseconds that the web engine has spent processing requests, including sending the response."
{WebResponseBodyBytes}
"The total number of bytes that the web engine has sent in the bodies of all responses.  Note that response headers are not included so this is not a measure of all bytes output."
{WebServiceDurationTime}
"The total number of milliseconds that servlets  have spent in their service methods."
{WebServletCurrentCount}
"The number of servlets (including JSPs) that the web engine has currently initialized.  Note that for a servlet that implements SingleThreadModel, the web engine may initialize many concurrent instances."
{WebServletDestroyedCount}
"The total number of servlets (including JSPs)that the web engine has destroyed (i.e. has sent the destroy message). Note that the web engine may have initialized, destroyed and re-initialized the same servlet several times."
{WebServletInitializedCount}
"The total number of servlets (including JSPs) that the web engine has initialized (i.e. has sent the init message).  Note that the web engine may have initialized, destroyed and re-initialized the same servlet several times.  Also note that for a servlet that implements SingleThreadModel, the web engine may initialize many concurrent instances."
{GsConnectionAcquireCount}
"The total number of times an instances of com.gemstone.connection.Connection has been acquired."
{GsConnectionAcquireTime}
"The total number of milliseconds spent acquiring instances of com.gemstone.connection.Connection."
{GsConnectionReleaseCount}
"The total number of times an instances of com.gemstone.connection.Connection has been released."
{GsConnectionReleaseTime}
"The total milliseconds spent releasing instances of com.gemstone.connection.Connection."
{IndexMaintenanceCount}
"The total number of field assignments that have resulted in indexes being updated."
{StatisticAgentNotifyCount}
"The total number of times the statistic agent in this VM has notified listeners of statistic events."
{StatisticAgentNotifyTime}
"The total milliseconds that the statistic agent in this VM has spent notifying listeners of statistic events.
Large values are most likely caused by waiting for a listener to respond."
{StatisticAgentSampleCount}
"The total number of times the statistic agent in this VM has sampled statistics."
{StatisticAgentSampleTime}
"The total milliseconds that the statistic agent in this VM has spent sampling statistics."
{PooledSessionsCreated}
"The total number of sessions created by the session pool manager."
{SessionPoolSize}
"The current number of active and inactive sessions in the session pool."
{PooledSessionsReturned}
"The total number of times pool sessions have changed status from active to inactive."
{PooledSessionsTerminated}
"The total number of sessions terminated by the session pool manager.
This happens when the number of inactive sessions exceeds the optimal pool size. If its consistently happening the optimal pool size should be increased or a different vm should be used."
{PooledSessionWaitStartedCount}
"The total number of times a request for a pooled session had to wait for a session to be returned to the pool."
{PooledSessionWaitFinishedCount}
"The total number of times a request for a pooled session that had to wait for a session completed. This statistic accounts for both waits that timed out and waits that acquired a session."
{PooledSessionWaitTime}
"The total number of milliseconds spent waiting for a pooled session to be returned to the pool."
{ActivationTime}
"The total time spent handling activation requests in the Activator's VM."
{Activations}
"The total number of activation requests handled by the Activator."
{TimeInStonePageDisposal}
"TimeInStonePageDisposal is the total amount of real time in milliseconds the stone has spent performing page disposal tasks."
{TimeInStoneLoop}
"Shows the cumulative amount of time in millisecondsthat the stone spends peforming tasks in the stone loop. Excludes timespent processing run queue requests and sleep time (see \[TimeInStoneLoopRunQ > TimeInStoneLoopRunQ Statistic] and \[TimeInStoneLoopSleep > TimeInStoneLoopSleep Statistic])."
{TimeInStoneLoopRunQ}
"Shows the cumulative amount of time in millisecondsthat the stone spends services session requests coming in on the run queue."
{TimeUntilNextCheckpoint}
"Time in seconds until the next checkpoint is scheduled to be written. Even when this statistic is zero a checkpoint might still not be done because the stone waits for other conditions before doing a checkpoint."
{TimeInStoneLoopSleep}
"Shows the cumulative amount of time in millisecondsthat the stone spends asleep, waiting for work."
{ffPageNotFound}
"Number of times that a page could not be removed because it was not found"
{ffCantGetFrameLock}
"Number of times that a page could not be removed because frame already locked."
{ffAioInProgress}
"Number of times that a page could not be removed because Aio was in progress"
{ffPageAttached}
"Number of times that a page could not be removed because it was attached"
{ffPageIsDirty}
"Number of times that a page could not be removed because it was dirty"
{ffPageIsLocked}
"Number of times that a page could not be removed because it was locked"
{ffWrap}
"Number of times the findFreeFrame clockHand wrapped around the cache."
{dPageNotFound}
"Number of times that a page could not be written because it was not found"
{dCantGetFrameLock}
"Number of times that a page could not be written because frame already locked."
{dWrap}
"Number of times the aioDirtyPage clockHand wrapped around the cache."
{chkpWrap}
"Number of times the checkpoint clockHand wrapped around the cache."
{dirtyCalls}
"Number of calls to the runDirtyPageClockHand C function."
{chkpCalls}
"Number of calls to the runCheckpointClockHand C function."
{ffCalls}
"Number of calls to the runFreeFrameClockHand C function."
{preemptCalls}
"Number of calls to the ShrPcSapPreemptPagesFromLocalCache C function."
{statSampleCalls}
"Number of calls to the runCacheStatSample C function."
{checkpointIoRatio}
"Value of the checkpointIoRatio config parameter."
{maxIoPerSec}
"Current limit for I/O per second for AIO writing threads."
{CacheMisses}
"The number of \[LocalPageCacheMisses > LocalPageCacheMisses Statistic] made during the last cycle of the shared page cache monitor loop. This is an experimental statistic that may be used in a future version of the shared page cache monitor for calculating \[AttachDelta > AttachDelta Statistic]."
{CacheEvents}
"The sum of \[LocalPageCacheMisses > LocalPageCacheMisses Statistic] plus \[LocalPageCacheHits > LocalPageCacheHits Statistic] made during the last cycle of the shared page cache monitor loop. This is an experimental statistic that may be used in a future version of the shared page cache monitor for calculating \[AttachDelta > AttachDelta Statistic]."
{CacheMissRatio}
"The ratio of \[CacheMisses > CacheMisses Statistic] to \[CacheEvents > CacheEvents Statistic] made during the last cycle of the shared page cache monitor loop, expressed in terms of \[CacheMisses > CacheMisses Statistic] per 1000 \[CacheEvents > CacheEvents Statistic].  This is an experimental statistic that may be used in a future version of the shared page cache monitor for calculating \[AttachDelta > AttachDelta Statistic]."
{CacheAttachFactor}
"An experimental statistic that may be used in a future version of the shared page cache monitor for calculating \[AttachDelta > AttachDelta Statistic].  If used, it will represent the percentage of free pages that could be attached to this process, based on its \[CacheMissRatio > CacheMissRatio Statistic]."
{CacheDetachFactor}
"An experimental statistic that may be used in a future version of the shared page cache monitor for calculating \[AttachDelta > AttachDelta Statistic].  If used, it will represent the percentage of currently attached pages that this process will have to detach, based on its \[CacheMissRatio > CacheMissRatio Statistic]."
{TimeInUpdateUnionsInCommit}
"The total amount of real time the stone has spent updating read and write set unions for remote gems performing commits."
{TimeInUpdateUnionsInAbort}
"The total amount of real time the stone has spent updating read and write set unions for remote gems performing aborts."
{UpdateUnionsInCommitCount}
"The total of times the stone has updated read and write set unions for remote gems performing commits."
{UpdateUnionsInAbortCount}
"The total of times the stone has updated read and write set unions for remote gems performing aborts."
{TimeInFramesFromFindFree}
"CPU time in milliseconds spent locating a free frame in the cache."
{PageLocateCount}
"Number of times the process located a page.  The page may have been read from disk or found in the cache. "
{SigAbortsSent}
"The number of SigAborts sent to this session from the Stone.  Note that the session may be in a sleep or I/O wait state and not yet aware of having been sent a SigAbort (see SigAbortsReceived). "
{SigAbortsReceived}
"The number of SigAborts received and recognized by this session."
{LostOtsSent}
"The number of LostOts sent to this session from the Stone.  Note that the session may be in a sleep or I/O wait state and not yet aware of having been sent a LostOt (see LostOtsReceived). "
{LostOtsReceived}
"The number of LostOts received and recognized by this session."
{OldestCrSession}
"The session ID of a session referencing the oldest commit record.  Note that more than one session may reference a commit record.  A value of -1 indicates the oldest commit record is not referenced by any session."
{RecoverTranlogFileId}
"The file ID of the tranlog currently being replayed during System recovery and restore."
{RecoverTranlogBlockId}
"The block ID of the tranlog currently being replayed during System recovery and restore."
{RecoverCrBacklog}
"The size of the commit record backlog in effect at the time that the tranlog entry currently being replayed was generated."
{SessionNotVoted}
"Stone sessionId of a session that has not yet voted on the possible dead objects."
{StnLoopCount}
"The total number times the stone has executed its service loop."
{OtherPageReads}
"The number of pages read by the process that were not object table, data, or bitmap pages since the process was started. These page reads are actual disk reads and not reads from the shared page cache."
{GemsInCacheCount}
"The number of gems currently attached to the cache. This stat is only interesting when there are remote gems."
{TimeInStnGetLocks}
"The total time spent by the stone retrieving the lockset and passing it to a remote gem."
{TimeInStnValidateLocks}
"The total time spent by the stone validating the lock set against a remote gem's write set."
{StnGetLocksCount}
"The total number of times the stone retrieved the lockset and passed it to a remote gem."
{StnValidateLocksCount}
"The total number of times the stone validated the lock set against a remote gem's write set."
{FreeOopCount}
"The number of free OOPS in the free list which have not been allocated to a gem."
{TotalSessionsCount}
"The total number of sessions currently logged in to the system."
{CommitTokenSession}
"The session ID of the session holding the commit token.  If no session is holding the commit token, the value will be zero."
{GcInReclaimAll}
"This statistic is 1 when the system is performing a reclaimAll, otherwise 0."
{GcVoteUnderway}
"Java:
This statistic is 1 when gems are voting on the possible dead, otherwise 0.

Smalltalk: 
Possible values and their meanings for this statistic are as follows:  
 
0 = no voting activity.  
1 = gems are voting on the possible dead. 
2 = voting completed, awaiting start of Possible Dead Write-Set Union Sweep (PDWSUS).  
3 = PDWSUS in progress.  
4 = PDWSUS completed."
{GcVoteState}
"Indicates the finalization state of possible dead objects.
Possible values and their meanings for this statistic are as follows:  
 
0 = no voting activity.  
1 = gems are voting on the possible dead. 
2 = voting completed, awaiting start of Possible Dead Write-Set Union Sweep (PDWSUS).  
3 = PDWSUS in progress.  
4 = PDWSUS completed."
{GcForceEpoch}
"This statistic is 1 when a user has requested that an Epoch GC be  manually started, otherwise 0."
{EpochForceGc}
"This statistic is 1 when a user has requested that an Epoch GC be manually started, otherwise 0."
{GcReclaimState}
"The state of the normal GcGem (or the Reclaim GcGem in a dual GcGem  configuration - see statistic GcEpochState for information on the state  of the Epoch GcGem).  Values are as follows:  
 
0 = Not active / sleeping. 
1 = Setup / background activity. 
2 = Reclaiming shadowed pages. 
3 = Rebuilding AllSymbols table (not used in Reclaim GcGem). 
4 = Write set union sweep (not used in Reclaim GcGem). 
5 = Epoch GC (not used in ReclaimGcGem)."
{GcEpochState}
"The state of the Epoch GcGem (see statistic GcReclaimState for  information on the state of the normal/Reclaim GcGem.   Values are as follows:  
 
0 = Not active / sleeping. 
1 = Setup / background activity. 
2 = (not used in Epoch GcGem). 
3 = Rebuilding AllSymbols table. 
4 = Write set union sweep. 
5 = Epoch GC."
{VoteState}
"0 = idle, 1 = sessions are voting on dead objects, 2 = sessions done voting, 3 = gc session sweeping wsUnion."
{DeadObjsExist}
"1 if there are dead objects not yet reclaimed, 0 otherwise. Refers to objects determined to be dead after voting has completed."
{PagesRemovedFromCacheCount}
"Total number of pages successfully removed from the cache by the cache page server or the Page Manager at the stone's request."
{PagesRemovedDirtyFromCacheCount}
"Number of dirty pages successfully removed from the cache by the cache page server or the Page Manager at the stone's request."
{PagesNotRemovedFromCacheCount}
"Number of pages the cache page server or Page Manager gem was unable to remove from the cache.  Requests to remove pages come from the stone."
{PagesNotFoundInCacheCount}
"PagesNotFoundInCacheCount is the total number of pages not found in the shared cache when the Page Manager gem or cache page server attempted to remove them."
{TimeInGcNotConnected}
"The total number of cpu milliseconds the gem spent garbage collecting the not connected set.  This statistic also includes time spent performing makeRoomInOldSpace and generational scavenge operations, which are performed as part of the not connected GC cycle."
{AttachDeltaPagesSatisfiedCount}
"The count of pages that the gem has detached to satisfy the \[AttachDelta > AttachDelta Statistic]."
{ShadowedPagesCount}
"Number of data pages added to the reclaim list due to commits by this gem. This statistic is only updated during a commit."
{RcConflictCount}
"The number of commits that resulted in an RC conflict."
{AllSymbolsConflictCount}
"The number of commits that resulted in a conflict on AllSymbols."
{CommitRetryFailureCount}
"The number of commits that failed after exceeding the retry count."
{PageReadsWaitingForCommit}
"The number of pages read while waiting for the commit token."
{PageReadsProcessingCommit}
"The number of pages read while the session is processing its part of the commit."
{PageReadsStoneCommit}
"The number of pages read while the stone is processing its part of the commit."
{MessagesToStnWaitingForCommit}
"The number of messages sent to the stone while waiting for the commit token."
{MessagesToStnProcessingCommit}
"The number of messages sent to the stone while the session is processing its part of the commit."
{MessagesToStnStoneCommit}
"The number of messages sent to the stone while the stone isprocessing its part of the commit."
{MessageKindToStone}
"The message type of the most recent message sent to the stone."
{TimeWaitingForStone}
"The total time the session spent waiting for a response from the stone."
{UpdateUnionsCommitCount}
"The total number of times the session updated its unions while waiting for the commit token.  This count will be at least one for every commit."
{TimeInUpdateUnionsCommit}
"The total real time the session spent updating its unions while waiting for the commit token."
{DirtyPageSweepCount}
"The number of times the page server has swept the cache for dirty pages or frames to add to the free list."
{RebuildScavPagesForCommitCount}
"The total number of times the session rebuilt its list of scavengable pages while processing a commit."
{PageReadsRebuildScavPagesCommit}
"The total of pages read while the session was rebuilding its list of scavengable pages while processing a commit."
{MessagesToStnRebuildScavPagesCommit}
"The number of messages the session sent to the stone while the session was rebuilding its list of scavengable pages while processing a commit."
{TimeInRebuildScavPagesCommit}
"The total amount of real time the session spent rebuilding its list of scavengable pages while processing a commit."
{OldSpaceOverflowCount}
"Number of times objects were moved from old space into the not connected set because old space became full.  A makeRoomInOldSpace operation will always preceeds an overflow."
{ClientPid}
"ClientPid is the process ID of the client process associated with this AIO page server process."
{StnLoopTimeInNetPoll}
"StnLoopTimeInNetPoll is the total amount of real time in milliseconds the stone spent calling the NetPoll() function."
{RemoteSessionCount}
"RemoteSessionCount is the number of sessions that are running on a host other than the stone's host."
{AioRateMax}
"AioRateMax is the current max IO rate being used by the page server expressed in IO operations per second."
{CheckpointState}
"CheckpointState is an internal statistic used to indicate the state of the checkpoint process.  A value of 0 indicates no checkpoint is in progress and a value of -1 indicates checkpoints are currently suspended."
{CommitQueueAddedToRunQueueCount}
"CommitQueueAddedToRunQueueCount is the number of times sessions from the commit queue were added to the run queue."
{CommitQueueAddedToRunQueueSessionCount}
"CommitQueueAddedToRunQueueSessionCount is the number of sessions from the commit queue which were added to the run queue."
{CommitQueueSessionNotReadyCount}
"CommitQueueSessionNotReadyCount is the number of times the stone was ready to assign the commit token to a session in the commit queue but no session was not ready to receive the token."
{CommitQueueThreshold}
"CommitQueueThreshold is the current setting of the STN_COMMIT_QUEUE_THRESHOLD configuration parameter.  This setting determines how large the commit queue must be before the stone will defer commit record disposal.  A value of -1 indicates this feature is disabled and commit record disposal will never be deferred."
{CommitRecordDisposalsDeferredCount}
"CommitRecordDisposalsDeferredCount is the number of times the stone deferred commit record disposal because the number of sessions in the commit queue exceeded the STN_COMMIT_QUEUE_THRESHOLD setting."
{CommitRecordDisposalState}
"CommitRecordDisposalState is an internal statistic used to analyze the the commit record disposal routines."
{CommitRecordsReadAbortCount}
"CommitRecordsReadAbortCount is the number of commit records read while processing an abort."
{CommitRecordsReadCommitWithoutTokenCount}
"CommitRecordsReadCommitWithoutTokenCount is the number of commit records read while processing a commit and the gem is waiting for the commit token."
{CommitRecordsReadCommitWithTokenCount}
"CommitRecordsReadCommitWithTokenCount is the number of commit records read while processing a commit and the gem has the commit token."
{LoginRequestsCount}
"LoginRequestsCount is the total number of login requests processed since the stone started."
{NextSleepTime}
"NextSleepTime is the number of milliseconds the page server will sleep during the next sleep period.  This value is adjusted to regulate the IO rate of the page server."
{RemovePagesFromCachesCount}
"RemovePagesFromCachesCount is the number of times the stone attempted to remove a list of pages from all shared page caches.  On the stone's shared cache, removal of pages is performed by the stone or the stone's cache page server.  On remote shared caches, the removal is performed by the cache page server for that cache."
{RemovePagesFromCachesPageCount}
"RemovePagesFromCachesPageCount is the total number of pages the stone attempted to remove from all shared page caches.  On the stone's shared cache, removal of pages is performed by the stone or the stone's cache page server.  On remote shared caches, the removal is performed by the cache page server for that cache."
{SocketsPolledCount}
"SocketsPolledCount is the number of TCP/IP sockets to the stone that were polled for activity during the most recent NetPoll operation.  The count is reset during each NetPoll operation and is not cumulative."
{SocketsPolledOobCount}
"SocketsPolledOobCount is the number of out of band TCP/IP sockets to the stone that were polled for activity during the most recent NetPollOob operation.  The count is reset during each NetPoll operation and is not cumulative."
{SocketsReadyCount}
"SocketsReadyCount is the number of TCP/IP sockets to the stone with an event ready to process during the most recent NetPoll operation.  The count is reset during each NetPoll operation and is not cumulative."
{SocketsReadyOobCount}
"SocketsReadyOobCount is the number of out of band TCP/IP sockets to the stone with an event ready to process during the most recent NetPollOob operation.  The count is reset during each operation and is not cumulative."
{StnLoopAioWaitCount}
"StnLoopAioWaitCount is the number of times the stone polled for an asynchronous write to the tranlog to complete.  The stone will only poll for AIO if there is no other outstanding work."
{StnLoopAioWaitTime}
"StnLoopAioWaitTime is the current setting of the STN_AIO_WAIT_TIME configuration parameter in milliseconds.  It specifies how long the stone will wait for an outstanding tranlog write to complete.  The stone waits for a pending AIO to complete to reduce CPU usage and only if there is no other work to do."
{StnLoopAioWaitTimedoutCount}
"StnLoopAioWaitTimedoutCount is the number of times the stone timed out waiting for an asynchronous write to the tranlog to complete.  The time the stone will wait is defined by the STN_AIO_WAIT_TIME configuration parameter and the StnLoopAioWaitTime statistic.  The stone waits for a pending AIO to complete to reduce CPU usage and only if there is no other work to do."
{StnLoopFifoWakeupBytes}
"StnLoopFifoWakeupBytes is the total number of bytes the stone received via the FIFO wakeup queue."
{StnLoopFifoWakeupCount}
"StnLoopFifoWakeupCount is the number of times the stone was awakened from sleeping because a gem or page server wrote a byte into the stone's FIFO wakeup queue."
{StnLoopHibernateCount}
"StnLoopHibernateCount is the total number of times the stone went to sleep waiting for a network event to occur.  This state occurs when StnLoopState is set to 17."
{StnLoopHibernateRealTime}
"StnLoopHibernateRealTime is the total number of milliseconds of real time the stone spent in stone loop state 17."
{StnLoopHibernateSleepTime}
"StnLoopHibernateSleepTime is the total number of milliseconds of real time the stone spent sleeping in stone loop state 17.  The stone will sleep when it is waiting for requests from gems to process and will awaken when a request is received."
{StnLoopHibernateSystemTime}
"StnLoopHibernateSystemTime is the total number of milliseconds of system CPU time the stone spent in stone loop state 17."
{StnLoopHibernateUserTime}
"StnLoopHibernateUserTime is the total number of milliseconds of user CPU time the stone spent in stone loop state 17."
{StnLoopMaxSleepTime}
"StnLoopMaxSleepTime is the current value of the STN_MAX_SLEEP_TIME configuration parameter.  This setting determines the maximum time in milliseconds the stone will sleep when there is no work to do before executing the main service loop."
{StnLoopNetPollBeforeSleepCount}
"StnLoopNetPollBeforeSleepCount is the number of times NetPoll was called while the stone was preparing to sleep."
{StnLoopNetPollCount}
"StnLoopNetPollCount is the total number of times the NetPoll function was called from the stone's main control loop."
{StnLoopNetPollOobCount}
"StnLoopNetPollOobCount is the total number of times the NetPollOob function was called from the stone's main control loop.  This function is used to poll out of band sockets to gems for activity."
{StnLoopPollCount}
"StnLoopPollCount is the number of times the stone called the select() or poll() function."
{StnLoopPollInterruptCount}
"StnLoopPollEintrCount is the number of times a poll() or select() call was interrupted by a signal before any events were detected."
{StnLoopPollNoEventCount}
"StnLoopPollNoEventCount is the number of times the stone called the select() or poll() function and no events were detected."
{StnLoopPollNoSleepCount}
"StnLoopPollNoSleepCount is the number of times the stone called the select() or poll() function with a timeout of 0.  In this case the function will not sleep and will return immediately"
{StnLoopPollTimeoutCount}
"StnLoopPollTimeoutCount is the number of times the stone called the select() or poll() function with a timeout greater than 0 and the timeout expired without detecting an event."
{StnLoopsPerNetPoll}
"StnLoopsPerNetPoll is the maximum number of times the stone will execute its main control loop before calling NetPoll when the stone is busy.  When the stone is not busy, it will always call NetPoll before going to sleep.  The default value is 1, meaning the stone will call NetPoll each time through its service loop."
{StnLoopState}
"StnLoopState is an indicator of where in the stone control loop the process is executing.  For state definitions, see the comments in the code."
{StnLoopTimeInNetPollOob}
"StnLoopTimeInNetPollOob is the number of milliseconds of real time the stone has spent in the NetPollOob function."
{StnLoopUpTime}
"StnLoopUpTime is the total number of seconds of real time the stone has been running in it's main service loop."
{StnOobSocketPollInterval}
"StnOobSocketPollInterval is the current setting of the STN_OOB_SOCKET_POLL_INTERVAL stone configuration parameter.  This setting determines how frequently the stone checks its out of band socket connections to gems for activity."
{StoneCommitState}
"StoneCommitState is an internal statistic used to determine the state of the stone's commit processing."
{TimeInCommitRecordDisposal}
"TimeInCommitRecordDisposal is the total amount of real time in milliseconds that the stone has spent disposing commit records.  Commit records disposed during repository startup are not included in this statistic."
{TimeInNetPoll}
"TimeInNetPoll is the number of milliseconds of real time the stone has spent in the NetPoll function.  NetPoll is used to receive requests from gems running on servers other than the stone's server."
{TimeInRemovePagesFromCaches}
"TimeInRemovePagesFromCaches is the total amount of real time in milliseconds the stone spent removing pages from all shared caches.  Removing pages from the shared caches is part of the page disposal algorithm."
{RecoverTranlogFileId}
"The file ID of the tranlog currently being replayed during System recovery and restore."
{RecoverTranlogBlockId}
"The block ID of the tranlog currently being replayed during System recovery and restore."
{TranlogFileId}
"The file ID of the tranlog currently being written to by the stone."
{TranlogRecordId}
"The record ID of the tranlog currently being written to by the stone."
{RecoverCrBacklog}
"The size of the commit record backlog in effect at the time that the tranlog entry currently being replayed was generated."
{GemHasCommitToken}
"A boolean counter that indicates if the gem holds the commit token."
{TimePerformingCommit}
"TimePerformingCommit is the number of milliseconds of real time the stone has spent performing commit processing, not including time taken by asynchronous writes to the tranlog."
{RemoteSharedPageCacheCount}
"RemoteSharedPageCacheCount is the total number of remote shared page caches attached to the system."
{OopsReturnedByGemsCount}
"OopsReturnedByGemsCount is the total number of free oops returned to the stone by any gem."
{PagesReturnedByGemsCount}
"PagesReturnedByGemsCount is the total number of free pages returned to the stone by any gem."
{PageMgrPagesReceivedFromStoneCount}
"PageMgrPagesReceivedFromStoneCount is the total number of pages the Page Manager session received from the stone to remove from shared page caches."
{PageMgrRemoveFromCachesCount}
"PageMgrRemoveFromCachesCount is the total number of times the Page Manager has attempted to remove pages from shared page caches."
{PageMgrRemoveFromCachesPageCount}
"PageMgrRemoveFromCachesPageCount is the total number of pages the Page Manager has attempted to remove from shared page caches.  This statistic includes pages processed by page removal retry operations, which occur whenever a page cannot be removed from a shared page cache on the first attempt."
{PageMgrPagesPendingRemovalRetryCount}
"PageMgrPagesPendingRemovalRetryCount is the current number of pages that could not be removed from shared page caches by the page manager on the first attempt and are waiting to be retried."
{PageMgrPagesRemovedFromCachesCount}
"PageMgrPagesRemovedFromCachesCount is the total number of pages the Page Manager has successfully removed from all shared page caches."
{PageMgrPagesNotRemovedFromCachesCount}
"PageMgrPagesNotRemovedFromCachesCount is the total number of pages the Page Manager was unable to remove from one or more shared page caches."
{PageMgrRemovePagesFromCachesPollCount}
"PageMgrRemovePagesFromCachesPollCount is the number of times the page manager called poll() or select() to determine which cache page servers have completed removing pages from their shared caches.  This statistic represents the value during the most recent page disposal operation and is not cumulative.  It will always vary between zero (when there are no remote shared caches on the system) and the number of remote shared page caches."
{PageMgrTimeWaitingForCachePgsvrs}
"TimeWaitingForCachePgsvrs is the total amount of real time in milliseconds the page manager has spent waiting to receive data from remote cache page servers."
{OopNumberHighWaterMark}
"OopNumberHighWaterMark is highest number of object identifiers allocated by the system."
{PinnedPagesCount}
"PinnedPagesCount is the number of pages the process has pinned (locked) in the shared cache.  Pages may be pinned by more than one process at the same time."
{PinnedPrivatePagesCount}
"PinnedPrivatePagesCount is the number of pages the process has pinned (locked) in its private page cache."
{TotalPinnedOrLockedPagesCount}
"TotalPinnedOrLockedPagesCount is the approximate total number of pages that are pinned or locked in the shared cache.  Each process may pin multiple pages in the shared cache at the same time but may lock only 1 page in the cache at a time."
{TimePerformingReadIo}
"TimePerformingReadIo is the total amount of real time in milliseconds the page server has spent reading pages from disk."
{TimePerformingReadRequests}
"TimePerformingReadRequests is the total amount of real time in milliseconds the page server has spent performing read requests for its client.  This statistic includes time reading pages from disk and time searching the shared page cache for pages."
{LocalCacheStalePcesRemovedCount}
"LocalCacheStalePcesRemovedCount is the number of stale page cache entries the process has removed from its private page cache lookup table.  Stale PCEs occur when a reference to page in the shared cache becomes invalid because the page is removed from the cache by another process."
{LocalCacheAllocatedPceCount}
"LocalCacheAllocatedPceCount is the number of page cache entries the process has allocated for collision chains."
{LocalCacheFreePceCount}
"LocalCacheFreePceCount is the number of page cache entries in the free pool"
{LocalCachePceCountLimit}
"LocalCachePceCountLimit is the maximum number of page cache entries the process will allocate before performing a reclaim."
{LocalCachePceReclaimCount}
"LocalCachePceReclaimCount is the number of page cache entry reclaim operations performed by the process."
{LocalCacheValidPcesRemovedCount}
"LocalCacheValidPcesRemovedCount is the number of valid page cache entries removed by a reclaim operation."
{PageServersInCacheCount}
"PageServersInCacheCount is the total number of page servers attached to the shared cache."
{SlotsRecoveredCount}
"SlotsRecoveredCount is the total number of slots the shared cache monitor has recovered because a client process shutdown abnormally."
{NumberOfScavenges}
"The number of scavenges executed by the in-memory garbage collector."
{NumberOfMarkSweeps}
"The number of mark/sweeps  executed by the in-memory garbage collector."
{NumSoftRefsCleared}
"Number of times the in-memory garbage collector has cleared the value instVar in instances of SoftReference."
{NumLiveSoftRefs}
"Number of instances of SoftReference in temporary object memory."
{NumNonNilSoftRefs}
"Number of instances of SoftReference in temporary object memory whose value is not nil and not a special object."
{NumRefsStubbedMarkSweep}
"The number of in-memory references that were stubbed (converted to a Pom objectId) by in-memory mark/sweep ."
{NumRefsStubbedScavenge}
"The number of in-memory references that were stubbed (converted to a Pom objectId) by in-memory scavenge."
{CodeGenGcCount}
"The number of times the code generation area has been garbage collected."
{PomGenScavCount}
"The number of times scavenge has thrown away the oldest pom generation space."
{NewGenSizeBytes}
"Number of used bytes in the new generation at the end of mark/sweep."
{TempObjSpacePercentUsed}
"Approximate percentage of the total reserved temporary object memory for this session which is in use.  Sessions will probably encounter an out of memory error if this value approaches or exceeds 100%.  This statistic is only updated at the end of a mark/sweep operation."
{GciRpcCommandsServiced}
"Number of GCI RPC commands serviced by this gem."
{OldGenSizeBytes}
"Number of used bytes in the old generation at the end of mark/sweep."
{PomGenSizeBytes}
"Number of used bytes in the pom generation at the end of mark/sweep. Pom generation holds clean copies of committed objects."
{PermGenSizeBytes}
"Number of used bytes in the perm generation at the end of mark/sweep. Perm generation holds copies of Classes."
{MeSpaceAllocatedBytes}
"Number of bytes allocated for remSet, in-memory oopMap and map entries."
{MeSpaceUsedBytes}
"Number of bytes occupied by remSet, in-memory oopMap and in-use map entries."
{WorkingSetSize}
"Number of objects in memory that have an objId assigned to them. Approximately
the number of committed objects in memory that have been faulted in or created and committed."
{SymbolCreationQueueSize}
"The number of sessions waiting for a Symbol creation request to be processed."
{FrameCount}
"FrameCount is the total number of frames in the shared page cache."
{SpinLockCount}
"SpinLockCount is the current seting of the configuration parameter SHR_SPIN_LOCK_COUNT.  It determines how many times a process will attempt to acquire a spin lock before sleeping on a semaphore."
{LogIOSlotCount}
"Number of slots available for asynchronous I/O operations for tranlog writes.  If this value drops below 3, the stone may have to wait for earlier asynchronous writes to complete before starting a new one.  This wait time is reported in TimeInLogIOWait."
{TimeInLogIOWait}
"The total amount of real time in milliseconds that the stone has had to wait for prior asynchronous tranlog writes to complete before starting a new one.  A high value here indicates problems with asynchronous writes on the stone machine."
{WaitsForOtherReader}
"PageRead operations avoided by waiting for read already in progress by another process."
{PagesNeedRemovingThreshold}
"Threshold for page manager to process the backlog described by PagesWaitingForRemovalInStoneCount." 
{PgsvrPid}
"Process ID of the session's pageserver (remote sessions only)."
{NumInPgsvrWaitQueue}
"Number of remote sessions logged out and waiting for their pgsvr process to die."
{NumInRemotePidQueryQueue}
"Number of sessions for which page manager is trying to determine existance."
{NumInRemoteKillQueue}
"Number of sessions that page manager is in the process of killing."
{PageManagerStarvedCount}
"Number of times the page manager session waited more than STN_PAGE_MGR_MAX_WAIT_TIME milliseconds for service from the stone."
{PageManagerMaxWaitTimeMs}
"The current value of the STN_PAGE_MGR_MAX_WAIT_TIME configuration option."
{HighWaterPageExtentId}
"The extent ID of the highest page ID that can be reclaimed by the reclaim gems.  This value is set by a gem performing a markGcCandidates (MGC) or full backup operation."
{HighWaterPageRecordId}
"The record ID of the highest page ID that can be reclaimed by the reclaim gems.  This value is set by a gem performing a markGcCandidates (MGC) or full backup operation."
{TimeInGetPagesForPageMgr}
"Total amount of time in milliseconds the stone spent processing requests from page manager for pages to remove from the cache."
{TimeInProcessPagesFromPageMgr}
"Total amount of time in milliseconds the stone spent processing pages removed from the cache by the page manager session."
}

set i 1
while {$i <= 47} {
    set statDocs(SessionStat$i) $statDocs(SessionStat0)
    set statDocs(VMStat$i) $statDocs(VMStat0)
    incr i
}

set i 0
while {$i <= 10} {
    set statDocs(sharedCounter$i) $statDocs(sharedCounter)
    incr i
}

# Every statDefinitions entry should also have a matching statDocs entry.
# Each StatDefinitions entry must be of the following form:
# {STATNAME} {TYPE LEVEL UNITS ISOS}
# where:
#  STATNAME is the name of the statistic
#  TYPE is one of the following: "counter" "uvalue" "svalue" "float"
#  LEVEL is one of the following: "common" "advanced" "wizard"
#  UNITS is a string that describes what the stat measures. Try to use
#    the same unit string of other stats.
#  ISOS is "true" if the statistic comes from the operating system
#    and is "false" if not.
array set statDefinitions {
    {InvalidPagesWrittenByGem} {uvalue advanced pages false}
    {RootPagesWrittenByGem} {uvalue advanced pages false} 
    {FragmentBmPagesWrittenByGem} {uvalue wizard pages false}
    {CommitRecordPagesWrittenByGem} {uvalue advanced pages false} 
    {DataPagesWrittenByGem} {uvalue advanced pages false}
    {OtInternalPagesWrittenByGem} {uvalue advanced pages false}
    {OtLeafPagesWrittenByGem} {uvalue advanced pages false} 
    {BmInternalPagesWrittenByGem} {uvalue advanced pages false}
    {BmLeafPagesWrittenByGem} {uvalue advanced pages false} 
    {EmptyBmLeafPagesWrittenByGem} {uvalue advanced pages false} 
    {MultObjPagesWrittenByGem} {uvalue wizard pages false}
    {RepBkupRestPagesWrittenByGem} {uvalue wizard pages false} 
    {CountBagLeafPagesWrittenByGem} {uvalue wizard pages false}
    {BitlistPagesWrittenByGem} {uvalue advanced pages false} 
    {OldBitlistPagesWrittenByGem} {uvalue advanced pages false} 
    {OldBitlistPagesWrittenByStone} {uvalue advanced pages false} 
    {OldBmInternalPagesWrittenByGem} {uvalue advanced pages false} 
    {OldBmInternalPagesWrittenByStone} {uvalue advanced pages false} 
    {OldBmLeafPagesWrittenByGem} {uvalue advanced pages false} 
    {OldBmLeafPagesWrittenByStone} {uvalue advanced pages false}
    {OldCommitRecordPagesWrittenByGem} {uvalue advanced pages false} 
    {OldCommitRecordPagesWrittenByStone} {uvalue advanced pages false} 
    {OldFragmentBmPagesWrittenByGem} {uvalue advanced pages false} 
    {OldFragmentBmPagesWrittenByStone} {uvalue advanced pages false} 
    {DeadDataPagesWrittenByGem} {uvalue wizard pages false}
    {CountMapLeafPagesWrittenByGem} {uvalue wizard pages false} 
    {CountBagInteriorPagesWrittenByGem} {uvalue wizard pages false}
    {LogRecordPagesWrittenByGem} {uvalue wizard pages false} 
    {Root40PagesWrittenByGem} {uvalue wizard pages false}
    {BackupRecordPagesWrittenByGem} {uvalue wizard pages false} 
    {LostOtPagesWrittenByGem} {uvalue wizard pages false} 
    {StonePidPagesWrittenByGem} {uvalue wizard pages false} 
    {InvalidPagesWrittenByStone} {uvalue advanced pages false}
    {RootPagesWrittenByStone} {uvalue advanced pages false} 
    {FragmentBmPagesWrittenByStone} {uvalue wizard pages false}
    {CommitRecordPagesWrittenByStone} {uvalue advanced pages false} 
    {DataPagesWrittenByStone} {uvalue advanced pages false}
    {OtInternalPagesWrittenByStone} {uvalue advanced pages false} 
    {OtLeafPagesWrittenByStone} {uvalue advanced pages false} 
    {BmInternalPagesWrittenByStone} {uvalue advanced pages false}
    {BmLeafPagesWrittenByStone} {uvalue advanced pages false} 
    {EmptyBmLeafPagesWrittenByStone} {uvalue advanced pages false} 
    {MultObjPagesWrittenByStone} {uvalue wizard pages false}
    {RepBkupRestPagesWrittenByStone} {uvalue wizard pages false} 
    {CountBagLeafPagesWrittenByStone} {uvalue wizard pages false}
    {BitlistPagesWrittenByStone} {uvalue advanced pages false} 
    {DeadDataPagesWrittenByStone} {uvalue wizard pages false}
    {CountMapLeafPagesWrittenByStone} {uvalue wizard pages false} 
    {CountBagInteriorPagesWrittenByStone} {uvalue wizard pages false}
    {LogRecordPagesWrittenByStone} {uvalue wizard pages false} 
    {Root40PagesWrittenByStone} {uvalue wizard pages false}
    {BackupRecordPagesWrittenByStone} {uvalue wizard pages false} 
    {LostOtPagesWrittenByStone} {uvalue wizard pages false} 
    {StonePidPagesWrittenByStone} {uvalue wizard pages false} 

    {SharedAttached} {uvalue common pages false}
    {TotalAttached} {uvalue common pages false}
    {AvgPercentShared} {svalue common pages false}
    {PagesRemovedForStone} {uvalue common pages false}
    {PagesPreempted} {uvalue common pages false}
    {PagesNotRemovedForStone} {uvalue advanced pages false}
    {PagesNotPreempted} {uvalue advanced pages false}
    {InUseByStoneTest} {uvalue wizard operations false}
    {RecoveredSlots} {uvalue wizard operations false}
    {SapServiceQueueSize} {uvalue wizard objects false}
    {SymbolCreationQueueSize} {uvalue common sessions false}
    {PagesWaitingForRemovalInSap} {uvalue advanced pages false}
    {PagesWaitingForRemovalInStoneCount} {uvalue advanced pages false}
    {RemoteCachesNeedServiceCount} {uvalue common requests false}
    {FreeFrameCount} {uvalue common frames false}
    {GemsInCacheCount} {uvalue common vms false}
    {LocalDirtyPageCount} {uvalue common pages false} 
    {GlobalDirtyPageCount} {uvalue common pages false} 
    {ActiveProcessCount} {uvalue common processes false} 
    {LastWakeupInterval} {uvalue common milliseconds false} 
    {SpinLockSmcQSleepCount} {uvalue common sessions false}
    {SpinLockNewSymSleepCount} {uvalue common sessions false}
    {SpinLockFreePceSleepCount} {uvalue common sessions false}
    {SpinLockFreeFrameSleepCount} {uvalue common sessions false}
    {SpinLockHashTableSleepCount} {uvalue common sessions false}
    {SpinLockPageFrameSleepCount} {uvalue common sessions false}
    {SpinLockSmuSleepCount} {uvalue common sessions false}
    {SpinLockSharedCtrSleepCount} {uvalue common sessions false}
    {SpinLockOtherSleepCount} {uvalue common sessions false}
    {PinnedPagesCount} {uvalue common pages false}
    {PinnedPrivatePagesCount} {uvalue common pages false}
    {PinnedDataPagesCount} {uvalue common pages false}
    {PinnedSharedCount} {uvalue common pages false}
    {PinnedOtPagesCount} {uvalue common pages false}
    {PinnedTotalCount} {uvalue common pages false}
    {RecentActiveProcessCount} {uvalue common processes false} 
    {FrameCount} {uvalue common frames false}
    {SpinLockCount} {uvalue common spins false}
    {TotalCommits} {counter common commits false}
    {TotalAborts} {counter common aborts false}
    {CommitRecordCount} {uvalue common "commit records" false}
    {AsyncWritesCount} {counter common operations false}
    {LogRecordsWritten} {counter common "log records" false}
    {LogRecordsIoCount} {counter common operations false}
    {CheckpointCount} {counter common checkpoints false} 
    {PagesNeedReclaimSize} {uvalue common pages false}
    {CommitQueueSize} {uvalue common sessions false}
    {LockReqQueueSize} {uvalue common sessions false}
    {NotifyQueueSize} {uvalue common sessions false}
    {LoginQueueSize} {uvalue common sessions false} 
    {RunQueueSize} {uvalue common sessions false}
    {SmcQueueSize} {uvalue common sessions false} 
    {PageWaitQueueSize} {uvalue common sessions false}
    {LogWaitQueueSize} {uvalue common sessions false} 
    {NumInSetLostOtQueue} {uvalue common sessions false}
    {ReclaimWaitQueueSize} {uvalue common sessions false} 
    {TempPagesDisposed} {counter common pages false}
    {PersistentPagesDisposed} {counter common pages false}
    {PageDisposesDeferred} {counter common operations false}
    {GsMsgCount} {counter wizard messages false}
    {GsMsgSessionId} {uvalue wizard sessions false}
    {GsMsgKind} {uvalue wizard enumeration false}
    {StnLoopState} {uvalue wizard enumeration false}
    {DeferCkptCompleteCount} {uvalue wizard commits false}
    {FailedAioCount} {counter common operations false}
    {CommitTokenSession} {uvalue common id false}
    {SessionWithOldestCr} {svalue common id false} 
    {SessionWithOldestCrNotInTrans} {svalue common id false} 
    {OldestCrSessNotInTrans} {svalue common id false}
    {RepositorySize} {uvalue common pages false}
    {PreparedCommits} {uvalue common sessions false}
    {HighWaterOop} {uvalue common none false} 
    {FreeOopCount} {counter common objects false}
    {SessionCount} {uvalue common sessions false} 
    {VmCount} {uvalue common vms false} 
    {ExtentCount} {uvalue common extents false} 
    {TranLogObjectLimit} {uvalue common objects false} 
    {ConcurrencyMode} {uvalue common enumeration false} 
    {CheckpointInterval} {uvalue common seconds false} 
    {HaltOnFatalError} {uvalue common "false or true" false} 
    {SessionTimeout} {uvalue common minutes false} 
    {TransactionTimeout} {uvalue common minutes false} 
    {SessionAbortTimeout} {uvalue common seconds false} 
    {SignalAbortCrBacklog} {uvalue common "commit records" false} 
    {MaxAioRate} {uvalue common ios/sec false} 
    {TargetPercentDirty} {uvalue common % false} 
    {FreeSpaceThreshold} {uvalue common megabytes false} 
    {DiskFullTerminationInterval} {uvalue common minutes false} 
    {MaxSessions} {uvalue common sessions false} 
    {OldestTranLogIdForRecovery} {svalue common id false} 
    {CurrentTranLogDirId} {svalue common id false} 
    {CurrentTranLogId} {svalue common id false} 
    {CurrentTranLogMaxSize} {uvalue common "log records" false} 
    {CurrentTranLogSize} {uvalue common "log records" false} 
    {TotalAbortSignalsSent} {counter common signals false}
    {TotalForcedAbortSignalsSent} {counter common signals false}
    {TotalSignalsSent} {counter common signals false}
    {TotalPagesAllocated} {counter common pages false}
    {TotalLocksGranted} {counter common locks false}
    {TotalLocksDenied} {counter common locks false}
    {CuQueueSize} {uvalue common sessions false} 
    {WaitingForSessionToVote} {uvalue common sessions false} 
    {TimeInStoneLoop} {counter wizard milliseconds false} 
    {TimeInStoneLoopRunQ} {counter wizard milliseconds false} 
    {TimeInStonePageDisposal} {counter common milliseconds false}
    {TimeUntilNextCheckpoint} {uvalue common seconds false} 
    {TimeInStoneLoopSleep} {counter wizard milliseconds false} 
    {StnLoopCount} {counter common operations false}
    {VoteState} {uvalue common enumeration false}
    {DeadObjsExist} {uvalue common "false or true" false}
    {SessionWithGcLock} {svalue common id false}
    {CheckpointIoRatio} {svalue common id false}
    {Spare2} {counter common operations false}
    {Spare3} {counter common operations false}
    {Spare4} {counter common operations false}
    {Spare5} {counter common operations false}

    {ExtentSize} {uvalue common kilobytes false}
    {ExtentFreeSpace} {uvalue common kilobytes false}
    {ExtentWeight} {uvalue common pages false}
    {ExtentReadOperations} {counter common operations false}
    {ExtentReadKBytes} {counter common kilobytes false}
    {ExtentWriteOperations} {counter common operations false}
    {ExtentWriteKBytes} {counter common kilobytes false}
    {ExtentPagesAllocated} {counter common pages false}

    {AioDirtyCount} {counter common pages false}
    {AioCkptCount} {counter common pages false}
    {AioWakeupInterval} {uvalue common milliseconds false} 
    {ClientPageReads} {counter common pages false}
    {ClientPageWrites} {counter common pages false}
    {PreemptedPagesCount} {counter common pages false}
    {PagesRemovedFromCacheCount} {counter common pages false}
    {PagesRemovedDirtyFromCacheCount} {counter common pages false}
    {PagesNotRemovedFromCacheCount} {counter common pages false}
    {PagesNotFoundInCacheCount}  {counter common pages false}
    {DirtyPageSweepCount} {counter common operations false}

    {ffPageNotFound} {counter wizard pages false}
    {ffCantGetFrameLock} {counter wizard pages false}
    {ffAioInProgress} {counter wizard pages false}
    {ffPageAttached} {counter wizard pages false}
    {ffPageIsDirty} { counter wizard pages false}
    {ffPageIsLocked} {counter wizard pages false}
    {ffWrap} {counter wizard operations false}
    {dPageNotFound} {counter wizard pages false}
    {dCantGetFrameLock} {counter wizard pages false}
    {dWrap} {counter wizard operations false}
    {chkpWrap} {counter wizard operations false}
    {dirtyCalls} {counter wizard operations false}
    {chkpCalls} {counter wizard operations false}
    {ffCalls} {counter wizard operations false}
    {preemptCalls} {counter wizard operations false}
    {statSampleCalls} {counter wizard operations false}
    {checkpointIoRatio} {uvalue wizard operations false}
    {maxIoPerSec} {uvalue wizard operations false}

    {Sessions} {uvalue common sessions false}
    {ClassesReadFromRepository} {counter common objects false} 
    {ObjMemSize} {uvalue common bytes false} 
    {FreeObjMemSize} {uvalue common bytes false} 
    {InUseObjMemSize} {uvalue common bytes false} 
    {NeedFinalizationCount} {counter common objects false} 
    {FinalizedCount} {counter common objects false} 
    {GcCount} {counter common scavenges false}
    {GcTime} {counter common milliseconds false}
    {FullGcCount} {counter common scavenges false}
    {FullGcTime} {counter common milliseconds false}
    {MethodsCompiled} {uvalue common items false}
    {PomObjsCount} {uvalue common objects false}
    {VmUserThreads} {uvalue common threads false}
    {CanonPomMapCollisions} {uvalue common objects false}
    {CanonPomMapEntries} {uvalue common objects false}
    {VoteSeqNumber} {uvalue common items false}
    {AllocatedPages} {uvalue common pages false}
    {PomScavCount} {counter common scavenges false}
    {Spare} {uvalue common operations false}
    {EJBHomesActivated} {counter common items false}
    {EJBInstancesAddedToPool} {counter common items false}
    {EJBInstancesTakenFromPool} {counter common items false}
    {EJBInstancesCreated} {counter common items false}
    {EJBInstancesPostCreated} {counter common items false}
    {EJBInstancesRemoved} {counter common items false}
    {EJBInstancesTimedOut} {counter common items false}
    {EJBInstancesDiscarded} {counter common items false}
    {EJBInstancesActivated} {counter common items false}
    {EJBInstancesPassivated} {counter common items false}
    {EJBFinderInstancesCreated} {counter common items false}
    {EJBFindersInvoked} {counter common operations false}
    {EJBFinderInstancesDestroyed} {counter common items false}
    {EJBSerializationTime} {counter common milliseconds false}
    {EJBSessionHandlesAcquired} {counter common items false}
    {EJBSessionHandleActivations} {counter common items false}
    {EJBEntityHandlesAcquired} {counter common items false}
    {EJBEntityHandlesActivations} {counter common items false}
    {EJBBusinessMethodInvocations} {counter common operations false}
    {EJBEntityContextsSet} {counter common operations false}
    {EJBEntityContextsUnset} {counter common operations false}
    {EJBSessionContextsSet} {counter common operations false}
    {EJBEntityLoads} {counter common operations false}
    {EJBEntityStores} {counter common operations false}
    {EJBSessionTxnAfterBegins} {counter common operations false}
    {EJBSessionTxnBeforeCompletions} {counter common operations false}
    {EJBSessionTxnAfterCompletions} {counter common operations false}
    {EJBGsSessionsCreated} {counter common sessions false}
    {EJBGsSessionsTerminated} {counter common sessions false}
    {EJBFreeGsSessionCount} {counter common sessions false}
    {EJBFreeGsSessionTime} {counter common milliseconds false}
    {EJBGetGsSessionCount} {counter common sessions false}
    {EJBGetGsSessionTime} {counter common milliseconds false}
    {EJBGsSessionPoolSize} {uvalue common sessions false}
    {EJBGsSessionsHandedOut} {counter common sessions false}
    {EJBGsSessionsReturned} {counter common sessions false}
    {EJBTransactionsSuspended} {counter common items false}
    {EJBTransactionsResumed} {counter common items false}
    {EJBBeansDeployed} {counter common items false}
    {EJBStubsServantsDeployed} {counter common items false}
    {EJBApplicationImportTime} {counter common milliseconds false}
    {EJBApplicationArtifactGenerationTime} {counter common milliseconds false}
    {EJBApplicationArtifactCompilationTime} {counter common milliseconds false}
    {EJBApplicationStubServantGenerationTime} {counter common milliseconds false}
    {EJBApplicationStubServantCompilationTime} {counter common milliseconds false}
    {EJBPreDispatchTime} {counter common milliseconds false}
    {EJBPostDispatchTime} {counter common milliseconds false}
    {JNDILookupTime} {counter common milliseconds false}
    {JNDILookups} {counter common operations false}
    {POACreateCount} {counter common items false}
    {POADeleteCount} {counter common items false}
    {ORBServantCount} {uvalue common items false}
    {ORBCurrentConnections} {uvalue common items false}
    {ORBRequestsCompleted} {counter common items false}
    {ORBRequestsSent} {counter common items false}
    {ORBRequestsReceived} {counter common items false}
    {ORBRequestBytesSent} {counter common bytes false}
    {ORBRequestBytesReceived} {counter common bytes false}
    {ORBRootPOAServantCount} {uvalue common items false}
    {ORBResponseWaitTime} {counter common milliseconds false}
    {ORBResponseBytesSent} {counter common bytes false}
    {ORBResponseBytesReceived} {counter common bytes false}
    {ORBRequestDurationTime} {counter common milliseconds false}
    {ActivationInitializers} {counter common items false}
    {ActivationInitializerTime} {counter common milliseconds false}
    {VMInitializers} {counter common items false}
    {VMInitializerTime} {counter common milliseconds false}
    {OTSTransactionsBegun} {counter common operations false}
    {OTSTransactionsCommitted} {counter common operations false}
    {OTSTransactionsRolledBack} {counter common items false}
    {OTSTransactionCommitTime} {counter common milliseconds false}
    {OTSTransactionTime} {counter common milliseconds false}
    {OTSResourcesRegistered} {counter common items false}
    {OTSSynchronizersRegistered} {counter common items false}
    {OTSReplayCompletionsIssued} {counter common operations false}
    {OTSResourcesTimedOut} {counter common items false}
    {JDBCConnectionPools} {uvalue common items false}
    {JDBCPooledConnections} {uvalue common items false}
    {JDBCPooledConnectionsInUse} {uvalue common items false}
    {JDBCGetConnectionTime} {counter common milliseconds false}
    {JDBCConnectionsRequested} {counter common items false}
    {JDBCConnectionsAcquired} {counter common items false}
    {JDBCCloseConnectionTime} {counter common milliseconds false}
    {JDBCExecuteQueryTime} {counter common milliseconds false}
    {JDBCExecuteUpdateTime} {counter common milliseconds false}
    {JDBCExecuteBatchTime} {counter common milliseconds false}
    {JDBCExecuteTime} {counter common milliseconds false}
    {JDBCConnectionsShared} {counter common items false}
    {JDBCConnectionsUnshared} {counter common items false}
    {JDBCGetConnectionCount} {counter common items false}
    {JDBCCloseConnectionCount} {counter common items false}
    {JDBCExecuteQueryCount} {counter common operations false}
    {JDBCExecuteUpdateCount} {counter common operations false}
    {JDBCExecuteBatchCount} {counter common operations false}
    {JDBCExecuteCount} {counter common operations false}
    {DependencyListCallbackCount} {counter common operations false}
    {DGCServantCount} {counter common items false}
    {DGCServantTime} {counter common milliseconds false}
    {DGCStubCount} {counter common items false}
    {DGCStubTime} {counter common milliseconds false}
    {RGCAuditThreadsActive} {uvalue common sessions false}
    {RGCAuditThreadsLimit} {uvalue common sessions false}
    {RGCDeadNotReclaimedSize} {uvalue common objects false} 
    {RGCDeadObjsCount} {counter common objects false}
    {RGCEpochCount} {counter common operations false} 
    {RGCEpochNewObjsSize} {uvalue common objects false}
    {RGCEpochScannedObjs} {uvalue common objects false}
    {RGCEpochPossibleDeadSize} {uvalue common objects false}
    {RGCEpochThreshold} {uvalue common pages false}
    {RGCEpochTime} {svalue common seconds false}
    {RGCEpochScheduledTime1} {svalue common seconds false}
    {RGCEpochScheduledTime2} {svalue common seconds false}
    {RGCEpochScheduledTime3} {svalue common seconds false}
    {RGCEpochScheduledTime4} {svalue common seconds false}
    {RGCEpochThreadsActive} {uvalue common sessions false}
    {RGCEpochThreadsLimit} {uvalue common sessions false}
    {RGCMaintThreadsActive} {uvalue common sessions false}
    {RGCMaintThreadsLimit} {uvalue common sessions false}
    {RGCMfcThreadsActive} {uvalue common sessions false}
    {RGCMfcThreadsLimit} {uvalue common sessions false}
    {RGCPagesNeedReclaiming} {uvalue common pages false}
    {RGCPossibleDeadSize} {uvalue common objects false}
    {RGCPossibleDeadWsUnionSize} {uvalue common objects false}
    {RGCReclaimCount} {counter common reclaims false}
    {RGCReclaimedPagesCount} {counter common pages false}
    {RGCReclaimNewDataPagesCount} {counter common pages false}
    {RGCReclaimPagesMax} {uvalue common pages false}
    {RGCReclaimPagesMin} {uvalue common pages false}
    {RGCReclaimSleepTime} {svalue common seconds false}
    {RGCReclaimThreadsActive} {uvalue common sessions false}
    {RGCReclaimThreadsLimit} {uvalue common sessions false}
    {RGCStatsPrintTime} {uvalue common seconds false}
    {RGCSweepCount} {counter common operations false}
    {RGCSweepThreadsActive} {uvalue common sessions false}
    {RGCSweepThreadsLimit} {uvalue common sessions false}
    {GcInReclaimAll} {uvalue common "false or true" false}
    {GcVoteUnderway} {uvalue common "false or true" false}
    {GcVoteState} {uvalue common state false}
    {ResponseTimeAverage} {uvalue common milliseconds false}
    {RequestLoadAverage} {uvalue common items false}
    {WebAdapterConnectionCloseCount} {counter common connections false}
    {WebAdapterConnectionOpenCount} {counter common connections false}
    {WebHttpSessionCreateCount} {counter common sessions false}
    {WebHttpSessionExpiredCount} {counter common sessions false}
    {WebHttpSessionInvalidatedCount} {counter common sessions false}
    {WebHttpSessionRemoveCount} {counter common sessions false}
    {WebJSPCompileCount} {counter common operations false}
    {WebJSPCompileTime} {counter common milliseconds false}
    {WebJSPParseTime} {counter common milliseconds false}
    {WebRequestsReceived} {counter common items false}
    {WebRequestsCompleted} {counter common items false}
    {WebRequestDurationTime} {counter common milliseconds false}
    {WebResponseBodyBytes} {counter common bytes false}
    {WebServletDestroyedCount} {counter common items false}
    {WebServletInitializedCount} {counter common items false}
    {GsConnectionAcquireCount} {counter common operations false}
    {GsConnectionAcquireTime} {counter common milliseconds false}
    {GsConnectionReleaseCount} {counter common operations false}
    {GsConnectionReleaseTime} {counter common milliseconds false}
    {IndexMaintenanceCount} {counter common operations false}
    {StatisticAgentNotifyCount} {counter common operations false}
    {StatisticAgentNotifyTime} {counter common milliseconds false}
    {StatisticAgentSampleCount} {counter common operations false}
    {StatisticAgentSampleTime} {counter common milliseconds false}
    {PooledSessionsCreated} {counter common sessions false}
    {SessionPoolSize} {uvalue common sessions false}
    {PooledSessionsReturned} {counter common sessions false}
    {PooledSessionsTerminated} {counter common sessions false}
    {PooledSessionWaitStartedCount} {counter common operations false}
    {PooledSessionWaitFinishedCount} {counter common operations false}
    {PooledSessionWaitTime} {counter common milliseconds false}
    {ActivationTime} {counter common milliseconds false}
    {Activations} {counter common operations false}
    {PreemptedDataPages} {counter common pages false}
    {PreemptedObjectTablePages} {counter common pages false}
    {PreemptedBitmapPages} {counter common pages false}
    {PreemptedCommitRecordPages} {counter common pages false}
    {PreemptedOtherPages} {counter common pages false}
    {ClockHandFrameId} {uvalue common frameId false}
    {PostCheckpointPages} {counter common pages false}
    {CommitCount} {counter common commits false}
    {FailedCommitCount} {counter common commits false}
    {AbortCount} {counter common aborts false}
    {ObjsCommitted} {counter common objects false}
    {NewObjsCommitted} {counter common objects false} 
    {ObjectsRead} {counter common objects false} 
    {ClassesRead} {counter common objects false} 
    {MethodsRead} {counter common objects false} 
    {ObjectsRefreshed} {counter common objects false} 
    {TimeWaitingForCommit} {counter common milliseconds false} 
    {PersistentPagesCommittedCount} {counter common pages false}
    {SleepDuringDisposeTempPageCount} {counter common operations false}
    {TimeProcessingCommit} {counter common milliseconds false}
    {TimeStoneCommit} {counter common milliseconds false} 
    {AbortSignalsSent} {counter common signals false}
    {AbortSignalsReceived} {counter common signals false}
    {ForcedAbortSignalsSent} {counter common signals false} 
    {ForcedAbortSignalsReceived} {counter common signals false}
    {MessagesToStone} {counter common messages false}
    {ProgressCount} {uvalue common objects false}
    {BytesCommittedCount} {counter common bytes false}
    {OmBytesFlushed} { counter common bytes false }
    {TransactionLevel} {svalue common enumeration false} 
    {TimeInGcNotConnected} {counter common milliseconds false} 
    {AttachDeltaPagesSatisfiedCount} {counter common pages false}
    {ShadowedPagesCount} {counter common pages false}
    {WorkingSetSize} {uvalue common objects false}
    {DirtyObjsSize} {uvalue common objects false}
    {ObjsReadCount} {counter common objects false}
    {FlushCount} {counter common operations false}
    {FlushedObjsCount} {counter common objects false}
    {PomMapCollisions} {uvalue common objects false}
    {PomMapEntries} {uvalue common objects false}
    {ClassMapEntries} {uvalue common objects false}
    {PomObjMapSize} {uvalue common items false}
    {PomClassMapSize} {uvalue common items false}
    {PrivatePageCacheSize} {uvalue common kilobytes false}
    {VoteNotDead} {uvalue common objects false}
    {VoteNotDeadSize} {uvalue common objects false}
    {ObjsReadWithTransientFields} {counter common objects false}
    {NativeThreadId} {uvalue common id false}
    {RcConflictCount} {counter common commits false}
    {AllSymbolsConflictCount} {counter common commits false}
    {CommitRetryFailureCount} {counter common commits false}
    {PageReadsWaitingForCommit} {counter common pages false}
    {PageReadsProcessingCommit} {counter common pages false}
    {PageReadsStoneCommit} {counter common pages false}
    {MessagesToStnWaitingForCommit} {counter common messages false}
    {MessagesToStnProcessingCommit} {counter common messages false}
    {MessagesToStnStoneCommit} {counter common messages false}
    {MessageKindToStone} {uvalue common operations false}
    {TimeWaitingForStone} {counter common milliseconds false} 
    {UpdateUnionsCommitCount} {counter common operations false} 
    {TimeInUpdateUnionsCommit} {counter common milliseconds false} 
    {RebuildScavPagesForCommitCount} {counter common operations false}
    {PageReadsRebuildScavPagesCommit} {counter common pages false}
    {MessagesToStnRebuildScavPagesCommit} {uvalue common operations false}
    {TimeInRebuildScavPagesCommit} {counter common milliseconds false} 
    {OldSpaceOverflowCount} {counter common operations false}
    {SessionStat0} {svalue common none false}
    {SessionStat1} {svalue common none false}
    {SessionStat2} {svalue common none false}
    {SessionStat3} {svalue common none false}
    {SessionStat4} {svalue common none false} 
    {SessionStat5} {svalue common none false}
    {SessionStat6} {svalue common none false}
    {SessionStat7} {svalue common none false}
    {SessionStat8} {svalue common none false}
    {SessionStat9} {svalue common none false} 
    {SessionStat10} {svalue advanced none false}
    {SessionStat11} {svalue advanced none false}
    {SessionStat12} {svalue advanced none false}
    {SessionStat13} {svalue advanced none false}
    {SessionStat14} {svalue advanced none false} 
    {SessionStat15} {svalue advanced none false}
    {SessionStat16} {svalue advanced none false}
    {SessionStat17} {svalue advanced none false}
    {SessionStat18} {svalue advanced none false}
    {SessionStat19} {svalue advanced none false} 
    {SessionStat20} {svalue advanced none false}
    {SessionStat21} {svalue advanced none false}
    {SessionStat22} {svalue advanced none false}
    {SessionStat23} {svalue advanced none false} 
    {SessionStat24} {svalue advanced none false} 
    {SessionStat25} {svalue advanced none false} 
    {SessionStat26} {svalue advanced none false} 
    {SessionStat27} {svalue advanced none false} 
    {SessionStat28} {svalue advanced none false} 
    {SessionStat29} {svalue advanced none false} 
    {SessionStat30} {svalue advanced none false} 
    {SessionStat31} {svalue advanced none false} 
    {SessionStat32} {svalue advanced none false} 
    {SessionStat33} {svalue advanced none false} 
    {SessionStat34} {svalue advanced none false} 
    {SessionStat35} {svalue advanced none false} 
    {SessionStat36} {svalue advanced none false} 
    {SessionStat37} {svalue advanced none false} 
    {SessionStat38} {svalue advanced none false} 
    {SessionStat39} {svalue advanced none false} 
    {SessionStat40} {svalue advanced none false} 
    {SessionStat41} {svalue advanced none false} 
    {SessionStat42} {svalue advanced none false} 
    {SessionStat43} {svalue advanced none false} 
    {SessionStat44} {svalue advanced none false} 
    {SessionStat45} {svalue advanced none false} 
    {SessionStat46} {svalue advanced none false} 
    {SessionStat47} {svalue advanced none false} 
    {VMStat0} {svalue common none false}
    {VMStat1} {svalue common none false}
    {VMStat2} {svalue common none false}
    {VMStat3} {svalue common none false}
    {VMStat4} {svalue common none false} 
    {VMStat5} {svalue common none false}
    {VMStat6} {svalue common none false}
    {VMStat7} {svalue common none false}
    {VMStat8} {svalue common none false}
    {VMStat9} {svalue common none false} 
    {VMStat10} {svalue advanced none false}
    {VMStat11} {svalue advanced none false}
    {VMStat12} {svalue advanced none false}
    {VMStat13} {svalue advanced none false}
    {VMStat14} {svalue advanced none false} 
    {VMStat15} {svalue advanced none false}
    {VMStat16} {svalue advanced none false}
    {VMStat17} {svalue advanced none false}
    {VMStat18} {svalue advanced none false}
    {VMStat19} {svalue advanced none false} 
    {VMStat20} {svalue advanced none false}
    {VMStat21} {svalue advanced none false}
    {VMStat22} {svalue advanced none false}
    {VMStat23} {svalue advanced none false} 
    {sharedCounter0} {svalue common none false}
    {sharedCounter1} {svalue common none false}
    {sharedCounter2} {svalue common none false}
    {sharedCounter3} {svalue common none false}
    {sharedCounter4} {svalue common none false} 
    {sharedCounter5} {svalue common none false}
    {sharedCounter6} {svalue common none false}
    {sharedCounter7} {svalue common none false}
    {sharedCounter8} {svalue common none false}
    {sharedCounter9} {svalue common none false} 
    {sharedCounter10} {svalue advanced none false}

    {UserTime} {counter common milliseconds true}
    {SysTime} {counter common milliseconds true}
    {MaxRSS} {counter common kilobytes true}
    {MajFlt} {counter common operations true}
    {MinorFaults} {counter common operations true}
    {SwapCount} {counter common operations true}
    {MsgSent} {counter common messages true}
    {MsgRecv} {counter common messages true}
    {VolCSW} {counter common operations true}
    {IVolCSW} {counter common operations true} 
    {SignalsReceived} {counter common signals true} 
    {InputBlocks} {counter common packets true}
    {OutputBlocks} {counter common packets true}
    {CharacterIO} {counter common bytes true}
    {SharedMemorySize} {uvalue common kilobytes true}
    {UnsharedDataSize} {uvalue common kilobytes true}
    {UnsharedStackSize} {uvalue common kilobytes true}
    {DataRSS} {uvalue common kilobytes true}
    {TextRSS} {uvalue common kilobytes true}
    {DataVmSize} {uvalue common kilobytes true}
    {PercentMemoryUsed} {uvalue common % true}
    {PercentCpuUsed} {uvalue common % true}
    {LwpTotalCount} {counter common threads true}
    {LwpCurCount} {uvalue common threads true}
    {HeapKBytes} {uvalue common kilobytes true}
    {StackKBytes} {uvalue common kilobytes true}
    {ImageKBytes} {uvalue common kilobytes true}
    {RSSKBytes} {uvalue common kilobytes true}
    {TrapTime} {counter common milliseconds true}
    {TextFaultSleepTime} {counter common milliseconds true}
    {DataFaultSleepTime} {counter common milliseconds true}
    {KernelFaultSleepTime} {counter common milliseconds true}
    {LockWaitSleepTime} {counter common milliseconds true}
    {AllOtherSleepTime} {counter common milliseconds true}
    {WaitCpuTime} {counter common milliseconds true}
    {StoppedTime} {counter common milliseconds true}
    {SystemCalls} {counter common operations true}
    {DataPages} {uvalue common pages true}
    {TextPages} {uvalue common pages true}
    {StackPages} {uvalue common pages true}
    {InOsWait} {uvalue common "false or true" false}
    {PrivatePages} {uvalue common pages true}
    {RealSharedMemoryPages} {uvalue common pages true}
    {RealMMFPages} {uvalue common pages true}
    {RealUandKPages} {uvalue common pages true}
    {RealDevIoPages} {uvalue common pages true}
    {VirtualTextPages} {uvalue common pages true}
    {VirtualDataPages} {uvalue common pages true}
    {VirtualStackPages} {uvalue common pages true}
    {VirtualSharedMemoryPages} {uvalue common pages true}
    {VirtualMMFPages} {uvalue common pages true}
    {VirtualUandKPages} {uvalue common pages true}
    {VirtualDevIoPages} {uvalue common pages true}
    {MaxOpenFd} {uvalue common items true}

    {UserTimeNT} {counter common milliseconds true}
    {PrivilegedTime} {counter common milliseconds true}
    {ProcessorTime} {counter common milliseconds true}
    {VirtualBytesPeak} {uvalue advanced bytes true}
    {VirtualBytes} {uvalue advanced bytes true}
    {PageFaults} {counter common operations true}
    {WorkingSetPeak} {uvalue advanced bytes true}
    {WorkingSet} {uvalue common bytes true}
    {PageFileBytesPeak} {uvalue advanced bytes true}
    {PageFileBytes} {uvalue advanced bytes true}
    {PrivateBytes} {uvalue advanced bytes true}
    {ThreadCount} {uvalue common threads true}
    {PriorityBase} {uvalue advanced priority true}
    {PoolPagedBytes} {uvalue advanced bytes true}
    {PoolNonpagedBytes} {uvalue advanced bytes true}
    {HandleCount} {uvalue common items true}

    {TotalFileReadOps} {counter common operations true}
    {TotalFileWriteOps} {counter common operations true}
    {TotalFileControlOps} {counter advanced operations true}
    {TotalFileDataOps} {counter common operations true}
    {TotalFileReadKBytes} {counter common kilobytes true}
    {TotalFileWriteKBytes} {counter common kilobytes true}
    {TotalFileControlKBytes} {counter wizard kilobytes true}
    {TotalContextSwitches} {counter advanced operations true}
    {TotalSystemCalls} {counter advanced operations true}
    {TotalInterrupts} {counter advanced operations true}
    {TotalProcessorTime} {counter common milliseconds true}
    {TotalUserTime} {counter common milliseconds true}
    {TotalPrivilegedTime} {counter common milliseconds true}
    {TotalDPCTime} {counter advanced milliseconds true}
    {TotalInterruptTime} {counter advanced milliseconds true}
    {TotalDPCsQueued} {counter advanced operations true}
    {TotalDPCRate} {uvalue advanced none true}
    {TotalDPCBypasses} {counter advanced operations true}
    {TotalAPCBypasses} {counter advanced operations true}
    {AlignmentFixups} {counter wizard operations true}
    {ProcessorQueueLength} {uvalue common threads true}
    {ExceptionDispatches} {counter wizard operations true}
    {FloatingEmulations} {counter wizard operations true}
    {RegistryQuotaInUse} {uvalue advanced % true}

    {AvailableBytes} {uvalue common bytes true}
    {CommittedBytes} {uvalue advanced bytes true}
    {CommitLimit} {uvalue advanced bytes true}
    {TotalPageFaults} {counter common operations true}
    {WriteCopies} {counter wizard operations true}
    {TransitionFaults} {counter wizard operations true}
    {CacheFaults} {counter wizard operations true}
    {DemandZeroFaults} {counter wizard operations true}
    {Pages} {counter common pages true}
    {PagesInput} {counter common pages true}
    {NtPageReads} {counter common operations true}
    {PagesOutput} {counter common pages true}
    {NtPageWrites} {counter common operations true}
    {TotalPoolPagedBytes} {uvalue advanced bytes true}
    {TotalPoolNonpagedBytes} {uvalue advanced bytes true}
    {PoolPagedAllocs} {counter wizard operations true}
    {PoolNonpagedAllocs} {counter wizard operations true}
    {FreeSystemPageTableEntries} {uvalue wizard items true}
    {CacheBytes} {uvalue advanced bytes true}
    {CacheBytesPeak} {uvalue advanced bytes true}
    {PoolPagedResidentBytes} {uvalue advanced bytes true}
    {SystemCodeTotalBytes} {uvalue advanced bytes true}
    {SystemCodeResidentBytes} {uvalue advanced bytes true}
    {SystemDriverTotalBytes} {uvalue advanced bytes true}
    {SystemDriverResidentBytes} {uvalue advanced bytes true}
    {SystemCacheResidentBytes} {uvalue advanced bytes true}
    {CommittedBytesInUse} {uvalue advanced % true}

    {Processes} {uvalue common processes true}
    {Threads} {uvalue common threads true}
    {Events} {uvalue common events true}
    {Semaphores} {uvalue common semaphores true}
    {Mutexes} {uvalue common mutexes true}
    {Sections} {uvalue common sections true}

    {Usage} {uvalue common % true}
    {UsagePeak} {uvalue common % true}

    {ThreadProcessorTime} {counter common milliseconds true}
    {ThreadUserTimeNT} {counter common milliseconds true}
    {ThreadPrivilegedTime} {counter common milliseconds true}
    {ContextSwitches} {counter common operations true}
    {PriorityCurrent} {uvalue common priority true}
    {ThreadPriorityBase} {uvalue advanced priority true}
    {StartAddress} {uvalue advanced none true}
    {ThreadState} {uvalue common enumeration true}
    {ThreadWaitReason} {uvalue common enumeration true}

    {BytesTotal} {counter common bytes true}
    {Packets} {counter common packets true}
    {PacketsReceived} {counter common packets true}
    {PacketsSent} {counter common packets true}
    {CurrentBandwidth} {uvalue common bits/sec true}
    {BytesReceived} {counter common bytes true}
    {PacketsReceivedUnicast} {counter advanced bytes true}
    {PacketsReceivedNonUnicast} {counter advanced packets true}
    {PacketsReceivedDiscarded} {uvalue common packets true}
    {PacketsReceivedErrors} {uvalue common packets true}
    {PacketsReceivedUnknown} {uvalue common packets true}
    {BytesSent} {counter common bytes true}
    {PacketsSentUnicast} {counter advanced packets true}
    {PacketsSentNonUnicast} {counter advanced packets true}
    {PacketsOutboundDiscarded} {uvalue common packets true}
    {PacketsOutboundErrors} {uvalue common packets true}
    {OutputQueueLength} {uvalue common packets true}

    {Segments} {counter common segments true}
    {ConnectionsEstablished} {uvalue common connections true}
    {ConnectionsActive} {counter common operations true}
    {ConnectionsPassive} {counter common operations true}
    {ConnectionFailures} {counter common operations true}
    {ConnectionsReset} {counter common operations true}
    {SegmentsReceived} {counter common segments true}
    {SegmentsSent} {counter common segments true}
    {SegmentsRetransmitted} {counter common segments true}

    {SentTcpBytes} {counter common bytes true}
    {RetransmittedTcpBytes} {counter common bytes true}
    {AcksSent} {counter advanced segments true}
    {DelayedAcksSent} {counter advanced segments true}
    {ControlSegmentsSent} {counter advanced segments true}
    {AcksReceived} {counter advanced segments true}
    {AckedBytes} {counter advanced bytes true}
    {DuplicateAcks} {counter advanced segments true}
    {AcksForUnsentData} {counter advanced segments true}
    {ReceivedInorderBytes} {counter advanced bytes true}
    {ReceivedOutOfOrderBytes} {counter advanced bytes true}
    {ReceivedDuplicateBytes} {counter advanced bytes true}
    {ReceivedPartialDuplicateBytes} {counter advanced bytes true}
    {RetransmitTimeouts} {counter common operations true}
    {RetransmitTimeoutDrops} {counter advanced connections true}
    {KeepAliveTimeouts} {counter advanced operations true}
    {KeepAliveProbes} {counter advanced operations true}
    {KeepAliveDrops} {counter advanced connections true}
    {ListenQueueFull} {counter advanced connections true}
    {HalfOpenQueueFull} {counter advanced connections true}
    {HalfOpenDrops} {counter advanced connections true}

    {FreeSpace} {uvalue common % true}
    {FreeMegabytes} {uvalue common megabytes true}
    {CurrentDiskQueueLength} {uvalue common items true}
    {DiskTime} {counter common milliseconds true}
    {DiskReadTime} {counter common milliseconds true}
    {DiskWriteTime} {counter common milliseconds true}
    {DiskTransfers} {counter common operations true}
    {DiskReads} {counter common operations true}
    {DiskWrites} {counter common operations true}
    {DiskKbytes} {counter advanced kilobytes true}
    {DiskReadKbytes} {counter advanced kilobytes true}
    {DiskWriteKbytes} {counter advanced kilobytes true}

    {CPUs} {uvalue common items true}
    {LoadAverage1} {float common threads true}
    {LoadAverage5} {float advanced threads true}
    {LoadAverage15} {float advanced threads true}
    {PhysicalMemory} {uvalue common megabytes true}
    {SchedulerRunCount} {counter advanced threads true}
    {SchedulerSwapCount} {counter advanced processes true}
    {SchedulerWaitCount} {counter advanced threads true}
    {FreeMemory} {uvalue common megabytes true}
    {ReservedSwap} {uvalue advanced megabytes true}
    {AllocatedSwap} {uvalue advanced megabytes true}
    {UnreservedSwap} {uvalue common megabytes true}
    {UnallocatedSwap} {uvalue advanced megabytes true}
    {PercentCpuActive} {uvalue common % true}
    {PercentCpuWaiting} {uvalue common % true}
    {PercentCpuIdle} {uvalue common % true}
    {PercentCpuUser} {uvalue advanced % true}
    {PercentCpuSystem} {uvalue advanced % true}
    {PercentCpuIOWait} {uvalue advanced % true}
    {PercentCpuSwapWait} {uvalue advanced % true}
    {PhysicalBlockReads} {counter common operations true}
    {PhysicalBlockWrites} {counter common operations true}
    {LogicalBlockReads} {counter common operations true}
    {LogicalBlockWrites} {counter common operations true}
    {RawIOReads} {counter common operations true}
    {RawIOWrites} {counter common operations true}
    {TotalCSW} {counter common operations true}
    {Traps} {counter advanced operations true}
    {Interrupts} {counter common operations true}
    {SystemReads} {counter advanced operations true}
    {SystemWrites} {counter advanced operations true}
    {SystemForks} {counter advanced operations true}
    {SystemVForks} {counter advanced operations true}
    {SystemExecs} {counter advanced operations true}
    {SystemSelects} {uvalue common operations true}
    {SystemFsReads}  {uvalue common operations true}
    {SystemFsWrites}  {uvalue common operations true}
    {SystemNfsReads}  {uvalue common operations true}
    {SystemNfsWrites}  {uvalue common operations true}
    {SystemNfsBytesRead}  {uvalue common operations true}
    {SystemNfsBytesWriten}  {uvalue common operations true}
    {MessageCount} {counter common operations true}
    {SemaphoreOps} {counter common operations true}
    {PathnameLookups} {counter advanced operations true}
    {InterruptsAsThreads} {counter advanced operations true}
    {InterruptsBlocked} {counter advanced operations true}
    {IdleThread} {counter advanced operations true}
    {TotalIVolCSW} {counter common operations true}
    {ThreadCreates} {counter common threads true}
    {ThreadMigrates} {counter advanced operations true}
    {CrossCalls} {counter advanced operations true}
    {FailedMutexEnters} {counter common operations true}
    {FailedReaderLocks} {counter common operations true}
    {FailedWriterLocks} {counter common operations true}
    {PhysicalAsyncBlockWrites} {counter advanced operations true}
    {ProcsInIOWait} {uvalue advanced processes true}
    {PageReclaims} {counter advanced operations true}
    {PageFreeReclaims} {counter advanced operations true}
    {PageIns} {counter advanced operations true}
    {PagesPagedIn} {counter common pages true}
    {PageOuts} {counter advanced operations true}
    {PagesPagedOut} {counter common pages true}
    {SwapIns} {counter advanced operations true}
    {PagesSwappedIn} {counter advanced pages true}
    {SwapOuts} {counter advanced operations true}
    {PagesSwappedOut} {counter common pages true}
    {ZeroFilledPages} {counter advanced pages true}
    {PagesFreedAutomatically} {counter advanced pages true}
    {PagesScanned} {counter common pages true}
    {PageDemonCycles} {counter advanced operations true}
    {HATMinorFaults} {counter advanced operations true}
    {UserMinorFaults} {counter advanced operations true}
    {MajorPageFaults} {counter common operations true}
    {CopyOnWriteFaults} {counter advanced operations true}
    {ProtectionFaults} {counter advanced operations true}
    {SoftwareLockFaults} {counter advanced operations true}
    {SystemMinorFaults} {counter advanced operations true}
    {PagerRuns} {counter advanced operations true}
    {ExecPagesPagedIn} {counter advanced pages true}
    {ExecPagesPagedOut} {counter advanced pages true}
    {ExecPagesFreed} {counter advanced pages true}
    {AnonymousPagesPagedIn} {counter advanced pages true}
    {AnonymousPagesPagedOut} {counter advanced pages true}
    {AnonymousPagesFreed} {counter advanced pages true}
    {FileSystemPagesPagedIn} {counter advanced pages true}
    {FileSystemPagesPagedOut} {counter advanced pages true}
    {FileSystemPagesFreed} {counter advanced pages true}

    {InputPackets} {counter common packets true}
    {OutputPackets} {counter common packets true}

    {InputErrors} {counter common items true}
    {OutputErrors} {counter common items true}
    {Collisions} {counter common items true}
    {InputBytes} {counter common bytes true}
    {OutputBytes} {counter common bytes true}
    {MulticastInputPackets} {counter advanced packets true}
    {MulticastOutputPackets} {counter advanced packets true}
    {BroadcastInputPackets} {counter advanced packets true}
    {BroadcastOutputPackets} {counter advanced packets true}
    {InputPacketsDiscarded} {counter advanced packets true}
    {OutputPacketsDiscarded} {counter advanced packets true}

    {ReadKBytes} {counter common kilobytes true}
    {WriteKBytes} {counter common kilobytes true}
    {ReadOperations} {counter common operations true}
    {WriteOperations} {counter common operations true}
    {WaitQueueLength} {float advanced operations true}
    {WaitQueueResponseTime} {float advanced milliseconds true}
    {WaitQueueServiceTime} {float advanced milliseconds true}
    {WaitQueueUtilization} {float common % true}
    {ActiveQueueLength} {float advanced operations true}
    {ActiveQueueResponseTime} {float advanced milliseconds true}
    {ActiveQueueServiceTime} {float advanced milliseconds true}
    {ActiveQueueUtilization} {float common % true}

    {SoftErrors} {counter advanced items true}
    {HardErrors} {counter advanced items true}
    {TransportErrors} {counter advanced items true}
    {MediaErrors} {counter advanced items true}
    {DeviceNotReady} {counter advanced items true}
    {NoDevice} {counter advanced items true}
    {Recoverable} {counter advanced items true}
    {IllegalRequest} {counter advanced items true}
    {PredictiveFailureAnalysis} {counter advanced items true}

    {UnswappableMemory} {uvalue common megabytes true}
    {LockedPages} {uvalue advanced pages true}
    {IOPages} {uvalue advanced pages true}
    {TotalPages} {uvalue advanced pages true}

    {AsyncWritesInProgress} {uvalue common operations false}


    {FreePages} {uvalue common pages false}
    {TimeInPgsvrNetReads} {counter common milliseconds false}
    {TimeInPgsvrNetWrites} {counter common milliseconds false}

    {PageReads} {counter common pages false}
    {PageIoCount} {counter common operations false}
    {PageWrites} {counter common pages false}

    {TimeWaitingForIo} {uvalue common milliseconds false}
    {PageIoTimeOverallAvg} {uvalue common microseconds false}
    {PageIoTime10SampleAvg} {uvalue common microseconds false}
    {PageIoTime100SampleAvg} {uvalue common microseconds false}

    {AttachedCount} {uvalue common pages false}
    {LocalPageCacheHits} {counter common operations false}
    {LocalPageCacheMisses} {counter common operations false} 
    {LocalPageCacheWrites} {counter common operations false}
    {MilliSecPerIoSample} {uvalue common none false}
    {FramesFromFreeList} {counter common frames false}
    {FramesAddedToFreeList} {counter common frames false}
    {FramesFromFindFree} {counter common frames false}
    {DataPageReads} {counter common pages false}
    {ObjTablePageReads} {counter common pages false}
    {BitMapPageReads} {counter common pages false}
    {BitmapPageReads} {counter common pages false}
    {OtherPageReads} {counter common pages false}
    {ObjectTableLookups} {counter common objects false}
    {PageSetDirtyCount} {counter common pages false}
    {FreeFrameLimit} {uvalue common frames false}

    {WebRequestAbortedCount} {counter common items false}
    {WebServletCurrentCount} {uvalue common items false}
    {WebServiceDurationTime} {counter common milliseconds false}
    {WebHttpSessionReapTime} {counter common milliseconds false}
    {WebHttpSessionCurrentCount} {uvalue common sessions false}
    {WebRequestCurrentCount} {uvalue common items false}
    {WebAdapterConnectionCurrentCount} {uvalue common connections false}
    {AttachDelta} {svalue common pages false}
    {NonSharedAttached} {svalue common pages false}
    {PrivateAttachLimit} {svalue common pages false}
    {NetWriteQueueSize} {uvalue common sessions false}
    {ORBUpcallCount} {uvalue common items false}
    {ORBQueuedRequests} {uvalue common items false}
    {AllSymbolsQueueSize} {uvalue common sessions false}
    {LwpCount} {uvalue common threads true}
    {Offset} {uvalue wizard none false}
    {IntSendCount} {counter common none false}
    {ClassCacheCount} {counter common none false}
    {MethodCacheCount} {counter common none false}
    {TimeInStnGetLocks} {counter common milliseconds false}
    {StnGetLocksCount} {counter common operations false}
    {TotalObjsCommitted} {counter common objects false}
    {TotalNewObjsCommitted} {counter common objects false}
    {timeCommitTokenHeld} {counter common milliseconds false}
    {VcCacheScavengesCount} {counter common operations false}
    {VcCacheSizeBytes} {uvalue common bytes false} 
    {CodeCacheSizeBytes} {uvalue common bytes false}
    {CodeCacheEntries} {uvalue common methods false}
    {CodeCacheStaleEntries} {uvalue common methods false} 
    {CodeCacheScavengesCount} {counter common operations false} 
    {NewSymbolsCount} {counter common symbols false} 
    {MarkSweepCount} {counter common operations false}
    {NewGenSizeBytes} {uvalue common bytes false}
    {TempObjSpacePercentUsed} {uvalue common % false}
    {GciRpcCommandsServiced} {counter common operations false}
    {OldGenSizeBytes} {uvalue common bytes false}
    {PomGenSizeBytes} {uvalue common bytes false}
    {PermGenSizeBytes} {uvalue common bytes false}
    {MeSpaceAllocatedBytes} {uvalue common bytes false}
    {MeSpaceUsedBytes} {uvalue common bytes false}
    {PomGenScavCount} {counter common operations false}
    {NumSoftRefsCleared} {counter common objects false}
    {NumLiveSoftRefs} {uvalue common objects false}
    {NumNonNilSoftRefs} {uvalue common objects false}
    {NumRefsStubbedScavenge} {counter common objects false}
    {NumRefsStubbedMarkSweep} {counter common objects false}
    {ScavengeCount} {counter common scavenges false}
    {TimeInScavenges} {counter common milliseconds false}
    {TimeInMarkSweep} {counter common milliseconds false}
    {CodeGenGcCount} {counter common operations false}
    {DeadObjCount} {counter common objects false} 
    {TrackedSetSize} {uvalue common objects false} 
    {DirtyListSize} {uvalue common objects false} 
    {MakeRoomInOldSpaceCount} {counter common operations false}
    {GcNotConnectedCount} {counter common operations false} 
    {GcNotConnectedDeadCount} {counter common objects false}
    {GcNotConnectedDeadCommittedCount} {counter common objects false}
    {DeferEpochThreshold} {uvalue common pages false}
    {ExportedSetSize} {uvalue common objects false}
    {NoRollbackSetSize} {uvalue common objects false} 
    {NotConnectedObjsSetSize} {uvalue common objects false}
    {InTransaction} {uvalue common none false}
    {GcPromoteDeadCount} {counter common objects false}
    {GcDeferPromoteDeadThreshold} {uvalue common pages false}
    {GcReclaimMaxPages} {uvalue common pages false}
    {Classes} {counter common objects false} 
    {ClassesFreed} {counter common objects false} 
    {JHandleMemSize} {uvalue common bytes false} 
    {FreeJHandleMemSize} {uvalue common bytes false} 
    {InUseJHandleMemSize} {uvalue common bytes false} 
    {ObjCount} {counter common objects false} 
    {GcObjCount} {counter common objects false}
    {DeadNotReclaimed} {uvalue common objects false}
    {DeadHandlesBufPoolSize} {uvalue common items false}
    {DeadPomHandleCount} {counter common objects false}
    {WorkOopMapSize} {uvalue common items false}

    {ReadCount} {counter common operations true}
    {WriteCount} {counter common operations true}
    {SeekCount} {counter common operations true}
    {TransferCount} {counter common operations true}
    {KBytesRead} {counter common kilobytes true}
    {KBytesWritten} {counter common kilobytes true}
    {KBytesTransferred} {counter common kilobytes true}

    {TimeWritingStats} {counter common milliseconds false}

    {SigAbortsSent} {counter common signals false}
    {SigAbortsReceived} {counter common signals false}
    {LostOtsSent} {counter common signals false}
    {LostOtsReceived} {counter common signals false}

    {CacheMisses} {uvalue wizard operations false}
    {CacheEvents} {uvalue wizard operations false}
    {CacheMissRatio} {uvalue wizard none false}
    {CacheAttachFactor} {uvalue wizard none false}
    {CacheDetachFactor} {uvalue wizard none false}

    {TimeInFramesFromFindFree} {counter common milliseconds false}
    {PageLocateCount} {counter common pages false}
    {ClientPid} {uvalue common none true}
    {GcEpochState} {uvalue wizard operations false}
    {GcReclaimState} {uvalue wizard operations false}
    {AioRateLimit} {uvalue common operations false}
    {AsyncFlushesInProgress} {uvalue common operations false}
    {CommitRecordsDisposedCount} {uvalue common records false}
    {DataSize} {uvalue common pages true}
    {DeadNotReclaimedSize} {uvalue common objects false}
    {DeadObjsCount} {counter common objects false}
    {DeadObjsReclaimedCount} {counter common objects false}
    {DetachAllPagesCount} {counter common operations false}
    {EpochGcCount} {counter common operations false}
    {EpochNewObjsSize} {uvalue common objects false}
    {EpochPossibleDeadSize} {uvalue common objects false}
    {EpochScannedObjs} {uvalue common objects false}
    {ExtentFlushCount} {counter common operations false}
    {FreeFrameCacheSize} {uvalue common frames false}
    {FreeFrameCacheNumFrames} {uvalue common frames false}
    {GcDeferEpochThreshold} {uvalue common pages false}
    {GcForceEpoch} {uvalue common none false}
    {EpochForceGc} {uvalue common none false}
    {GcPagesNeedReclaiming} {uvalue common pages false}
    {GcPossibleDeadSize} {uvalue common objects false}
    {GcPossibleDeadWsUnionSize} {uvalue common objects false}
    {GcReclaimNewDataPagesCount} {counter common pages false}
    {GcSweepCount} {counter common operations false}
    {GcWsUnionSweepCount}  {counter common operations false}
    {LocalCacheFreeFrameCount} {counter common frames false}
    {LocalCacheOverflowCount} {counter common operations false}
    {ObjectTablePageReads} {counter common pages false}
    {OldestCrSession} {svalue common sessions false}
    {PossibleDeadSize} {uvalue common objects false}
    {ReclaimCount} {counter common reclaims false}
    {ReclaimQueueSize} {uvalue common sessions false}
    {ReclaimedPagesCount} {counter common pages false}
    {RecoverCrBacklog} {uvalue common items false}
    {RecoverTranlogBlockId} {uvalue common id false}
    {RecoverTranlogFileId} {uvalue common id false}
    {TranlogRecordId} {uvalue common id false}
    {TranlogFileId} {uvalue common id false}
    {SessionNotVoted} {svalue common sessions false}
    {SigAbortCount} {counter common signals false}
    {SigLostOtCount} {counter common signals false}
    {StackSize} {uvalue common pages true}
    {StnValidateLocksCount} {counter common operations false}
    {TargetFreeFrameCount} {uvalue common frames false}
    {TextSize} {uvalue common pages true}
    {TimeInStnValidateLocks} {counter common milliseconds false}
    {TimeInUpdateUnionsInAbort} {counter common milliseconds false}
    {TimeInUpdateUnionsInCommit} {counter common milliseconds false}
    {TotalSessionsCount} {uvalue common sessions false}
    {UpdateUnionsInAbortCount} {counter common operations false}
    {UpdateUnionsInCommitCount} {counter common operations false}
    {StnLoopTimeInNetPoll} {counter advanced milliseconds false}
    {RemoteSessionCount} {svalue common sessions false}
    {AioRateMax} {uvalue common operations false}
    {CheckpointState} {svalue common state false}
    {CommitQueueAddedToRunQueueCount} {counter common operations false}
    {CommitQueueAddedToRunQueueSessionCount} {counter common operations false}
    {CommitQueueSessionNotReadyCount} {counter common operations false}
    {CommitQueueThreshold} {svalue common sessions false}
    {CommitRecordDisposalsDeferredCount} {counter common operations false}
    {CommitRecordDisposalState} {uvalue common operations false}
    {CommitRecordsReadAbortCount} {counter common operations false}
    {CommitRecordsReadCommitWithoutTokenCount} {counter common operations false}
    {CommitRecordsReadCommitWithTokenCount} {counter common operations false}
    {LoginRequestsCount} {counter common operations false}
    {NextSleepTime} {uvalue common milliseconds false}
    {RemovePagesFromCachesCount} {counter common operations false}
    {RemovePagesFromCachesPageCount} {counter common operations false}
    {SocketsPolledCount} {uvalue common operations false}
    {SocketsPolledOobCount} {uvalue common operations false}
    {SocketsReadyCount} {uvalue common operations false}
    {SocketsReadyOobCount} {uvalue common operations false}
    {StnLoopAioWaitCount} {counter common operations false}
    {StnLoopAioWaitTimedoutCount} {counter common operations false}
    {StnLoopAioWaitTime} {uvalue common milliseconds false}
    {StnLoopAioWaitTimedoutCount} {counter common operations false}
    {StnLoopFifoWakeupBytes} {counter common bytes false}
    {StnLoopFifoWakeupCount} {counter common operations false}
    {StnLoopHibernateCount} {counter common operations false}
    {StnLoopHibernateRealTime} {counter common milliseconds false}
    {StnLoopHibernateSleepTime} {counter common milliseconds false}
    {StnLoopHibernateSystemTime} {counter common milliseconds false}
    {StnLoopHibernateUserTime} {counter common milliseconds false}
    {StnLoopMaxSleepTime} {uvalue common milliseconds false}
    {StnLoopNetPollCount} {counter common operations false}
    {StnLoopNetPollOobCount} {counter common operations false}
    {StnLoopPollCount} {counter common operations false}
    {StnLoopPollInterruptCount} {counter common operations false}
    {StnLoopPollNoEventCount} {counter common operations false}
    {StnLoopPollNoSleepCount} {counter common operations false}
    {StnLoopPollTimeoutCount} {counter common operations false}
    {StnLoopsPerNetPoll} {uvalue common operations false}
    {StnLoopTimeInNetPollOob} {counter common milliseconds false}
    {StnLoopUpTime} {counter common seconds false}
    {StnOobSocketPollInterval} {svalue common seconds false}
    {StoneCommitState} {uvalue common operations false}
    {TimeInCommitRecordDisposal} {counter common milliseconds false}
    {TimeInNetPoll} {counter common milliseconds false}
    {StnLoopTimeInNetPollOob} {counter common milliseconds false}
    {TimeInRemovePagesFromCaches} {counter common milliseconds false}
    {RecoverTranlogFileId} {uvalue common things false}
    {RecoverTranlogBlockId} {uvalue common things false}
    {RecoverCrBacklog} {uvalue common things false}
    {GemHasCommitToken} {uvalue common things false}
    {TimePerformingCommit} {counter common milliseconds false}
    {RemoteSharedPageCacheCount} {uvalue common things false}
    {OopsReturnedByGemsCount} {counter common objects false}
    {PagesReturnedByGemsCount} {counter common pages false}
    {PageMgrPagesReceivedFromStoneCount} {counter common pages false}
    {PageMgrRemoveFromCachesCount}  {counter common pages false}
    {PageMgrRemoveFromCachesPageCount} {counter common pages false}
    {PageMgrPagesPendingRemovalRetryCount} {counter common operations false}
    {PageMgrPagesRemovedFromCachesCount} {counter common pages false}
    {PageMgrPagesNotRemovedFromCachesCount} {counter common pages false}
    {PageMgrRemovePagesFromCachesPollCount} {counter common operations false}
    {PageMgrTimeWaitingForCachePgsvrs} {counter common milliseconds false}
    {OopNumberHighWaterMark} {uvalue common objects false}
    {TimePerformingReadIo} {counter common milliseconds false}
    {TimePerformingReadRequests} {counter common milliseconds false}
    {LocalCacheStalePcesRemovedCount} {uvalue common PCEs false}
    {LocalCacheAllocatedPceCount} {uvalue common PCEs false}
    {LocalCacheFreePceCount} {uvalue common PCEs false}
    {LocalCachePceCountLimit} {uvalue common PCEs false}
    {LocalCachePceReclaimCount} {uvalue common operations false}
    {LocalCacheValidPcesRemovedCount} {uvalue common PCEs false}
    {PageServersInCacheCount} {uvalue common Pgsvrs false}
    {SlotsRecoveredCount} {uvalue common Slots false}
    {LogIOSlotCount} {uvalue common items false}
    {TimeInLogIOWait} {counter common milliseconds false}
    {WaitsForOtherReader} {counter common operations false}
    {PagesNeedRemovingThreshold} {uvalue common Pages false}
    {PgsvrPid} {uvalue common PID false}
    {NumInPgsvrWaitQueue}  {uvalue common Sessions false}
    {NumInRemotePidQueryQueue}  {uvalue common Sessions false}
    {NumInRemoteKillQueue}  {uvalue common Sessions false}
    {PageManagerStarvedCount} {counter common operations false}
    {PageManagerMaxWaitTimeMs} {uvalue common milliseconds false}
    {HighWaterPageExtentId} {uvalue common ID false}
    {HighWaterPageRecordId} {uvalue common ID false}
    {TimeInGetPagesForPageMgr} {counter common milliseconds false}
    {TimeInProcessPagesFromPageMgr} {counter common milliseconds false}
 }
# foreach i [array names statDefinitions] {
#     if {[llength $statDefinitions($i)] != 4} {
# 	puts "DEBUG: bad stat def for $i: $statDefinitions($i)"
#     }
# }
array set vsdhelp {
{Context Switch} {
An operating system context switch occurs when a thread is moved from executing to non-executing status. If a thread needs a non-cpu resource (disk, lock, semaphore, and timer are examples) then its called an [voluntary context switch > VolCSW Statistic]. If a thread still wants to execute but the operating system scheduler decides to preempt it so some other thread can execute then its called a [involuntary context switch > IVolCSW Statistic].
}
{Chart Window Features} {
Multiple chart windows can exist.

!Chart Information
   * [General Interface Features]
   * [Creating Chart Windows > How to Create a New Chart]

!Chart Menus
   * [Chart > Chart Window Chart Menu]
   * [Line > Chart Window Line Menu]

!Chart Controls
   * optional [X: > Chart Window X: Display]
   * optional [Y: > Chart Window Y: Display]
   * optional [Min: > Chart Window Min: Display]
   * optional [Max: > Chart Window Max: Display]
   * [Statistic Selector > Chart Window Statistic ComboBox]
   * [Filter Selector > Chart Window Filter MenuButton]
   * [Operator Selector > Chart Window Operator MenuButton]
   * [Number Entry > Chart Window Number Entry]
   * [Graph > Chart Window Graph]
}

{Chart Window X: Display} {
This display shows the time coordinate of the data point currently under the mouse pointer. The format of the displayed information it determined by [Chart Menu <b>Time Format</b> SubMenu].
This display will only exist if [Chart Menu <b>Show Current Values</b> Item] is on. 
This display is on each [chart window > Chart Window Features].
}
{Chart Window Y: Display} {
This display shows the value coordinate of the data point currently under the mouse pointer.
This display will only exist if [Chart Menu <b>Show Current Values</b> Item] is on. 
This display is on each [chart window > Chart Window Features].
}
{Chart Window Min: Display} {
This display shows the minimum value of the currently selected line's data points. Only data points displayed on the graph are considered (see [trimming > File Trimming] and [zooming > How to Zoom] to learn how to control what data points are displayed).
This display will only exist if [Chart Menu <b>Show Min and Max</b> Item] is on.
This display is on each [chart window > Chart Window Features].
}
{Chart Window Max: Display} {
This display shows the maximum value of the currently selected line's data points. Only data points displayed on the graph are considered (see [trimming > File Trimming] and [zooming > How to Zoom] to learn how to control what data points are displayed).
This display will only exist if [Chart Menu <b>Show Min and Max</b> Item] is on.
This display is on each [chart window > Chart Window Features].
}
{Chart Window Statistic ComboBox} {
This control allows you to change the statistic of the currently selected line. It also display the statistic of the currently selected line. Changing the selection will also update the [Statistic Information Window].

!Bindings
   * Clicking on a name with the <em>mouse</em> both selects it and causes it to become the current line's statistic.
   * The <em>down</em> arrow key selects the next statistic.
   * The <em>up</em> arrow key selects the previous statistic.
   * The <em>letter keys</em> select the next statistic whose first letter matches the key.
   * <tt>control-s</tt> starts a [search > List Search Control] which results in selecting a statistic.
   * <em>Return</em> causes the selected statistic to become the current line's statistic.
   * <em>Esc</em> cancels the change leaving the current line's statistic unchanged.
This combobox is on each [chart window > Chart Window Features].
}
{Chart Window Filter MenuButton} {
Displays the current line's filter and allows the filter to be changed. Possible filters are:
   * No Filter (None)
   * PerSecond
   * PerSample
   * Smooth
   * Aggregate
See [How to Filter Statistics] for a description of what each filter does.
This menu button is on each [chart window > Chart Window Features].
}
{Chart Window Operator MenuButton} {
Displays and sets the tranforming operation that will be applied to the current line using the value in the [number entry > Chart Window Number Entry]. The supported operations are:
   * <b>S</b>: [scale > Display Scaling a Line]; uses the line's <em>display scale</em> constant
   * <b>/</b>: [divide > Value Scaling a Line]; uses the line's <em>value scale</em> constant
   * <b>*</b>: [multiply > Value Scaling a Line]; uses the line's <em>value scale</em> constant
   * <b>+</b>: [add > Offsetting a Line]; uses the line's <em>offset</em> constant
   * <b>-</b>: [subtract > Offsetting a Line]; uses the line's <em>offset</em> constant
This menu button is on each [chart window > Chart Window Features].
}
{Chart Window Number Entry} {
This entry displays and sets numeric constants associated with the current line. Which constant is displayed is controlled by which operator is selected by the [operator menu button > Chart Window Operator MenuButton]. Each line has three constants:
   * a <em>display scale</em> used by the <b>S</b> operator.
   * a <em>value scale</em> used by the <b>/</b> and <b>*</b> operators.
   * an <em>offset</em> used by the <b>+</b> and <b>-</b> operators.
For the scale constants the up spinner button doubles the constant and the down spinner button halves the constant.
For the offset constant the up spinner button adds one to the constant and the down spinner subtracts one from the constant.
Scale constants can not be set to zero.
This entry is on each [chart window > Chart Window Features].
}

{Chart Window Graph} {
!Graph Controls
   * [Graph Display]
   * [X Axis]
   * [Left Y Axis]
   * [Right Y Axis]
   * optional [Graph Legend]
A graph is on each [chart window > Chart Window Features].
}

{Graph Display} {
Contains a graphical display of each line on the chart. An effort is made to give each line a unique color or style. The selected line's color is determined by the [Main Chart Menu <b>Selected Line Color...</b> Item].

Information about the current line is shown in the upper left corner of the graph. This information can be [disabled > Chart Menu Show Line Stats Item]. Two small red triangles at the bottom of the graph display indicate the range of data points used to calculate the line statistics. During [auto updating > File Menu Auto Update Item] this range will not automatically expand. To get it to expand <em>right click</em> in the graph display.

If [cross hairs > Chart Menu Show CrossHairs Item] are enabled then a single vertical and horizontal black line will be drawn and they will always intersect where the mouse points in the graph. If the mouse leaves the graph the cross hairs disappear.

If [grid lines > Chart Menu Show Grid Lines Item] are enabled then faint dashed lines are drawn from every axis tick.

!Bindings
   * <em>Left clicking</em> on a line will select it.
   * <em>Middle clicking</em> will do a [time zoom > How to Zoom].
   * <em>Right clicking</em> [zooms out > How to Zoom] one level.
   * <em>Moving</em> the mouse over a data point temporarily selects the line and [displays > Chart Menu Show Current Values Item] the data point's coordinates.
   * The <em>left</em> arrow key move a [zoom level > How to Zoom] one sample to the left.
   * The <em>right</em> arrow key move a [zoom level > How to Zoom] one sample to the right.
   * The <em>control-left</em> arrow key move a [zoom level > How to Zoom] to the left by however many time samples are in the graph.
   * The <em>control-right</em> arrow key move a [zoom level > How to Zoom] to the right by however many time samples are in the graph.
 
This display is on each [graph > Chart Window Graph].
}
{X Axis} {
The ticks on this axis are labeled with the time in a format determined by [Chart Menu <b>Time Format</b> SubMenu]. The labels reflect the data plotted in the graph of this axis. Each line's time coordinates are plotted on this axis.
This axis's title, if not [disabled > Chart Menu Show Time Axis Title Item], will show a description of the file the current line's data came from.
This axis is on each [graph > Chart Window Graph].
}
{Left Y Axis} {
The ticks on this axis are labeled with numbers that reflect the data plotted in the graph on this axis. Each line's values are plotted on either this axis or the other Y axis. An axis only exists if at least one line is plotted on it.
This axis's title, if not [disabled > Chart Menu Show Left Axis Title Item], will show a description of the current line's units if it was [plotted > Line Menu Graph on Left Axis Item] on the left axis.
This axis is on each [graph > Chart Window Graph].
}
{Right Y Axis} {
The ticks on this axis are labeled with numbers that reflect the data plotted in the graph on this axis. Each line's values are plotted on either this axis or the other Y axis. An axis only exists if at least one line is plotted on it.
This axis's title, if not [disabled > Chart Menu Show Right Axis Title Item], will show a description of the current line's units if it was [plotted > Line Menu Graph on Left Axis Item] on the right axis.
This axis is on each [graph > Chart Window Graph].
}
{Graph Legend} {
A graph's legend has an entry for every line on a graph. For each line the legend shows:
   * the line's unselected color
   * a description of the instance and statistic the line represents
   * the line's [symbol > Line Menu Symbol SubMenu]
A graph's legend can be [hidden > Chart Menu Show Legend Item] to save space. If it is hidden then a description of the current's line instance will be written in the upper left corner of the [graph > Graph Display]. Legends are very helpful so are usually not disabled. The best reason for disabling a legend is if your graph contains a large number of lines.

!Bindings
   * <em>Left clicking</em> on a legend entry toggles selection of that line.
   * <em>Middle clicking</em> on a legend entry deletes the line.

A legend is on each [graph > Chart Window Graph].
}
{Chart Window Chart Menu} {
Operations on this menu apply to the entire chart.
Configuration done with this menu will only effect its chart.\
For global configuration changes use the [main chart menu > Main Window Chart Menu].

[Selection Key > Keyboard Selection Keys]: <tt>Alt-c</tt>

This menu can be [torn off > Tear Off Menus].

This menu is on each [chart window > Chart Window Features].

!Items
   * [Add From Template > Chart Menu Add From Template SubMenu]
   * [Save Template > Chart Menu Save Template Item]
   * [Paste > Chart Menu Paste Item]
   * [Print > Chart Menu Print Item]
   * [Snapshot > Chart Menu Snapshot Item]
   * [Help... > Chart Menu Help... Item]
   * [Zoom In > Chart Menu Zoom In Item]
   * [Zoom Out > Chart Menu Zoom Out Item]
   * [Compare Two Points > Chart Menu Compare Two Points Item]
   * [Compute Scale All > Chart Menu Compute Scale All Item]
   * [Unscale All > Chart Menu Unscale All Item]
   * [Show Legend > Chart Menu Show Legend Item]
   * [Time Format > Chart Menu Time Format SubMenu]
   * [Show Time Axis Title > Chart Menu Show Time Axis Title Item]
   * [Show Left Axis Title > Chart Menu Show Left Axis Title Item]
   * [Show Right Axis Title > Chart Menu Show Right Axis Title Item]
   * [Show Current Values > Chart Menu Show Current Values Item]
   * [Show Min and Max > Chart Menu Show Min and Max Item]
   * [Show Line Stats > Chart Menu Show Line Stats Item]
   * [Show CrossHairs > Chart Menu Show CrossHairs Item]
   * [Show Grid Lines > Chart Menu Show Grid Lines Item]
   * [Close > Chart Menu Close Item]
}

{vsdsh} {
vsdsh is the text version if vsd. It allows scripts to be written that will load and process statmonitor data.
When vsdsh is started it will first attempt to load and interpret [Tcl code > Tcl Language] from the file <tt>~/.vsdshrc</tt>.
Then if it was given a file on the command line it will load and interpret it as [Tcl code > Tcl Language] and exit. Otherwise it display a prompt at which [Tcl code > Tcl Language] can be interactively entered. To exit back to the environment that started vsdsh type <tt>exit</tt>.
}
{Tcl Language} {
Tcl stands for tool command language. Tcl is pronounced <em>tickle</em>.\
Learn more about it at <tt><u>www.scriptics.com</u></tt>. For a quick overview\
of the language see:
   * <tt><u>http://www.scriptics.com/scripting/primer.html</u></tt>
   * <tt><u>http://www.scriptics.com/scripting/syntax.html</u></tt>
In the context of VSD and [vsdsh] the following extension to standard Tcl are available. These extensions tend to be valuable when writing scripting code that VSD or [vsdsh] will load:
   * [BLT Vectors]
   * [sltcl]
In the context of VSD the following additional extensions to standard Tcl are available. These extensions are used for GUI features are probably not of interest to those writing scripting code:
   * Tk
   * Tix
   * BLT
}
{BLT Vectors} {
!Synopsis
   * <tt>vector create</tt> <em>vecName</em> <em>?switches?</em>
   * <tt>vector destroy</tt> <em>vecName</em>
   * <tt>vector expr</tt> <em>expression</em>
   * <tt>vector names</tt> <em>?pattern...?</em>

!Description
The <tt>vector</tt> command creates a vector of floating poing values. The vector's values can be manipulated through a Tcl array variable or with Tcl commands.

!Introduction
A vector is simply an ordered set of numbers. The components of a vector are real numbers, indexed by counting numbers. 
Vectors are common data structures for many applications. For example, a graph may use two vectors to represent the X-Y coordinates of the data plotted. The graph will automatically be redrawn when the vectors are updated or changed. By using vectors, you can separate data analysis from the graph widget. This makes it easier, for example, to add data transformations, such as splines. It's possible to plot the same data to in multiple graphs, where each graph presents a different view or scale of the data. 
You could try to use Tcl's associative arrays as vectors. Tcl arrays are easy to use. You can access individual elements randomly by specifying the index, or the set the entire array by providing a list of index and value pairs for each element. The disadvantages of associative arrays as vectors lie in the fact they are implemented as hash tables. 
   * There's no implied ordering to the associative arrays. If you used vectors for plotting, you would want to insure the second component comes after the first, an so on. This isn't possible since arrays are actually hash tables. For example, you can't get a range of values between two indices. Nor can you sort an array. 
   * Arrays consume lots of memory when the number of elements becomes large (tens of thousands). This is because each element's index and value are stored as strings in the hash table The C programming interface is unwieldy. Normally with vectors, you would like to view the Tcl array as you do a C array, as an array of floats or doubles. But with hash tables, you must convert both the index and value to and from decimal strings, just to access an element in the array. This makes it cumbersome to perform operations on the array as a whole. 

The <tt>vector</tt> command tries to overcome these disadvantages while still retaining the ease of use of Tcl arrays. The <tt>vector</tt> command creates both a new Tcl command and associate array which are linked to the vector components. You can randomly access vector components though the elements of array. Not have all indices are generated for the array, so printing the array (using the <tt>parray</tt> procedure) does not print out all the component values. You can use the Tcl command to access the array as a whole. You can copy, append, or sort vector using its command. If you need greater performance, or customized behavior, you can write your own C code to manage vectors. 

!Examples
   * When you create a new vector you give it a name. Both a Tcl command and an array variable with that name are created. You can use either the command or variable to query or modify components of the vector. The number of components in a vector can be given when its created. By default they are initialized to zero. This example creates a vector named y that contains fifty components:  <tt>vector create y(50)</tt>
   * Indexing vector components
      * Vector components are indexed from zero. The vector's array variable can be used to read or set individual components. This example sets y's first element:  <tt>set y(0) 9.25</tt>
      * The array index must be a number less than the number of components. For example, it's an error if you try to set the 51st element of y:  <tt>puts "y has &#91;y length] components"; set y(50) 0.02</tt>
      * You can also specify a range of indices using a colon <tt>:</tt> to separate the first and last indices of the range. This example sets the first six components in y to 25.2:  <tt>set y(0:5) 25.2</tt>
      * If you don't include an index, then it will default to the first and/or last component of the vector. This example leaves out both indexes so it will print out all the components of y:  <tt>puts "y = $y(:)"</tt>  
      * Non-numeric Indices
         * <tt>end</tt> The index end, specifies the last component of the vector. It's an error to use this index if the vector is empty (length is zero).
         * <tt>++end</tt> The index ++end can be used to extend the vector by one component and initialize it to a specific value. You can't read from the array using this index, though. For example <tt>set y(++end) 0.02</tt> extends the vector by one component.
         * <tt>min</tt> The index min returns the component with the smallest value.
         * <tt>max</tt> The index max returns the component with the largest value.
   * To delete components from a vector, simply unset the corresponding array element. In the following example, the first component of y is deleted. All the remaining components of y will be moved down by one index as the length of the vector is reduced by one. Example: <tt>unset y(0); puts "new first element is $y(0)"</tt>
   * In this example a vector x is created without an initial length specification. In this case, the length is zero. The <b>set</b> operation resets the vector, extending it and setting values for each new component. The name of the vector is used as a command to set its component values given a list of them: <tt>vector create x; x set { 0.02 0.04 0.06 0.08 0.10 0.12 0.14 0.16 0.18 0.20}</tt>
   * The <b>range</b> operation lists the components of a vector between two indices. This example lists all the components in vector x: <tt>puts "x = &#91;x range 0 end]"</tt>
   * You can search for a particular value using the <b>search</b> operation. It returns a list of indices of the components with the same value. If no component has the same value, it returns "". This example finds the index of the components with the largest value: <tt>x search $x(max)</tt>
   * You can append vectors or new values onto an existing vector with the <b>append</b> operation. This example appends assorted vectors and values to x: <tt>x append x2 x3 { 2.3 4.5 } x4</tt>
   * The <b>sort</b> operation sorts the vector. If any additional vectors are specified, they are rearranged in the same order as the vector. For example, you could use it to sort data points represented by x and y vectors. In this example the vector x is sorted while the components of y are rearranged so that the original x,y coordinate pairs are retained: <tt>x sort y</tt>
   * The <b>expr</b> operation lets you perform arithmetic on vectors. The result is stored in the vector. This example adds y to x and then multiplies x by 2: <tt>x expr { x + y }; x expr { x * 2 }</tt>
   * When a vector is modified, resized, or deleted, it may trigger call-backs to notify the clients of the vector. For example, when a vector used in the graph widget is updated, the vector automatically notifies the widget that it has changed. The graph can then redrawn itself at the next idle point. By default, the notification occurs when Tk is next idle. This way you can modify the vector many times without incurring the penalty of the graph redrawing itself for each change. You can change this behavior using the <b>notify</b> operation. To make vector x notify after every change: <tt>x notify always</tt>. To turn off notification on vector x: <tt>x notify never</tt>. To force a notification now: <tt>x notify now</tt>.
   * To delete a vector, use the vector <b>delete</b> command. Both the vector and its corresponding Tcl command are destroyed. For example to remove vector x: <tt>vector destroy x</tt>

!Syntax
Vectors are created using the vector <b>create</b> operation. The create operation can be invoked in one of three forms: 
   * <tt>vector create</tt> <em>vecName</em>:  This creates a new vector <em>vecName</em> which initially has no components. 
   * <tt>vector create</tt> <em>vecName</em> <tt>(</tt><em>size</em><tt>)</tt>:  This form creates a new vector which will contain <em>size</em> number of components. The components will be indexed starting from zero <tt>(0)</tt>. The default value for the components is zero.
   * <tt>vector create</tt> <em>vecName</em> <tt>(</tt><em>first</em><tt>:</tt><em>last</em><tt>)</tt>: This form creates a new vector with components indexed <em>first</em> through <em>last</em>. <em>First</em> and <em>last</em> can be any integer value so long as <em>first</em> is less than <em>last</em>.

Vector names must start with a letter and consist of letters, digits, or underscores. 

You can automatically generate vector names using the <tt>#auto</tt> vector name. The <b>create</b> operation will return the unique vector name.

!Vector Indices
Vectors are indexed by integers. You can access the individual vector components via its array variable or Tcl command. The string representing the index can be an integer, a numeric expression, a range, or a special keyword.
The index must lie within the current range of the vector, otherwise an an error message is returned. Normally the indices of a vector are start from 0. But you can use the <b>offset</b> operation to change a vector's indices on-the-fly. 
You can also use numeric expressions as indices. The result of the expression must be an integer value. 
The following special non-numeric indices are available: <b>min</b>, <b>max</b>, <b>end</b>, and <b>++end</b>.
The indices <b>min</b> and <b>max</b> will return the minimum and maximum values of the vector.
The index <b>end</b> returns the value of the last component in the vector.
The index <b>++end</b> is used to append new value onto the vector. It automatically extends the vector by one component and sets its value.
A range of indices can be indicated by a colon <tt>:</tt> seperating two indices. The colon seperated indices can be integers, keywords, or empty. If no index is supplied the first or last component is assumed. 

For more information on BLT vectors get the public domain BLT distribution and see the <b>vector</b> man page or html file.
}

{sltcl} {
The sltcl set of commands all start with the <tt>sl_</tt> prefix. These are the actual commands used to read statmon files and convert their data to [vectors > BLT Vectors].
!Builtin Commands
   * [sl_create]
   * [sl_stat]
   * [sl_kill]
}

{Instance List Data} {
For each instance a sublist of the following exists:
   1 instance name
   1 object name
   1 start time
   1 isActive
   1 sample count
   1 file id
   1 instanceId
}

{Data File Commands} {
Whenever a file is created with [sl_create -file > sl_create] a new Tcl data file command is created. File commands support the following options:
   * <b>-info</b>: return a list of information about the file. The list has the following items:
      1 name
      1 version
      1 platform
      1 productVersion
      1 machine
      1 time string
      1 estimated sampleInterval
      1 isEnabled
      1 list of object types
      1 first timestamp
      1 trimLeft timestamp
      1 trimRight timestamp
   * <b>-instancecount</b>: returns the number of instances the file has.
   * <b>-instances</b>: returns a list of all the files instances. See [Instance List Data] for a description of the result.
   * <b>-objinstances</b> <em>objName</em>: returns a list of all the files instances of the named object type. See [Instance List Data] for a description of the result.
   * <b>-free</b>: frees up all resources used by loading the file and deletes the command.
   * <b>-dump</b>: dump the internal data structures, that contain the files data, in a printable form, to stdout.
   * <b>-update</b>: rereads the file to so if it has more data that can be read. This can be used to continue an interrupted create or read more data from a file that has grown.
   * <b>-disable</b>: Act as if the file has not been loaded.
   * <b>-enable</b>: Act as if the file has been loaded.
   * <b>-trimleft</b> <em>timeStamp</em>: Trim all of the data collected before the timestamp from the file. See [File Trimming] for more information.
   * <b>-trimright</b> <em>timeStamp</em>: Trim all of the data collected after the timestamp from the file. See [File Trimming] for more information.
   * <b>-append</b> <em>fileName</em>: causes this file to start reading the new named file onto the end of the current data. The new files data needs to be newer than the current data. Also the current file needs to be fully loaded.
}

{Line Commands} {
Whenever a file is created with [sl_create -line > sl_create] or [sl_create -derivedline > sl_create] a new Tcl line command is created. Line commands support the following options:
   * <b>-info</b>: return a list of information about the line. The list has the following items:
      1 instance name
      1 statistic name
      1 x vector name
      1 y vector name
      1 scale
      1 filter
      1 object name
      1 fileId list
      1 source list
      1 combo operator
      1 instId
      1 isNormalized
      1 normalize offset
      1 divider
   * <b>-changectr</b> <em>statName</em>: changes the line's statistic.
   * <b>-refilter</b> <em>filter</em>: changes the line's filter.
   * <b>-scale</b> <em>number</em>: scales the y values by <em>number</em>.
   * <b>-adder</b> <em>number</em>: offset the y values by <em>number</em>.
   * <b>-divider</b> <em>number</em>: divides the y values by <em>number</em>.
   * <b>-normalize</b>: forces the min y value to always be zero by subtracting to raw y min value from every y data point.
   * <b>-unnormalize</b>: undoes any normalization.
   * <b>-stats</b> <em>ts1 ts2</em>: returns a list of stats for y data between the specified timestamps. This returned list is:
      1 total number of samples in the range
      1 minimum y value in the range
      1 maximum y value in the range
      1 average of all y values in the range
      1 standard deviation of all y values in the range
      1 first actual timestamp in the range
      1 last actual timestamp in the range
   * <b>-trimleft</b> <em>timeStamp</em>: Trim all of the data collected before the timestamp from all the files used to make the line. See [File Trimming] for more information.
   * <b>-trimright</b> <em>timeStamp</em>: Trim all of the data collected after the timestamp from all the files used to make the line. See [File Trimming] for more information.
   * <b>-copy</b>: copies a line and returns the name of the copies line command.
   * <b>-free</b>: frees up all the resources used by the line and deletes the command.
}

{sl_create} {
The sl_create command lets you create [Data File Commands] and [Line Commands].
!Usages
   * <b>sl_create -file</b> <em>filename</em> ?<em>progressCallback</em>?: Creates a [Data File Commands] by loading the named statmon file. Returns the name of the created [command > Data File Commands]. If a progress callback is specified then it must be a Tcl proc that takes a single argument which is an integer in the range 0..100. The callback will always be called with a value of 100 when reading is complete. The callback should return 1 if loading should continue and 0 if it should be interrupted.
   * <b>sl_create -line</b> <em>instIdList statName filter isAbsolute</em>: Creates a [line > Line Commands] for the given instances and statistic name, and using the given [filter > Statistic Definitions]. Returns the name of the created [command > Line Commands]. If more than one instance is given then their data is all [combined > Main Menu Combine Item] together. The <em>isAbsolute</em> boolean determines if the time data for the created line will be [absolute or relative > Main Menu Absolute TimeStamps Item].
   * <b>sl_create -derivedline</b> <em>lineList</em> <b>+|-|/</b> <em>filter copyChildren</em>: Creates a [line > Line Commands] for the given lines using the given operator,and [filter > Statistic Definitions]. Returns the name of the created [command > Line Commands].  The <em>copyChildren</em> boolean determines if the input lines will be [copied or referenced > Main Menu Copy Referenced Lines Item]. For more information see [Line Arithmetic].
}

{sl_stat} {
The sl_stat command is used to perform global operations that are not limited to a particular data file.
!Usages
   * <b>sl_stat -names</b>: Returns a list of all known statistic names.
   * <b>sl_stat -enabledinstances</b>: Returns a list of instances from all the enabled files. See [Instance List Data] for a description of the result.
   * <b>sl_stat -enabledobjinstances</b> <em>objTypeList</em>: Returns a list of instances from all the enabled files of the given obj types. See [Instance List Data] for a description of the result.
   * <b>sl_stat -ctrzero</b> <em>statName instIdList</em>: Returns boolean indicating if named statistic is zero for all the given instances.
   * <b>sl_stat -enabledfiles</b>: Returns a list of [files > Data File Commands] that are enabled.
   * <b>sl_stat -allfiles</b>: Returns a list of all the [files > Data File Commands] that are loaded.
   * <b>sl_stat -alias</b> <em>oldname newname</em>: Causes the statistic <em>newname</em> to be used whenever <em>oldname</em> is found in a loaded statmon file.
   * <b>sl_stat -info</b> <em>name</em> ?<em>infolist</em>?: Returns a list of information on the named statistic. If the optional <em>infolist</em> exists then it must have at most three elements. Empty elements will be ignored. Non-empty ones will modify that value in the statistic's definition:
      1 statistic's [kind > Statistic Definitions]
      1 statistic's [level > Statistic Definitions]
      1 statistic's [default filter > Statistic Definitions]
          The result list has the following elements:
      1 statistic's [kind > Statistic Definitions]
      1 statistic's [level > Statistic Definitions]
      1 statistic's [default filter > Statistic Definitions]
      1 possible empty list of object types that use the statistic
   * <b>sl_stat -level</b> ?<em>levelname</em>?: With no argument returns the current statistic level. Otherwise sets the statistic level. See [Main Menu Statistic Level SubMenu].
   * <b>sl_stat -getdate</b> <em>ts</em> ?<b>elapsed</b>|<b>date</b>|<b>time</b>?: Given a timestamp convert it to a formatted string and return it. In no format is specified it defaults to <tt>date</tt>.
   * <b>sl_stat -objctrs</b> <em>objList</em>: returns a list of statistic names for the given object types.
   * <b>sl_stat -instinfo</b> <em>instId</em>: returns data describing the given instance id. See [Instance List Data] for a description of the result.
}
{sl_kill} {
The sl_kill command can be usd to kill a process. Vsd uses it to stop a statmonitor it is managing.
!Usages
   * <b>sl_kill</b> <em>pid</em>: kills the process with the given pid.
}

{VSD Files} {
The following files are created by VSD:
   * <u><tt>~/.vsdrc</tt></u> The <em>memory file</em> is written each time VSD exits. Its read\
each time VSD starts. VSD uses it to remember its configuration. Deleting it\
will force VSD back to its factory settings.
   * <u><tt>~/.vsdconfig</tt></u> The <em>config file</em> is never written be VSD. Its read\
and interpreted each time VSD is started. It can be used to reconfigure VSD's\
defaults. Its syntax is [Tcl > Tcl Language].
   * <u><tt>~/.vsdtemplates</tt></u> The <em>template file</em> is read when VSD is started\
and any time the [Template Menu <b>Reload Template File</b> Item] is selected.\
Its written whenever the [Chart Menu <b>Save Template</b> Item] is selected.\
See [Template Syntax] for a description of its contents.
   * <u><tt>bin/vsd</tt></u> The <em>source file</em> is never written be VSD. Its read and interpreted each time VSD is started. It contains most of VSD's implementation. Its syntax is [Tcl > Tcl Language].
   * <u><tt>bin/vsdwish</tt><em>OS</em></u> The <em>binary file</em> is never written be VSD. Its used to start VSD. Its the virtual machine that interprets the [Tcl > Tcl Language] code. The <em>OS</em> part of the name is a platform dependent suffix that names the operating system the binary file will run on.

The <tt>~</tt> represents your home directory. If you are not sure what\
directory VSD is using as your home you can see the absolute paths to these files [here > About VSD].
}

{CacheTooSmall Template} {
The intent of this template is to give you the statistics that will allow you to determine if the shared page cache needs to be made larger.
   * [FreeFrameCount > FreeFrameCount Statistic] for each [shrpc > Shrpc Type] on the [Right Y Axis].
   * [FramesFromFindFree > FramesFromFindFree Statistic] for each [shrpc > Shrpc Type].
   * [FramesFromFreeList > FramesFromFreeList Statistic] for each [shrpc > Shrpc Type]

See [Shared Page Cache Health] for help on shared page cache sizing. 
}

{CommitInfo Template} {
The intent of this template is to give a picture of the overall transactional throughput.
   * [TotalCommits > TotalCommits Statistic] for each [stone > Stn Type].
   * [CommitRecordCount > CommitRecordCount Statistic] for each [stone > Stn Type] on the [Right Y Axis].
   * [CommitQueueSize > CommitQueueSize Statistic] for each [stone > Stn Type] on the [Right Y Axis].
}

{EpochSweeps Template} {
The intent of this template is to show statistics related to repository epoch garbage collection.
   * [EpochCount > EpochCount Statistic] by [combining > Main Menu Combine Item] all [stone > Stn Type].
   * [EpochScannedObjs > EpochScannedObjs Statistic] by [combining > Main Menu Combine Item] all [stone > Stn Type] on the [Right Y Axis].
   * [EpochNewObjsSize > EpochNewObjsSize Statistic] by [combining > Main Menu Combine Item] all [stone > Stn Type] on the [Right Y Axis].
   * [EpochPossibleDeadSize > EpochPossibleDeadSize Statistic] by [combining > Main Menu Combine Item] all [stone > Stn Type] on the [Right Y Axis].
   * [PossibleDeadSize > PossibleDeadSize Statistic] by [combining > Main Menu Combine Item] all [stone > Stn Type] on the [Right Y Axis].
}

{Garbage Template} {
The intent of this template is to give a picture of the overall repository garbager collection activity.
   * [PagesNeedReclaimSize > PagesNeedReclaimSize Statistic] by [combining > Main Menu Combine Item] all [stone > Stn Type] on the [Right Y Axis].
   * [ReclaimedPagesCount > ReclaimedPagesCount Statistic] by [combining > Main Menu Combine Item] all [stone > Stn Type] on the [Right Y Axis].
   * [EpochCount > EpochCount Statistic] by [combining > Main Menu Combine Item] all [stone > Stn Type].
   * [ReclaimCount > ReclaimCount Statistic] by [combining > Main Menu Combine Item] all [stone > Stn Type].
   * [CommitCount > CommitCount Statistic] by [combining > Main Menu Combine Item] all [sessions > Session Type] named <b>*Gc</b>.
}

{PageServer Template} {
This template gives a picture of the overall async-io done by page servers.
   * [AioDirtyCount > AioDirtyCount Statistic] by [combining > Main Menu Combine Item] all [page servers > Pgsvr Type].
   * [AioCkptCount > AioCkptCount Statistic] by [combining > Main Menu Combine Item] all [page servers > Pgsvr Type].
   * [LocalDirtyPageCount > LocalDirtyPageCount Statistic] for each [shrpc > Shrpc Type].

See [AIO page servers] for more information.
}

{SpaceFree Template} {
This template gives you the statistics that allow you to determine how much of a resource is available. Currently the only resources supported by this template are the shared page cache and the object repository.
   * [FreeFrameCount > FreeFrameCount Statistic] for each [shrpc > Shrpc Type].
   * [FreePages > FreePages Statistic] for each [stone > Stn Type] on the [Right Y Axis].

See [Shared Page Cache Health] for help on shared page cache sizing. 
}

{CPU Template} {
This template gives a picture of overall CPU usage. It shows one set of statistics for Solaris, and another for NT.
!Solaris
   * [UserTime > UserTime Statistic] by [combining > Main Menu Combine Item] all instances.
   * [PercentCpuActive > PercentCpuActive Statistic] for each [Solaris system > SolarisSystem Type] on the [Right Y Axis].
   * [PercentCpuWaiting > PercentCpuWaiting Statistic] for each [Solaris system > SolarisSystem Type] on the [Right Y Axis].
!Windows NT
   * [SysTime > SysTime Statistic] by [combining > Main Menu Combine Item] all instances.
   * [TotalProcessorTime > TotalProcessorTime Statistic] for each [NT system > NtSystem Type].
   * [ProcessorQueueLength > ProcessorQueueLength Statistic] for each [NT system > NtSystem Type] on the [Right Y Axis].
}

{CacheMix Template} {
The intent of this template is to give a picture of the overall [Shared Page Cache Health]. When you bring up this template, the following stats are displayed:
   * [FreeFrameCount > FreeFrameCount Statistic] for each [shrpc > Shrpc Type] on the [Right Y Axis].
   * [LocalDirtyPageCount > LocalDirtyPageCount Statistic] for each [shrpc > Shrpc Type]
   * [FreeFrameLimit > FreeFrameLimit Statistic] for each [shrpc > Shrpc Type]
   * [BitlistPagesWrittenByGem > BitlistPagesWrittenByGem Statistic] for each [shrpc > Shrpc Type]
   * [BitlistPagesWrittenByStone > BitlistPagesWrittenByStone Statistic] for each [shrpc > Shrpc Type]
   * [BmInternalPagesWrittenByGem > BmInternalPagesWrittenByGem Statistic] for each [shrpc > Shrpc Type]
   * [BmInternalPagesWrittenByStone > BmInternalPagesWrittenByStone Statistic] for each [shrpc > Shrpc Type]
   * [BmLeafPagesWrittenByGem > BmLeafPagesWrittenByGem Statistic] for each [shrpc > Shrpc Type]
   * [BmLeafPagesWrittenByStone > BmLeafPagesWrittenByStone Statistic] for each [shrpc > Shrpc Type]
   * [CommitRecordPagesWrittenByGem > CommitRecordPagesWrittenByGem Statistic] for each [shrpc > Shrpc Type]
   * [CommitRecordPagesWrittenByStone > CommitRecordPagesWrittenByStone Statistic] for each [shrpc > Shrpc Type]
   * [DataPagesWrittenByGem > DataPagesWrittenByGem Statistic] for each [shrpc > Shrpc Type]
   * [OtInternalPagesWrittenByGem > OtInternalPagesWrittenByGem Statistic] for each [shrpc > Shrpc Type]
   * [OtInternalPagesWrittenByStone > OtInternalPagesWrittenByStone Statistic] for each [shrpc > Shrpc Type]
   * [OtLeafPagesWrittenByGem > OtLeafPagesWrittenByGem Statistic] for each [shrpc > Shrpc Type]
   * [OtLeafPagesWrittenByStone > OtLeafPagesWrittenByStone Statistic] for each [shrpc > Shrpc Type]
}

{Shared Page Cache} {
The SPC serves three types of data to the processes attached to the cache:

   * data pages
      * [DataPagesWrittenByGem > DataPagesWrittenByGem Statistic]
   * object table pages
      * [OtInternalPagesWrittenByGem > OtInternalPagesWrittenByGem Statistic]
      * [OtLeafPagesWrittenByGem > OtLeafPagesWrittenByGem Statistic]
   * commit record pages
      * [BitlistPagesWrittenByGem > BitlistPagesWrittenByGem Statistic]
      * [BmInternalPagesWrittenByGem > BmInternalPagesWrittenByGem Statistic]
      * [BmLeafPagesWrittenByGem > BmLeafPagesWrittenByGem Statistic]
      * [CommitRecordPagesWrittenByGem > CommitRecordPagesWrittenByGem Statistic]

There is a smattering of other types of data in the cache, but the types listed above cover 99% of the cases.

If you create a VSD chart from the [CacheMix Template], you can see the mix of these different types of pages in the cache as it performs various operations.

In a healthy cache, [DataPagesWrittenByGem > DataPagesWrittenByGem Statistic] will dominate. If you have a large number of objects in the repository, then you will start to see a sizable number of object table pages ([OtInternalPagesWrittenByGem > OtInternalPagesWrittenByGem Statistic] and [OtLeafPagesWrittenByGem > OtLeafPagesWrittenByGem Statistic]). Other page types may rise and fall within cache while certain maintenance operations are being performed.

!How big should I make my shared page cache?

The optimal cache size should be able to handle the working set of data pages, object table pages and commit record pages during your most time critical system operating periods.

!If your shared page cache is too small:

Your sessions will be performing too many [LocalPageCacheMisses > LocalPageCacheMisses Statistic]. Before taking any action, compare the [LocalPageCacheMisses > LocalPageCacheMisses Statistic] for the session with the [ObjsReadCount > ObjsReadCount Statistic]. 

   * If they are equal, then every time your session references an object that has not been loaded into the vm's object memory, you are being forced to load the page that that object resides on from disk into the shared page cache. You can double check by comparing [LocalPageCacheMisses > LocalPageCacheMisses Statistic] to the [PagesPreempted > PagesPreempted Statistic] stat in the [shrpc > Shrpc Type] - these two stats should be roughly equivalent. You can probably benefit from a larger cache size.

   * If the [LocalPageCacheMisses > LocalPageCacheMisses Statistic] is a small percentage of your [ObjsReadCount > ObjsReadCount Statistic], then your cache is pretty close to the right size. 

   * If [ObjsReadCount > ObjsReadCount Statistic] is a very small percentage of the [LocalPageCacheMisses > LocalPageCacheMisses Statistic], yet the absolute number of [LocalPageCacheMisses > LocalPageCacheMisses Statistic] is very high, then you may be taking hits on object table page references or a commit record backlog. First check your stone's [CommitRecordCount > CommitRecordCount Statistic]. If it is in the 1000's, then you have a commit record backlog problem. Finally, take a look at [ObjTablePageReads > ObjTablePageReads Statistic]. If they are roughly equal then you'll need to increase the cache size. 

An alternative to increasing the size of the shared page cache is to increase the size of the POM Cache in the vm. If the cache misses are due to object reads, then this technique could reduce the need to increase the size of the shared page cache.

!If your shared page cache is too large:

See also: [Shared Page Cache Health], [Writing]
}

{AIO page servers} {
!How many AIO page servers do I need?
The system will not let you allocate more than one page server per extent. I have heard that two or three extents per aio page server is a good rule of thumb.

You can tell you need more if:
   * [LocalDirtyPageCount > LocalDirtyPageCount Statistic] is taking up close to a third or more of the frames in the cache.
AND
   * The [AioWakeupInterval > AioWakeupInterval Statistic] for page servers named <b>aioWriter</b> (the aio threads in the [SAP]) is spending noticeable time at 0. When [AioWakeupInterval > AioWakeupInterval Statistic] is at zero the thread is scanning the cache and writing pages as fast as it can.

Each page server thread has 4 thresholds of interest:
   *  [LocalDirtyPageCount > LocalDirtyPageCount Statistic] < 1% of cache
idle. [AioWakeupInterval > AioWakeupInterval Statistic] threshold equal to 1000 milliseconds.
   *  1% of cache < [LocalDirtyPageCount > LocalDirtyPageCount Statistic] < 50% of cache
1 cache scan per second. [AioWakeupInterval > AioWakeupInterval Statistic] threshold equal to 1000 milliseconds.
   *  50% of cache < [LocalDirtyPageCount > LocalDirtyPageCount Statistic] > 75% of cache
1 cache scan per 1/2 second. [AioWakeupInterval > AioWakeupInterval Statistic] threshold equal to 500 milliseconds.
   *  75% of cache < [LocalDirtyPageCount > LocalDirtyPageCount Statistic]
continuous cache scans. [AioWakeupInterval > AioWakeupInterval Statistic] threshold equal to 0 milliseconds.

See also: [Extents and Tranlogs], [Shared Page Cache Health]
}

{Extents and Tranlogs} {
!What's the skinny on Raw Partitions?
Put your tranlogs on raw partitions

   * Tranlog i/o is the number one limiting factor in commit performance.
   * If you don't put your tranlogs on a raw partition, then at least make sure that your tranlog directory is not on the same spindle as your extents.
   * Try to alternate tranlogs across two spindles and archive one while the other is active.

Put extents on raw partitions

   * Since GemStone does random access to the extents, it is not as important to put your extents on raw partitions. In fact, because of the disk i/o buffering done by the os, file-based extents may lead to better performance.

Always put separate extents on separate spindles
   * If/when you add more [AIO page servers], you will get the optimal i/o performance by having each extent on a separate spindle.

!How many extents should I have?

You can tell if you need more extents if:
   * Your [AIO page servers] are maxed out and dirty pages are dominating your [shared page cache > Shared Page Cache Health].
OR
   * You are running out of space on your current disk partition.

!How big should I allow my extents to be?

!Which allocation mode should I use?
   * [Extent Allocation Modes]
}

{Extent Allocation Modes} {
   * Sequential Allocation Mode
   * Weighted Allocation Mode
}

{Writing} {
!Scenario Description:

In this scenario we are imagining that you are loading your repository with initial data. There is minimal repository reading going on and the primary activity is the creation of new objects that are to be stored in the repository (The extent stat [ExtentReadKBytes > ExtentReadKBytes Statistic] will be very, very low, if not zero and the extent stat [ExtentWriteKBytes > ExtentWriteKBytes Statistic] will be very high).

!Principle
The goal is to mazimize the [ObjsCommitted > ObjsCommitted Statistic] per second as this will be your true measure of performance. 

!System Parameter Settings:

   * Reduce the size of the [shared page cache > Shared Page Cache]

With a minimum amount of reading going on the primary purpose of the cache is to provide a home for dirty pages until the [AIO page servers] are able to write the dirty pages to disk. The cache is also holding onto the active commit records. Use a large cache until you have maximized your commit rate and i/o rate, then reduce the size of the cache until The stone and/or sessions start getting [LocalPageCacheMisses > LocalPageCacheMisses Statistic]. 

Also keep an eye on the [WriteKBytes > WriteKBytes Statistic] stat for the disk volume where the tranlogs are being written. The stat should be fairly steady, so if you see swings in the write rate, take a look at the health of the stone.

!VM Parameter Settings:

   * Increase the [private page cache size > PrivatePageCacheSize Statistic] to eliminate any [FramesAddedToFreeList > FramesAddedToFreeList Statistic] activiy for the [sessions > Session Type] doing the writes.
   * Maximize the number of objects per commit. There is a fixed overhead per commit, so it is advantageous to commit as many objects per commit as possible. The primary limiting factor in this case is the amount of java heap ([ObjMemSize > ObjMemSize Statistic]) used by the session - the objects are kept in java object memory until the commit at which time the persistent objects can be gc'ed freeing up object memory for more new objects.

See also: [Extent Allocation Modes], [Shared Page Cache]
}

{Shared Page Cache Health} {
To check you shared page cache's heath bring up a chart using the [CacheMix Template] and take a look at the following three statistics:
   * [FreeFrameCount > FreeFrameCount Statistic]
   * [LocalDirtyPageCount > LocalDirtyPageCount Statistic]
   * [DataPagesWrittenByGem > DataPagesWrittenByGem Statistic]

[FreeFrameCount > FreeFrameCount Statistic] should be ratcheting along between 0 and 2000 frames. If [FreeFrameCount > FreeFrameCount Statistic] is flat-lined at zero, your working-set of pages may be larger than the cache. First check that the [sessions > Session Type] are not doing excessive [FramesAddedToFreeList > FramesAddedToFreeList Statistic], then consider increasing the size of the [Shared Page Cache].

[LocalDirtyPageCount > LocalDirtyPageCount Statistic] should be way less than a third of the cache. If there are lots of dirty pages in the cache, then take a look at adding more [AIO page servers].

The bulk of the pages in the cache should be [DataPagesWrittenByGem > DataPagesWrittenByGem Statistic]. 

If you see a large number of [CommitRecordPagesWrittenByGem > CommitRecordPagesWrittenByGem Statistic], [BitlistPagesWrittenByGem > BitlistPagesWrittenByGem Statistic], [BmInternalPagesWrittenByGem > BmInternalPagesWrittenByGem Statistic], or [BmLeafPagesWrittenByGem > BmLeafPagesWrittenByGem Statistic], you may be suffering from a high commit record backlog and you should take steps to alleviate that situation.

See also: [AIO page servers], [Shared Page Cache]
}

{Chart Menu Add From Template SubMenu} {
This submenu has an item for every template.\
Selecting one of these items causes that template to be [expanded > Template Expansion]\
and every line the expansion produces is added to this chart.

[Selection Key > Keyboard Selection Keys]: <tt>Alt-a</tt>

This menu can be [torn off > Tear Off Menus].

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Save Template Item} {
Selecting this menu item causes all of the lines on the chart to be\
saved as a template.
The saved template is written to the [template file > VSD Files].

The name of the template will be based upon the chart window's name.
You can rename the template by editing the [template file > VSD Files] and [reloading > Template Menu Reload Template File Item] it

Each line on the chart is used as a pattern when saving it to the template.\
Exact information on the instances is no recorded in the template.\
This is so when the template is used later, with another file, it should\
be able to match some of its instances. In some case the saved template\
can be made more useful by editing the [template file > VSD Files].\
Also some template features can only be used by directly editing the file.

[Selection Key > Keyboard Selection Keys]: <tt>Alt-s</tt>

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Paste Item} {
Selecting this menu item causes the last item that was cut or copied\
to be added to this chart as one or more lines. If it finds something\
on the clipboard to paste it will remove that item from the clipboard.\
A paste operation does nothing if the clipboard is empty.

A paste can also be done with a host dependent <em>Paste</em> key.

[Accelerator Key > Keyboard Accelerators]: <tt>control-v</tt>

See [How to Cut, Copy, and Paste] for more information.

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Print Item} {
Selecting this menu item causes the chart to be printed. This is only supported on Unix platforms. The command name stored in the <tt>vsd(exec:lpr)</tt> variable is executed with the contents of a postscript file. The default value of this variable is <tt>lpr</tt> and can be customized in the [config file > VSD Files].

The temporary postscript file is written to VSD's working directory. Use [Main Menu Change Directory... Item] to change this directory.

[Accelerator Key > Keyboard Accelerators]: <tt>control-p</tt>

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Snapshot Item} {
Selecting this menu item causes a picture of the chart to be taken and written to the file <tt>snapshot.gif</tt>. The file is always written to VSD's working directory and any existing file will be overwritten. Use [Main Menu Change Directory... Item] to change the working directory.

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Help... Item} {
Selecting this menu item causes a [help window > Help Window Features] to\
popup with a description of the [chart window > Chart Window Features].

[Selection Key > Keyboard Selection Keys]: <tt>Alt-h</tt>

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Zoom In Item} {
Selecting this menu item begins a zoom in operation on the chart's\
graph. A zoom in consists of the following steps:
   1 Click in the graph at the point you wish to be the upper left hand corner.
   1 Click in the graph at the point you wish to be the lower right hand corner.

Once the operation has begun it can be canceled at any time with\
a right click of the mouse.

See [How to Zoom] for more information.

[Accelerator Key > Keyboard Accelerators]: <tt>control-z</tt>

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Zoom Out Item} {
Selecting this menu item does a zoom out operation on the chart's\
graph. A zoom out will reverse the effects of the most recent zoom in.\
A zoom out does nothing unless the graph is zoomed in at least\
once.

A right click of the mouse over the graph will also do a zoom out.

See [How to Zoom] for more information.

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Compare Two Points Item} {
This operation item allows you to [log > Log Window] information obtained\
by comparing two points. Unlike the [Line Menu <b>Log Delta</b> Item] the\
two points can be from any of the lines on the chart's [graph > Graph Display].

Once the operation has begun it can be canceled at any time with\
a right click of the mouse.

!Usage
   1 Select the item.
   1 [Select > Selecting a Point for an Operation] the first point.
   1 [Select > Selecting a Point for an Operation] the second point. A thin black line will be drawn between the\
first point and the mouse cursor to remind you of what you are comparing.
   1 View the [logged > Log Window] information.

!Logged Information
The following information is logged by this operation:
   * A description of the lines the points were on.
   * The exact coordinates of the two points.
   * <b>time delta</b>: the absolute difference between the two point's X coordinates.
   * <b>value delta</b>: the difference between the two point's Y coordinates.\
This is done by subtracting the first point's Y value from the second point's\
Y value.
   * <b>value/time delta</b>: the result of dividing the <em>value delta</em>\
by the <em>time delta</em>.\
This delta is only shown if the <em>time delta</em> is not zero.
   * <b>data statistics</b>: [statistics > Data Statistics] for the data points\
on each line. The data points of interest are the ones in the range defined\
by the X values of the two selected points.

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Data Statistics} {
The following statistics on sets of data values are supported by VSD:
   * <b>count</b>: the number of points in the data set.
   * <b>min</b>: the minimum Y value of the points in the data set.
   * <b>max</b>: the maximum Y value of the points in the data set.
   * <b>mean</b>: the average Y value of all the points in the data set.
   * <b>stddev</b>: the standard deviation of all the Y values in the data set.\
Larger standard deviation values mean that more values far away from the\
average exist.
}

{Selecting a Point for an Operation} {
Various chart operations require that you select one or more points on a\
chart's graph. In most of these cases the mouse cursor changes to cross hairs\
to tell you that the graph is in a special mode. Once the mouse cursor is\
over a valid point that can be selected the it changes to a target.\
If you click when its a target the point will be selected.

Note that during this process the mouse will automatically highlights the\
line its closest to and display the coordinates of the line point its\
closest to. See [How to Get Information About a Location] for more information.

In some cases the point must be on a certain line. If another line is\
nearby you may have trouble with its point always being selected instead\
the line you need. Move the line to its own chart or rescale it or change\
its Y axis to remedy this problem.
}

{Chart Menu Compute Scale All Item} {
Selecting this menu item causes every line on the chart to have an\
[optimal scale > Line Menu Compute Scale Item] computed for it.

[Accelerator Key > Keyboard Accelerators]: <tt>control-S</tt>

For more information on scaling see [Display Scaling a Line].

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Unscale All Item} {
Selecting this menu item causes every line on the chart to be\
[unscaled > Line Menu Compute Scale Item].

[Accelerator Key > Keyboard Accelerators]: <tt>control-N</tt>

For more information on scaling see [Display Scaling a Line].

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Show Legend Item} {
If this item is on then the [chart window > Chart Window Features] will have a [legend > Graph Legend] control.\
Screen space can be saved by turning it off. If it is turned off then\
a description of the selected line will be printed in the  upper left corner of\
the [graph > Graph Display].

Use [Main Chart Menu <b>Show Legend</b> Item] to control the initial state\
of this item.

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Time Format SubMenu} {
This submenu controls what format a timestamp will be displayed in.\
It allows any one, and only one, of the following formats to be selected:
   * [Elapsed Time in Seconds > Elapsed Time in Seconds Format] 
   * [Hour:Minute:Second > Hour:Minute:Second Format]
   * [Month/Day Hour:Minute:Second > Month/Day Hour:Minute:Second Format]

[Selection Key > Keyboard Selection Keys]: <tt>Alt-t</tt>

This menu can be [torn off > Tear Off Menus].

Use [Main Chart Menu <b>Time Format</b> SubMenu] to control the initial state\
of this item.

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Elapsed Time in Seconds Format} {
Use this format to get the least amount of information printed about the timestamp.

If the time stamp is [relative > Main Menu Absolute TimeStamps Item]\
then this is the number of seconds since the first sample in the file\
it is from. The exact format is <u><em>num</em><b>s</b></u> where:
   * <em>num</em> is a sequence of digits
   * <b>s</b> stands for seconds

If the time stamp is [absolute > Main Menu Absolute TimeStamps Item]\
then just the time of day in hours, minutes, and seconds is printed.\
This is exactly the same as the [Hour:Minute:Second Format].
}

{Hour:Minute:Second Format} {
If the time stamp is [relative > Main Menu Absolute TimeStamps Item]\
then this is the number of hours, minutes, and seconds\
since the first sample in the file it is from.\
Only non-zero counts are show.\
The exact format is\
<u><em>num</em><b>h</b><em>num</em><b>m</b><em>num</em><b>s</b></u> where:
   * <em>num</em> is a sequence of digits
   * <b>h</b> stands for hours
   * <b>m</b> stands for minutes
   * <b>s</b> stands for seconds

If the time stamp is [absolute > Main Menu Absolute TimeStamps Item]\
then just the time of day in hours, minutes, and seconds is printed.\
The exact format is <u><em>hours</em><b>:</b><em>minutes</em><b>:</b><em>seconds</em></u> where:
   * <em>hours</em> is a value in the range 0..23; two digits are always printed.
   * <em>minutes</em> is a value in the range 0..59.
   * <em>seconds</em> is a value in the range 0..61;\
the value 60 allows for the occasional leap second;\
the value 61 allows for the occasional double leap second.
}

{Month/Day Hour:Minute:Second Format} {
If the time stamp is [relative > Main Menu Absolute TimeStamps Item]\
then this is the elapsed number of days, hours, minutes, and seconds\
since the first sample in the file it is from.\
Only non-zero counts are show.\
The exact format is\
<u><em>num</em><b>d</b><em>num</em><b>h</b><em>num</em><b>m</b><em>num</em><b>s</b></u> where:
   * <em>num</em> is a sequence of digits
   * <b>h</b> stands for days
   * <b>h</b> stands for hours
   * <b>m</b> stands for minutes
   * <b>s</b> stands for seconds

If the time stamp is [absolute > Main Menu Absolute TimeStamps Item]\
then the month, day of the month, and  the time of day in hours, minutes, and seconds is printed.\
The exact format is <u><em>month</em><b>/</b><em>day</em> <em>hours</em><b>:</b><em>minutes</em><b>:</b><em>seconds</em></u> where:
   * <em>month</em> is a value in the range 1..12; two digits are always printed.
   * <em>day</em> is a value in the range 1..31; two digits are always printed.
   * <em>hours</em> is a value in the range 0..23; two digits are always printed.
   * <em>minutes</em> is a value in the range 0..59.
   * <em>seconds</em> is a value in the range 0..61;\
the value 60 allows for the occasional leap second;\
the value 61 allows for the occasional double leap second.
}

{Chart Menu Show Time Axis Title Item} {
If this item is on then the [chart window > Chart Window Features] will display a title under the graph's [X Axis].
Screen space can be saved by turning it off.

Use [Main Chart Menu <b>Show Time Axis Title</b> Item] to control the initial state\
of this item.

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Show Left Axis Title Item} {
If this item is on then the [chart window > Chart Window Features] will display a title next to the graph's [Left Y Axis].
Screen space can be saved by turning it off.

Use [Main Chart Menu <b>Show Left Axis Title</b> Item] to control the initial state\
of this item.

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Show Right Axis Title Item} {
If this item is on then the [chart window > Chart Window Features] will display a title next to the graph's [Right Y Axis].
Screen space can be saved by turning it off.

Use [Main Chart Menu <b>Show Right Axis Title</b> Item] to control the initial state\
of this item.

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Show Current Values Item} {
If this item is on then the [chart window > Chart Window Features] will have\
[X: > Chart Window X: Display] and [Y: > Chart Window Y: Display] controls
Screen space can be saved by turning it off.

Use [Main Chart Menu <b>Show Current Values</b> Item] to control the initial state\
of this item.

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Show Min and Max Item} {
If this item is on then the [chart window > Chart Window Features]\
will have [Min: > Chart Window Min: Display] and [Max: > Chart Window Max: Display] controls.
Screen space can be saved by turning it off.

Use [Main Chart Menu <b>Show Min and Max</b> Item] to control the initial state\
of this item.

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Show Line Stats Item} {
If this item is on then the [chart window > Chart Window Features]\
will display [line statistics > Data Statistics] in the upper left corner of its [graph > Graph Display].
Turning it off saves the cost of computing these statistics and can make it easier to view lines with points in the upper left corner.

Use [Main Chart Menu <b>Show Line Stats</b> Item] to control the initial state\
of this item.

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Show CrossHairs Item} {
If this item is on then the [chart window > Chart Window Features] will draw cross hair lines on its [graph > Graph Display].

Use [Main Chart Menu <b>Show CrossHairs</b> Item] to control the initial state\
of this item.

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Show Grid Lines Item} {
If this item is on then the [chart window > Chart Window Features] will draw dotted grid lines on its [graph > Graph Display].

Use [Main Chart Menu <b>Show Grid Lines</b> Item] to control the initial state\
of this item.

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Close Item} {
Selecting this item causes the chart window to no longer exist.\
This can also be done using the native window manager.

To close all your chart windows use the [Main Chart Menu <b>Close All Charts</b> Item].

This item is part of the [chart menu > Chart Window Chart Menu].
}


{Chart Window Line Menu} {
This menu is disable until a [line is selected > How to Select a Line].
Operations on this menu apply to the selected line.

[Selection Key > Keyboard Selection Keys]: <tt>Alt-l</tt>

This menu can be [torn off > Tear Off Menus].

This menu is on each [chart window > Chart Window Features].

!Items
   * [Log Info > Line Menu Log Info Item]
   * [Log Delta > Line Menu Log Delta Item]
   * [Compute Scale > Line Menu Compute Scale Item]
   * [Unscale > Line Menu Unscale Item]
   * [Graph on Left Axis > Line Menu Graph on Left Axis Item]
   * [Symbol > Line Menu Symbol SubMenu]
   * [Style > Line Menu Style SubMenu]
   * [Update > Line Menu Update Item]
   * [Add Lines > Line Menu Add Lines Item]
   * [Diff Lines > Line Menu Diff Lines Item]
   * [Divide Lines > Line Menu Divide Lines Item]
   * [Normalize > Line Menu Normalize Item]
   * [Trim Left > Line Menu Trim Left Item]
   * [Trim Right > Line Menu Trim Right Item]
   * [Untrim Left > Line Menu Untrim Left Item]
   * [Untrim Right > Line Menu Untrim Right Item]
   * [Copy > Line Menu Copy Item]
   * [Cut > Line Menu Cut Item]
   * [Delete > Line Menu Delete Item]
}

{Line Menu Log Info Item} {
Selecting this item causes information on the current line to be written to the [log window >Log Window]. The information includes:
   * A description of the line's instances and statistic
   * the line's [value scale > Value Scaling a Line] if any
   * the line's [offset > Offsetting a Line] if any
   * the line's filter. The prefix <tt>filter:</tt> is used.
   * the line's units. The prefix <tt>units:</tt> is used.
   * an indicator if the line was normalized. The keyword <tt>normalized</tt> is used.
   * the line's files. The prefix <tt>file:</tt> or <tt>files:</tt> is used.
   * if the line is a [combination > Main Menu Combine Item] of more than one instance then a list of each of the instances. The keyword <tt>dataSources:</tt> heads this section.
   * if the line was created using [arithmetic > Line Arithmetic] then full information, except for line statistics, is given on each of the derived lines. Also the operator used is show.
   * the line's statistics which include:
      * the statistic range. This consists of the times of the first and last sample used to compute the statistics
      * the minimum value in the statistic range
      * the maximum value in the statistic range
      * the average of all the values in the statistic range
      * the standard deviation of all the values in the statistic range

[Selection Key > Keyboard Selection Keys]: <tt>Alt-i</tt>

This item is part of the [line menu > Chart Window Line Menu].
}

{Line Menu Log Delta Item} {
This operation item allows you to [log > Log Window] information obtained\
by comparing two points on the selected line.

[Accelerator Key > Keyboard Accelerators]: <tt>control-d</tt>

Once the operation has begun it can be canceled at any time with\
a right click of the mouse.

!Usage
   1 Select the line the two points are on.
   1 Select the item.
   1 [Select > Selecting a Point for an Operation] the first point.
   1 [Select > Selecting a Point for an Operation] the second point. A thin black line will be drawn between the\
first point and the mouse cursor to remind you of what you are comparing.
   1 View the [logged > Log Window] information.

!Logged Information
The following information is logged by this operation:
   * A description of the line the points were on.
   * The exact coordinates of the two points.
   * <b>time delta</b>: the absolute difference between the two point's X coordinates.
   * <b>value delta</b>: the difference between the two point's Y coordinates.\
This is done by subtracting the first point's Y value from the second point's\
Y value.
   * <b>value/time delta</b>: the result of dividing the <em>value delta</em>\
by the <em>time delta</em>.
   * <b>data statistics</b>: [statistics > Data Statistics] for all the data points\
on the line between the two selected points.

This item is part of the [line menu > Chart Window Line Menu].
}

{Line Menu Compute Scale Item} {
Selecting this item sets the current lines [display scale > Display Scaling a Line] to a value such that the lines maximum value will display at the top of the Y axis its plotted on.

[Accelerator Key > Keyboard Accelerators]: <tt>control-s</tt>

This item is part of the [line menu > Chart Window Line Menu].
}
{Line Menu Unscale Item} {
Selecting this item sets the current line's [display scale > Display Scaling a Line] to one.

[Accelerator Key > Keyboard Accelerators]: <tt>control-n</tt>

This item is part of the [line menu > Chart Window Line Menu].
}
{Line Menu Graph on Left Axis Item} {
If this item is checked then the current line is plotted on the [left axis > Left Y Axis]. Otherwise its plotted on the [right axis > Right Y Axis]. If you have two lines whose values differ greatly then plotting them on seperate axis can help in comparing the two lines visually.

[Accelerator Key > Keyboard Accelerators]: <tt>control-a</tt>

This item is part of the [line menu > Chart Window Line Menu].
}
{Line Menu Symbol SubMenu} {
This submenu lets you select the symbol that will be used to display the data points of the current line. By default no symbol is used to the data points blend in with the lines that connect them. Using a symbol lets you see the actual data points. Symbols tend to blend together if you have a large number of data points so only use this feature when you have [zoomed > How to Zoom] in to a smaller region. The symbols are:
   * <b>scross</b>: a simple X
   * <b>splus</b>: a simple +
   * <b>square</b>: a square
   * <b>triangle</b>: a triangle
   * <b>circle</b>: a circle
   * <b>diamond</b>: a diamond
   * <b>plus</b>: a fancy +
   * <b>cross</b>: a fancy X

[Selection Key > Keyboard Selection Keys]: <tt>Alt-s</tt>

This menu can be [torn off > Tear Off Menus].

This submenu is part of the [line menu > Chart Window Line Menu].
}
{Line Menu Style SubMenu} {
This submenu lets you select the style used to connect the data points when displaying the current line. The default style is <b>linear</b>. The style does not change the actual data points just the lines drawn between them. The available styles are:
   * <b>linear</b>: a simple line segment is drawn between each pair of data points.
   * <b>step</b>: two line segments are drawn between each pair of data points. The first is a horizontal line segment that steps to the next X-coordinate. The second is a vertical line that steps to the next Y-coordinate.
   * <b>natural</b>: multiple line segments, generated using a cubic spline, are drawn between each pair of data points.
   * <b>quadratic</b>: multiple line segments, generated using a quadratic spline, are drawn between each pair of data points.

[Selection Key > Keyboard Selection Keys]: <tt>Alt-t</tt>

This menu can be [torn off > Tear Off Menus].

This submenu is part of the [line menu > Chart Window Line Menu].
}
{Line Menu Update Item} {
Selecting this item will cause all the files used by the current line to be [updated > How to Update the View of a Data File] which may result in the line becoming longer.

[Accelerator Key > Keyboard Accelerators]: <tt>control-u</tt>

This item is part of the [line menu > Chart Window Line Menu].
}
{Line Menu Add Lines Item} {
Selecting this item starts the process of adding another line to the current line. Vsd will prompt you to select the other line. You can <em>left click</em> on either the line or its [legend > Graph Legend] entry to select it. You can <em>right click</em> to cancel the operation. If you do select another line then a new line is produced which is the result of adding the first two lines together. See [line arithmetic > Line Arithmetic] for more information.

[Accelerator Key > Keyboard Accelerators]: <tt>control-+</tt>

This item is part of the [line menu > Chart Window Line Menu].
}
{Line Menu Diff Lines Item} {
Selecting this item starts the process of subtracting another line from the current line. Vsd will prompt you to select the other line. You can <em>left click</em> on either the line or its [legend > Graph Legend] entry to select it. You can <em>right click</em> to cancel the operation. If you do select another line then a new line is produced which is the result of subtracting the first line from the second. See [line arithmetic > Line Arithmetic] for more information.

[Accelerator Key > Keyboard Accelerators]: <tt>control--</tt>

This item is part of the [line menu > Chart Window Line Menu].
}
{Line Menu Divide Lines Item} {
Selecting this item starts the process of dividing the current line by another line. Vsd will prompt you to select the other line. You can <em>left click</em> on either the line or its [legend > Graph Legend] entry to select it. You can <em>right click</em> to cancel the operation. If you do select another line then a new line is produced which is the result of dividing the first line by the second. See [line arithmetic > Line Arithmetic] for more information.

[Accelerator Key > Keyboard Accelerators]: <tt>control-/</tt>

This item is part of the [line menu > Chart Window Line Menu].
}
{Line Menu Normalize Item} {
If this item is checked then the line will be [normalized > Normalizing a Line]. Its renormalized any time its data points change.
If its not checked then you are free to set the line's [offset > Offsetting a Line] to any value.

This item is part of the [line menu > Chart Window Line Menu].
}
{Line Menu Trim Left Item} {
Selecting this item start a trim left operation. You can either select a data point on the current line or <em>right click</em> to cancel the operation. To select a data point move the mouse over the line. The cursor will turn into a circle when its over a valid trim point. If you want to ignore all the data to the left of this trim point then <em>left click</em>.

See [File Trimming] for more information.

This item is part of the [line menu > Chart Window Line Menu].
}
{Line Menu Trim Right Item} {
Selecting this item start a trim right operation. You can either select a data point on the current line or <em>right click</em> to cancel the operation. To select a data point move the mouse over the line. The cursor will turn into a circle when its over a valid trim point. If you want to ignore all the data to the right of this trim point then <em>left click</em>.

See [File Trimming] for more information.

This item is part of the [line menu > Chart Window Line Menu].
}
{Line Menu Untrim Left Item} {
Selecting this item causes any left trims done to the current line's files to be undone. See [File Trimming] for more information.

This item is part of the [line menu > Chart Window Line Menu].
}
{Line Menu Untrim Right Item} {
Selecting this item causes any right trims done to the current line's files to be undone. See [File Trimming] for more information.

This item is part of the [line menu > Chart Window Line Menu].
}
{Line Menu Copy Item} {
Selecting this item makes a copy of the currently selected line and puts it on the paste clipboard. For more information see [How to Cut, Copy, and Paste].

[Accelerator Key > Keyboard Accelerators]: <tt>control-c</tt> or a host dependent <em>Copy</em> key.

This item is part of the [line menu > Chart Window Line Menu].
}
{Line Menu Cut Item} {
Selecting this item removes the currently selected line from the graph and puts it on the paste clipboard. For more information see [How to Cut, Copy, and Paste].

[Accelerator Key > Keyboard Accelerators]: <tt>control-x</tt> or a host dependent <em>Cut</em> key.

This item is part of the [line menu > Chart Window Line Menu].
}
{Line Menu Delete Item} {
Selecting this item deletes the currently selected line. Once its deleted it can not be undeleted.

You can also delete a line by middle clicking the mouse on its [legend > Graph Legend] entry.

[Accelerator Key > Keyboard Accelerators]: <tt>Del</tt>

This item is part of the [line menu > Chart Window Line Menu].
}

{Display Scaling a Line} {
You usually want to change the scale of a line because it looks like a\
flat line due to another line with very large values. The easiest thing\
you can do is graph the line on the other y axis. This will cause the\
line to be scaled independently of lines on the other axis.
The next easiest thing is to use the [Line Menu <b>Compute Scale</b> Item]. This will\
compute a scale value for the current line that make it visable on the\
current graph. You can quickly undo this with the [Line Menu <b>Unscale</b> Item].
You can also manually change the scale using the up or down arrow\
by the [number entry > Chart Window Number Entry] in the upper right corner of a chart. First click\
on the [button > Chart Window Operator MenuButton] next the the number entry and pick <b>S</b> from the dropdown.\
Each click doubles or halves the scale.
You can also enter any scale you want by clicking on the existing value and\
changing it using the keyboard.
The default scale is one. Changing the\
scale just causes the line to be drawn differently, it does not modify\
the actual values of the data points.
}

{Value Scaling a Line} {
The data points of a line can all be multiplied (or divided) by a constant. This is done\
by adding (or subtracting) a constant value from every data point on the line.
To specify a multiplier constant select a line and then click on the [button > Chart Window Operator MenuButton] next\
to the the number entry in the upper right corner of a chart window. Pick <b>*</b>\
or <b>/</b> from the dropdown and then enter the constant into the [number entry > Chart Window Number Entry].\
Each click of the up or down arrow doubles or halves the constant.
Multiplier constants are always done after the data is filtered and\
before an offset constant and scale constant are applied.
Note that unlike a scale, which is for display purposes only, a multiplier\
actually changes the y values of the line's data points. A common use\
is to change the units of a line. For example kilobytes can be changed to\
bytes by multiplying by 1024.
}

{Offsetting a Line} {
The data points of a line can all be offset by a constant. This is done\
by adding (or subtracting) a constant value from every data point on the line.
To specify an offset constant select a line and then click on the [button > Chart Window Operator MenuButton] next\
to the the number entry in the upper right corner of a chart window. Pick <b>+</b>\
or <b>-</b> from the dropdown and then enter the constant into the [number entry > Chart Window Number Entry].\
Each click of the up or down arrow change the offset constant by one.
Offset constants are always done after a multiplier constant is applied\
and before a scale constant is applied.
Note that the normalization feature automatically computes the offset so if\
a line is normalized then a user supplied constant is ignored.
}

{Normalizing a Line} {
If a line is normalized then an offset is computed so that its\
minimum data point will have a value of zero.\
The normalization offset is recomputed any time the data for the line changes.
If a line is normalized then it can not be offset by a constant value\
other than the one computed by the normalization code. 
Normalization is ignored unless the filter is "none".
}

{Tear Off Menus} {
If you find yourself constantly going back to the same menu item time\
after time you may find turning the menu into a button box helpful.\
If the menu has a dashed line at its top this indicates that the menu\
can be torn off. Once you do this it will be a box of buttons in its own\
window. Now you can just click on these buttons. For a nested menu you\
keep using this can be a real win.
The only way to get rid of a torn off menu is the use your window manager's\
window close or kill operation.
}

{List Multiple Selection} {
Some list items allow more than one item in the list to be selected.
   * A single item can be selected by clicking on it.
   * Multiple disjoint items can be selected by holding the <tt>Control</tt>\
key down when clicking on the items.
   * Multiple contiguous items can be selected by holding the <tt>Shift</tt> key down\
or by drag selecting.
   * A selected item can be deselected by holding the <tt>Control</tt>\
key down and clicking on it.
}

{String Entry Editing} {
When entering a string the following  special editing operations are available:
   * <tt>Control-a</tt> or the <em>Home</em> moves the cursor to the beginning of the string. If the shift modifier is used with the <em>Home</em> key then the selection is also extended to the beginning.
   * <tt>Control-e</tt> or the <em>End</em> key moves the cursor to the end of the string. If the shift modifier is used with the <em>End</em> key then the selection is also extended to the end.
   * <tt>Control-b</tt> moves the cursor back one character.
   * <tt>Control-f</tt> moves the cursor forward one character.
   * <tt>Control-t</tt> reverses the order of the two characters to the left of the cursor.
   * <tt>Control-k</tt> deletes all the characters to the right of the cursor.
   * <tt>Control-d</tt> or the <em>Delete</em> key deletes a single character to the right of the cursor.
   * <tt>Meta-d</tt> deletes a single word to the right of the cursor.
   * <tt>Control-/</tt> selects all the text.
   * <tt>Control-\</tt> clears any selection.
   * <tt>Control-h</tt> or the <em>Backspace</em> key deletes a single character to the left of the cursor if nothing is selected. Otherwise they delete the selection.
   * <tt>Meta-w</tt>, <tt>F16</tt>, or the <em>Copy</em> key copies the selection to the clipboard. Does nothing if no selection.
   * <tt>Control-w</tt>, <tt>F20</tt>, or the <em>Cut</em> key copies the selection to the clipboard and deletes the selection. Does nothing if no selection.
   * <tt>Control-y</tt>, <tt>F18</tt>, or the <em>Paste</em> key inserts the contents of the clipboard at the position of the cursor.
}

{Mouse Help} {
If you hold the mouse pointer over a widget explanatory text will appear\
in the [status box > Main Window Status Display].
}

{Bell Messages} {
If vsd ever beeps this indicates a warning or error.\
Look for the reason why in the [status box > Main Window Status Display].
Bell messages timeout after 10 seconds.
}

{Keyboard Selection Keys} {
Many menus, menu items, and buttons have a selection key. Selection keys are\
indicated by underlining a letter in the name of the control.\
Its used by holding down the <tt>Alt</tt> key and pressing the selection key.\
Using the selection key is equivalent to clicking the mouse on the control.
Keyboard selection keys are case-insensitive.
Keyboard selection keys only work if the control the selection key is bound\
to is visible on the screen and its window is selected.
}

{Keyboard Accelerators} {
Some menu items have keyboard accelerators.\
Accelerators allow you to quickly invoke a menu item.\
Accelerators are displayed next to the name of the menu item.\
Using the accelerator is equivalent to clicking the mouse on the item.
Keyboard accelerators are case-sensitive.
Keyboard accelerators work as long as the window the menu belongs to is selected.
}

{General Interface Features} {
   * [Tear Off Menus]
   * [List Multiple Selection]
   * [String Entry Editing]
   * [Mouse Help]
   * [Context Sensitive Help]
   * [Bell Messages]
   * [Keyboard Selection Keys]
   * [Keyboard Accelerators]
}

{Context Sensitive Help} {
A [help window > Help Window Features] containing context sensitive help can be created by pressing the <tt>F1</tt> key or your keyboard dependent <em>Help</em> key.
The help text will pertain to the window and widget that has keyboard focus.
}

{How to Load a Data File} {
[Type > String Entry Editing] in the full path in the [File: > Main Window File ComboBox] control and hit return.
The [Main Menu <b>Load Data File...</b> Item] can be used to browse for a file to load.
The command line can specify files to load when [vsd is started > How to Start VSD].
While a file is loading you can interrupt that load by clicking on\
the <b>Interrupt</b> button in the progress window. All the data already read\
will be available and the load can be continued later with the [File Menu <b>Update</b> Item].
You can also switch to a data file you already have loaded by dropping\
down the [File: > Main Window File ComboBox] control's list and selecting it.
You can get some information about a loaded data file with the [File Menu <b>Info...</b> Item].
For more information related to loaded files see [Controlling the Enabled Files].
}

{How to Update the View of a Data File} {
The [File Menu <b>Update</b> Item] will reread the current data file if it has\
changed since the last time vsd read it. It can also be used to continue\
the loading of a data file that was interrupted.\
Any charts displaying data from that file will also be updated.
If the [File Menu <b>Auto Update</b> Item] is turned on then vsd will keep doing the update\
operation everytime the file changes. The auto update interval is based\
on the sample interval of the data file.
}

{How to Create a Data File} {
Data files are created by a [statmonitor]. You can run the <tt>statmonitor</tt> command directly\
from the command line or you can use the [Main Menu <b>Monitor...</b> Item].
The [Monitor Window] will show you all the statistic sources on the local machine\
that you can monitor. Click on the sources you want stats for, adjust\
any of the startup parameters, and then click on Start.\
Vsd will automatically load the data file once it has some samples in it.
When you are done click on Stop. Vsd will shutdown any monitors it started\
when you exit vsd.
}

{How to Compare Files} {
In many cases vsd is used to compare multiple runs of the same load under\
different configurations or versions of the product.\
The following features facilitate comparsion of files:
   * Turn off the [Main Menu <b>Single File Mode</b> Item] so that more than one file can be loaded.
   * Turn on the [Main Menu <b>Combine</b> Item] and turn off the [Main Menu <b>Combine Across Files</b> Item]. This way\
you select a large group of object instances and get a line for each file\
being compared.
   * Turn off the [Main Menu <b>Absolute TimeStamps</b> Item] so that vsd will act as if each data\
run started at the same time.

Many data runs have a startup period at the beginning and a shutdown period at\
the end which are usually misleading for comparison purposes. To get rid\
of these do the following:
   * Chart a good representative line from each file.
   * Then for each line use the [Line Menu <b>Trim Left</b> Item] to get rid of all the data from the\
file's startup period and the [Line Menu <b>Trim Right</b> Item] to get rid of all the data from the\
file's shutdown period.
See [File Trimming] for more information.

If you want to compute the difference between two data runs then try this:
   * Chart a line from each data run's file.
   * Then select one of the lines and pick the [Line Menu <b>Diff Lines</b> Item] and\
then select the other line.
The result will be a third line whose values\
are the difference between the two original lines.\
See [Line Arithmetic] for more information.
}
 
{How to Merge Files} {
In some cases you may have multiple data files that you want to treat as\
a single file. If the files are in chronological order and have data for the same processes then you can simply concatenate them together into a single file. Just do it in the correct order. If they are compressed then you need to uncompress them before they can be concatenated.

A better way of concatenating a bunch of chronological files is to use vsd's append features. It can be done when vsd is started with the [-a > append load command line switch] switch. It can also be done interactively with the [Append Data File... > File Menu Append Data File... Item] menu item.

Another way is to use the external <tt>statmerge</tt> tool which reads multiple files a writes all their data to a single new file. Its best to use <tt>statmerge</tt> when you have multiple files with samples that need to be woven together because they took place at the same time on different machines.

The following features facilitate merging of files without using any of the above techniques:
   * Turn off the [Main Menu <b>Single File Mode</b> Item] so that more than one file can be loaded.
   * Turn on the [Main Menu <b>Combine Across Files</b> Item] so that when a combined line is created\
it will combine all the selected instances into a single line.
   * Turn on the [Main Menu <b>Absolute TimeStamps</b> Item] so that vsd will show the actual times\
each data sample was taken in each file.
}
{Statmonitor Output Format} {
Files written by [statmonitor] have a simple text format. Vsd allows the files to be compressed using the standard gzip format.
Vsd also allows files to be concatenated. You should only concatenate files which do not overlap in time and they should be ordered by time when concatenated.

The first line of the file must be of the form:
   * <tt>STATMON "</tt><em>digits</em><tt>"</tt>
where <em>digits</em> is one or more digits. This number represents the format version used in writing the rest of the file. The following describes version <b>2</b> which is used by the current statmonitor and vsd.

A <em>propertyDefinition</em> has the form:
   * <em>propertyName</em><tt> = "</tt><em>propertyValue</em><tt>"</tt>
where <em>propertyName</em> is a name and <em>propertyValue</em> is a string.
The next four lines are <em>propertyDefinitions</em> with these names:
   1 <tt>Platform</tt>  the value describes the operating system that the file was generated on.
   1 <tt>GemStoneVersion</tt>  the value describes the version of statmonitor's product.
   1 <tt>Machine</tt>  the value describes specific details about the machine the file was generated on.
   1 <tt>Time</tt>  the value describes the time, including timezone, that the first sample was written.

The next item in the format is a definition of the instance types used. The form is:
   * <tt>StatTypes = &#91;</tt><em>typeList</em><tt>]</tt>
where a <em>typeList</em> is zero or more comma seperated <em>typeDefinitions</em>. A <em>typeDefinition</em> has the form:
   * <em>typeName</em><tt> ( </tt><em>statNames</em><tt> ) </tt><em>typeId</em>
where <em>typeName</em> is the name of the type, <em>typeId</em> is a number used to identity this type, and <em>statNames</em> is five or more names representing the type's statistics. These names define what the fields in each instance snapshot (see the following) is. The first five <em>statNames</em> must always be:
   1 <tt>StatTypeNum</tt>  the numeric id of the snapshot's type
   1 <tt>Time</tt>  the time the snapshot was taken
   1 <tt>ProcessName</tt>  a string describing the snapshot's instance
   1 <tt>ProcessId</tt>  a number describing the process associated with the snapshot's instance. Zero if no associated process.
   1 <tt>SessionId</tt>  a number uniquely identifying the snapshot's instance. Zero if not applicable.

The next line has the form:
   * <tt>%%%%Generated by the statistics monitor</tt>
The next line has the form:
   * <tt>ENDHEADER</tt>
The next line is a blank line.
After this each line is an instance snapshot. Each instance snapshot is a list of whitespace seperated strings. A string must be provided for each of the snapshot's type's statNames. Most of the strings are unsigned numbers.
}
{How to Start VSD} {
Vsd can be started with one or more command line arguments. Unless the argument is a switch its expected to be the name of a [statmonitor] output file to load.
!Switches
   * [-a > append load command line switch]
   * [-n > normal load command line switch]
   * [-u > update command line switch]
}
{append load command line switch} {
The <tt>-a</tt> command line switch causes any file loaded from the command line to be concatenated together. This is done by loading the first one after the <tt>-a</tt> normally and then [appending > File Menu Append Data File... Item] the rest of the files to it. Only files up to the next [-n > normal load command line switch] switch will be appended.
}
{normal load command line switch} {
The <tt>-n</tt> command line switch causes any file loaded from the command line to be loaded normally. It turns off and previous [-a > append load command line switch] switch.
}
{update command line switch} {
The <tt>-u</tt> command line switch causes the previously loaded file to have [auto update > File Menu Auto Update Item] turned on.
}
{How to Select} {
Statistics are kept for a fixed number of [instances > Instance Definition]. The [types > Instance Type Definition] of the instances are defined by the data file but in most cases the well known types are used.

To graph a line you need to select the instances and statistic name of interest. The following links tell you how to control what instances and statistics will be available to select and how to do the actual selection.
   * [Controlling the Enabled Files]
   * [Controlling the Listed Object Instances]
   * [Controlling the Listed Statistic Names]
   * [How to Select Object Instances]
   * [How to Select Statistics]
}
 
{Controlling the Enabled Files} {
The main window will only let you see object instances from enabled files.\
Before a file can be enabled it first must be loaded.
If the [Main Menu <b>Single File Mode</b> Item] is checked then only one loaded file can be\
enabled at a time. In this mode each time a file is loaded it will enabled\
and the previous file disabled. If an already loaded file is picked from\
the [File: > Main Window File ComboBox] control then it becomes the enabled file.
If the [Main Menu <b>Single File Mode</b> Item] is unchecked then more than one loaded file can be\
enabled. Object instances for all the enabled files will be shown in the\
main window. The [File: > Main Window File ComboBox] control will show the current selected loaded file.\
The [Main Window File Menu] item's operate on this file. Each file can be\
explicitly enabled or disabled with the [File Menu <b>Enabled</b> Item].
}
 
{Controlling the Listed Object Instances} {
The order the instances are listed on can be controlled by clicking on\
the column header. The primary sort key will be the clicked on column.\
Click on the same column again to reverse the order.
If the [Main Menu <b>Single File Mode</b> Item] is checked then only instances from the\
most currently selected file will be listed. Otherwise the instances\
from every enabled file are listed. You can control which files are\
enabled by selecting the file with the [File: > Main Window File ComboBox] control and\
then using the [File Menu <b>Enabled</b> Item].
}
 
{Controlling the Listed Statistic Names} {
The statistics list will only contain the name of statistics that\
all of the selected instances have in common. If no instances are\
selected then all known statistics are listed.
If the [Main Menu <b>No Flatlines</b> Item] is unchecked then statistics whose values\
are all zero have names show in a light font.\
Otherwise these statistic names are not listed.
The [Main Menu <b>Statistic Level</b> SubMenu] lets you select what level of statistics\
are listed. Any statistics that belong to a level higher than the selected one\
will not be listed.
}
 
{How to Select Object Instances} {
If you are interested in just one instance select it by clicking on it.
If you are interested in all of the instances of a certain type then\
select them all. Only statistics the selected instances all have in common will be show.\
If the [Main Menu <b>Combine</b> Item] is checked then all the data for the selected instances\
will be added together when a line is created. Otherwise each instance\
will get its own line.\
If [Main Menu <b>Combine Across Files</b> Item] is checked then it will cause combine\
to ignore what file an instance is from. If its unchecked then only instances\
from the same file will be combined together.
To search for an instance enter <tt>control-s</tt>. A search window will popup\
in which you can type. Enter <tt>control-s</tt> or <tt>tab</tt> to find the next match.\
Enter <tt>return</tt> to get rid of the search window. If you enter a number then\
the search will be based on the process id field. Otherwise the name field\
is used.
Right clicking over the instance list gets a [popup menu > Instance List PopupMenu]. If you pick\
[Select > Instance List PopupMenu Select SubMenu] submenu you can then do one of the following:
   * The <b>Clear</b> item unselects all the instances.
   * The <b>All</b> item selects all the instances.
   * The <b>by Statistic</b> item will select all of the instances that support\
the currently selected statistics. This gives you an easy way to find\
what instances support a statistic you are interested in.
   * The <b>by Type</b> item will select instances whose type is the same as the\
type of a currently selected instance. So if you want all 'Sessions'\
selected just select one and then pick <b>by Type</b>.
}
 
{How to Select Statistics} {
Click on the statistic you want to select.
If you select [more than one > List Multiple Selection] statistic you get a line for each one.

To search for a statistic whose name starts with a known prefix simply\
type the letters of that prefix and the first statistic with that\
prefix will be shown.

To find a statistic whose name contains a known substring do a [search > List Search Control] by typing <tt>control-s</tt>.
}

{List Search Control} {
This control allows a list to be searched. The search always finds the next item in the list that has a substring containing the text being searched for. As text is typed in the search is done automatically. The control contains the text from the last search.

When doing an [instance > Main Window Instance Table] search if you just type in a number then only the <b>Pid</b> column is searched and vsd beeps when it finds a completely matching pid. Otherwise the search is done on the <b>Name</b> column. If you want to search for a number in the name column then you must also include a non-numeric prefix. For example to search for a session id prefix it with the <tt>-</tt> character.

!Bindings
   * [standard editing > String Entry Editing]
   * <tt>control-s</tt> or <tt>tab</tt> to find the next matching list element
   * <tt>control-r</tt> to find the previous matching list element
   * <tt>return</tt> or click somewhere else to terminate the search

The following controls support this control:
   * [Main Window Instance Table]
   * [Main Window Statistic List]
   * [Chart Window Statistic ComboBox]
   * [Statistic Window Name ComboBox]
}
 
{How to Get Statistic Information} {
If the [Main Menu <b>Show Statistic Info</b> Item] is checked then a\
[seperate window > Statistic Information Window]\
will be created that will be kept updated with information on the most\
currently selected statistic.
In the [statistic information window > Statistic Information Window] you can browse all the available statistics\
and modify the statistic's level and/or the statistic's default filter.\
Any modification will be saved when you exit vsd.
}
 
{How to Filter Statistics} {
The filters are: Default, None, PerSecond, PerSample, Smooth, and Aggregate.
<b>Default</b> gets you None if the statistic represents a snapshot of a value.\
It gets you PerSecond if the statistic represents a value that always increases.
<b>None</b> shows you the raw values for the statistic with no filtering at all.
<b>PerSample</b> shows you the difference between two consecutive samples\
of the statistic.
<b>PerSecond</b> is the same as PerSample except it divides the difference by the number\
of elapsed seconds between the two samples.
<b>Smooth</b> is like none except any values much larger or smaller than the average are smoothed out.
<b>Aggregate</b> shows you a running total of per sample deltas for the statistic.\
The running total is reset to zero when the current delta is zero or\
changes direction. For example if the last couple of delta where positive\
then a change in direction would be a delta with a negative value.
When a line is added to a chart the default filter is used.\
The default filter for a statistic can be redefined using the [Default Filter MenuButton].
Once the line is added you can change its filter using the [Chart Window Filter MenuButton].
}
 
{How to Create a New Chart} {
Select the [instances > How to Select Object Instances]\
and [statistics > How to Select Statistics]\
to display in the new chart and click on the\
[Main Window New Chart Button].
You can let VSD generate a name for the new chart or enter one yourself\
in the [Chart: > Main Window Chart ComboBox] control.
The new chart will be configured based on options found in the [Main Window Chart Menu].\
If you change these options they will be saved and used the next time\
you start vsd.

A chart window can be created with the following controls:
   * [Add Line > Main Window Add Line Button]
   * [New Chart > Main Window New Chart Button]
   * [Add To Chart > Main Chart Menu Add To Chart Item]
   * [New Template Chart > Template Menu New Template Chart SubMenu]

To learn more about what can be done with a chart see [Chart Window Features].
}
 
{How to Add a Line to an Existing Chart} {
Select the [instances > How to Select Object Instances]\
and [statistics > How to Select Statistics]\
to add and click on the [Main Window <b>Add Line</b> Button].\
The line will be added to the chart shown in the [Chart: > Main Window Chart ComboBox] control.
}
 
{How to Cut, Copy, and Paste} {
You can copy or cut the selected line from a chart.\
Once this is done it can be pasted once to a chart.\
This allows you to easily move lines from one chart to another and\
to create a copy of a line to modify without changing the orignal.
You can copy and paste the current object instance and statistic selection\
from the main window to a chart window. This allows for easier chart\
targeting in cases that you have a large number of charts.
A copy or cut puts an item on the clipboard and deletes any item that was\
already on the clipboard.
A paste causes the clipboard to be emptied.

!Keyboard Bindings
   * <b>Copy</b> is done with <tt>control-c</tt> or a host dependent <em>Copy</em> key.
   * <b>Cut</b> is done with <tt>control-x</tt> or a host dependent <em>Cut</em> key.
   * <b>Paste</b> is done with <tt>control-v</tt> or a host dependent <em>Paste</em> key.

!Related Menu Items
   * [copy selection > Main Menu Copy Selection Item]
   * [copy selected line > Line Menu Copy Item]
   * [cut selected line > Line Menu Cut Item]
   * [paste selection or line > Chart Menu Paste Item]
}
 
{How to Select a Line} {
Move the mouse onto the line you want to select. Once the line\
is highlighted click on it.
You can also select a line by clicking on it in the legend.
Deselect a line by clicking on it again.
}
 
{How to Get Information About a Location} {
Move the mouse in the graph itself.\
If the mouse gets close to a line it will be highlighted. Also if the\
mouse is close to an actual data point its X and Y values will be displayed.
}
 
{How to Delete a Line} {
Select the line and then use the [Line Menu <b>Delete</b> Item].
Or move the mouse over the line's [legend > Graph Legend] entry\
and click on the middle mouse button.
}
 
{How to Zoom} {
Zooming allows you see details in a particular area of a chart.\
It also removes some visual lossage that occurs when lots of samples\
are displayed on a finite sized chart. Multiple zoom levels are supported\
for each chart. Note that when a chart is zoomed data points that lie\
outside the zoom window will not be visible. Also the stats displayed for\
the selected line will exclude data points to the left or right of the zoom window.

A zoom in can be done in a number of ways.
<b>Time Zooms:</b> The easiest is to middle click the mouse in the area you want to\
see better. This only zooms the time (x) axis so it lets you easily focus\
on a point in time without any loss of value (y) axis in that time period.
<b>Box Zooms:</b> You can also zoom in using the [Chart Menu <b>Zoom In</b> Item].\
First start a zoom using the menu item.\
Then set the first point of the zoom by clicking on it with the left button.\
Now move the mouse to the other point and click again.\
A zoom can be cancelled by clicking the right mouse button.\
This zooms both the x and y axis so some data in the time period might\
not be visible on the graph.

You can adjust a zoom level by using the left or right arrow keys.\
This time shifts the zoom level by one sample. If you use the <tt>control</tt> key\
with the left or right arrow keys then the time shift is by however many\
time samples are in the zoom level.

To zoom out one level click the right mouse button over the graph or use
the [Chart Menu <b>Zoom Out</b> Item].
}
 
{How to Change a Line} {
First select the line. Then you can change its:
   * <b>statistic</b> using the [Chart Window Statistic ComboBox].
   * <b>filter</b> using the [Chart Window Filter MenuButton].
   * <b>data set</b> using [File Trimming].
   * <b>adder</b> using the [Chart Window Operator MenuButton] and the [Chart Window Number Entry]. See [Normalizing a Line] and [Offsetting a Line] for more information.
   * <b>muliplier</b> using the [Chart Window Operator MenuButton] and the [Chart Window Number Entry]. See [Value Scaling a Line] for more information.
   * <b>scale</b> using the [Chart Window Operator MenuButton] and the [Chart Window Number Entry]. See [Display Scaling a Line] for more information.
   * <b>display symbol</b> using the [Line Menu <b>Symbol</b> SubMenu].
   * <b>display axis</b> using the [Line Menu <b>Graph on Left Axis</b> Item].
}
 
{How to Compare Data} {
   * To see the difference between two points on the same line use the [Line Menu <b>Log Delta</b> Item].
   * To see the difference between any two points on a chart use the [Chart Menu <b>Compare Two Points</b> Item].
   * To see the difference between all the points on two lines use the [Line Menu <b>Diff Lines</b> Item].
}

{How to Customize a Chart} {
Many menu items exist in the [Chart Window Chart Menu] that allow the chart display\
to be customized. Feel free to play with these; they will only change\
the current chart.
}

{Help Links} {
Help links are show in blue and underlined.\
If you click on a link then the link will be followed\
to the new help topic which will be displayed in the current window.\
If you <tt>control</tt> click or right click on a link then the new help\
topic will be shown in a new help window.
}

{Help Window Features} {
Any number of help windows can exist.

!How to Use A Help Window
   * [General Interface Features]
   * [Help Links]

!Keyboard Bindings
   * <tt>control-b</tt> goes back to the previous help view.
   * <tt>control-f</tt> goes forward after a back.
   * <tt>control-s</tt> pops up a [search window > Help Search Control].

!Help Controls
   * <b>Back</b> goes back to the previous help topic
   * <b>Forward</b> returns to a help topic left by going back.
   * <b>Search...</b> pops up a [search window > Help Search Control].
   * <b>Dismiss</b> closes the help window.
}

{Help Search Control} {
This control allows the text of help topics to be searched. Type in the text you are interested in finding. You will hear a beep if the text can not be found in the current help topic. By default the search is done on the help topic in the current window. You can search all topics by clicking on the <b>All Topics</b> button.
Searches are case-insensitive.

!Bindings
   * [standard editing > String Entry Editing]
   * <tt>control-s</tt>, <tt>tab</tt>, or the <b>Next</b> button to find the next match in the current help topic.
   * <tt>control-r</tt> or the <b>Prev</b> button to find the previous match in the curreent help topic.
   * the <b>All Topics</b> button causes a search to be done on all help topics. The help window's contents will change to a results topic which is a list of links to all the topics that contain the text.
   * <tt>return</tt> or click somewhere else to terminate the search
}

{Font Window} {
This dialog window lets you pick a font its used by the following:
   * [Choose Chart Font... > Main Chart Menu Choose Chart Font... Item]
   * [Choose Text Font... > Help Menu Choose Text Font... Item]
Its a modal dialog so it needs to be closed before the rest of vsd will respond to the mouse.
!Menus
This dialogs menu are used to pick the font. Any font you pick will be show immediately with some sample text in this dialog. If you want to see it in an actual window use the <b>Apply</b> button.
   * [File > Font File Menu]
   * [Font > Font Menu]
   * [Size > Font Size Menu]
   * [Format > Font Format Menu]
!Buttons
   * <b>Ok</b> causes any font picked to be used and the dialog to be closed.
   * <b>Apply</b> causes the font picked to be used temporarily. This allows you to see what it looks like in an actual window and then change it again, accept it with the <b>Ok</b> button, or reject it with the <b>Cancel</b> button.
   * <b>Cancel</b> causes any changes made to be rejected and the dialog to be closed.
}
{Font File Menu} {
!Items
   * <b>Reset</b>: causes the dialog's font to go back to the one it started with.
   * <b>Apply</b>: causes the font picked to be used temporarily. This allows you to see what it looks like in an actual window and then change it again, accept it with the <b>Ok</b> button, or reject it with the <b>Cancel</b> button.
   * <b>OK</b>: causes any font picked to be used and the dialog to be closed.
   * <b>Cancel</b>: causes any changes made to be rejected and the dialog to be closed.
This menu is part of the [font dialog > Font Window].
}
{Font Menu} {
This menu allows a single font to be selected. It has an item for every font that vsd could find on your system.

This menu can be [torn off > Tear Off Menus].

This menu is part of the [font dialog > Font Window].
}
{Font Size Menu} {
This menu allows the size of the font to be selected. A number of predefined sizes are offered. If no of those do what you want then select <b>Other...</b> which causes the font dialog window to have a numeric entry field.

This menu can be [torn off > Tear Off Menus].

This menu is part of the [font dialog > Font Window].
}
{Font Format Menu} {
This menu allows you to select any number of the following font modifiers:
   * <b>Bold</b>: makes the font look darker.
   * <b>Italic</b>: makes the font look slanted.
   * <b>Underline</b>: draws a line under the font.
   * <b>Overstrike</b>: draws a line through the font.

This menu can be [torn off > Tear Off Menus].

This menu is part of the [font dialog > Font Window].
}

{Log Window} {
Vsd has at most a single log window. Information is written to it and it can be cut and paste from it to your favorite text editor. If you close the log window then any information written to it is deleted. 
The operations that write to the log window are:
   * [Log... button > File Info Log... Button]
   * [Log Info menu item > Line Menu Log Info Item]
   * [Log Delta menu item > Line Menu Log Delta Item]
   * [Compare Two Points menu item > Chart Menu Compare Two Points Item]
}
{File Information Window} {
This window is created/updated when the [file info... item > File Menu Info... Item] is selected. It shows the following information on the current file:
   * the product version of the [statmonitor] that generated the file
   * a description of the machine and operating system that [statmonitor] ran on when generating the file
   * the time that the first data sample in the file was taken and an estimate of the interval.

You can get even more information about the file by clicking on the [Log...button > File Info Log... Button].
You can get rid of this window by clicking on the <b>Dismiss</b> button.
}

{File Info Log... Button} {
Clicking on this button causes the following information to be [logged > Log Window]:
   * the absolute file name
   * the product version of the [statmonitor] that generated the file
   * a description of the machine and operating system that [statmonitor] ran on when generating the file
   * the time that the first data sample in the file was taken and an estimate of the interval.
   
This button is on the [File Information Window].
}

{Monitor Window} {
Vsd has at most one monitor window. It allows you to easily run a [statmonitor] whose output will be automatically loaded into vsd. Its created or brought to the front by selecting the [Monitor... > Main Menu Monitor... Item] item.
The main display in this window shows a list of valid statistic sources. You can select any one of these. For each source the following is shown:
   * <b>Cache Name</b>:  this is either the name of an existing cache on the local machine or <tt>none</tt> which allows you to collect operating system statistics only.
   * <b>StatMon</b>:  this will be <tt><none></tt> if this vsd does not have a [statmonitor] running on this source. Otherwise its the process id of the monitor. Each vsd can have at most one monitor per source.
   * <b>Version</b>:  if the source is a product's statistic cache then this is the version of that product. Otherwise its the version of the operating system.
   * <b>Creator</b>:  if the source is a product's statistic cache then this is the name of the user who started that product's servers. Otherwise its the host name of the machine.

![Controls > Statmonitor Option Controls]

!Buttons
   * <b>Refresh</b>:  updates the list of statistic sources
   * <b>Start</b>:  starts a [statmonitor] on the selected statistic source. This button is disabled until a valid statistic source is selected. The start will use the values of the [statmonitor options > Statmonitor Option Controls].
   * <b>Status</b>:  shows the status of a running [statmonitor]. This button is disabled until a statistic source with a running statmonitor is selected.
   * <b>Stop</b>:  stops a running [statmonitor]. This button is disabled until a statistic source with a running statmonitor is selected.
   * <b>Dismiss</b>:  closes the monitor window.
}
{Statmonitor Option Controls} {
The following controls both show how a running [statmonitor] is configured and how you want to configure one you are starting. When starting a statmonitor first set the options you desire then click on the <b>Start</b> button.
   * <b>StatMon Output:</b> shows the name of the running statmonitor's output file. If left blank when starting then vsd will generate a unique name. You can type in any file name you desire before starting.
   * <b>Sample Interval:</b> specifies the sampling interval in seconds.
   * <b>Write Interval:</b> tells statmonitor how long to buffer samples internally before flushing them to the output file. Setting this to zero causes the <b>Sample Interval</b> to be used.
   * <b>Level:</b>  tells statmonitor how many operating system statistics it should collect. If you look at the [operating system types > Instance Type Definition] each one documents what the level must be for it to get collected. The default level is one. If the level is zero then no operating system statistics will be collected. Increasing the level causes additional statistics and instance types to be collected. On Windows NT setting the level higher than two can causes an ever increasing number of [thread instances > NtThread Type] to be collected which vsd will not handle well so only collect at this level for short periods of time. On Solaris setting the level higher than three can cause statmonitor to consume a great deal more CPU so it should only be done if the [SystemPages Type] is really needed.
   * <b>AppStat Count:</b>  tells statmonitor how many shared counter statistics to collect from the shared cache. By default it doesn't collect any. If its told to collect one or more then you will see a single [AppStat Type] instance and it will have statistics named <tt>sharedCounter</tt><em>id</em> where <em>id</em> is a number starting at zero. The number of statistics it will have is determined by the <em>numAppStats</em> argument. By default the value of all shared counters is zero. You must instrument your code if you want change their values. The Java methods to use are <tt>initSharedCounter</tt> and <tt>incrementSharedCounter</tt> on the <tt>StatisticAccess</tt> interface in the <tt>gemstone.services</tt> package.
   * <b>Compress</b>  if checked causes the output file to be compressed saving a significant amount of disk space.
   * <b>Pids:</b>  given a list of process ids tells statmonitor to collect additional processes. For each process id given statmonitor will collect a [Process Type] instance.
   * <b>Sessions:</b> given a list of session ids causes statmonitor to only collect cache statistics for the specified [sessions > Session Type].
}

{Statistic Information Window} {
Vsd has at most one statistic information window. Its purpose is to display information on the most recently selected statistic. It can also be used to customize the default filter and the level of any statistic. Its created by checking the [Show Statistic Info > Main Menu Show Statistic Info Item] checkbox.

!Controls
   * [statistic name selector > Statistic Window Name ComboBox]
   * [Default Filter MenuButton]
   * [Level MenuButton]
   * [Statistic Help Button]
!Displays
   * <b>Kind:</b> shows what kind of statistic it is. It will be one of the following:
      * <b>counter</b>: a statistic whose value always increases
      * <b>svalue</b>: a statistic whose value is a signed 32 bit integer.
      * <b>uvalue</b>: a statistic whose value is an unsigned 32 bit integer.
      * <b>float</b>: a statistic whose value is a floating point number
   * <b>Types:</b> shows which [instance types > Instance Type Definition] are known to support this statistic. If none are known then <tt>unknown</tt> is shown. Until a file is loaded vsd has no idea of which types support a statistic.
   * <b>Statistic Description</b> show a textual description of the statistic.
   * <b>Units:</b> shows the units that the statistic's value represents. Some of the more common unit strings are:
      * <b>none</b>
      * <b>minutes</b>
      * <b>seconds</b>
      * <b>milliseconds</b>
      * <b>items</b>
      * <b>bytes</b>
      * <b>kilobytes</b>
      * <b>megabytes</b>
      * <b>pages</b>
      * <b>locks</b>
      * <b>frames</b>
      * <b>commit records</b>
      * <b>log records</b>
      * <b>objects</b>
      * <b>sessions</b>
      * <b>vms</b>
      * <b>messages</b>
      * <b>signals</b>
      * <b>symbols</b>
      * <b>methods</b>
      * <b>threads</b>
      * <b>packets</b>
      * <b>segments</b>
      * <b>connections</b>
      * <b>extents</b>
      * <b>processes</b>
      * <b>events</b>
      * <b>semaphores</b>
      * <b>mutexes</b>
      * <b>sections</b>
      * <b>%</b>:  the value is a percentage
      * <b>false</b> or <b>true</b>:  the value is 0 (false) or 1 (true). 
      * <b>priority</b>
      * <b>enumeration</b>:  the value is a fixed set of values each of which has a specific meaning.
      * <b>id</b>:  the value is just a numeric identifier.
      * <b>bits/sec</b>:  bits per second.
      * <b>ios/sec</b>:  input/output operations per second.
      * <b>operations</b>
      * <b>aborts</b>
      * <b>commits</b>
      * <b>reclaims</b>
      * <b>checkpoints</b>
      * <b>scavenges</b>
}
{Level MenuButton} {
Shows and sets the level of the current statistic. The level can be used to limit the number of statistics [shown > Main Menu Statistic Level SubMenu] by vsd. The level will be one of the following:
   * <b>common</b>  the most useful statistics.
   * <b>advanced</b>  statistic is only of interest to advanced users
   * <b>wizard</b>  statistic is meant for internal developers
If you change the level with this menu button then it will be remembered in [memory file > VSD Files].

This button is on the [statistic information window > Statistic Information Window].
}
{Statistic Help Button} {
Clicking on this button creates a [help window > Help Window Features] containing the topic that describes the current statistic.

This button is on the [statistic information window > Statistic Information Window].
}
{Default Filter MenuButton} {
Shows and sets the default filter of the current statistic. The default filter is the one that will be used when a line is created for this statistic. It can be any of the following:
   * <b>Default</b>
   * <b>None</b>
   * <b>PerSecond</b>
   * <b>PerSample</b>
   * <b>Smooth</b>
   * <b>Aggregate</b>
See [How to Filter Statistics] for a description of the various filters.

This button is on the [statistic information window > Statistic Information Window].
}
{Statistic Window Name ComboBox} {
This control displays the current statistic. It also will let you change it.
!Bindings
   * Clicking on a name with the <em>mouse</em> both selects it and causes it to become the current statistic.
   * The <em>down</em> arrow key selects the next statistic.
   * The <em>up</em> arrow key selects the previous statistic.
   * The <em>letter keys</em> select the next statistic whose first letter matches the key.
   * <tt>control-s</tt> starts a [search > List Search Control] which results in selecting a statistic.
   * <em>Return</em> causes the selected statistic to become the current statistic.
   * <em>Esc</em> cancels the change leaving the current statistic unchanged.

This control is on the [statistic information window > Statistic Information Window].
}
{Main Window Features} {
Vsd only has a single main window and it always exists. If this window\
is closed or killed then vsd will terminate.

!How to Use The Main Window
   * [General Interface Features]
   * [How to Load a Data File]
   * [How to Update the View of a Data File]
   * [How to Create a Data File]
   * [How to Compare Files]
   * [How to Merge Files]
   * [How to Select]
   * [Controlling the Enabled Files]
   * [Controlling the Listed Object Instances]
   * [Controlling the Listed Statistic Names]
   * [How to Select Object Instances]
   * [How to Select Statistics]
   * [How to Get Statistic Information]
   * [How to Create a New Chart]
   * [How to Add a Line to an Existing Chart]

!Main Menus
   * [Main > Main Window Main Menu]
   * [File > Main Window File Menu]
   * [Chart > Main Window Chart Menu]
   * [Template > Main Window Template Menu]
   * [Help > Main Window Help Menu]

!Main Controls
   * [File: > Main Window File ComboBox]
   * [Instance Table > Main Window Instance Table]
   * [Statistic List > Main Window Statistic List]
   * [Chart: > Main Window Chart ComboBox]
   * [Add Line > Main Window Add Line Button]
   * [New Chart > Main Window New Chart Button]
   * [Status Display > Main Window Status Display]
}

{Main Window Main Menu} {
!Items
   * [Load Data File... > Main Menu Load Data File... Item]
   * [Monitor... > Main Menu Monitor... Item]
   * [Change Directory... > Main Menu Change Directory... Item]
   * [Copy Selection > Main Menu Copy Selection Item]
   * [Show Statistic Info > Main Menu Show Statistic Info Item]
   * [Combine > Main Menu Combine Item]
   * [Combine Across Files > Main Menu Combine Across Files Item]
   * [No Flatlines > Main Menu No Flatlines Item]
   * [Single File Mode > Main Menu Single File Mode Item]
   * [Absolute TimeStamps > Main Menu Absolute TimeStamps Item]
   * [Copy Referenced Lines > Main Menu Copy Referenced Lines Item]
   * [Statistic Level > Main Menu Statistic Level SubMenu]
   * [Dump Statistic Info > Main Menu Dump Statistic Info Item]
   * [Confirm Exit > Main Menu Confirm Exit Item]
   * [Exit > Main Menu Exit Item]
   * [Trace API Calls > Main Menu Trace API Calls Item]
   * [ForceError > Main Menu ForceError Item]
   * [Restart > Main Menu Restart Item]
   * [Debug > Main Menu Debug Item]

[Selection Key > Keyboard Selection Keys]: <tt>Alt-m</tt>

This menu is on the [main window > Main Window Features].
}

{Main Menu Load Data File... Item} {
Pops up file selection dialog which can be used to pick the data file to load.
See [How to Load a Data File] for more information.

[Selection Key > Keyboard Selection Keys]: <tt>Alt-l</tt>

This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu Monitor... Item} {
Pops up the [Monitor Window].
See [How to Create a Data File] for more information.

[Accelerator Key > Keyboard Accelerators]: <tt>control-m</tt>

This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu Change Directory... Item} {
Pops up a dialog that asks for the directory VSD should use as its working directory. Initially this is the directory VSD was started from but it can be changed using this item.
The operations that use the VSD working directory are:
   * [Chart Menu Print Item]
   * [Chart Menu Snapshot Item]

This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu Copy Selection Item} {
Copies the currently selected [instances > How to Select Object Instances] and [statistics > How to Select Statistics] to the clipboard.
See [How to Cut, Copy, and Paste] for more information.

[Accelerator Key > Keyboard Accelerators]: <tt>control-c</tt>

This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu Show Statistic Info Item} {
Controls whether the [statistic information window > Statistic Information Window] is displayed.
See [How to Get Statistic Information] for more information.

This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu Combine Item} {
Controls what is done with a [multiple > List Multiple Selection] [instance > How to Select Object Instances] selection when a line is [created > How to Add a Line to an Existing Chart].
If this item is checked then all the data for the selected instances\
will be added together into a single line. Otherwise a line is created for each  instance.

The [Combine Across Files > Main Menu Combine Across Files Item] item modifies how many of the selected instances are combined. 

This can also be done using the [Instance List PopupMenu <b>Combine</b> Item].

This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu Combine Across Files Item} {
Controls what is done with a [multiple > List Multiple Selection] [instance > How to Select Object Instances] selection when a line is [created > How to Add a Line to an Existing Chart].
If this item is checked then when a [combine > Main Menu Combine Item] is done all the instances are combined into a single line.\
Otherwise instances are only combined if they are from the same file. So you end up with a line for each selected file.

This can also be done using the [Instance List PopupMenu <b>Combine Across Files</b> Item].

This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu No Flatlines Item} {
If checked then:
   * the names of statistics with all zero raw values for the selected instances will not be displayed.
   * lines will not be created if all their filtered values are zero. A [bell message > Bell Messages] will be displayed if this causes no lines to be created. Note that this option is ignored when creating a line using [line arithmetic > Line Arithmetic].

If unchecked then:
   * the names of statistics with all zero raw values for the selected instances will be displayed in a faint font.

See [Controlling the Listed Statistic Names] for more information.

This can also be done using the [Instance List PopupMenu <b>No Flatlines</b> Item].

This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu Single File Mode Item} {
In general you want to check this item if you want to work with more than one file at a time. See the following for examples:
   * [How to Compare Files]
   * [How to Merge Files]

If checked then:
   * only one loaded file can be [enabled > Controlling the Enabled Files] at a time.

If unchecked then:
   * more than one loaded file can be [enabled > Controlling the Enabled Files].

See the following for more information:
   * [Controlling the Enabled Files]
   * [Controlling the Listed Object Instances]
   * [Main Window File ComboBox]

This can also be done using the [Instance List PopupMenu <b>Single File Mode</b> Item].

This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu Absolute TimeStamps Item} {
If checked then:
   * Created lines will use absolute timestamps which can be useful when [merging > How to Merge Files] files.

If unchecked then:
   * Created lines will use relative timestamps which can be useful when [comparing > How to Compare Files] files.

Once a line is created its timestamps can not be changed. If you want to change them just set this item and recreate the line.

Absolute and relative timestamps have different display formats. For more on this see [Chart Menu Time Format SubMenu].

This can also be done using the [Instance List PopupMenu <b>Absolute TimeStamps</b> Item].

This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu Copy Referenced Lines Item} {
If checked then:
   * copies of the source lines are made when [line arithmetic > Line Arithmetic] is done. This prevents subsequent changes to the sources lines effecting the result line.

If unchecked then:
   * references of the source lines are used when [line arithmetic > Line Arithmetic] is done. This allows subsequent changes to the sources lines to also change the result line.

This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu Statistic Level SubMenu} {
This submenu lets you select what level of statistics\
are listed. Any statistics that belong to a level higher than the selected one\
will not be listed.

Each statistic name belongs to one of three levels. You can customize the level by using the [Level MenuButton] on the [Statistic Information Window].

!Items
   * [Common Statistics Only > Common Statistics Only Item]
   * [Advanced & Common Statistics > Advanced & Common Statistics Item]
   * [All Statistics > All Statistics Item]

See [Controlling the Listed Statistic Names] for more information.

This item is part of the [main menu > Main Window Main Menu].
}

{Common Statistics Only Item} {
Causes only those statistics whose level is <em>common</em> to be shown in statistic lists.

This item is part of the [statistic level submenu > Main Menu Statistic Level SubMenu].
}

{Advanced & Common Statistics Item} {
Causes only those statistics whose level is <em>common</em> or <em>advanced</em> to be shown in statistic lists.

This item is part of the [statistic level submenu > Main Menu Statistic Level SubMenu].
}

{All Statistics Item} {
Causes all statistics to be shown in statistic lists.

This item is part of the [statistic level submenu > Main Menu Statistic Level SubMenu].
}

{Main Menu Dump Statistic Info Item} {
Causes information on all known statistics to be dumped to a log window.

This item will only appear if vsd is run in [Wizard Mode].
This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu Confirm Exit Item} {
If checked then:
   * vsd will ask for confirmation before it completes an [exit > Main Menu Exit Item] operation.

If unchecked then:
    * vsd will perform an [exit > Main Menu Exit Item] operation without asking the user for confirmation.

This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu Exit Item} {
Causes vsd to terminate. Before terminating vsd will:
   * confirm with the user that the exit was intended if the [Main Menu Confirm Exit Item] is checked.
   * kill off any monitors left running. See [Monitor Window] for more information.
   * writes the <u><tt>~/.vsdrc</tt></u> <em>memory file</em>. See [VSD Files] for more information.

If the window manager closes the main window then these same actions are taken. If you want to exit vsd without performing any of these actions then kill the vsd process.

This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu Trace API Calls Item} {
If checked then:
   * any call by vsd to its lower level C APIs will result in a trace message written to its stderr. This is intended to help debug crashes that are hard to reproduce.

If unchecked then:
   * API calls are not traced.

This item will only appear if vsd is run in [Wizard Mode].
This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu ForceError Item} {
Picking this item forces an error. This allows vsd developers to make sure the error catching logic is functioning correctly.

This item will only appear if vsd is run in [Wizard Mode].
This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu Restart Item} {
Picking this item causes vsd to reread its [Tcl > Tcl Language] [source file > VSD Files]. This allows vsd developers to make changes to vsd and then apply the changes without exiting and restarting vsd.

This item will only appear if vsd is run in [Wizard Mode].
This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu Debug Item} {
Picking this item causes vsd to source "tkcon.tcl" from the same directory the ".vsdrc" is located in. In a vsd developers environment "tkcon.tcl" is a debugger that allows inspection of vsd's internal state.

This item will only appear if vsd is run in [Wizard Mode].
This item is part of the [main menu > Main Window Main Menu].
}

{Wizard Mode} {
Wizard mode enables certain advanced vsd features intended for vsd developers.

Wizard mode can be enabled either of the following:
   * Setting the <b>VSD_WIZARD</b> enviroment variable in the environment that starts vsd.
   * Setting the Tcl variable <b>vsd(wizard)</b> in <u><tt>~/.vsdconfig</tt></u>. See [VSD Files] for more information.
}

{Main Window File Menu} {
All of the items on this menu operate on the [<em>current file</em> > Main Window File ComboBox].
If no [<em>current file</em> > Main Window File ComboBox] exists then all the items will be disabled.

!Items
   * [Append Data File... > File Menu Append Data File... Item]
   * [Info... > File Menu Info... Item]
   * [Update > File Menu Update Item]
   * [Update All > File Menu Update All Item]
   * [Auto Update > File Menu Auto Update Item]
   * [Enabled > File Menu Enabled Item]
   * [Untrim Left > File Menu Untrim Left Item]
   * [Untrim Right > File Menu Untrim Right Item]
   * [Dump > File Menu Dump Item]

[Selection Key > Keyboard Selection Keys]: <tt>Alt-f</tt>

This menu is on the [main window > Main Window Features].
}

{File Menu Append Data File... Item} {
Pops up file selection dialog which can be used to pick a data file to append to the currently loaded file. This allows you to easily concatenate multiple physical files. Data will no longer be read from the current file location. Instead it will only be read from the new appended location. You should only append files that are newer than the current data.
This operation will fail if the current file load has been interrupted. You need to do an [update > File Menu Update Item] to finish the load before an append can be done.
See [How to Load a Data File] for more information.

This item is part of the [file menu > Main Window File Menu].
}

{File Menu Info... Item} {
Causes the [File Information Window] to be loaded with information on the [<em>current file</em> > Main Window File ComboBox].

This item is part of the [file menu > Main Window File Menu].
}

{File Menu Update All Item} {
Causes any data not already read from any [enabled > Controlling the Enabled Files] file to be read now. This can be used on files that [statmonitor] is still writing data to or on files whose load was interrupted.

[Accelerator Key > Keyboard Accelerators]: <tt>control-U</tt>

This item is part of the [file menu > Main Window File Menu].
}

{File Menu Update Item} {
Causes any data not already read from the [<em>current file</em> > Main Window File ComboBox] to be read now. This can be used on files that [statmonitor] is still writing data to or on files whose load was interrupted.

[Accelerator Key > Keyboard Accelerators]: <tt>control-u</tt>

This item is part of the [file menu > Main Window File Menu].
}

{File Menu Auto Update Item} {
If checked causes an automatic update to be done on the [<em>current file</em> > Main Window File ComboBox] whenever it should have changed. The interval of the first couple of timestamps in a file are used to estimate when a file should have changed.

This item is part of the [file menu > Main Window File Menu].
}

{File Menu Enabled Item} {
This item is only useful in [multi-file mode > Main Menu Single File Mode Item]. Checking this item causes the [<em>current file</em> > Main Window File ComboBox] to be one of those whose instances are [displayed > Main Window Instance Table]. Unchecking this item causes vsd to act as if the [<em>current file</em> > Main Window File ComboBox] was never loaded.

This item is part of the [file menu > Main Window File Menu].
}

{File Menu Untrim Left Item} {
This item is only enabled if the [<em>current file</em> > Main Window File ComboBox] was trimmed left. Selecting it undoes all left trims to the file.
See [File Trimming] for more information.

This item is part of the [file menu > Main Window File Menu].
}

{File Menu Untrim Right Item} {
This item is only enabled if the [<em>current file</em> > Main Window File ComboBox] was trimmed right. Selecting it undoes all right trims to the file.
See [File Trimming] for more information.

This item is part of the [file menu > Main Window File Menu].
}

{File Menu Dump Item} {
Causes vsd to write to its stdout details in the internal data structures its using to contain the data read from the [<em>current file</em> > Main Window File ComboBox].

This item will only appear if vsd is run in [Wizard Mode].
This item is part of the [file menu > Main Window File Menu].
}

{Main Window Chart Menu} {
!Items
   * [Add To Chart > Main Chart Menu Add To Chart Item]
   * [New Chart... > Main Chart Menu New Chart... Item]
   * [Show Legend > Main Chart Menu Show Legend Item]
   * [Time Format > Main Chart Menu Time Format SubMenu]
   * [Default Line Style > Main Chart Menu Default Line Style SubMenu]
   * [Show Time Axis Title > Main Chart Menu Show Time Axis Title Item]
   * [Show Left Axis Title > Main Chart Menu Show Left Axis Title Item]
   * [Show Right Axis Title > Main Chart Menu Show Right Axis Title Item]
   * [Show Current Values > Main Chart Menu Show Current Values Item]
   * [Show Min and Max > Main Chart Menu Show Min and Max Item]
   * [Show Line Stats > Main Chart Menu Show Line Stats Item]
   * [Show CrossHairs > Main Chart Menu Show CrossHairs Item]
   * [Show Grid Lines > Main Chart Menu Show Grid Lines Item]
   * [Selected Line Color... > Main Chart Menu Selected Line Color... Item]
   * [Choose Chart Font... > Main Chart Menu Choose Chart Font... Item]
   * [Close All Charts > Main Chart Menu Close All Charts Item]

[Selection Key > Keyboard Selection Keys]: <tt>Alt-c</tt>

This menu can be [torn off > Tear Off Menus].

This menu is on the [main window > Main Window Features].
}

{Main Chart Menu Add To Chart Item} {
Does the same thing as the [Add Line > Main Window Add Line Button] button.
This item is part of the [main chart menu > Main Window Chart Menu].
}

{Main Chart Menu New Chart... Item} {
Does the same thing as the [New Chart > Main Window New Chart Button] button.
This item is part of the [main chart menu > Main Window Chart Menu].
}

{Main Chart Menu Show Legend Item} {
This item determines if a new [chart window > Chart Window Features] will have  a [legend > Graph Legend] control.

The value its set to will be remembered by vsd in its [memory file > VSD Files].

Use [Chart Menu <b>Show Legend</b> Item] to change this item for a particular chart.

This item is part of the [main chart menu > Main Window Chart Menu].
}

{Main Chart Menu Time Format SubMenu} {
This submenu determines the default time format for a new chart.

The value its set to will be remembered by vsd in its [memory file > VSD Files].

Use [Chart Menu <b>Time Format</b> SubMenu] to change this item for a particular chart.

[Selection Key > Keyboard Selection Keys]: <tt>Alt-t</tt>

This menu can be [torn off > Tear Off Menus].

This item is part of the [main chart menu > Main Window Chart Menu].
}

{Main Chart Menu Default Line Style SubMenu} {
This submenu determines the default line style used when creating lines.

The value its set to will be remembered by vsd in its [memory file > VSD Files].

See [line styles > Line Menu Style SubMenu] to learn more.

This menu can be [torn off > Tear Off Menus].

This item is part of the [main chart menu > Main Window Chart Menu].
}

{Main Chart Menu Show Time Axis Title Item} {
This item determines if a new [chart window > Chart Window Features] will display a title string under the graph's [X Axis].

The value its set to will be remembered by vsd in its [memory file > VSD Files].

Use [Chart Menu <b>Show Time Axis Title</b> Item] to change this item for a particular chart.

This item is part of the [main chart menu > Main Window Chart Menu].
}

{Main Chart Menu Show Left Axis Title Item} {
This item determines if a new [chart window > Chart Window Features] will display a title string next to the graph's [Left Y Axis].

The value its set to will be remembered by vsd in its [memory file > VSD Files].

Use [Chart Menu <b>Show Left Axis Title</b> Item] to change this item for a particular chart.

This item is part of the [main chart menu > Main Window Chart Menu].
}

{Main Chart Menu Show Right Axis Title Item} {
This item determines if a new [chart window > Chart Window Features] will display a title string next to the graph's [Right Y Axis].

The value its set to will be remembered by vsd in its [memory file > VSD Files].

Use [Chart Menu <b>Show Right Axis Title</b> Item] to change this item for a particular chart.

This item is part of the [main chart menu > Main Window Chart Menu].
}

{Main Chart Menu Show Current Values Item} {
This item determines if a new [chart window > Chart Window Features] will have  [X: > Chart Window X: Display] and [Y: > Chart Window Y: Display] controls.

The value its set to will be remembered by vsd in its [memory file > VSD Files].

Use [Chart Menu <b>Show Current Values</b> Item] to change this item for a particular chart.

This item is part of the [main chart menu > Main Window Chart Menu].
}

{Main Chart Menu Show Min and Max Item} {
This item determines if a new [chart window > Chart Window Features] will have  [Min: > Chart Window Min: Display] and [Max: > Chart Window Max: Display] controls.

The value its set to will be remembered by vsd in its [memory file > VSD Files].

Use [Chart Menu <b>Show Min and Max</b> Item] to change this item for a particular chart.

This item is part of the [main chart menu > Main Window Chart Menu].
}

{Main Chart Menu Show Line Stats Item} {
This item determines if a new [chart window > Chart Window Features] will display [line statistics > Data Statistics] in the upper left corner of its [graph > Graph Display].

The value its set to will be remembered by vsd in its [memory file > VSD Files].

Use [Chart Menu <b>Show Line Stats</b> Item] to change this item for a particular chart.

This item is part of the [main chart menu > Main Window Chart Menu].
}

{Main Chart Menu Show CrossHairs Item} {
This item determines if a new [chart window > Chart Window Features] will draw cross hair lines on its [graph > Graph Display].

The value its set to will be remembered by vsd in its [memory file > VSD Files].

Use [Chart Menu <b>Show CrossHairs</b> Item] to change this item for a particular chart.

This item is part of the [main chart menu > Main Window Chart Menu].
}

{Main Chart Menu Show Grid Lines Item} {
This item determines if a new [chart window > Chart Window Features] will draw dotted grid lines on its [graph > Graph Display].

The value its set to will be remembered by vsd in its [memory file > VSD Files].

Use [Chart Menu <b>Show Grid Lines</b> Item] to change this item for a particular chart.

This item is part of the [main chart menu > Main Window Chart Menu].
}

{Main Chart Menu Selected Line Color... Item} {
Selecting this item will cause a color chooser dialog window to popup.\
Use it to pick the color to use for the selected line.\
You will not be able to do anything else until you finish or cancel the color choice.\
Your choice will be recorded in the [memory file > VSD Files].

This item is part of the [main chart menu > Main Window Chart Menu].
}

{Main Chart Menu Choose Chart Font... Item} {
Selecting this item will cause the [font chooser > Font Window] to pop up.\
Use it to pick the chart font. You will not be able to do anything else until\
you finish or cancel the font choice.\
Your choice will be recorded in the [memory file > VSD Files].

The chart font is used for most everything that displays text in a font window. The only exception are the menus.

Font changes will appear immediately in any existing chart. In some cases you need to reselect the active line and [unshow/show > Chart Menu Show Legend Item] the [legend > Graph Legend] to get the new font to display.

This item is part of the [main chart menu > Main Window Chart Menu].
}

{Main Chart Menu Close All Charts Item} {
Selecting this item causes all the existing chart windows to no longer exist.

To close just a single chart window use the [Chart Menu <b>Close</b> Item].

This item is part of the [main chart menu > Main Window Chart Menu].
}

{Main Window Template Menu} {
!Items
   * [Reload Template File > Template Menu Reload Template File Item]
   * [New Template Chart > Template Menu New Template Chart SubMenu]
   * [Templates Use Selection > Template Menu Templates Use Selection Item]

[Selection Key > Keyboard Selection Keys]: <tt>Alt-t</tt>

This menu can be [torn off > Tear Off Menus].

This menu is on the [main window > Main Window Features].
}

{Template Menu Reload Template File Item} {
Causes the [template file > VSD Files] to be reloaded. Use this if you have edited the template file and want the changes to be used immediately.

[Selection Key > Keyboard Selection Keys]: <tt>Alt-r</tt>

This item is part of the [main template menu > Main Window Template Menu].
}

{Template Menu New Template Chart SubMenu} {
Each item on this submenu represents a template from the [template file > VSD Files]. Selecting an item from this submenu causes a [new chart > Chart Window Features] to be created. The [contents > Template Syntax] of the template [determines what lines > Template Expansion] will be added to the created chart.

Vsd has a set of [predefined templates > Predefined Templates]. Each one of these will show up as an item on this submenu. Also any [user defined templates > Chart Menu Save Template Item] will show up.

[Selection Key > Keyboard Selection Keys]: <tt>Alt-c</tt>

This menu can be [torn off > Tear Off Menus].

This item is part of the [main template menu > Main Window Template Menu].
}

{Predefined Templates} {
The following are template definitions that come with VSD. They are stored in the [template file > VSD Files] and can be used from the [New Template Chart > Template Menu New Template Chart SubMenu] menu or the [Add From Template > Chart Menu Add From Template SubMenu].
   * [CPU > CPU Template]
   * [CacheMix > CacheMix Template]
   * [CacheTooSmall > CacheTooSmall Template]
   * [CommitInfo > CommitInfo Template]
   * [EpochSweeps > EpochSweeps Template]
   * [Garbage > Garbage Template]
   * [PageServer > PageServer Template]
   * [SpaceFree > SpaceFree Template]

<b>NOTE:</b> If you get an updated VSD release the definitions of these templates may have changed and new definitions may exist. Your old [template file > VSD Files] will still contain the definitions from an older VSD release. The way to get the new definitions is to delete or rename you template file. This will cause VSD to write a new default template file. You can then edit it and copy any of your own template definitions to it.
}

{Template Menu Templates Use Selection Item} {
If unselected then the [selected instances > Main Window Instance Table] are ignored when a template is used.
If selected then the [selected instances > Main Window Instance Table] will be the only ones that match general patterns in the template.

This item is part of the [main template menu > Main Window Template Menu].
}

{Main Window Help Menu} {
!Items
   * [How to... > Help Menu How to... Item]
   * [Main Window... > Help Menu Main Window... Item]
   * [Chart Window... > Help Menu Chart Window... Item]
   * [All Topics... > Help Menu All Topics... Item]
   * [All Help Text... > Help Menu All Help Text... Item]
   * [Choose Text Font... > Help Menu Choose Text Font... Item]
   * [About VSD... > Help Menu About VSD... Item]

[Selection Key > Keyboard Selection Keys]: <tt>Alt-h</tt>

This menu is on the [main window > Main Window Features].
}

{Help Menu How to... Item} {
Selecting this item creates a [help window > Help Window Features] containing links to all the help topics that tell you how to do something.

This item is part of the [main chart menu > Main Window Help Menu].
}

{Help Menu Main Window... Item} {
Selecting this item creates a [help window > Help Window Features] containing the help topic that describes vsd's [main window > Main Window Features].

This item is part of the [main chart menu > Main Window Help Menu].
}

{Help Menu Chart Window... Item} {
Selecting this item creates a [help window > Help Window Features] containing the help topic that describes vsd's [chart windows > Chart Window Features].

This item is part of the [main chart menu > Main Window Help Menu].
}

{Help Menu All Topics... Item} {
Selecting this item creates a [help window > Help Window Features] containing links to all the help topics. The links are sorted alphabetically.

This item is part of the [main chart menu > Main Window Help Menu].
}

{Help Menu All Help Text... Item} {
Selecting this item creates a [help window > Help Window Features] containing the contents of all the help topics. The contents are sorted by topic name. Creation of this help window can take a long time.

This item is part of the [main chart menu > Main Window Help Menu].
}

{Help Menu Choose Text Font... Item} {
This item allows the font used by vsd to display help text to be customized.
Selecting it brings up a [font dialog > Font Window].

This item is part of the [main chart menu > Main Window Help Menu].
}

{Help Menu About VSD... Item} {
Selecting this item brings up a window that displays various information about vsd. This information includes:
   * version numbers
   * file locations
   * home page

This item is part of the [main chart menu > Main Window Help Menu].
}

{Main Window Add Line Button} {
Creates one or more lines from the selected [instances > How to Select Object Instances]\
and [statistics > How to Select Statistics] and then adds them to the current chart window. If a chart window does not exist then a new one will be created.

The current chart's name is displayed in the [Chart: > Main Window Chart ComboBox] control.

If a new chart window is created then its name can be entered in the [Chart: > Main Window Chart ComboBox] control before this operation is started. Otherwise a default name is used.

For details on how the selection is used to create lines see [Line Creation].

This operation can also be done by double clicking when selecting a\
[instance > How to Select Object Instances]\
or [statistic > How to Select Statistics].

[Accelerator Key > Keyboard Accelerators]: <tt>control-a</tt>
This control is on the [main window > Main Window Features].
}
{Line Creation} {
For a line to be created at least one [instance > How to Select Object Instances] and one [statistic > How to Select Statistics] must be selected.

If more than one instance is selected then vsd needs to decide how to combine them. See [combine > Main Menu Combine Item] and [combine across files > Main Menu Combine Across Files Item] for a description of how this is done.

If [no flatlines > Main Menu No Flatlines Item] is true, and you are not using [line arithmetic > Line Arithmetic], then the line will not be created if all its values are zero. 

The default filter for the statistic on the line is used when creating the line.

A unique color and dash style for the line is picked based on what lines the chart already contains.

!Operations That Create Lines
   * [New Chart > Main Window New Chart Button]
   * [Add Line > Main Window Add Line Button]
   * [copy & paste > How to Cut, Copy, and Paste]
   * [Add Lines > Line Menu Add Lines Item]
   * [Diff Lines > Line Menu Diff Lines Item]
   * [Divide Lines > Line Menu Divide Lines Item]
   * [New Template Chart > Template Menu New Template Chart SubMenu]
   * [Add From Template > Chart Menu Add From Template SubMenu]
}
{Main Window New Chart Button} {
Does the same thing as the [Add Line > Main Window Add Line Button] button with the following exceptions:
   * It will never use an existing chart.
   * An empty chart window is created if no lines are created. So this is the operation to use to get an empty chart that you plan to [paste > How to Cut, Copy, and Paste] a line to.

[Accelerator Key > Keyboard Accelerators]: <tt>control-n</tt>
This control is on the [main window > Main Window Features].
}

{Main Window File ComboBox} {
The file control has the following functions:
   * display name of current file
   * display names of all loaded files
   * display a history of files loaded in the past
   * change the current file
   * load a new file

!Drop Down List
The file control's drop down list contains three types of elements:
   * The first element is always <u><tt>Browse For File...</tt></u> which if selected will do the same thing as the [Main Menu <b>Load Data File...</b> Item].
   * The names of files loaded in the past are always at the bottom of the list. Vsd [remembers > VSD Files] the last ten loaded files. These entries are always displayed as full absolute path names. Selecting one will cause it to be loaded.
   * Currently loaded files are always in the middle of the list. They are displayed with the same [syntax > Loaded File Description Syntax] as that used for the <em>current file</em>. Selecting one causes it to become the <em>current file</em>.

!Current File
The <em>current file</em> is a loaded file whose [description > Loaded File Description Syntax] is displayed in the file control's string entry. It is the one that can be operated on by the [Main Window <b>File</b> Menu]. If [single file mode > Main Menu Single File Mode Item] is on then it is also the only one whose instances will be displayed.

!Loading a New File
See [How to Load a Data File].

This control is on the [main window > Main Window Features].
}

{Main Window Instance Table} {
This table lists all the [instances > Instance Definition] from each [enabled > Controlling the Enabled Files] [file > Main Window File ComboBox].

Its main purpose it to allow instances to be [selected > How to Select Object Instances] so that lines can be [created > Line Creation] for the selected instance's [statistics > Main Window Statistic List].

For each instance in the list the following items are displayed:
   * <b>Name</b>: a string of characters that somewhat uniquely identifies the instance.
   * <b>Type</b>: see [Instance Type Definition].
   * <b>Pid</b>: The id of the process associated with this instance. This item is optional.
   * <b>StartTime</b>: The time the very first sample was taken for this instance.
   * <b>File</b>: the [id > Loaded File Description Syntax] of the file the instance's samples where read from.
   * <b>Samples</b>: The number of samples taken so far for this instance. This can change if data is still being collected the file is [updated > How to Update the View of a Data File]. A green font is used to show that more samples are still possible.

!Sorting
The instance list is sorted. You can tell which column is the primary sort key by looking at the column headers. The one with an extra decoration drawn around its name is the primary sort key. If the decoration is raised then the sort order is increasing. If the decoration is sunken then the sort order is descreasing.
Click on a header to make it the primary sort key. Click on the same header to toggle its sort order.

!Selecting Instances
See [How to Select Object Instances].

!Bindings
   * <tt>control-s</tt> starts an instance [search > List Search Control].
   * <tt>right mouse button</tt> accesses the [popup menu > Instance List PopupMenu].
   * [List Multiple Selection]
   * <tt>double click</tt> on an item does an [add line operation > Main Window Add Line Button].

This control is on the [main window > Main Window Features].
}

{Main Window Statistic List} {
This control lists all the statistics for the selected [instances > Main Window Instance Table]. If no instances are selected then all known statistics will be shown. The statistics are sorted in alphabetic order.

See [How to Select Statistics] for more information on how to use this control.

!Bindings
   * <tt>control-s</tt> starts a statistic [search > List Search Control].
   * [List Multiple Selection]
   * <tt>double click</tt> on an item does an [add line operation > Main Window Add Line Button].

This control is on the [main window > Main Window Features].
}

{Main Window Status Display} {
This control, located at the bottom of the main window, is used to display all [messages > Bell Messages] and [mouse help > Mouse Help].
}

{Instance List PopupMenu} {
Most of the items on this menu can also be found the [Main Window <b>Main</b> Menu]. The unique item is [Select > Instance List PopupMenu Select SubMenu]. They are duplicated here for easy use while working with instances.

!Items
   * [Search... > Instance List PopupMenu Search... Item]
   * [Select > Instance List PopupMenu Select SubMenu]
   * [Combine > Instance List PopupMenu Combine Item]
   * [Combine Across Files > Instance List PopupMenu Combine Across Files Item]
   * [No Flatlines > Instance List PopupMenu No Flatlines Item]
   * [Single File Mode > Instance List PopupMenu Single File Mode Item]
   * [Absolute TimeStamps > Instance List PopupMenu Absolute TimeStamps Item]

This menu can be [torn off > Tear Off Menus].

This popmenu is on the [Main Window Instance Table] control.
}

{Instance List PopupMenu Search... Item} {
Starts an instance [search > List Search Control] operation.

[Accelerator Key > Keyboard Accelerators]: <tt>control-s</tt>
This item is part of the [instance list popup menu > Instance List PopupMenu].
}

{Instance List PopupMenu Select SubMenu} {
See [How to Select Object Instances] for more information.

!Items
   * <b>Clear</b>: unselects every instance in the list.
   * <b>by Statistic</b>: select every instance that support the currently selected statistics.
   * <b>by Type</b>: for every currently selected instance; select all other instances of the same type.
   * <b>All</b>: select every instance in the list.

This menu can be [torn off > Tear Off Menus].

This menu is part of the [instance list popup menu > Instance List PopupMenu].
}

{Instance List PopupMenu Combine Item} {
Does the same thing as the [Main Menu Combine Item].

This item is part of the [instance list popup menu > Instance List PopupMenu].
}

{Instance List PopupMenu Combine Across Files Item} {
Does the same thing as the [Main Menu Combine Across Files Item].

This item is part of the [instance list popup menu > Instance List PopupMenu].
}

{Instance List PopupMenu No Flatlines Item} {
Does the same thing as the [Main Menu No Flatlines Item].

This item is part of the [instance list popup menu > Instance List PopupMenu].
}

{Instance List PopupMenu Single File Mode Item} {
Does the same thing as the [Main Menu Single File Mode Item].

This item is part of the [instance list popup menu > Instance List PopupMenu].
}

{Instance List PopupMenu Absolute TimeStamps Item} {
Does the same thing as the [Main Menu Absolute TimeStamps Item].

This item is part of the [instance list popup menu > Instance List PopupMenu].
}

{Instance Definition} {
The term <b>instance</b> is used to refer to a logical identifiable entity which has associated with it a set of statistics. A finite number of data samples exist for each instance. Each sample is a snapshot of all the instances statistic values at a particular point in time.

An instance's identity is determined by the following properties:
   * a name
   * a [type > Instance Type Definition]
   * an optional process id
   * the file the instance's samples where read from
}

{Instance Type Definition} {
Each [instance > Instance Definition] has a type. Each type has:
   * a name
   * a version number
   * a set of statistic names

The type is identified by its name and version number. Vsd automatically generates version numbers when it finds two types with the same name but different static names. This only happens when vsd loads more than one file. The first type loaded by vsd is always version one. Vsd shows other version numbers as a suffix on the type name.

!Well Known Instance Types
[statmonitor] is the standard generator of vsd data files and it defines the following well known types in its output. They fall into two main categories:
   * <b>Cache Instance Types</b>
      * [Vm Type]
      * [Shrpc Type]
      * [Pgsvr Type]
      * [Stn Type]
      * [Extent Type]
      * [Session Type]
      * [Statmon Type]
      * [AppStat Type]
   * <b>Operating System Instance Types</b>
      * [Process Type]
      * [TCP Type]
      * [SolarisSystem Type]
      * [Disk Type]
      * [SimpleNetwork Type]
      * [ComplexNetwork Type]
      * [Partition Type]
      * [SystemPages Type]
      * [NtSystem Type]
      * [NtMemory Type]
      * [NtObjects Type]
      * [NtPagingFile Type]
      * [NtNetwork Type]
      * [NtLogicalDisk Type]
      * [NtThread Type]

If data files are generated with other tools they are free to define their own types.
}

{SAP} {
SAP stands for system agent process. Physically its a Java VM. Each stone has a primary SAP and can have any number of optional remote SAPs. SAPs are started and stopped when the stone is started and stopped. The SAP manages all communication with the stone. In vsd its represented by:
   * a [Vm > Vm Type] and whose name ends with <tt>sap</tt>
   * a [shared page cache monitor > Shrpc Type]
   * a [pageService > Pgsvr Type]
   * one or more [aioWriters > Pgsvr Type]
}

{Vm Type} {
Represents a Java virtual machine. This type has a great number of statistics.
They include:
   * OS [Process Type] statistics
   * statistics for vm internals
   * statistics for Java code that may be executed in this VM. Examples of these are ORB, EJB, OTS, and Activator statistics.

!Vm Type Versions
}

{Session Type} {
Represents a single GemStone session. Sessions are always associated with a single VM process but a VM can have more than one session.

!Session Type Versions
}

{Pgsvr Type} {
Represents two different kinds of threads that run in the [SAP] VM.
   * Each SAP has a single pgsvr thread named <u><tt>pageService</tt></u>. Its services the pages in the shared page cache frames. It removes pages that are no longer needed and preempts pages when frames are in high demand.
   * Each SAP can have one or more threads named <u><tt>aioWriter</tt><em>x</em></u>. These threads scan the pages in the shared page cache and writing dirty ones as fast as they can to the extents.

!Pgsvr Type Versions
}

{Extent Type} {
Represents a single [stone > Stn Type] extent file. Stones can have one or more extents. The statistics measure how much the extent is being used and how much of it is in use.

!Extent Type Versions
}

{Shrpc Type} {
Represents the shared page cache manager. Each [SAP] VM has a single instance of this type. The statistics measure how the frames in the shared cache are being used.
!Shrpc Type Versions
}

{Stn Type} {
Represents the stone service. This is a single process that each GemStone system has. In addition to the standard [process > Process Type] statistics, its statistics measure extent and tranlog usage and transaction performance.

!Stn Type Versions
}

{Statmon Type} {
Represents the [statmonitor] process that collected the data. The only statistic this type has, other than the standard [process > Process Type] ones, is the [TimeWritingStats Statistic].

!Statmon Type Versions
}

{AppStat Type} {
Represents the application statistics collected by [statmonitor]. Statmonitor can be told when it starts to collection a certain number of appstats by using the <tt>-n</tt> command line switch. These shared counter statistics will always be zero unless application code has been written to change their values.

!AppStat Type Versions
}

{Process Type} {
Represents a single operating system process. Many of the other types include the process type's statistics. If [statmonitor] is started from vsd a instance of this type will be collected for vsd.
Also each <tt>-P</tt> [statmonitor] command line argument will result in an instance of this type.

Only collected by [statmonitor] if it started with a <tt>-s</tt> level greater than zero.

!Process Type Versions
}

{SolarisSystem Type} {
Represents a single Solaris machine. These statistics are the best ones to look at first to see overall resource usage on a machine.

Only collected by [statmonitor] if it started with a <tt>-s</tt> level greater than zero.

!SolarisSystem Type Versions
}

{NtSystem Type} {
Represents a single Windows NT machine. These statistics are the best ones to look at first to see overall resource usage on a machine.

Only collected by [statmonitor] if it started with a <tt>-s</tt> level greater than zero.

!NtSystem Type Versions
}
{NtMemory Type} {
Represents the memory management subsystem of a Windows NT machine. These statistics let you determine how much paging your machine is doing.

Only collected by [statmonitor] if it started with a <tt>-s</tt> level greater than zero.

!NtMemory Type Versions
}
{NtObjects Type} {
Represents the resource tracking subsystem of a Windows NT machine. These statistics are just counts of a number of system objects.

Only collected by [statmonitor] if it started with a <tt>-s</tt> level greater than zero.

!NtObjects Type Versions
}
{NtPagingFile Type} {
Represents a single Windows NT paging file. Paging files are used to provide virtual memory swap space. If it fills up you will start to get out of memory errors.

Only collected by [statmonitor] if it started with a <tt>-s</tt> level greater than one.

!NtPagingFile Type Versions
}
{NtNetwork Type} {
Represents a Windows NT network subsystem.

Only collected by [statmonitor] if it started with a <tt>-s</tt> level greater than one.

!NtNetwork Type Versions
}
{NtLogicalDisk Type} {
Represents a single formatted Windows NT file system. More than one of these can exist.

Only collected by [statmonitor] if it started with a <tt>-s</tt> level greater than one.

!NtLogicalDisk Type Versions
}
{NtThread Type} {
Represents a single Windows NT native thread. Each process can have one or more native threads. This type lets you see process like statistics for each thread. However a huge number of thread instances can exist so collecting at this level should only be done for short periods of time.

Only collected by [statmonitor] if it started with a <tt>-s</tt> level greater than two.

!NtThread Type Versions
}

{Disk Type} {
Represents a single operating system disk. Disks represent the physical device. They can be partioned into one or more [partitions > Partition Type].

Only collected by [statmonitor] if it started with a <tt>-s</tt> level greater than one.

!Disk Type Versions
}

{TCP Type} {
Represents a machines TCP networking subsystem.

On Solaris only collected by [statmonitor] if it started with a <tt>-s</tt> level greater than one.
On Windows NT only collected by [statmonitor] if it started with a <tt>-s</tt> level greater than zero.

!TCP Type Versions
}

{SimpleNetwork Type} {
Represents a machines simple network adaptors. Typically this is the loopback adaptor. The loopback adapter is used when inter-process communication is done with sockets on the same machine.

Only collected by [statmonitor] if it started with a <tt>-s</tt> level greater than two.

!SimpleNetwork Type Versions
}

{ComplexNetwork Type} {
Represents a machines complex network adaptors. Typically this is any adaptor except for loopback.

Only collected by [statmonitor] if it started with a <tt>-s</tt> level greater than two.

!ComplexNetwork Type Versions
}

{Partition Type} {
Represents a single partition on an operating system disk. Each file system is usually on a single partition.

Only collected by [statmonitor] if it started with a <tt>-s</tt> level greater than two.

!Partition Type Versions
}

{SystemPages Type} {
Represents advanced Solaris memory management statistics. These statistics are expensive to collect and in most cases statistics on [SolarisSystem Type] are adequate.

Only collected by [statmonitor] if it started with a <tt>-s</tt> level greater than three.

!SystemPages Type Versions
}

{Loaded File Description Syntax} {
For loaded files vsd displays a short descriptive string to identify the file.
The exact syntax is <u><em>id</em><tt>. </tt><em>name os host version</em></u> where:
   * <em>id</em> is a unique number. Its used in the [instance table's > Main Window Instance Table] <b>File</b> column.
   * <em>name</em> is a trimmed form of the absolute file name. It will only be trimmed if the trimmed name differs from all other loaded file trimmed names.
   * <em>os</em> the operating system that the file's data was collected on.
   * <em>host</em> the host name of the machine the file's data was collected on.
   * <em>version</em> the version of the product the file's data was collected on.
}

{Main Window Chart ComboBox} {
The chart control has the following functions:
   * display name of current chart
   * display names of all existing charts
   * enter name for a new chart
   * pick the current chart

!Current Chart
The last [chart window > Chart Window Features] that was selected is the current chart. Its name is displayed in this control.
To change the current chart just click on that chart window or drop down the chart control's combobox and pick it from the list. The drop down list contains the names of all existing chart windows.

!Naming a New Chart
Any time a [chart window > Chart Window Features] is created it must be given an name. By default the name is <u><tt>Chart </tt><em>x</em></u> where <em>x</em> is a number. You can use the chart control to enter your own name by clicking on it and [typing > String Entry Editing] in the new name. After the name has been entered create the new chart and it should have the entered name.

This control is on the [main window > Main Window Features].
}

{Version History} {
Each of the following sections describe the features added to a major version of VSD. It also tries to describe any bug fixes and other changes in minor versions.

!Version 207.06
    * [file combining > Main Menu Combine Across Files Item] can now combine the files into multiple groups. The grouping is defined by adding a regular expression by defining the <tt>vsd(combineFilePattern)</tt> variable in your [.vsdconfig > VSD Files] file.
   * Templates can now be named when they are created
   * Template syntax now supports limiting the matching instances to ones from a subset of the active files. See [Template Syntax] for the details.
   * Fixed a bug that caused an error when saving complex templates.
!Version 207.05
   * Changed instance table column order so that the potentially wide name column is on the far right. 
   * Fixed chart window legend ordering.
   * Fixed instance sorting.
   * Fixed order lines are added to a chart when multiple files are loaded.
   * Fixed counter combine of 64-bit statistics.
   * File ids now start with one instead of zero.
   * Time Axis title now corrected for GemFire.
!Version 207.04
   * Added [Update All > File Menu Update All Item] menu item.
!Version 207.03
   * Added GSS support.
!Version 207.02
   * Fix for bug 28189; trim right no longer corrupts time axis.
!Version 207.01
   * Fix for bug 28111; loading of compressed statmon files works once again.
!Version 207.00
   * Added <em>GemFire</em> support.
!Version 206.05
   * Shipped with <em>Facets 2.0</em>.
   * Added [Change Directory > Main Menu Change Directory... Item] menu item.
!Version 206.04
   * Fix for bug 27122 ([File Trimming] could cause vsd to crash).
!Version 206.03
   * Added resizer control on main window so that the size of the statistic list can be changed.
!Version 206.02
   * Changing the [statistic level > Main Menu Statistic Level SubMenu] now updates statistics listed in the main and statistic info windows.
   * Documented how [an instance search > List Search Control] works.
   * The GEMSTONE environment variable is now set correctly and the correct statmonitor executable is now found when starting a statmonitor from the [Monitor Window].
   * Shipped with <em>Facets 1.1</em>.
!Version 206.01
   * If [line arithmetic > Line Arithmetic] is done on disjoint lines you will now get a [message > Bell Messages] telling you the lines did not overlap. Also the help now states that only the overlapping portions of lines are used when doing [line arithmetic > Line Arithmetic].
!Version 206.00
   * A file can now be appended to an already loaded file. See [File Menu Append Data File... Item].
   * Added [-u > update command line switch], [-a > append load command line switch] and [-n > normal load command line switch] command line switches.
   * Chart legend entries now change color when their line is selected.
!Version 205.00
   * A picture can be taken of a chart using the [snapshot > Chart Menu Snapshot Item] menu item.
   * [Concatenated > Statmonitor Output Format] statmonitor data files are now supported.
   * The [Monitor Window] will now display caches that can be attached to. It used to only display stones which made it impossible to attach to a remote cache.
!Version 204.01
   * Double clicking on a statistic in the main window, or typing <tt>Enter</tt>, or clicking <tt>Add Line</tt> when no chart windows exist will no longer cause a beep with the message <tt>no title for</tt>.  Instead a new chart window will be created.
!Version 204.00
   * A template can now be defined as a logical collection of other templates. Currently the only way to create such a template is to edit the [template file > VSD Files]. See [<em>namesLineSpec</em> > Template Syntax] for the syntax.
!Version 203.01
   * The [statistic name selector > Statistic Window Name ComboBox] will now only list statistics used in at least one of the files it has loaded. If no files have been loaded yet then it will list all the statistics it knows about.
!Version 203.00
   * You can now cancel on operation that is adding a bunch of lines to a chart. Just click on the chart and hit the <tt>Esc</tt> key or <tt>Control-G</tt>. You can also just close the chart window.
   * [Compute Scale > Line Menu Compute Scale Item] and [Compute Scale All > Chart Menu Compute Scale All Item] had been broken since version 201.00. They now work.
!Version 202.01
   * When vsd is started it now checks to see if new features have been added since it was last run and pops up a help window that describes the new features.
!Version 202.00
   * [User defined statistics > Statistic Definitions] are now supported.
   * [User defined aliases > Statistic Aliases] are now supported.
!Version 201.00
   * Vsd is now built independent of GSJ and GSS.
   * Updated Tcl and Tk to version 8.3.3.
   * Updated Tix to version 8.1.1.
   * Updated BLT to version 2.4u.
   * Different [line styles > Line Menu Style SubMenu] are now supported.
   * Chart [printing > Chart Menu Print Item] for Unix is back.
!Version 200.00
   * [close all chart windows > Main Chart Menu Close All Charts Item]
   * [display message when bell is rung > Bell Messages]
   * [display help based on mouse position > Mouse Help]
   * [cut, copy, and paste of lines > How to Cut, Copy, and Paste]
   * [adding or subtracting a line by a constant > Offsetting a Line]
   * [multiplying or dividing a line by a constant > Value Scaling a Line]
   * [normalizing a line > Normalizing a Line]
   * [Line Arithmetic]
   * [Multiple Files]
   * [control when templates use selected instances > Template Menu Templates Use Selection Item]
   * Template [syntax > Template Syntax] has been enhanced.
   * [hyper-linked help > Help Window Features]
   * [X axis > X Axis] now shows the file the selected line came from.
   * Data from a loaded file can be [trimmed > File Trimming].
   * Monitors started using [vsd > Main Menu Monitor... Item] will collect\
process statitics on vsd.
   * Display of statistic whose value's are all zero can be supressed. See [Controlling the Listed Statistic Names].
   * Searching for a statistic by typing in its first character has been enhanced\
so that a multi-character prefix can be used. See [How to Select Statistics].
   * Instances can now be selected based on type or statistic. See [How to Select Object Instances].
   * The chart printing feature no longer exists.
   * The <u>Main Menu <b>Single Counter Mode</b> Item</u> no longer exists.
}

{File Trimming} {
Trimming data causes vsd to act as if that data does not exist.\
Each loaded file can have a two sequences of its data trimmed.
The <em>Left</em> sequence always starts with the file's first data sample.
The <em>Right</em> sequence always ends with the file's last data sample.
Trimming is always done with a single line even though it will cause the\
entire file to be trimmed. Using a line gives the trimmer a graphical\
display to pick the most meaningful trim point.
Trimming can be done more than once to a sequence making the sequence
larger each time.\
Untrimming totally reverses all trim operations on the sequence.

The menu items that support file trimming are:
   * Line [Trim Left > Line Menu Trim Left Item]
   * Line [Trim Right > Line Menu Trim Right Item]
   * Line [Untrim Left > Line Menu Untrim Left Item]
   * Line [Untrim Right > Line Menu Untrim Right Item]
   * File [Untrim Left > File Menu Untrim Left Item]
   * File [Untrim Right > File Menu Untrim Right Item]
}

{Line Arithmetic} {
Two source lines on the same chart can be used to produce a new result line.\
The values in the result line are the result of adding, subtracting, or\
dividing the values of the source lines.\
The menu items that support line arithmetic are:
   * [Add Lines > Line Menu Add Lines Item]
   * [Diff Lines > Line Menu Diff Lines Item]
   * [Divide Lines > Line Menu Divide Lines Item]

The resulting line will only have data in the time period the two original lines had in common. Line arithmetic can not be done on disjoint lines. You can [combine > Main Menu Combine Item] disjoint statistics which is much like adding lines.

If a [copy > Main Menu Copy Referenced Lines Item] of the source lines\
is made then subsequent changes to the sources lines will have no effect\
on the result line.

If the result line has a [reference > Main Menu Copy Referenced Lines Item]\
to the source lines then subsequent changes in the source lines will be\
propogated the the result line.
}
{Multiple Files} {
Vsd now has much better support for working with multiple files:
   * The [instance table > Main Window Instance Table] shows the file id the instance was loaded from. You can [control > Controlling the Enabled Files] which files instances will be displayed.
   * [Template expansion > Template Expansion] will create a chart for each file making it easy to compare files.
   * Some other options have been added allowing files to be [compared > How to Compare Files] and [merged > How to Merge Files].
}
{statmonitor} {
The statistic monitor is a process that periodically samples statistics and writes their values to a file. The source of the statistics can be a shared cache created by a [stone > Stn Type] or the operating system. For both sources they must reside on the machine the statistic monitor is running on. By default statmonitor will be monitoring both a shared cache and the operating system.

The executable to run to create a statistic monitor is <tt>statmonitor</tt>. Its located in the <tt>bin</tt> subdirectory. Its important to use the statmonitor executable that was distributed with the product whose shared cache you wish to monitor. If you don't then its likely your statmonitor will fail to start with a version mismatch error.

Statmonitor will keep running until its interrupted or its reached the limit set by <tt>-h</tt> or <tt>-t</tt>.

Statmonitor requires a single argument when you start it. That is the name of the [stone > Stn Type] whose cache statistics will be monitored. If you only want to monitor operating system statistics then use the string <tt>none</tt> as the stone name.

For a description of the format of the files written by statmonitor see [Statmonitor Output Format].

Statmonitor accepts a large number of optional switches after the required stone name. They fall into one of the following categories.

!Input Control Switches
   * <tt>-i</tt> <em>interval</em>:  specifies the sampling interval in seconds. The default is twenty seconds. The minimum is one second. Overrides any previous <tt>-i</tt> or <tt>-I</tt> switches.
   * <tt>-I</tt> <em>msInterval</em>:  specifies the sampling interval in milliseconds (thousandths of a second). The default is twenty seconds. The current minimum is 100 milliseconds. Subsecond sampling intervals cause an actual timestamp to not be written to the output file for each sample. Instead a simple counter is written and the analyzer running vsd needs to remember the actual interval used. Overrides any previous <tt>-i</tt> or <tt>-I</tt> switches.
   * <tt>-m</tt> <em>stoneHost</em>:  if the cache you will monitor is remote from the stone then in addition to the required stone name you must also specify the host the stone is running on.
   * <tt>-n</tt> <em>numAppStats</em>:  tells statmonitor how many shared counter statistics to collect from the shared cache. By default it doesn't collect any. If its told to collect one or more then you will see a single [AppStat Type] instance and it will have statistics named <tt>sharedCounter</tt><em>id</em> where <em>id</em> is a number starting at zero. The number of statistics it will have is determined by the <em>numAppStats</em> argument. By default the value of all shared counters is zero. You must instrument your code if you want change their values. The Java methods to use are <tt>initSharedCounter</tt> and <tt>incrementSharedCounter</tt> on the <tt>StatisticAccess</tt> interface in the <tt>gemstone.services</tt> package.
   * <tt>-p</tt> <em>sessionId</em>:  causes statmonitor to only collect cache statistics for the specified [sessions > Session Type]. This switch can be repeated if you want to monitor more than one session. By default statmonitor will collect cache statistics on all sessions. This switch exists for historical reasons. Its not clear if it serves any useful purpose.
   * <tt>-P</tt> <em>processId</em>: This switch can be repeated if you want to monitor more than one additional [process > Process Type]. By default statmonitor collects statistics for all the processes that have cache statistics. This switch lets you collect process statistics for processes that don't have cache statistics. For example your web server.
   * <tt>-s</tt> <em>level</em>:  tells statmonitor how many operating system statistics it should collect. If you look at the [operating system types > Instance Type Definition] each one documents what the level must be for it to get collected. The default level is one. If the level is zero then no operating system statistics will be collected. Increasing the level causes additional statistics and instance types to be collected. On Windows NT setting the level higher than two can causes an ever increasing number of [thread instances > NtThread Type] to be collected which vsd will not handle well so only collect at this level for short periods of time. On Solaris setting the level higher than three can cause statmonitor to consume a great deal more CPU so it should only be done if the [SystemPages Type] is really needed.
   * <tt>-v</tt> <em>vsdPid</em>: Used by vsd when it is starting statmonitor. This causes statmonitor to collect [process > Process Type] statistics automatically on the vsd that started it.

!Output Control Switches
   * <tt>-f</tt> <em>fileName</em>:  specifies the name of the file statmonitor will write its output to. If not specified defaults to <u><tt>statmon</tt><em>id</em><tt>.out</tt></u>. If you want statmonitor to write to its standard output, instead of a file, then use the string <tt>stdout</tt> as the <em>fileName</em> argument.
   * <tt>-z</tt>:  causes statmonitor's output file to be compressed. Vsd is able to read these files transparently. If you want to uncompress use the gunzip executable.
   * <tt>-r</tt>:  causes statmonitor to restart a new output file when the current one completes. The <tt>-h</tt> or <tt>-t</tt> switches control when a restart is done. The base name of each file is given a unique suffix. Note that the generated files can be concatenated together and treated by vsd as a single file.
   * <tt>-h</tt> <em>hours</em>: causes statmonitor to only write to its output file for the given number of hours. Once that time is up statmonitor exits or restarts a new file (see <tt>-r</tt>). By default statmonitor writes until its interrupted or killed.
   * <tt>-t</tt> <em>times</em>: causes statmonitor to only write to its output file the given number of samples. Once that limits has been reached statmonitor exits or restarts a new file (see <tt>-r</tt>). By default statmonitor writes until its interrupted or killed.
   * <tt>-u</tt> <em>seconds</em>: tells statmonitor how long to buffer samples internally before flushing them to the output file. By default it will buffer for 60 seconds. Setting this to zero causes the interval (<tt>-i</tt> or <tt>-I</tt>) value to be used.
}
{Template Expansion} {
A template is made up of a list of [<em>lineSpecs</em> > Template Syntax]. Each lineSpec can end up [creating > Line Creation] zero or more lines on a chart. If you want all the lines generated by the expansion to go to a single chart window then use [Add From Template > Chart Menu Add From Template SubMenu]. Otherwise a chart is created for each unique file in the selected instances.

!Operations that Expand Templates
   * [New Template Chart > Template Menu New Template Chart SubMenu]
   * [Add From Template > Chart Menu Add From Template SubMenu]
}
{Statistic Aliases} {
Statistic aliases can be added to the [config file > VSD Files].
A statistic alias causes vsd to always use an existing statistic definition when it sees an aliased name. Aliases can be used to map older non-existent names to an existing statistic.
For each alias you want to define add a line of the following form:
   * <tt>sl_stat -alias</tt> <em>oldname newname</em>
where <em>oldname</em> is the statistic name you want mapped to <em>newname</em>.
}
{Statistic Definitions} {
Statistic definitions can be added to the [config file > VSD Files].
Each statistic definition must have the following attributes defined:
   * <b>name:</b> Names the statistic. This attribute is required. Should be an alphanumeric string.
   * <b>kind:</b> See [Statistic Information Window]'s <b>Displays</b> section for a description. This attribute is optional and defaults to <tt>uvalue</tt>. Legal values are:
      * <tt>counter</tt>
      * <tt>uvalue</tt>
      * <tt>svalue</tt>
      * <tt>float</tt>
   * <b>level:</b> See [Level MenuButton] for a description. This attribute is optional and defaults to <tt>common</tt>. Legal values are:
      * <tt>common</tt>
      * <tt>advanced</tt>
      * <tt>wizard</tt>
   * <b>units:</b> Describes the units that the statistic's value represents. This attribute is optional and defaults to <tt>none</tt>. Can be any string. See [Statistic Information Window]'s <b>Displays</b> section for list of common unit strings. 
   * <b>isOSStat:</b> Use a true value to indicate that the statistic value is generated by the operating system. This attribute is optional and defaults to <tt>false</tt>. Must be a boolean value.
   * <b>filter:</b> See [Default Filter MenuButton] for a description. This attribute is optional and defaults to <tt>default</tt>. Legal values are:
      * <tt>default</tt>
      * <tt>none</tt>
      * <tt>persecond</tt>
      * <tt>persample</tt>
      * <tt>smooth</tt>
      * <tt>aggregate</tt>
   * <b>description:</b> Documents the statistic. This attribute is optional and defaults to an empty string. Can be any string. To start a new paragraph in the description use an end of line. When refering to another statistic in the description text use this form to make it a hyper-link:
      * <tt> &#91;</tt><em>SN</em><tt> > </tt><em>SN</em><tt> Statistic]</tt> where <em>SN</em> is the name of the other statistic. Note that if your description string is enclosed in quotes <tt>""</tt> instead of curly brackets <tt>{}</tt> then you will need to escape the first square bracket with a backslash <tt>\</tt>.
Any user defined statistics will override definitions shipped with vsd.
For each statistic you want to define add a line of this form:
   * <tt>set statdef(</tt><em>name</em><tt>) {</tt><em>type level units isOSStat filter description</em><tt>}</tt>
To leave an optional attribute empty use an empty pair of curly brackets <tt>{}</tt>.
}
{Template Syntax} {
The contents of the [template file > VSD Files] must be [tcl code > Tcl Language]. The code in this file should define templates. Each template definition consists of a <em>name</em> and a <em>templateSpec</em>. To define a template an element must be added to the Tcl array named <b>vsdtemplates</b> and the index of the element must be the templates <em>name</em>.

The standard format of a template definition is: <tt>set vsdtemplates(</tt><em>name</em><tt>) </tt><em>templateSpec</em>.

What follows is the syntax for <em>templateSpecs</em>.
Square brackets <tt>[[]</tt> are used in the syntax descriptions to designate\
an optional element.

A <em>list</em> starts with an open curly brace <b>{</b> and is terminated\
by a matching close curly brace <b>}</b>. Whitespace is use to seperate\
elements in a <em>list</em>. The curly braces are not required for single element lists.

A <em>templateSpec</em> is a <em>list</em> of <em>lineSpec</em>.
A <em>lineSpec</em> is either a <em>namesLineSpec</em>, a <em>simpleLineSpec</em> or an <em>operatorLineSpec</em>.
A <em>namesLineSpec</em> is a <em>list</em> in the following format:
   * <b>@</b> <em>nameList</em>
The <em>nameList</em> is a <em>list</em> of zero or more template names. A <em>namesLineSpec</em> is treated as the collection of all the named templates.

A <em>simpleLineSpec</em> is a <em>list</em> in the following format: 
   * <b>{</b><em>typeList namePattern stat scale filter axis</em> <tt>[[</tt><em>divider offset normalize</em><tt>] [[</tt><em>statFilter</em><tt>]</tt><b>}</b>
An <em>operatorLineSpec</em> is a <em>list</em> in the following format: 
   * <b>{</b><em>operator lineSpec1 lineSpec2 scale filter axis</em> <tt>[[</tt><em>divider offset normalize</em><tt>] [[</tt><em>statFilter</em><tt>]</tt><b>}</b>

The <em>typeList</em>, <em>namePattern</em>, and <em>stat</em> are used to select the data that will be plotted.
The <em>typeList</em> is a <em>list</em> of zero or more object type strings and/or file numbers.\
Examples of object type strings are Stn, Shrpc, Vm, Session, Extent and Pgsvr.\
Each type in the list will be selected.
File numbers can be used to limit the spec to the numbered file.
If no types are specified then all the types that support <em>stat</em> will be selected.
If no file numbers are specified then all files enabled will be selected.
An optional plus character <b>+</b> can be appended to the last type in the\
list. This will cause all of the instances that match this <em>lineSpec</em>\
to be [combined > Main Menu Combine Item].

The <em>namePattern</em> can be used to restrict which instances of the\
 types should be selected. It can be a simple name or a [pattern > Glob Style Pattern Syntax]. Use the pattern <b>*</b> if you don't care about the name.

The <em>stat</em> must be a valid statistic name for the given <em>typeList</em>.

The <em>operator</em> field must be one of the following strings:
   * <b>plus</b>
   * <b>diff</b>
   * <b>divide</b>

Both <em>lineSpec1</em> and <em>lineSpec2</em> are a <em>lineSpec</em>.\
The lines produced by these specs are combined together using the <em>operator</em>\
to produce the visible line. If one spec produces more lines than the\
other than the final line from the lessor spec is used repeatedly.

The <em>scale</em> must be a number. See [Display Scaling a Line] to learn what this number will do.

The <em>filter</em> must be one of the following strings:
  <b>none</b>, <b>persecond</b>, <b>persample</b>, <b>smooth</b>, or <b>aggregate</b>.
See [How to Filter Statistics] to learn what this string will do.

The <em>axis</em> must be the string <b>y</b> or <b>y2</b>.\
This [controls what Y axis > Line Menu Graph on Left Axis Item] the line will be graphed on

The <em>divider</em> must be a number. See [Value Scaling a Line]\
to learn what this number will do.

The <em>offset</em> must be a number. See [Offsetting a Line]\
to learn what this number will do.
The <em>offset</em> number is ignored if <em>normalize</em> is not zero.

The <em>normalize</em> must be the number zero or one.\
See [Normalizing a Line] to learn what this number will do.

!Statistic Filters
The optional <em>statFilter</em> is a <em>list</em> that lets you exclude lines\
based on their stat values. Its format is:
   <b>{</b><em>count min max mean stddev</em><b>}</b>
Each line produced by a template's lineSpec is checked against this filter before its added to the chart. Each line's values must pass each of the constraints imposed by the non-empty items in the filter.
Any statFilter item can be an empty string <b>{}</b>,
a single number, or a list of two numbers.

If an item is the empty string <b>{}</b> it is ignored.

If an item is a list of two numbers (i.e. <b>{36 100}</b>) then\
the first number must be less than the second number and\
if the stat is less than the first or greater than the second\
then it is excluded.

If an item is a number then it is used as follows:
   * If <em>count</em> >= 0 then any line with less samples than the filter is excluded.
   * If <em>count</em> < 0 then any line with more samples than the absolute value\
of the filter is excluded.
   * If <em>min</em> >= 0 then any line whose min is less than the filter is excluded.
   * If <em>min</em> < 0 then any line whose min is greater than the filter is excluded.
   * If <em>max</em> >= 0 then any line whose max is less than the filter is excluded.
   * If <em>max</em> < 0 then any line whose max is greater than the absolute value of the filter is excluded.
   * If <em>mean</em> >= 0 then any line whose mean is less than the filter is excluded.
   * If <em>mean</em> < 0 then any line whose mean is greater than the absolute value of the filter is excluded.
   * If <em>stddev</em> >= 0 then any line whose stddev is less than the filter is excluded.
   * If <em>stddev</em> < 0 then any line whose stddev is greater than the absolute value of the filter is excluded.

!Filter examples:
   * <tt>{100}</tt> only includes stats who have at least 100 samples.
   * <tt>{{} {} 100}</tt> only includes stats whose max is >= 100.
   * <tt>{{} 20 {} {} -5}</tt> only includes stats whose min >= 20\
and whose standard deviation is less than 5.
   * <tt>{{100 200} {} {-500} {120 240}}</tt> only includes stats who have\
at least 100 samples but no more than 200 samples\
and whose maximum value is less than 500\
and whose average value is between 120 and 240.
}
{Glob Style Pattern Syntax} {
   * <b>*</b> Matches any sequence of characters including a null string.
   * <b>?</b> Matches any single character.
   * <b>[[</b><em>chars</em><b>]</b> Matches any character in the set given by\
<em>chars</em>. If a sequence of the form <em>x</em><b>-</b><em>y</em> appears\
in <em>chars</em>, then any character between <em>x</em> and <em>y</em>,\
inclusive, will match.
   * <b>\</b><em>x</em> Matches the single character <em>x</em>.\
This provides a way of avoiding the special\
interpretation of the characters <b>*?[[]\</b> in the pattern.
}
}

#!Vector Operations
#<em>not yet documented</em>
#!Instance Operations
#<em>not yet documented</em>

############################# Start the program #########################
if {![info exists vsdIsRunning]} {
    set vsdIsRunning 1
    wm withdraw .
    set w .vsd
    toplevel $w
    RunVSD $w
}
