item2
Next»

contents

 

Introduction - 1

History - 2

Overview - 3

Advanced features - 4

Work in progress - 5

One possibility - 6

Conclusion - 7

 

References

Appendix 1 - blowfish

Appendix 2 - tkspline

3.1 - Extending Tcl Scripts with C code

Consider the following Tcl script, which performs some simple calculations and prints the time taken to perform each one:

   proc sum {a b} {
      return [expr {$a+$b}]
   }
   proc pow3 {a} {
      return [expr {$a*$a*$a}]
   }

   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:

   $ tclkit time.tcl
   Tcl noop: 0.01 microseconds
   Tcl expr: 0.75 microseconds
   Tcl vars: 1.8 microseconds
   Tcl sum : 4.46 microseconds
   Tcl expr: 1.08 microseconds
   Tcl vars: 2.8 microseconds
   Tcl pow3: 4.98 microseconds

Now, we can start adding some C code to the top of time.tcl using Critcl. We’ll define three C functions:

  • noop - which demonstrates why scripted no-ops are quicker than compiled ones ÔÄ∫ÔÄ≠ÔÄ©
  • add - equivalent to the sum Tcl procedure
  • cube - equivalent to the pow3 Tcl procedure

   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.

see also

Critcl Home Page

Tclkit Home Page

Starkit Home Page

Wikit Home Page

Tclers' Wiki

Steve's Website

Jean-Claude's Website

Paper by S. Landers & J.C. Wippler, as presented at Tcl/Tk 2002 conference - see also original PDF.

Papers & Presentations