lists: fix crash in ListInsertElements
[jimtcl.git] / bench.tcl
blobc34236c3f3a34b870571b187a7e4b6a4ba3c1fe2
1 set batchmode 0
2 set benchmarks {}
4 proc bench {title script} {
5 global benchmarks batchmode
7 set Title [string range "$title " 0 20]
9 set failed [catch {time $script} res]
10 if {$failed} {
11 if {!$batchmode} {puts "$Title - This test can't run on this interpreter"}
12 lappend benchmarks $title F
13 } else {
14 set t [lindex $res 0]
15 lappend benchmarks $title $t
16 set ts " $t"
17 set ts [string range $ts [expr {[string length $ts]-10}] end]
18 if {!$batchmode} {puts "$Title -$ts microseconds per iteration"}
22 ### BUSY LOOP ##################################################################
24 proc whilebusyloop {} {
25 set i 0
26 while {$i < 1850000} {
27 incr i
31 proc forbusyloop {} {
32 for {set i 0} {$i < 1850000} {incr i} {}
35 ### FIBONACCI ##################################################################
37 proc fibonacci {x} {
38 if {$x <= 1} {
39 expr 1
40 } else {
41 expr {[fibonacci [expr {$x-1}]] + [fibonacci [expr {$x-2}]]}
45 ### HEAPSORT ###################################################################
47 set IM 139968
48 set IA 3877
49 set IC 29573
51 set last 42
53 proc make_gen_random {} {
54 global IM IA IC
55 set params [list IM $IM IA $IA IC $IC]
56 set body [string map $params {
57 global last
58 expr {($max * [set last [expr {($last * IA + IC) % IM}]]) / IM}
60 proc gen_random {max} $body
63 proc heapsort {ra_name} {
64 upvar 1 $ra_name ra
65 set n [llength $ra]
66 set l [expr {$n / 2}]
67 set ir [expr {$n - 1}]
68 while 1 {
69 if {$l} {
70 set rra [lindex $ra [incr l -1]]
71 } else {
72 set rra [lindex $ra $ir]
73 lset ra $ir [lindex $ra 0]
74 if {[incr ir -1] == 0} {
75 lset ra 0 $rra
76 break
79 set i $l
80 set j [expr {(2 * $l) + 1}]
81 while {$j <= $ir} {
82 set tmp [lindex $ra $j]
83 if {$j < $ir} {
84 if {$tmp < [lindex $ra [expr {$j + 1}]]} {
85 set tmp [lindex $ra [incr j]]
88 if {$rra >= $tmp} {
89 break
91 lset ra $i $tmp
92 incr j [set i $j]
94 lset ra $i $rra
98 proc heapsort_main {} {
99 set n 6100
100 make_gen_random
102 set data {}
103 for {set i 1} {$i <= $n} {incr i} {
104 lappend data [gen_random 1.0]
106 heapsort data
109 ### SIEVE ######################################################################
111 proc sieve {num} {
112 while {$num > 0} {
113 incr num -1
114 set count 0
115 for {set i 2} {$i <= 8192} {incr i} {
116 set flags($i) 1
118 for {set i 2} {$i <= 8192} {incr i} {
119 if {$flags($i) == 1} {
120 # remove all multiples of prime: i
121 for {set k [expr {$i+$i}]} {$k <= 8192} {incr k $i} {
122 set flags($k) 0
124 incr count
128 return $count
131 proc sieve_dict {num} {
132 while {$num > 0} {
133 incr num -1
134 set count 0
135 for {set i 2} {$i <= 8192} {incr i} {
136 dict set flags $i 1
138 for {set i 2} {$i <= 8192} {incr i} {
139 if {[dict get $flags $i] == 1} {
140 # remove all multiples of prime: i
141 for {set k [expr {$i+$i}]} {$k <= 8192} {incr k $i} {
142 dict set flags $k 0
144 incr count
148 return $count
151 ### ARY ########################################################################
153 proc ary n {
154 for {set i 0} {$i < $n} {incr i} {
155 set x($i) $i
157 set last [expr {$n - 1}]
158 for {set j $last} {$j >= 0} {incr j -1} {
159 set y($j) $x($j)
163 ### REPEAT #####################################################################
165 proc repeat {n body} {
166 for {set i 0} {$i < $n} {incr i} {
167 uplevel 1 $body
171 proc use_repeat {} {
172 set x 0
173 repeat {1000000} {incr x}
176 ### UPVAR ######################################################################
178 proc myincr varname {
179 upvar 1 $varname x
180 incr x
183 proc upvartest {} {
184 set y 0
185 for {set x 0} {$x < 100000} {myincr x} {
186 myincr y
190 ### NESTED LOOPS ###############################################################
192 proc nestedloops {} {
193 set n 10
194 set x 0
195 incr n 1
196 set a $n
197 while {[incr a -1]} {
198 set b $n
199 while {[incr b -1]} {
200 set c $n
201 while {[incr c -1]} {
202 set d $n
203 while {[incr d -1]} {
204 set e $n
205 while {[incr e -1]} {
206 set f $n
207 while {[incr f -1]} {
208 incr x
217 ### ROTATE #####################################################################
219 proc rotate {count} {
220 set v 1
221 for {set n 0} {$n < $count} {incr n} {
222 set v [expr {$v <<< 1}]
226 ### DYNAMICALLY GENERATED CODE #################################################
228 proc dyncode {} {
229 for {set i 0} {$i < 100000} {incr i} {
230 set script "lappend foo $i"
231 eval $script
235 proc dyncode_list {} {
236 for {set i 0} {$i < 100000} {incr i} {
237 set script [list lappend foo $i]
238 eval $script
242 ### PI DIGITS ##################################################################
244 proc pi_digits {} {
245 set N 300
246 set LEN [expr {10*$N/3}]
247 set result ""
249 set a [string repeat " 2" $LEN]
250 set nines 0
251 set predigit 0
252 set nines {}
254 set i0 [expr {$LEN+1}]
255 set quot0 [expr {2*$LEN+1}]
256 for {set j 0} {$j<$N} {incr j} {
257 set q 0
258 set i $i0
259 set quot $quot0
260 set pos -1
261 foreach apos $a {
262 set x [expr {10*$apos + $q * [incr i -1]}]
263 lset a [incr pos] [expr {$x % [incr quot -2]}]
264 set q [expr {$x / $quot}]
266 lset a end [expr {$q % 10}]
267 set q [expr {$q / 10}]
268 if {$q < 8} {
269 append result $predigit $nines
270 set nines {}
271 set predigit $q
272 } elseif {$q == 9} {
273 append nines 9
274 } else {
275 append result [expr {$predigit+1}][string map {9 0} $nines]
276 set nines {}
277 set predigit 0
280 #puts $result$predigit
283 ### EXPAND #####################################################################
285 proc expand {} {
286 for {set i 0} {$i < 100000} {incr i} {
287 set a [list a b c d e f]
288 lappend b {expand}$a
292 ### MINLOOPS ###################################################################
294 proc miniloops {} {
295 for {set i 0} {$i < 100000} {incr i} {
296 set sum 0
297 for {set j 0} {$j < 10} {incr j} {
298 # something of more or less real
299 incr sum $j
304 ### wiki.tcl.tk/8566 ###########################################################
306 # Internal procedure that indexes into the 2-dimensional array t,
307 # which corresponds to the sequence y, looking for the (i,j)th element.
309 proc Index { t y i j } {
310 set indx [expr { ([llength $y] + 1) * ($i + 1) + ($j + 1) }]
311 return [lindex $t $indx]
314 # Internal procedure that implements Levenshtein to derive the longest
315 # common subsequence of two lists x and y.
317 proc ComputeLCS { x y } {
318 set t [list]
319 for { set i -1 } { $i < [llength $y] } { incr i } {
320 lappend t 0
322 for { set i 0 } { $i < [llength $x] } { incr i } {
323 lappend t 0
324 for { set j 0 } { $j < [llength $y] } { incr j } {
325 if { [string equal [lindex $x $i] [lindex $y $j]] } {
326 set lastT [Index $t $y [expr { $i - 1 }] [expr {$j - 1}]]
327 set nextT [expr {$lastT + 1}]
328 } else {
329 set lastT1 [Index $t $y $i [expr { $j - 1 }]]
330 set lastT2 [Index $t $y [expr { $i - 1 }] $j]
331 if { $lastT1 > $lastT2 } {
332 set nextT $lastT1
333 } else {
334 set nextT $lastT2
337 lappend t $nextT
340 return $t
343 # Internal procedure that traces through the array built by ComputeLCS
344 # and finds a longest common subsequence -- specifically, the one that
345 # is lexicographically first.
347 proc TraceLCS { t x y } {
348 set trace {}
349 set i [expr { [llength $x] - 1 }]
350 set j [expr { [llength $y] - 1 }]
351 set k [expr { [Index $t $y $i $j] - 1 }]
352 while { $i >= 0 && $j >= 0 } {
353 set im1 [expr { $i - 1 }]
354 set jm1 [expr { $j - 1 }]
355 if { [Index $t $y $i $j] == [Index $t $y $im1 $jm1] + 1
356 && [string equal [lindex $x $i] [lindex $y $j]] } {
357 lappend trace xy [list $i $j]
358 set i $im1
359 set j $jm1
360 } elseif { [Index $t $y $im1 $j] > [Index $t $y $i $jm1] } {
361 lappend trace x $i
362 set i $im1
363 } else {
364 lappend trace y $j
365 set j $jm1
368 while { $i >= 0 } {
369 lappend trace x $i
370 incr i -1
372 while { $j >= 0 } {
373 lappend trace y $j
374 incr j -1
376 return $trace
379 # list::longestCommonSubsequence::compare --
381 # Compare two lists for the longest common subsequence
383 # Arguments:
384 # x, y - Two lists of strings to compare
385 # matched - Callback to execute on matched elements, see below
386 # unmatchedX - Callback to execute on unmatched elements from the
387 # first list, see below.
388 # unmatchedY - Callback to execute on unmatched elements from the
389 # second list, see below.
391 # Results:
392 # None.
394 # Side effects:
395 # Whatever the callbacks do.
397 # The 'compare' procedure compares the two lists of strings, x and y.
398 # It finds a longest common subsequence between the two. It then walks
399 # the lists in order and makes the following callbacks:
401 # For an element that is common to both lists, it appends the index in
402 # the first list, the index in the second list, and the string value of
403 # the element as three parameters to the 'matched' callback, and executes
404 # the result.
406 # For an element that is in the first list but not the second, it appends
407 # the index in the first list and the string value of the element as two
408 # parameters to the 'unmatchedX' callback and executes the result.
410 # For an element that is in the second list but not the first, it appends
411 # the index in the second list and the string value of the element as two
412 # parameters to the 'unmatchedY' callback and executes the result.
414 proc compare { x y
415 matched
416 unmatchedX unmatchedY } {
417 set t [ComputeLCS $x $y]
418 set trace [TraceLCS $t $x $y]
419 set i [llength $trace]
420 while { $i > 0 } {
421 set indices [lindex $trace [incr i -1]]
422 set type [lindex $trace [incr i -1]]
423 switch -exact -- $type {
424 xy {
425 set c $matched
426 eval lappend c $indices
427 lappend c [lindex $x [lindex $indices 0]]
428 uplevel 1 $c
431 set c $unmatchedX
432 lappend c $indices
433 lappend c [lindex $x $indices]
434 uplevel 1 $c
437 set c $unmatchedY
438 lappend c $indices
439 lappend c [lindex $y $indices]
440 uplevel 1 $c
444 return
447 proc umx { index value } {
448 global lastx
449 global xlines
450 append xlines "< " $value \n
451 set lastx $index
454 proc umy { index value } {
455 global lasty
456 global ylines
457 append ylines "> " $value \n
458 set lasty $index
461 proc matched { index1 index2 value } {
462 global lastx
463 global lasty
464 global xlines
465 global ylines
466 if { [info exists lastx] && [info exists lasty] } {
467 #puts "[expr { $lastx + 1 }],${index1}c[expr {$lasty + 1 }],${index2}"
468 #puts -nonewline $xlines
469 #puts "----"
470 #puts -nonewline $ylines
471 } elseif { [info exists lastx] } {
472 #puts "[expr { $lastx + 1 }],${index1}d${index2}"
473 #puts -nonewline $xlines
474 } elseif { [info exists lasty] } {
475 #puts "${index1}a[expr {$lasty + 1 }],${index2}"
476 #puts -nonewline $ylines
478 catch { unset lastx }
479 catch { unset xlines }
480 catch { unset lasty }
481 catch { unset ylines }
484 # Really, we should read the first file in like this:
485 # set f0 [open [lindex $argv 0] r]
486 # set x [split [read $f0] \n]
487 # close $f0
488 # But I'll just provide some sample lines:
490 proc commonsub_test {} {
491 set x {}
492 for { set i 0 } { $i < 20 } { incr i } {
493 lappend x a r a d e d a b r a x
496 # The second file, too, should be read in like this:
497 # set f1 [open [lindex $argv 1] r]
498 # set y [split [read $f1] \n]
499 # close $f1
500 # Once again, I'll just do some sample lines.
502 set y {}
503 for { set i 0 } { $i < 20 } { incr i } {
504 lappend y a b r a c a d a b r a
507 compare $x $y matched umx umy
508 matched [llength $x] [llength $y] {}
511 ### MANDEL #####################################################################
513 proc mandel {xres yres infx infy supx supy} {
514 set incremx [expr {(0.0+$supx-$infx)/$xres}]
515 set incremy [expr {(0.0+$supy-$infy)/$yres}]
517 for {set j 0} {$j < $yres} {incr j} {
518 set cim [expr {$infy+($incremy*$j)}]
519 set line {}
520 for {set i 0} {$i < $xres} {incr i} {
521 set counter 0
522 set zim 0
523 set zre 0
524 set cre [expr {$infx+($incremx*$i)}]
525 while {$counter < 255} {
526 set dam [expr {$zre*$zre-$zim*$zim+$cre}]
527 set zim [expr {2*$zim*$zre+$cim}]
528 set zre $dam
529 if {$zre*$zre+$zim*$zim > 4} break
530 incr counter
532 # output pixel $i $j
537 ### RUN ALL ####################################################################
539 if {[string compare [lindex $argv 0] "-batch"] == 0} {
540 set batchmode 1
543 bench {[while] busy loop} {whilebusyloop}
544 bench {[for] busy loop} {forbusyloop}
545 bench {mini loops} {miniloops}
546 bench {fibonacci(25)} {fibonacci 25}
547 bench {heapsort} {heapsort_main}
548 bench {sieve} {sieve 10}
549 bench {sieve [dict]} {sieve_dict 10}
550 bench {ary} {ary 100000}
551 bench {repeat} {use_repeat}
552 bench {upvar} {upvartest}
553 bench {nested loops} {nestedloops}
554 bench {rotate} {rotate 100000}
555 bench {dynamic code} {dyncode}
556 bench {dynamic code (list)} {dyncode_list}
557 bench {PI digits} {pi_digits}
558 bench {expand} {expand}
559 bench {wiki.tcl.tk/8566} {commonsub_test}
560 bench {mandel} {mandel 60 60 -2 -1.5 1 1.5}
562 proc istcl {} {
563 return [expr {![catch {info tclversion}]}]
566 if {$batchmode} {
567 if {[catch {info patchlevel} ver]} {
568 set ver Jim[info version]
570 puts [list $ver $benchmarks]