guile-devel
[Top][All Lists]
Advanced

[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/




reply via email to

[Prev in Thread] Current Thread [Next in Thread]