Version 7 of Dynamic call graph

Updated 2005-11-29 15:37:21

if 0 {Richard Suchenwirth 2005-07-13 - Here's a simple sketch how you can get the "dynamic call graph" (which shows which procedure actually called which other in a program run). The idea is to overload the proc command, so that every proc body is augmented (in the beginning) with a call to a helper that records the names of caller and callee in a global array: }

 rename proc _proc
 _proc proc {name argl body} {
    _proc $name $argl callgraph'report\n$body
 }

#-- This argument-less proc is prefixed to every proc defined with the overloaded command:

 _proc callgraph'report {} {
    if [catch {info level -2} res] {set res ""}
    set ::callgraph([lindex $res 0],[lindex [info level -1] 0]) ""
 }

#--- Testing

 proc a {} {b; c }
 proc b args {d; e}
 proc c {} {b; d}
 proc d {} {}
 proc e {} {}

 a
 parray callgraph

if 0 {which returns (the values are always "", a key a,b expresses that a called b):

 callgraph(,a)      =
 callgraph(,parray) =
 callgraph(a,b)     =
 callgraph(a,c)     =
 callgraph(b,d)     =
 callgraph(b,e)     =
 callgraph(c,b)     =
 callgraph(c,d)     =

If there is nothing left of the comma, the procedure was called outside of any proc, i.e. interactively or at script toplevel. Note that parray was also instrumented, because its file was sourced after the overloading of proc. You can do further analyses on the callgraph array, for instance find out all callers of b:

   array names callgraph *,b

or all procedures that b called:

   array names callgraph b,*

Another enhancement would be to record the number an edge of the callgraph was traversed, by counting up:

 _proc callgraph'report {} {
    if [catch {info level -2} res] {set res ""}
    set edge [lindex $res 0],[lindex [info level -1] 0]
    if [info exists ::callgraph($edge)] {
        incr ::callgraph($edge)
    } else {set ::callgraph($edge) 1}
 }

I used the same idea to generate a history of the procedure calls to stderr - VPT

 _proc proc {name arg body} {
     _proc $name $arg "puts stderr \[string repeat {  } \[info level]]$name\n$body" 
 }

Here is some code that does Static call graph


Here is another approach to tracing procedure calls ... Pstack. The advantage to this approach is that only the procedures of interest are traced which is helpful when debugging. The output is also indented based on call depth. tjk


Category Debugging | Arts and crafts of Tcl-Tk programming }