Question

Is there any way to count the commands before execution (may be callstack number including tclcmds) from specified proc name? I think it is needed to assume that the source is available (not for precomiled). Thanking you.

Était-ce utile?

La solution

Dynamic Analysis

You can use traces to find how many commands are executed during the execution of a particular procedure. Under the assumption that the command is not re-entered (i.e., isn't recursive) you do:

proc theProcedureOfInterest {} {
    # Whatever in here...
    for {set i 0} {$i < 5} {incr i} {
        puts i=$i
    }
}
trace add execution theProcedureOfInterest {enter leave enterstep} countCalls
proc countCalls {cmd args} {
    global counter
    switch [lindex $args end] {
        enter {
            set counter 0
        }
        enterstep {
            incr counter
            puts >>>$cmd
        }
        leave {
            puts "$counter calls in $cmd"
        }
    }
}

theProcedureOfInterest

If you execute the above code, you get this output:

>>>for {set i 0} {$i < 5} {incr i} {
        puts i=$i
    }
>>>set i 0
>>>puts i=0
i=0
>>>incr i
>>>puts i=1
i=1
>>>incr i
>>>puts i=2
i=2
>>>incr i
>>>puts i=3
i=3
>>>incr i
>>>puts i=4
i=4
>>>incr i
12 calls in theProcedureOfInterest

That code has 12 command calls inside it, and you can count them yourself too.

This will also trace into procedures called from that procedure (and making it handle recursive calls is possible, but rather more involved). Be aware that changing the definition of the procedure will remove the trace (just reapply it if desired) and also note that this sort of tracing has a substantial performance impact (it greatly inhibits possible optimizations in Tcl's bytecode compiler).

Static Analysis

To get a static analysis of the code, you need the dkf-improved-disassembler branch (I've not merged it yet). Then, you can do:

set disassembled [::tcl::unsupported::getbytecode script {
    # Whatever in here...
    for {set i 0} {$i < 5} {incr i} {
        puts i=$i
    }
}]
set commandCount [llength [dict get $disassembled commands]]

You can also look at the commands element to see the identified commands (dict get [lindex [dict get $disassembled commands] $n] source). It will inspect into commands like for, but not into custom commands with bodies (since it doesn't understand that they're part of the code as opposed to just a funny string). It also has no idea how often they're executed; it's static analysis after all.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top