Posted to tcl by apn at Thu May 05 02:44:34 GMT 2022view raw
- I was surprised by the following
- (win) 1 % proc x {l e} {linsert $l 0 $e}
- (win) 2 % proc y {l args} {linsert $l 0 {*}$args}
- (win) 3 % set l {} ; time {set l [x $l a]} 50000
- 95.58538800000001 microseconds per iteration
- (win) 4 % set l {} ; time {set l [y $l a]} 50000
- 82.88127 microseconds per iteration
- Proc y is more than 10% faster despite the use of args and {*}
- Disassembling shows the difference
- (win) 5 % tcl::unsupported::disassemble proc x
- ByteCode 0x0000028C3E210D50, refCt 1, epoch 17, interp 0x0000028C3B79C620 (epoch 17)
- Source "linsert $l 0 $e"
- Cmds 1, src 15, inst 16, litObjs 0, aux 0, stkDepth 2, code/src 0.00
- Proc 0x0000028C3E1D2D90, refCt 1, args 2, compiled locals 2
- slot 0, scalar, arg, "l"
- slot 1, scalar, arg, "e"
- Commands 1:
- 1: pc 0-14, src 0-14
- Command 1: "linsert $l 0 $e"
- (0) loadScalar1 %v0 # var "l"
- (2) loadScalar1 %v1 # var "e"
- (4) list 1
- (9) reverse 2
- (14) listConcat
- (15) done
- (win) 6 % tcl::unsupported::disassemble proc y
- ByteCode 0x0000028C3E211A50, refCt 1, epoch 17, interp 0x0000028C3B79C620 (epoch 17)
- Source "linsert $l 0 {*}$args"
- Cmds 1, src 21, inst 16, litObjs 2, aux 0, stkDepth 4, code/src 0.00
- Proc 0x0000028C3E1C4E50, refCt 1, args 2, compiled locals 2
- slot 0, scalar, arg, "l"
- slot 1, scalar, arg, "args"
- Commands 1:
- 1: pc 0-14, src 0-20
- Command 1: "linsert $l 0 {*}$args"
- (0) expandStart
- (1) push1 0 # "linsert"
- (3) loadScalar1 %v0 # var "l"
- (5) push1 1 # "0"
- (7) loadScalar1 %v1 # var "args"
- (9) expandStkTop 4
- (14) invokeExpanded
- (15) done
- If I understand that correctly, y invokes the C implemented Tcl_LinsertObjCmd while x does it all in byte code which is measurably slower.