Hi Ken,
Ken Raeburn wrote:
On Jul 31, 2009, at 02:02, Daniel Kraft wrote:
Iterative prime sieve, (length (find-primes-to 5000)):
Scheme: 0.42s
Elisp, no void checks, lexical let: 3.40s
Elisp, no void checks, dynamic let: 4.43s
Elisp, void checks, dynamic let: 5.12s
Elisp, void checks, lexical let: 4.06s
As Ken says, it would be good to see an Emacs timing too.
I'd like to provide one, but have no idea how to do so... I just
managed to find out how to evaluate elisp code from a buffer, but it
would be cool to get some elisp REPL if possible (maybe even without
starting emacs itself and just from a shell?) -- and how to I time?
As well as byte-compile and time then?
[...]
Thanks for the emacs hints! For the prime sieve, emacs itself takes
about 1.89s (interpreted) and 0.32s (compiled). So it's significantly
faster than my elisp version at the moment, the reason might be the
performance hit from the primitive calls already discussed (but I don't
know). And the compiled version is even faster than Guile runs the
Scheme code.
The "tight loop" takes in emacs about 0.91s (interpreted) and 0.26s
(compiled) when using lexical-let and 0.58s / 0.16s when using dynamic
binding. So with the manual guile-primitive hack, my version actually
reaches emacs here; which is still quite unfair of course, as my code is
faster with lexical-let and emacs is slower...
Ok, I guess a quick summary is in order: I think implementing dynamic
binding directly using dynamic-wind instead of with fluids is a good
idea, as long as we don't already want to keep the fluids for future
multi-threading. If this ever comes, we are probably again forced
back to fluids. Do you think we should switch or not? Regarding tail
calls, my opinion is that there's no "easy" way to make them work with
dynamically bound arguments (as arguments are in elisp), if there is
at all -- and that we should not bother. I don't think emacs does
general tail-call optimization (does it?), and there will be a way to
switch lambda arguments back to lexical scoping, so that for those
lambda's tail-calls will be optimized just fine with the current
compiler/VM infrastructure.
If the new thread keeps running while the creating thread exits the
scope that created a dynamic binding, while the new thread wants to keep
using or updating it... ugh.
Yep, so I think we should either make dynamic bindings thread local
(keep the fluids) or make them global with the problems of concurrent
access but simply declare they are unsafe to use with multiple threads
and users should instead use lexical bindings in relevant code.
I did not get your opinion about which of these ways to go for dynamic
bindings... From my point of view, both have quite advantages and
disadvantages; fluids are cleaner and can be used in the multi-threaded
context (should it become topical), but getting rid of them with
dynamic-wind promises better performance and simpler working when single
threaded. Maybe we could even provide both implementations to choose
for the user, I'll investigate how much effort that would be and what
problems there arise.
Yours,
Daniel
--
Done: Arc-Bar-Cav-Ran-Rog-Sam-Tou-Val-Wiz
To go: Hea-Kni-Mon-Pri