proc timeit {txt cmd} { set num 100 set count 1000 set run {} for {set n 0} {$n < 100} {incr n} { lappend run $cmd } set val [uplevel 1 [list time \ [join $run {; }] $count]] set tmp [lreplace $val 0 0 \ [expr {[lindex $val 0]/(1.0*$num)}]] puts "$txt: [lrange $tmp 0 1]" }
set a 1 ; set b 2 timeit "Tcl noop" {} timeit "Tcl expr" {expr {1+2}} timeit "Tcl vars" {expr {$a+$b}} timeit "Tcl sum " {sum 1 2} timeit "Tcl expr" {expr {2*2*2}} timeit "Tcl vars" {expr {$b*$b*$b}} timeit "Tcl pow3" {pow3 2}
Note the sum and pow3 procedures that we will be timing. The timeit procedure runs each test 100 times, invoking the interpreter 1000 times to get an average value per iteration.
If we save the above script in a file time.tcl and run it using a Tcl 8.4 interpreter on an Apple Mac iBook 500Mhz, it gives the following:
package require critcl critcl::cproc noop {} void {} critcl::cproc add {int x int y} int { return x + y; } critcl::cproc cube {int x} int { return x * x * x; }
Note that the critcl::cproc procedure defines a C function, and sets up the corresponding Tcl command. We can now add the commands to invoke these to end of the time.tcl script:
timeit " C noop" noop timeit " C sum " {add 1 2} timeit " C vars" {add $a $b} timeit " C pow3" {cube 2} timeit " C vars" {cube $b}
Running the new version of time.tcl using the Critcl Starkit gives the following results:
$ critcl time.tcl Tcl noop: 0.02 microseconds Tcl expr: 0.78 microseconds Tcl vars: 1.86 microseconds Tcl sum : 4.49 microseconds Tcl expr: 0.97 microseconds Tcl vars: 2.63 microseconds Tcl pow3: 4.58 microseconds C noop: 2.96 microseconds C sum : 2.07 microseconds C vars: 3.22 microseconds C pow3: 1.94 microseconds C vars: 2.52 microseconds
When running this the first time, there is a pause for a few seconds after the last of the Tcl test results is printed, while the generated code for the C functions is compiled and the corresponding shared library is cached. On subsequent runs there is no discernible pause because Critcl detects that the source hasn't changed and just loads the shared library.
This example demonstrates the ease with which C code can be added to a Tcl script, and shows the corresponding speed up.