Example usage:$ monitor_memory_graph-3.tcl 9332 50(50 is the scaling factor for the graph. Different applications may need a different scaling factor to make a graph that pleases you.)Change History2006.07.20 Revision 3:I changed vsz= to vsize= after Will Dye pointed out that it fails in Linux with vsz. I didn't realize that vsz was an alias for vsize in NetBSD until now.2007.08.27I fixed a bug with the exec of ps in Linux. It seems that the Linux or GNU ps doesn't accept -o vsize=,rss=. So I've fixed that. The code is also available here: http://megapkg.googlecode.com/svn/trunk/tools/monitor_memory_graph-3.tcl

#!/usr/bin/env tclkit8.5
package require Tk
set ::cursor(x) 1
set ::rsspeak 0
set ::rsspeaktext ""
set ::vszpeak 0
set ::vszpeaktext ""
set ::follow_graph 1
proc draw.value {win value height id peak_ptr peaktext_ptr} {
global cursor scale
upvar $peak_ptr peak
upvar $peaktext_ptr peaktext
set lasty [lindex [$win coords $id] end]
# 800 is a good height for the graph offset
set y [expr {800 - ($value / double($scale))}]
$win coords $id [concat [$win coords $id] [list $cursor(x) $y]]
#
# Test if this value is greater than the previous peak.
#
if {$value > $peak} {
set peak $value
#
# Change the previous peak's color
#
if {"" ne $peaktext} {
$win itemconfigure $peaktext -fill white -font {fixed 10}
}
set peaktext [$win create text $cursor(x) $y -text $value \
-fill orange -font {fixed 14}]
} else {
$win create text $cursor(x) $y -text $value -fill white -font {fixed 10}
}
}
proc update.stats {win pid} {
global cursor
if {[catch {exec ps -p $pid -o vsize= -o rss=} res]} {
return -code error $res
}
foreach {vsz rss} [string trim $res] break
global rsspeak rsspeaktext
set height [winfo height $win]
draw.value $win $rss $height $::rssid rsspeak rsspeaktext
incr cursor(x) 50
global vszpeak vszpeaktext
draw.value $win $vsz $height $::vszid vszpeak vszpeaktext
incr cursor(x) 50
$win config -scrollregion [$win bbox all]
if {$::follow_graph} {
$win xview moveto 1.0
}
after 1000 [list update.stats $win $pid]
}
proc view.tag {win tag} {
foreach {x1 y1 x2 y2} [$win bbox all] break
foreach {tx1 ty1 _ _} [$win bbox $tag] break
$win xview moveto [expr {$tx1 / double($x2)}]
$win yview moveto [expr {$ty1 / double($y2)}]
}
proc main {argc argv} {
if {2 != $argc} {
puts stderr "syntax is: [info script] pid scale"
return 1
}
frame .controls
pack [checkbutton .controls.follow -text "Follow Graph" -variable ::follow_graph] -side left
pack [button .controls.rssPeak -text "Jump to RSS Peak" -command {
set ::follow_graph 0
view.tag .graph.c $::rsspeaktext
}] -side left
pack [button .controls.vsz -text "Jump to VSZ Peak" -command {
set ::follow_graph 0
view.tag .graph.c $::vszpeaktext
}] -side left
pack .controls -fill x
frame .graph
canvas .graph.c \
-xscrollcommand {.graph.xscroll set} \
-yscrollcommand {.graph.yscroll set} \
-bg black
scrollbar .graph.xscroll -command {.graph.c xview} -orient horizontal
scrollbar .graph.yscroll -command {.graph.c yview}
pack .graph -fill both -expand 1
grid .graph.c -row 0 -column 0 -sticky nesw
grid .graph.xscroll -row 1 -column 0 -sticky we
grid .graph.yscroll -row 0 -column 1 -sticky ns
grid columnconfigure .graph 0 -weight 100
grid rowconfigure .graph 0 -weight 100
set ::vszid [.graph.c create line 0 0 1 1 -fill red]
set ::rssid [.graph.c create line 0 0 1 1 -fill green]
set ::scale [lindex $argv 1]
update idletasks
after idle [list update.stats .graph.c [lindex $argv 0]]
}
main $::argc $::argv
