This page is about benchmarking Tcl's proc vs Itcl based code to see how much oveerhead Itcl adds and how to make it's performance better.
I decided to compare plain Tcl recursive calling vs Itcl inheriting, using chain and delegating.
If Itcl class has no variables and procs do not use any variables:
ITcl: Chain 10 level deep 51.347 ITcl: Chain 11 level deep 55.769 ITcl: Chain 12 level deep 61.921 ITcl: Chain 13 level deep 72.064 ITcl: Chain 14 level deep 76.513 ITcl: Chain 15 level deep 77.732 ITcl: Chain 16 level deep 84.874 ITcl: Chain 17 level deep 91.932 ITcl: Chain 18 level deep 121.868 ITcl: Chain 19 level deep 114.08 ITcl: Chain 20 level deep 108.025 ITcl: Delegate 10 level deep 32.479 ITcl: Delegate 11 level deep 36.436 ITcl: Delegate 12 level deep 39.776 ITcl: Delegate 13 level deep 41.741 ITcl: Delegate 14 level deep 45.113 ITcl: Delegate 15 level deep 49.032 ITcl: Delegate 16 level deep 52.265 ITcl: Delegate 17 level deep 54.443 ITcl: Delegate 18 level deep 93.945 ITcl: Delegate 19 level deep 71.611 ITcl: Delegate 20 level deep 70.01 ITcl: Inherit 10 level deep 25.959 ITcl: Inherit 11 level deep 28.699 ITcl: Inherit 12 level deep 31.088 ITcl: Inherit 13 level deep 33.196 ITcl: Inherit 14 level deep 35.765 ITcl: Inherit 15 level deep 38.178 ITcl: Inherit 16 level deep 44.797 ITcl: Inherit 17 level deep 43.085 ITcl: Inherit 18 level deep 54.318 ITcl: Inherit 19 level deep 47.477 ITcl: Inherit 20 level deep 50.636 Tcl: Recursive 10 level deep 10.403 Tcl: Recursive 11 level deep 11.743 Tcl: Recursive 12 level deep 12.324 Tcl: Recursive 13 level deep 14.245 Tcl: Recursive 14 level deep 14.721 Tcl: Recursive 15 level deep 16.241 Tcl: Recursive 16 level deep 16.997 Tcl: Recursive 17 level deep 17.485 Tcl: Recursive 18 level deep 18.763 Tcl: Recursive 19 level deep 22.154 Tcl: Recursive 20 level deep 21.667
So it seems that inheriting and calling methods from the same object seems to be the fastest way and using chan is the worst way.
But things change when we define 20 variables at each level - so a 20 level deep test actually increments 19 * 20 = 380 variables:
ITcl: Chain 10 level deep 104.602 ITcl: Chain 11 level deep 112.974 ITcl: Chain 12 level deep 126.078 ITcl: Chain 13 level deep 138.874 ITcl: Chain 14 level deep 147.253 ITcl: Chain 15 level deep 161.369 ITcl: Chain 16 level deep 173.584 ITcl: Chain 17 level deep 188.603 ITcl: Chain 18 level deep 198.702 ITcl: Chain 19 level deep 242.112 ITcl: Chain 20 level deep 226.422 ITcl: Delegate 10 level deep 59.411 ITcl: Delegate 11 level deep 68.117 ITcl: Delegate 12 level deep 70.796 ITcl: Delegate 13 level deep 78.662 ITcl: Delegate 14 level deep 84.386 ITcl: Delegate 15 level deep 90.361 ITcl: Delegate 16 level deep 96.495 ITcl: Delegate 17 level deep 103.415 ITcl: Delegate 18 level deep 109.857 ITcl: Delegate 19 level deep 116.133 ITcl: Delegate 20 level deep 121.538 ITcl: Inherit 10 level deep 75.653 ITcl: Inherit 11 level deep 105.711 ITcl: Inherit 12 level deep 92.505 ITcl: Inherit 13 level deep 104.654 ITcl: Inherit 14 level deep 107.463 ITcl: Inherit 15 level deep 120.157 ITcl: Inherit 16 level deep 150.662 ITcl: Inherit 17 level deep 134.11 ITcl: Inherit 18 level deep 144.124 ITcl: Inherit 19 level deep 154.595 ITcl: Inherit 20 level deep 163.931 Tcl: Recursive 10 level deep 61.822 Tcl: Recursive 11 level deep 68.536 Tcl: Recursive 12 level deep 79.564 Tcl: Recursive 13 level deep 82.756 Tcl: Recursive 14 level deep 93.726 Tcl: Recursive 15 level deep 96.324 Tcl: Recursive 16 level deep 102.629 Tcl: Recursive 17 level deep 109.943 Tcl: Recursive 18 level deep 118.434 Tcl: Recursive 19 level deep 123.855 Tcl: Recursive 20 level deep 129.817
The most interesting part is that delegates now seem to work much faster than the other ones. Still, 25% performance loss
Now, the tclbench based test that did the trick:
package require Itcl set itclvars 0 set minlevel 10 set maxlevel 20 set iter 10000 proc ::level1 {a b c d e} { } itcl::class ::class1 { public method level1 {a b c d e} { return 1 } } itcl::class ::classI1 { inherit ::class1 } itcl::class ::classD1 { inherit ::class1 } itcl::class ::classC1 { public method level {a b c d e} { return 1 } } for {set i 2} {$i <= $maxlevel} {incr i} { set varcode "" set varproccode "" set varitclcode "" set varlist [list] for {set j 0} {$j < $itclvars} {incr j} { set vn v${i}c${j} lappend varlist $vn append varcode "protected variable $vn 0" \n set ::$vn 0 append varproccode "incr ::$vn" \n append varitclcode "incr $vn" \n } set ip [expr {$i-1}] proc ::level$i {a b c d e} "$varproccode \; return \[::level$ip \$a \$b \$c \$d \$e\]" itcl::class ::classD$i " $varcode public method level$i \{a b c d e\} \{ $varitclcode return \[::oD$ip level$ip \$a \$b \$c \$d \$e\] \} " itcl::class ::classI$i "inherit ::classI$ip $varcode public method level$i \{a b c d e\} \{ $varitclcode return \[level$ip \$a \$b \$c \$d \$e\] \} " itcl::class ::classC$i "inherit ::classC$ip $varcode public method level \{a b c d e\} \{ $varitclcode return \[chain \$a \$b \$c \$d \$e\] \} " } for {set i 1} {$i <= $maxlevel} {incr i} { ::classI$i ::oI$i ::classD$i ::oD$i ::classC$i ::oC$i } if {[catch { ::oI$maxlevel level$maxlevel 1 2 3 4 5 ::oD$maxlevel level$maxlevel 1 2 3 4 5 ::oC2 level 1 2 3 4 5 ::level2 1 2 3 4 5 }]} { puts stderr $::errorInfo exit 1 } for {set i $minlevel} {$i <= $maxlevel} {incr i} { bench -desc "Tcl: Recursive [format %2d $i] level deep" -iter $iter \ -body "::level$i a b c d e" bench -desc "ITcl: Inherit [format %2d $i] level deep" -iter $iter \ -body "::oI$i level$i a b c d e" bench -desc "ITcl: Delegate [format %2d $i] level deep" -iter $iter \ -body "::oD$i level$i a b c d e" bench -desc "ITcl: Chain [format %2d $i] level deep" -iter $iter \ -body "::oC$i level a b c d e" }
If someone wishes to make improvements ot the code, please also update the benchmarks.