Version 1 of tcl size

Updated 2005-03-01 11:45:57

See also:

CMcC 20050301 - jyl was trying to track down what seemed to be a leak in a tcl program, which reminded me of a component of tclhttpd which tries to measure the size of variables and procs in an interpreter.

I've packaged that up here, may it be of use.

 namespace eval tclsize {}

 # DataSize --
 #
 #        return the data size for the interpreter or for a particular namespace.
 #
 # Arguments:
 #        ns        (optional) if given, show the data size for this namespace
 #
 # Results:
 #        Returns {size namecount varcount}
 proc tclsize::DataSize {{ns "::"} {interp ""}} {
     set ng 0
     set nv 0
     set size 0

     foreach g [interp eval $interp info vars ${ns}::*] {
         incr ng
         if {[interp eval $interp array exists $g]} {
             foreach {name value} [interp eval $interp array get $g] {
                 incr size [string length $name]
                 incr size [string length $value]
                 incr nv
             }
         } elseif {[interp eval $interp info exists $g]} {
             # info vars returns declared but undefined namespace vars
             incr size [string length $g]
             incr size [string length [interp eval $interp set $g]]
         }
         incr nv
     }

     foreach child [namespace children $ns] {
         foreach {csize cnv cng} [DataSize $child $interp] break
         incr size $csize
         incr nv $cnv
         incr ng $cng
     }

     return [list $size $nv $ng]
 }

 # CodeSize --
 #
 #        return the code size for the interpreter or for a particular namespace.
 #
 # Arguments:
 #        ns        (optional) if given, show the code size for this namespace
 #
 # Results:
 #        Returns {size proc_count}

 proc tclsize::CodeSize {{ns ::} {interp ""}} {
     set np 0
     set size 0

     foreach g [interp eval $interp info procs ${ns}::*] {
         incr np
         incr size [string length $g]
         incr size [string length [interp eval $interp info args $g]]
         incr size [string length [interp eval $interp info body $g]]
     }

     foreach child [interp eval $interp namespace children $ns] {
         foreach {csize cnp} [CodeSize $child $interp] break
         incr size $csize
         incr np $cnp
     }

     return [list $size $np]
 }

 # InterpSize --
 #
 #        return the data and code size for an interpreter
 #
 # Arguments:
 #        ns        (optional) if given, show the data size for this namespace
 #
 # Results:
 #        Returns {total datasize namecount varcount codesize proccount}
 proc tclsize::InterpSize {{interp ""} {recurse 1}} {
     foreach {data names vars} [DataSize] break
     foreach {code procs} [CodeSize] break

     if {$recurse} {
         foreach child [interp slaves $interp] {
             foreach {cdata cnames cvars} [DataSize $child] break
             incr data $cdata
             incr names $cnames
             incr cvars $cvars

             foreach {ccode cprocs} [CodeSize $child] break
             incr code $ccode
             incr procs $cprocs
         }
     }

     return [list [expr {$data + $code}] $data $names $vars $code $procs]
 }

 if {[info script] eq $argv0} {
     foreach {total data names vars code procs} [tclsize::InterpSize] break
     puts [subst {
         Total accounted: $total bytes.
         Data size: $data bytes in $vars variables ($names names.)
         Code size: $code bytes in $procs procs.
     }]
 }