[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Elisp performance
From: |
Andy Wingo |
Subject: |
Re: Elisp performance |
Date: |
Tue, 04 Aug 2009 17:47:05 +0200 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/23.0.92 (gnu/linux) |
Hi Daniel,
On Wed 29 Jul 2009 14:50, Daniel Kraft <address@hidden> writes:
> For the timings, I used a simple prime sieve implemented imperatively
> with while and set's, because the recursive one would put elisp without
> tail-calls at a disadvantage (and because lexical binding does not yet
> work for lambda arguments); the code is attached. Both Scheme and Elisp
> version are identical with just syntax changed (set! -> setq, define ->
> defun, begin -> progn). Additionally, for lexical let all let's were
> replaced by lexical-let's in the elisp version.
After some thought on it, your approach sounds good. If you are
benchmarking "how fast does X implement the prime sieve", it would be
better to compare idiomatic code -- for Scheme, that would be a
functional solution to the problem. But if your goal is "how fast is
idiom X in language Y compared to language Z", your approach makes sense
to me.
> 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
>
> So it apparent that both disabling void checks and using lexical let's
> instead of the standard dynamic ones improve performance notably.
> However, were quite out of reach of the Scheme version.
>
> My conjecture is that
Don't conjecture, profile ;-)
Also, disassembly is your friend here.
> 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:
>
> scheme@(guile-user)> (set! + (lambda (a b) 42))
> scheme@(guile-user)> +
> #<program b700a790 at <unknown port>:0:8 (a b)>
> scheme@(guile-user)> (+ 1 2)
> 3
> scheme@(guile-user)> (let ((+ (lambda (a b) 42)))
> ... (+ 1 2))
> 42
This looks like a bug to me in the compiler. I guess we should open-code
primitives based on value and not variable identity.
> In any case, because of dynamic scoping and the expected behaviour of
> flet to change possibly primitives during its extent, I think we can't
> do anything like that for Elisp (except providing guile-primitive for
> hand-optimizing such calls).
Hmmmmmm. It seems that Emacs does inline, but it also reacts to flet.
ELISP> (defun add (x y) (+ x y))
add
ELISP> (compile-defun 'add)
nil
ELISP> (disassemble #'add)
byte code for add:
args: (x y)
0 varref x
1 varref y
2 plus
3 return
ELISP> (require 'cl)
cl
ELISP> (flet ((+ (x y) (- x y))) (add 10 20))
-10
How does this work? Ken do you know?
Regards,
Andy
--
http://wingolog.org/
- Re: Elisp performance, Andy Wingo, 2009/08/04
- Re: Elisp performance, Andy Wingo, 2009/08/04
- Re: Elisp performance, Andy Wingo, 2009/08/04
- Re: Elisp performance, Andy Wingo, 2009/08/04
- Re: Elisp performance, Andy Wingo, 2009/08/04
- Re: Elisp performance,
Andy Wingo <=
- Re: Elisp performance, Andy Wingo, 2009/08/04