## ******************************************************** ## ## Description: timers.tcl Version 1.0 ## Provides timing routines for measuring the performance ## of Tcl code. ## ## Comments: ## I tried using various forms of "calibration" to ## "improve" the quality of the reported values, the net ## result was that the "bare" calls are as accurate as the ## calibrated versions -- these calls are VERY fast! ## Accuracy is at least 1% of the reported time. ## ## ******************************************************** ;#barecode package provide timers 1.0 ;## i like to use the ::TIMEIT flag to switch timing ;## code on and off. 0 for false, 1 for true. if { ! [ info exists ::TIMEIT ] } { set ::TIMEIT 1 } ;## initialize the default start tag as a safety feature ;## in case someone calls __t::end before __t::start. namespace eval __t { set S 0 } ;## short circuit efficiently if debugging is off if { ! $::TIMEIT } { proc __t::start { args } {} proc __t::end { args } {} proc __t::mark { args } {} return {} } ;## so we can stand alone and still be useful! if { ! [ llength [ info commands myName ] ] } { proc myName {} { return [ lindex [info level -1] 0 ] } } if { ! [ llength [ info commands addLogEntry ] ] } { proc addLogEntry { args } { puts $args } } ;#end ## ******************************************************** ## ## Name: __t::start ## ## Description: ## Set the start point for timing. As many start points ## as are needed may be defined using the optional "tag" ## argument. ## ## Parameters: ## tag - an optional modifcation to the name of the timer ## ## Usage: ## proc timeit {} { ## __t::start ## __t::end "null timing loop" ## } ## ## Comments: ## proc __t::start { { tag "" } } { set ms [ clock clicks -milliseconds ] set us [ clock clicks ] set ::__t::S$tag [ list $us $ms ] } ## ******************************************************** ## ******************************************************** ## ## Name: __t::end ## ## Description: ## Set a timing endpoint and issue a report. ## ## Parameters: ## msg - a message to be interpolated into the report ## tag - used to identify a start point ## logfile - optional third argument to addLogEntry, q.v. ## ## Usage: ## proc timeit {} { ## __t::start ## __t::end "null timing loop" ## } ## ## Comments: ## The $msg argument will be used in the log entry. ## None of the arguments is required. ## Use the command __t::mark if you just want the value back. ## This command does not return anything. proc __t::end { { msg "" } { tag "" } { logfile "" } } { set ut [ clock clicks ] set mt [ clock clicks -milliseconds ] set ust [ lindex [ set ::__t::S$tag ] 0 ] set mst [ lindex [ set ::__t::S$tag ] 1 ] set udt [ expr { ($ut-$ust)/1000000.0 } ] set mdt [ expr { ($mt-$mst)/1000.0 } ] set dt $udt if { $dt < 0 || $dt > 1 } { set dt $mdt } set caller [ uplevel myName ] ;## caught because we probably don't want to let a ;## timing code exception cause a blip. catch { addLogEntry "$msg $dt sec." "0" $caller "" $logfile } __t::start $tag } ## ******************************************************** ## ******************************************************** ## ## Name: __t::mark ## ## Description: ## Set a timing endpoint and return the last dt. ## ## Parameters: ## tag - an optional modifcation to the name of the timer ## ## Usage: ## proc timeit {} { ## __t::start ## return "null call took [ __t::mark ] seconds" ## } ## ## Comments: ## This is the benchmarking call. Note that __t::start ## MUST be called explicitly to reset the timer. proc __t::mark { { tag "" } } { set ut [ clock clicks ] set mt [ clock clicks -milliseconds ] set ust [ lindex [ set ::__t::S$tag ] 0 ] set mst [ lindex [ set ::__t::S$tag ] 1 ] set udt [ expr { ($ut-$ust)/1000000.0 } ] set mdt [ expr { ($mt-$mst)/1000.0 } ] set dt $udt if { $dt < 0 || $dt > 1 } { set dt $mdt } return $dt } ## ********************************************************
And here is the short form of all this from comp.lang.tcl:
proc dt { ustart mstart } { set ut [ clock clicks ] set mt [ clock clicks -milliseconds ] set udt [ expr { ($ut-$ustart)/1000000.0 } ] set mdt [ expr { ($mt-$mstart)/1000.0 } ] if { $udt < 0 || $udt > 1 } { return $mdt } return $udt }
For more on this subject, see Don Libes' Stopwatch project at http://expect.nist.gov/stopwatch (link broken 2013-04-02)
See also: