在 tcl 中计算 proc 内的命令? [英] Counting commands inside the proc in tcl?

查看:36
本文介绍了在 tcl 中计算 proc 内的命令?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有什么方法可以在执行前从指定的 proc 名称计算命令(可能是调用堆栈编号,包括 tclcmds)?我认为需要假设源是可用的(不是预编译的).谢谢你.

解决方案

动态分析

您可以使用跟踪来查找在执行特定过程期间执行了多少命令.在不重新输入命令(即不是递归的)的假设下,您执行以下操作:

proc theProcedureOfInterest {} {#这里随便...对于 {set i 0} {$i <5} {增加我} {把 i=$i}}trace 添加执行 theProcedureOfInterest {enter leave enterstep} countCallsproc countCalls {cmd args} {全局计数器开关 [lindex $args 结束] {进入 {设置计数器 0}输入{增量计数器把 >>>$cmd}离开 {将$counter 调用放入 $cmd"}}}利息程序

如果你执行上面的代码,你会得到这样的输出:

<前>>>>对于 {set i 0} {$i <5} {增加我} {把 i=$i}>>>设置我 0>>> 把 i=0我=0>>>增加我>>> 把 i=1我=1>>>增加我>>> 把 i=2我=2>>>增加我>>> 把 i=3我=3>>>增加我>>> 把 i=4我=4>>>增加我12 次调用 theProcedureOfInterest

该代码内部有 12 个命令调用,您也可以自己计算.

这也将跟踪到从该过程调用的过程(并使其处理递归调用是可能的,但涉及更多).请注意,更改过程的定义将删除跟踪(如果需要,只需重新应用它),还要注意这种跟踪对性能有重大影响(它极大地抑制了 Tcl 字节码编译器中可能的优化).

静态分析

要对代码进行静态分析,您需要dkf-improved-disassembler 分支(我还没有合并它).然后,你可以这样做:

set 反汇编 [::tcl::unsupported::getbytecode script {#这里随便...对于 {set i 0} {$i <5} {增加我} {把 i=$i}}]set commandCount [llength [dict get $disassembled commands]]

您还可以查看 commands 元素以查看已识别的命令(dict get [lindex [dict get $disassembled commands] $n] source).它会检查像 for 这样的命令,但不会检查带有正文的自定义命令(因为它不明白它们是代码的一部分,而不仅仅是一个有趣的字符串).它也不知道它们被执行的频率;毕竟是静态分析.

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.

解决方案

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.

这篇关于在 tcl 中计算 proc 内的命令?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆