On Jul 29, 2009, at 08:50, 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
It doesn't mean much without testing on the same machine, of course,
but I get ~1s times for running your lexical-let elisp version in
emacs. It'd be a bit of a symbolic win if you can match Emacs's own
Lisp execution times. :-) Though of course, Emacs runs nearly
everything byte-compiled, so it would only be symbolic. (In this
case, the byte-compiled lexical-let version took about 0.2s on my
machine, even better than the Scheme version on your machine.)
I should run some timing tests myself -- I'm particularly interested
in the allocation/gc performance of Guile vs Emacs, for obvious reasons.
My conjecture is that the remaining bottle-neck are the primitive
calls, as they are still resolved using the dynamic-binding and
fluid mechanisms; so maybe it is really a good idea to change
function bindings to just global ones without dynamic scoping, and
implement flet/flet* with dynamic-wind. In contrast to variables,
for functions access performance is a lot more important than let
performance, I guess, so this might be the way to go. What do you
think?
Sounds reasonable to me, but I'm not an expert in that area.
Obviously, it would help a lot to do so. On the other hand,
switching to primitive-ref's would help even more, but I fear we can
not easily do so, because we can not know if a symbol targets a
primitive or was rebound at compile time... BTW, a quick test with
Scheme:
[....]
So it seems that the Scheme compiler just ignores this
possibility... Is (set! + ...) and expecting (+ 1 2) to change
invalid, or should this strictly be regarded as a bug?
In general I don't think you can assume it for all symbols, but if it
helps, the Emacs byte-compiler also assumes that "+" and "cons" and
certain other functions won't be redefined. It's even got an "add1"
opcode.
So if I understand right, if you make similar assumptions and change
how function bindings are handled, your performance for this code
drops to under a second? It sounds like maybe you can get within
shouting distance of Emacs's own performance already, at least for
certain test cases.
Would this interfere with possibly blending Scheme GOOPS code with
Elisp someday? Or is the generic support there at a lower level than
this? (E.g., a "marker" object holds a buffer handle, possibly nil,
and an offset that automatically gets adjusted if text is inserted
before it. You can use "(+ 1 marker)" and get back an integer one
greater than the marker's current offset. If markers were implemented
using GOOPS, would this use of "+" work, given the changes you're
suggesting?)
Ken