Comment 3 for bug 654289

Revision history for this message
Matt Kaufmann (kaufmann) wrote : Re: EVAL is slow on LET-expressions

Thank you; that indeed does solve the problem. Sorry I missed that in
the manual (I now see it mentioned in Section 4.6).

I'm still a bit surprised at the performance compared to CCL, which
also does compilation by default (though perhaps not for EVAL; I don't
know). I wonder if it might be good if EVAL were to bind
*evaluator-mode* to :interpret.

The rest of this comment is just FYI:

I've found a workaround, which I'll probably use so that my code works
in CMUCL as well and also avoids the need for #+sbcl -- unless someone
cares to suggest a workaround for CMUCL (I didn't find any occurrences
of "interpreter" in its user's manual, or using (apropos "EVAL")).
FYI, my workaround is to bind special variables to large objects; the
following illustrates the idea applied to the simplified first example
in the bug report.

lhug-8:~> /p/bin/sbcl-1.0.43
This is SBCL 1.0.43, an implementation of ANSI Common Lisp.
More information about SBCL is available at <http://www.sbcl.org/>.

SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses. See the CREDITS and COPYING files in the
distribution for more information.
* (declaim (optimize (compilation-speed 0) (speed 3) (space 0) (safety 0)))

* (defun make-tree (n acc)
    (cond ((zerop n) acc)
   (t (make-tree (1- n) (cons acc acc)))))

MAKE-TREE
* (defconstant big (make-tree 10000 nil))

BIG
* (defun test ()
    (print (eq (eval `(let ((x 17)) (cdr (cons x (quote ,BIG)))))
        big)))

TEST
* (let (old new)
    (setq old (get-internal-real-time))
    (test)
    (setq new (get-internal-real-time))
    (/ (- new old) (* 1.0 internal-time-units-per-second)))

T
4.762
* (defvar *my-special* nil)

*MY-SPECIAL*
* (defun test2 ()
    (print (eq (eval `(let ((*my-special* 17)) (quote ,BIG)))
        big)))

TEST2
* (let (old new)
    (setq old (get-internal-real-time))
    (test2)
    (setq new (get-internal-real-time))
    (/ (- new old) (* 1.0 internal-time-units-per-second)))

T
4.764
* (defun test-fast ()
    (print (eq (eval `(quote ,BIG))
        big)))

TEST-FAST
* (let (old new)
    (setq old (get-internal-real-time))
    (test-fast)
    (setq new (get-internal-real-time))
    (/ (- new old) (* 1.0 internal-time-units-per-second)))

T
0.0
* (defun test3 ()
    (print (eq (eval `(let ((x 17)) (declare (ignore x)) (quote ,BIG)))
        big)))

TEST3
* (let (old new)
    (setq old (get-internal-real-time))
    (test3)
    (setq new (get-internal-real-time))
    (/ (- new old) (* 1.0 internal-time-units-per-second)))

T
4.751
* (defun test-fast2 ()
    (print (eq (eval `(let () (quote ,BIG)))
        big)))

TEST-FAST2
* (let (old new)
    (setq old (get-internal-real-time))
    (test-fast2)
    (setq new (get-internal-real-time))
    (/ (- new old) (* 1.0 internal-time-units-per-second)))

T
0.0
*