janet-lang / janet

A dynamic language and bytecode vm
https://janet-lang.org
MIT License
3.45k stars 223 forks source link

Speed up range creation #1235

Closed primo-ppcg closed 1 year ago

primo-ppcg commented 1 year ago

I think that range is sufficiently fundamental, both as an array initializer and iterating construct, to warrant a direct C implementation. The current implementation is as a Janet function, with the three argument form implemented in terms of seq, which I found surprising.

I've prepared a fork which moves range into corelib (I've placed it next to slice, which seemed appropriate), with the following results:

(use spork/test)

(timeit-loop [:timeout 1] "1 arg " (range 1000))
(timeit-loop [:timeout 1] "2 args" (range 0 1000))
(timeit-loop [:timeout 1] "3 args" (range 0 2000 2))

master:

1 arg  1.000s, 15.52µs/body
2 args 1.000s, 17.72µs/body
3 args 1.000s, 25.46µs/body

experimental fork:

1 arg  1.000s, 1.537µs/body
2 args 1.000s, 1.541µs/body
3 args 1.000s, 1.543µs/body

which is approximately 10-15 times faster, depending on the number of arguments.

sogaiu commented 1 year ago

As usual my times are slightly slower, but still a nice speed up that seems to be in a similar range (no pun intended) (^^;

master (4ff81a5a):

Janet 1.29.1-4ff81a5a linux/x64/gcc - '(doc)' for help
repl:1:> (do (use spork/test) :ok)
:ok

repl:2:> (timeit-loop [:timeout 1] "1 arg " (range 1000))
1 arg  1.000s, 20.04µs/body
nil

repl:3:> (timeit-loop [:timeout 1] "2 args" (range 0 1000))
2 args 1.000s, 22.83µs/body
nil

repl:4:> (timeit-loop [:timeout 1] "3 args" (range 0 2000 2))
3 args 1.000s, 31.03µs/body
nil

branch in fork (61712bae):

Janet 1.29.1-61712bae linux/x64/gcc - '(doc)' for help
repl:1:> (do (use spork/test) :ok)
:ok

repl:2:> (timeit-loop [:timeout 1] "1 arg " (range 1000))
1 arg  1.000s, 1.626µs/body
nil

repl:3:> (timeit-loop [:timeout 1] "2 args" (range 0 1000))
2 args 1.000s, 1.656µs/body
nil

repl:4:> (timeit-loop [:timeout 1] "3 args" (range 0 2000 2))
3 args 1.000s, 1.678µs/body
nil