我已经为正式方法领域的特定工具实现了许多TCL扩展(扩展在C中实现,但我不希望解决方案依赖于这个事实).因此,我的工具的用户可以使用TCL进行原型设计算法.其中许多只是线性的命令列表(它们很强大),例如:
my_read_file f
my_do_something a b c
my_do_something_else a b c
Run Code Online (Sandbox Code Playgroud)
现在,我对时机感兴趣.可以更改脚本以获取:
puts [time [my_read_file f] 1]
puts [time [my_do_something a b c] 1]
puts [time [my_do_something_else a b c] 1]
Run Code Online (Sandbox Code Playgroud)
而不是这个我想要定义执行TCL脚本和获取/写入所有命令的时间的过程xsource.某种形式的探查器.我写了一个天真的实现,其主要思想如下:
set f [open [lindex $argv 0] r]
set inputLine ""
while {[gets $f line] >= 0} {
set d [expr [string length $line] - 1]
if { $d >= 0 } {
if { [string index $line 0] != "#" } {
if {[string index $line $d] == "\\"} {
set inputLine "$inputLine [string trimright [string range $line 0 [expr $d - 1]]]"
} else {
set inputLine "$inputLine $line"
set inputLine [string trimleft $inputLine]
puts $inputLine
puts [time {eval $inputLine} 1]
}
set inputLine ""
}
}
}
Run Code Online (Sandbox Code Playgroud)
它适用于线性命令列表,甚至允许多行注释和命令.但是如果用户使用if语句,循环和过程定义,它就会失败.你能提出更好的方法吗?它必须是纯TCL脚本,尽可能少的扩展.
做你要求的一种方法是使用执行跟踪.这是一个可以做到这一点的脚本:
package require Tcl 8.5
# The machinery for tracking command execution times; prints the time taken
# upon termination of the command. More info is available too (e.g., did the
# command have an exception) but isn't printed here.
variable timerStack {}
proc timerEnter {cmd op} {
variable timerStack
lappend timerStack [clock microseconds]
}
proc timerLeave {cmd code result op} {
variable timerStack
set now [clock microseconds]
set then [lindex $timerStack end]
set timerStack [lrange $timerStack 0 end-1]
# Remove this length check to print everything out; could be a lot!
# Alternatively, modify the comparison to print more stack frames.
if {[llength $timerStack] < 1} {
puts "[expr {$now-$then}]: $cmd"
}
}
# Add the magic!
trace add execution source enterstep timerEnter
trace add execution source leavestep timerLeave
# And invoke the magic, magically
source [set argv [lassign $argv argv0];set argv0]
# Alternatively, if you don't want argument rewriting, just do:
# source yourScript.tcl
Run Code Online (Sandbox Code Playgroud)
然后你会这样称呼它(假设你把它放在一个名为的文件中timer.tcl):
tclsh8.5 timer.tcl yourScript.tcl
Run Code Online (Sandbox Code Playgroud)
请注意,此脚本具有相当大的开销,因为它会禁止许多通常使用的优化策略.对于你在自己的C代码中使用真正的肉的用途来说,这并不重要,但是当它在Tcl中有很多循环时,你会注意到很多.