Posted to tcl by apn at Thu May 05 02:44:34 GMT 2022view raw

  1. I was surprised by the following
  2.  
  3. (win) 1 % proc x {l e} {linsert $l 0 $e}
  4. (win) 2 % proc y {l args} {linsert $l 0 {*}$args}
  5. (win) 3 % set l {} ; time {set l [x $l a]} 50000
  6. 95.58538800000001 microseconds per iteration
  7. (win) 4 % set l {} ; time {set l [y $l a]} 50000
  8. 82.88127 microseconds per iteration
  9.  
  10. Proc y is more than 10% faster despite the use of args and {*}
  11.  
  12. Disassembling shows the difference
  13.  
  14. (win) 5 % tcl::unsupported::disassemble proc x
  15. ByteCode 0x0000028C3E210D50, refCt 1, epoch 17, interp 0x0000028C3B79C620 (epoch 17)
  16. Source "linsert $l 0 $e"
  17. Cmds 1, src 15, inst 16, litObjs 0, aux 0, stkDepth 2, code/src 0.00
  18. Proc 0x0000028C3E1D2D90, refCt 1, args 2, compiled locals 2
  19. slot 0, scalar, arg, "l"
  20. slot 1, scalar, arg, "e"
  21. Commands 1:
  22. 1: pc 0-14, src 0-14
  23. Command 1: "linsert $l 0 $e"
  24. (0) loadScalar1 %v0 # var "l"
  25. (2) loadScalar1 %v1 # var "e"
  26. (4) list 1
  27. (9) reverse 2
  28. (14) listConcat
  29. (15) done
  30.  
  31. (win) 6 % tcl::unsupported::disassemble proc y
  32. ByteCode 0x0000028C3E211A50, refCt 1, epoch 17, interp 0x0000028C3B79C620 (epoch 17)
  33. Source "linsert $l 0 {*}$args"
  34. Cmds 1, src 21, inst 16, litObjs 2, aux 0, stkDepth 4, code/src 0.00
  35. Proc 0x0000028C3E1C4E50, refCt 1, args 2, compiled locals 2
  36. slot 0, scalar, arg, "l"
  37. slot 1, scalar, arg, "args"
  38. Commands 1:
  39. 1: pc 0-14, src 0-20
  40. Command 1: "linsert $l 0 {*}$args"
  41. (0) expandStart
  42. (1) push1 0 # "linsert"
  43. (3) loadScalar1 %v0 # var "l"
  44. (5) push1 1 # "0"
  45. (7) loadScalar1 %v1 # var "args"
  46. (9) expandStkTop 4
  47. (14) invokeExpanded
  48. (15) done
  49.  
  50. If I understand that correctly, y invokes the C implemented Tcl_LinsertObjCmd while x does it all in byte code which is measurably slower.
  51.  
  52.  
  53.