[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 ====== 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} { uplevel [list _proc $name $arg "puts stderr \[string repeat { } \[info level]]$name\n$body"] } ====== The uplevel is needed for commands within namespaces. (Thanks to Ralf Fassel) [EvilSon] ---- 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] <> Debugging | Arts and crafts of Tcl-Tk programming