Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Eval performance

8 views
Skip to first unread message

Dr Jon D Harrop

unread,
Oct 28, 2005, 5:43:29 AM10/28/05
to
I'm trying to write a benchmark based on the symbolic differentiation
example discussed recently. By using s-exprs, the Lisp implementation
should be short and fast. However, I'm having trouble getting good
performance using "eval". I believe I need to use compile but I'm not
sure how.

So how can this code be optimised:

(declaim (optimize (speed 3) (safety 3) (space 0) (debug 0)))

(define (d e x)
(typecase e
(number 0)
(symbol (if (eq e x) 1 0))
((cons (eql log) list)
(let ((f (cadr e)))
`(* ,(d f x) (/ 1 ,f))))
((cons (eql +) list)
(let ((f (cadr e)) (g (caddr e)))
`(+ ,(d f x) ,(d g x))))
((cons (eql *) list)
(let ((f (cadr e)) (g (caddr e)))
`(+ (* ,f ,(d g x)) (* ,g ,(d f x)))))
((cons (eql expt) list)
(let ((f (cadr e)) (g (caddr e)))
`(* (expt ,f ,g)
(+ (/ (* ,g ,(d f x)) ,f)
(* (log ,f) ,(d g x))))))))

(define e1 '(+ (* (* a x) x) (* b x) c))

(define (f n g)
(if (= n 0) g `(expt ,(f (- n 1) g) ,(f (- n 1) g))))

(define n 15)

(print "build")
(define e2 (time (f n e1)))

(print "deriv")
(define e3 (time (d e2 'x)))

(print "eval")
(define a 0.1)
(define b 0.1)
(define c 0.1)
(define x 0.1)
(defun eval2 () (eval e3))
(compile 'eval2)
(print (time (eval2)))
(setf a 0.2)
(setf b 0.2)
(setf c 0.2)
(setf x 0.2)
(print (time (eval2)))
(setf a 0.3)
(setf b 0.3)
(setf c 0.3)
(setf x 0.3)
(print (time (eval2)))

Cheers,
Jon.

Pascal Bourguignon

unread,
Oct 28, 2005, 6:47:39 AM10/28/05
to
"Dr Jon D Harrop" <j...@ffconsultancy.com> writes:

> I'm trying to write a benchmark based on the symbolic differentiation
> example discussed recently. By using s-exprs, the Lisp implementation
> should be short and fast. However, I'm having trouble getting good
> performance using "eval". I believe I need to use compile but I'm not
> sure how.

> [...]
> (define ...)

What is define?


> (defun eval2 () (eval e3))
> (compile 'eval2)

What you need to compile is not the call to eval, it's the expression evaluated!

(defparameter e3 '(+ (* 1/2 x x) (* 4 x) 16))
(funcall (eval (compile nil `(lambda (x) ,e3))) 42)

--
"I have challenged the entire quality assurance team to a Bat-Leth
contest. They will not concern us again."

Rainer Joswig

unread,
Oct 28, 2005, 6:56:23 AM10/28/05
to
Am 28.10.2005 11:43 Uhr schrieb "Dr Jon D Harrop" unter
<j...@ffconsultancy.com> in
1130492608....@z14g2000cwz.googlegroups.com:

> I'm trying to write a benchmark based on the symbolic differentiation
> example discussed recently. By using s-exprs, the Lisp implementation
> should be short and fast. However, I'm having trouble getting good
> performance using "eval". I believe I need to use compile but I'm not
> sure how.

I'd say this is a waste of time. You are starting wrong. You
are focused on optimizing micro-benchmarks. This is simply
the wrong approach. Plus having a basic understanding
of Lisp before writing performance oriented code might
help.

First develop some useful architecture based on Lisp.
Then optimize where necessary. It may help to read some code
that exists.

A start would be reading the chapters (and reading the Common Lisp code)
from this book: http://www.norvig.com/paip.html


>
> So how can this code be optimised:

Throw it away. Learn to write Lisp code first.

Pisin Bootvong

unread,
Oct 28, 2005, 7:03:33 AM10/28/05
to

Is this Common Lisp?

1. Common Lisp doesn't have DEFINE.
2. variable namespace and function namespace of Common Lisp is separate
(eval e3) expression in eval2 will always fail since e3 is undefined
variable.
3. (eval e3) is not a way to use eval. EVAL takes expression tree.
which is list. #'e3 is a function not the expression list. It might
work, but I don't think it's what you want.

I don't think it has anything to do with eval. Perhaps you could first
print out built s-exp then compare time between passing that s-exp to
eval and typing that s-exp as a function and run it.

There is comp.lang.scheme group.

Dr Jon D Harrop

unread,
Oct 28, 2005, 7:20:07 AM10/28/05
to
Pascal Bourguignon wrote:
> "Dr Jon D Harrop" <j...@ffconsultancy.com> writes:
>
> > I'm trying to write a benchmark based on the symbolic differentiation
> > example discussed recently. By using s-exprs, the Lisp implementation
> > should be short and fast. However, I'm having trouble getting good
> > performance using "eval". I believe I need to use compile but I'm not
> > sure how.
> > [...]
> > (define ...)
>
> What is define?

Oops! Sorry, I posted the code I had half ported to Scheme. Still, you
get the idea. :-)

> > (defun eval2 () (eval e3))
> > (compile 'eval2)
>
> What you need to compile is not the call to eval, it's the expression
> evaluated!
>
> (defparameter e3 '(+ (* 1/2 x x) (* 4 x) 16))
> (funcall (eval (compile nil `(lambda (x) ,e3))) 42)

I see. Yes, of course.

Thanks,
Jon.

Pascal Costanza

unread,
Oct 28, 2005, 11:05:30 AM10/28/05
to
Dr Jon D Harrop wrote:
> I'm trying to write a benchmark based on the symbolic differentiation
> example discussed recently. By using s-exprs, the Lisp implementation
> should be short and fast. However, I'm having trouble getting good
> performance using "eval". I believe I need to use compile but I'm not
> sure how.
>
> So how can this code be optimised:
[...]

It's not clear what you are trying to do. Depending on the actual
purpose of the program, you may neither need eval nor compile. In fact,
symbolic differentiation is a nice example for macro programming in
which you can compile a derivative without any loss of runtime
performance at all.

But I basically agree with Rainer, learn to write Lisp code first.


Pascal

--
My website: http://p-cos.net
Closer to MOP & ContextL:
http://common-lisp.net/project/closer/

Thomas A. Russ

unread,
Oct 28, 2005, 11:53:32 AM10/28/05
to
"Dr Jon D Harrop" <j...@ffconsultancy.com> writes:

OK, this isn't an optimization per se, but I would find the dispatch
clearer if rewritten to use CASE for the CONSes:

> (define (d e x)
> (typecase e
> (number 0)
> (symbol (if (eq e x) 1 0))
> ((cons (eql log) list)
> (let ((f (cadr e)))
> `(* ,(d f x) (/ 1 ,f))))
> ((cons (eql +) list)
> (let ((f (cadr e)) (g (caddr e)))
> `(+ ,(d f x) ,(d g x))))
> ((cons (eql *) list)
> (let ((f (cadr e)) (g (caddr e)))
> `(+ (* ,f ,(d g x)) (* ,g ,(d f x)))))
> ((cons (eql expt) list)
> (let ((f (cadr e)) (g (caddr e)))
> `(* (expt ,f ,g)
> (+ (/ (* ,g ,(d f x)) ,f)
> (* (log ,f) ,(d g x))))))))

(define (d e x)
(typecase e
(number 0)
(symbol (if (eq e x) 1 0))

(cons
(ecase (first e)
(* (let ((f (cadr e)))


`(* ,(d f x) (/ 1 ,f))))

(+ (let ((f (cadr e)) (g (caddr e)))


`(+ ,(d f x) ,(d g x))))

(* (let ((f (cadr e)) (g (caddr e)))


`(+ (* ,f ,(d g x)) (* ,g ,(d f x)))))

(expt (let ((f (cadr e)) (g (caddr e)))


`(* (expt ,f ,g)
(+ (/ (* ,g ,(d f x)) ,f)

(* (log ,f) ,(d g x))))))))))


--
Thomas A. Russ, USC/Information Sciences Institute

Peter Seibel

unread,
Oct 28, 2005, 1:44:17 PM10/28/05
to
"Dr Jon D Harrop" <j...@ffconsultancy.com> writes:

> I'm trying to write a benchmark based on the symbolic differentiation
> example discussed recently. By using s-exprs, the Lisp implementation
> should be short and fast. However, I'm having trouble getting good
> performance using "eval". I believe I need to use compile but I'm not
> sure how.

Uh, why do you need to use EVAL at all to do symbolic differentiation?
Isn't the whole point that it's symbolic?

-Peter

--
Peter Seibel * pe...@gigamonkeys.com
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp * http://www.gigamonkeys.com/book/

Arthur Lemmens

unread,
Oct 28, 2005, 2:40:17 PM10/28/05
to
Thomas A. Russ wrote:

> (ecase (first e)
> (* (let ((f (cadr e)))
> `(* ,(d f x) (/ 1 ,f))))
> (+ (let ((f (cadr e)) (g (caddr e)))
> `(+ ,(d f x) ,(d g x))))
> (* (let ((f (cadr e)) (g (caddr e)))
> `(+ (* ,f ,(d g x)) (* ,g ,(d f x)))))

This sounds like a good case for destructuring-bind:

(destructuring-bind (operator f &optional g)
e
(ecase operator
(log `(* ,(d f x) (/ 1 ,f)))
(+ `(+ ,(d f x) ,(d g x)))
(* `(+ (* ,f ,(d g x)) (* ,g ,(d f x))))))

Untested of course (but I fixed the * instead of LOG typo).


Dr Jon D Harrop

unread,
Oct 28, 2005, 2:54:30 PM10/28/05
to
Peter Seibel wrote:
> Uh, why do you need to use EVAL at all to do symbolic differentiation?
> Isn't the whole point that it's symbolic?

I'm trying to combine different, interesting tasks into a single
program. Ultimately, I'm trying to make a benchmark that will show
Lisp/Scheme in the best possible light.

As other people have already shown, the derivative function in Lisp can
be written fairly clearly and succinctly (especially compared to C/C++,
Java etc.) so I think that is a good demonstration of clarity. With
s-exprs, you don't have the overhead of declaring an expr type in Lisp,
as I do in the other implementations (including OCaml), and there is
continuity in the sytax (as opposed to a+b and Plus(a, b) in the ML).

Currently, I'm using a derivative function to differentiate a big
expression. Then I'm evaluating the derivate at a few points. The Lisp
uses eval for the evaluation because the derivative function generated
an s-expr. My other implementations have to include a custom eval
function, which requires more code and they (typically) cannot compile
to native code so Lisp should be a lot faster.

However, compilation time is clearly going to be overwhelming (now that
I've got it "working" I can't actually execute it because compilation
takes too long and uses too much RAM) because the expression is huge.
So I need to use small expressions and, preferably, ones with recursive
functions in them.

To make Lisp look good (assuming the compiled Lisp s-expr will be
evaluated more quickly than the interpreters written in other
languages), evaluation must be done much more than all other
operations. So, perhaps it would be best to symbolically differentiate
a medium-sized expression and then tabulate it over a large range of
parameter values, or to ditch symbolic differentiation and write a
program to evaluate other programs (I think this is a much bigger task
though, but the results would be much more interesting as well).

Cheers,
Jon.

Pascal Costanza

unread,
Oct 28, 2005, 3:00:07 PM10/28/05
to

What about genericizing it?

(defun derive (e x)
(if (atom e)
(atom-derive x e)
(apply #'cons-derive x e)))

(defgeneric atom-derive (x e))

(defmethod atom-derive (x (e number))
0)
(defmethod atom-derive (x (e symbol))
(if (eq x e) 1 0))

(defgeneric cons-derive (x op f &optional g))

(defmethod cons-derive (x (op (eql '+)) f &optional g)
`(+ ,(derive f x) ,(derive g x)))

(defmethod cons-derive (x (op (eql '*)) f &optional g)
`(+ (* ,f ,(derive g x)) (* ,g ,(derive f x)))))

etc.

In this way you get an extensible derivation protocol. ;)

Also untested of course (and I didn't fix anything).

Arthur Lemmens

unread,
Oct 28, 2005, 3:19:45 PM10/28/05
to
Dr Jon D Harrop wrote:

> Ultimately, I'm trying to make a benchmark that will show
> Lisp/Scheme in the best possible light.

Kenny, can you please get us ilias back?

Marco Antoniotti

unread,
Oct 28, 2005, 3:20:36 PM10/28/05
to

Peter Seibel wrote:
> "Dr Jon D Harrop" <j...@ffconsultancy.com> writes:
>
>
>>I'm trying to write a benchmark based on the symbolic differentiation
>>example discussed recently. By using s-exprs, the Lisp implementation
>>should be short and fast. However, I'm having trouble getting good
>>performance using "eval". I believe I need to use compile but I'm not
>>sure how.
>
>
> Uh, why do you need to use EVAL at all to do symbolic differentiation?
> Isn't the whole point that it's symbolic?

Because OCaml does not have EVAL (you have to build it from scratch
using your home-brewed set of types to represent what in Lisp is
represented by itself) and the OP is ticked by that :)

Cheers
--
Marco

Arthur Lemmens

unread,
Oct 28, 2005, 3:40:32 PM10/28/05
to
Pascal Costanza wrote:

> Arthur Lemmens wrote:

>> This sounds like a good case for destructuring-bind:
>>
>> (destructuring-bind (operator f &optional g)
>> e
>> (ecase operator
>> (log `(* ,(d f x) (/ 1 ,f)))
>> (+ `(+ ,(d f x) ,(d g x)))
>> (* `(+ (* ,f ,(d g x)) (* ,g ,(d f x))))))
>>
>> Untested of course (but I fixed the * instead of LOG typo).
>
> What about genericizing it?

That wouldn't 'look good' on Mr. Harrop's LOC benchmarks,
so I'm afraid we can't allow that...

Kaz Kylheku

unread,
Oct 28, 2005, 4:08:31 PM10/28/05
to
Dr Jon D Harrop wrote:
> I'm trying to write a benchmark based on the symbolic differentiation
> example discussed recently. By using s-exprs, the Lisp implementation
> should be short and fast. However, I'm having trouble getting good
> performance using "eval". I believe I need to use compile but I'm not
> sure how.

Huh? You mean you want to differentiate a formula symbolically, but
then treat it as a Lisp expression and evaluate it?

Well, you have two choices. You can do the differentiation in a macro,
so that some kind of differentiation notation can be available as
program syntax. The programmer can write:

(derivative (* 3 x) x) ;; d/dx 3x

which will hopefully replace itself with:

3

To turn an expression into a compiled function at runtime, you do
something like:

(defun compile-expr-into-fun (expr)
(compile nil `(lambda () ,expr)))

Suppose you just want a single evaluation of the expression. Is it
faster to just EVAL it, or to compile it into a function and funcall
that? The answer is "it depends". Some Lisps compile everything, so the
two are the same.

Dr Jon D Harrop

unread,
Oct 28, 2005, 5:11:22 PM10/28/05
to
Excellent idea! :-)

Cheers,
Jon.

Dr Jon D Harrop

unread,
Oct 28, 2005, 5:13:25 PM10/28/05
to

Perhaps using non-whitespace bytes instead of LOC would be better in
this case?

Pascal Costanza

unread,
Oct 28, 2005, 6:07:08 PM10/28/05
to

ROTFL!

Dr. Thomas Fischbacher

unread,
Oct 29, 2005, 2:09:52 AM10/29/05
to
Jon Harrop wrote:

> I'm trying to combine different, interesting tasks into a single
> program. Ultimately, I'm trying to make a benchmark that will show
> Lisp/Scheme in the best possible light.

Gee. Does this actually mean we will see more of your Wikipedia Link
spam in the articles on Lisp and Scheme in the future as well?

From:

http://en.wikipedia.org/w/index.php?title=Talk:O%27Caml_programming_language&oldid=26697518

===>
On Commercials in this article

Looking at the article in its present state, there are 16 external
(non-wikipedia) OCaml-related links in it. Seven of them point to
http://www.ffconsultancy.com, and all of them seem to have been made by
a user from the IP 80.229.56.224, which resolves to jdh30.plus.com.

Doing a bit of research, this is the machine of the owner of
ffconsultancy.com, Dr. Jon Harrop. This brings up the question whether
we actually see here a violation of Wikipedia:What_Wikipedia_is_not
rules, as this article might be abused for self-promotion and
advertising issues. Doubly so, as there is quite some consensus of Jon
Harrop showing quite undue behaviour on the usenet as well as some
mailing lists, alienating large parts of the functional community.

I therefore strongly suggest deleting all references to
ffconsultancy.com from the article.

Motion seconded, carried, and implemented. --MarkSweep (call me
collect) 22:58, 26 October 2005 (UTC)

I just re-added many of the links before I read this. I am happy to have
the direct links to commercial products removed (the OCaml book and
Presenta) if this is against Wikipedia policy (note that Wikipedia
references many other books though - perhaps we should add a references
section?). However, I see no sense in removing links to free software
written in OCaml that happen to be available from the same site,
particularly the maze generator, ray tracers and example programs from
scientific computing. I have also added some links to other
OCaml-related pages. If I can provide any useful information, please
contact me (the objection was made by 152.78.153.226?). - Jon Harrop
<j...@ffconsultancy.com>.
<===

Jon, maybe you have not noticed yet: there may be some people around who
think that you do not quite qualify as an expert functional hacker.
However, you seem to have a 1:10 ratio of producing material - most of
it of highly questionable quality (and many people did repeatedly tell
you so) - and advertizing it, sometimes to the borderline of vandalism:

http://en.wikipedia.org/w/index.php?title=Ocaml&limit=20&action=history

# (cur) (last) 20:19, 28 October 2005 MarkSweep (re-added a few links)
# (cur) (last) 20:16, 28 October 2005 MarkSweep m (Reverted edits by
80.229.56.224 to last version by MarkSweep)
# (cur) (last) 10:23, 28 October 2005 80.229.56.224 (Re-added links to
freely-available OCaml programs that were removed without adequate reason)
# (cur) (last) 22:57, 26 October 2005 MarkSweep (rm linkspam)
# (cur) (last) 22:54, 26 October 2005 MarkSweep (→External links - rm
links (FFTW and Unison are not directly relevant here; scientific
computing link is nothing but an advertisement))

Please also take a look at the ffconsultancy.com links in an older
version of that article, such as:

http://en.wikipedia.org/w/index.php?title=Ocaml&oldid=26478312

I do not know what your business plan is, but it looks a bit like:

1.: Make a lot of fuss, alienate all the proficient people in the field,
as well as now the Wikipedians, and see that there is not one left who
knows about the field but does not know your questionable methods.

2.: ???

3.: Profit.

Huh? I know that internet trolling is a booming business. Could it be
that you think there is big money to be made in the future by...
consulting trolls?

--
Dr. Thomas Fischbacher

jos...@corporate-world.lisp.de

unread,
Oct 29, 2005, 5:53:21 AM10/29/05
to

Dr Jon D Harrop wrote:
> Peter Seibel wrote:
> > Uh, why do you need to use EVAL at all to do symbolic differentiation?
> > Isn't the whole point that it's symbolic?
>
> I'm trying to combine different, interesting tasks into a single
> program. Ultimately, I'm trying to make a benchmark that will show
> Lisp/Scheme in the best possible light.

This is approach is highly questionable.

I'm definitely not interested in constructing benchmarks to
make Lisp look good.

There is so much wrong in the above paragraph that I wouldn't even
know where to start...

Vesa Karvonen

unread,
Oct 29, 2005, 6:41:34 AM10/29/05
to
jos...@corporate-world.lisp.de wrote:
> Dr Jon D Harrop wrote:
[...]

> > I'm trying to combine different, interesting tasks into a single
> > program. Ultimately, I'm trying to make a benchmark that will show
> > Lisp/Scheme in the best possible light.

> This is approach is highly questionable.

Indeed. It is extremely difficult to make fair comparisons of any kind
between programming languages. To intentionally design biased benchmarks
is just one step away from being scientific misconduct.

-Vesa Karvonen

Dr Jon D Harrop

unread,
Oct 29, 2005, 7:00:32 AM10/29/05
to
Dr. Thomas Fischbacher wrote:
> Jon Harrop wrote:
>
> > I'm trying to combine different, interesting tasks into a single
> > program. Ultimately, I'm trying to make a benchmark that will show
> > Lisp/Scheme in the best possible light.
>
> Gee. Does this actually mean we will see more of your Wikipedia Link
> spam in the articles on Lisp and Scheme in the future as well?

In point of fact, they readded a link to my site (the ray tracer
benchmark). I am more annoyed that they don't want a link to FFTW,
which is probably the most famous software currently written in OCaml.
Anyway, that page is all about OCaml and has nothing to do with c.l.l.

Cheers,
Jon.

Dr Jon D Harrop

unread,
Oct 29, 2005, 7:16:10 AM10/29/05
to

Not if you state that the test was specifically designed to emphasise
the benefits of efficient run-time code generation. IMHO, many people
believe that such a test cannot exist. I think they would be very
interested to see if it can be created.

Cheers,
Jon.

Rob Thorpe

unread,
Oct 29, 2005, 10:22:58 AM10/29/05
to
Dr Jon D Harrop wrote:

Is it a very big expression, is that why the compiler is having a
problem?

It's worth remembering:-
CMUCL and GCL contain an interpreter and a compiler.
SBCL does not, it only has a compiler. When you type something into
the REPL it compiles in, then executes the compiled code. I think the
authors did this because they didn't think it was worthwhile to to
maintain the interpreter code. The interpreter is quite complex and
only really used for a very few things.

If you write a program that generates some lisp code in CMUCL or GCL
you could execute the code by evaling it. In SBCL it may be more
appropriate to evaluate something like "(defun generated (args)
(...code...))", then call "generated" later in the code. This will
avoid the compiler compiling it more than once.


I also don't think there's much to be said for writing a program to
make CL look good. But it is useful to show what things CL is good at.

Paul F. Dietz

unread,
Oct 29, 2005, 10:26:47 AM10/29/05
to
Rob Thorpe wrote:

> The interpreter is quite complex and
> only really used for a very few things.

It's very useful for testing the compiler. :)

Paul

Rainer Joswig

unread,
Oct 29, 2005, 10:47:43 AM10/29/05
to
Am 29.10.2005 13:16 Uhr schrieb "Dr Jon D Harrop" unter
<j...@ffconsultancy.com> in
1130584570....@g44g2000cwa.googlegroups.com:

>
> Not if you state that the test was specifically designed to emphasise
> the benefits of efficient run-time code generation. IMHO, many people
> believe that such a test cannot exist.

Who?

> I think they would be very
> interested to see if it can be created.

Why not enter "run-time code generation" and "benchmark" into
the Google search field and press return?

Or go to comp.benchmark and ask there?

>
> Cheers,
> Jon.
>


Rob Warnock

unread,
Oct 29, 2005, 10:16:08 PM10/29/05
to
Rob Thorpe <robert...@antenova.com> wrote:
+---------------

| If you write a program that generates some lisp code in CMUCL or GCL
| you could execute the code by evaling it. In SBCL it may be more
| appropriate to evaluate something like "(defun generated (args)
| (...code...))", then call "generated" later in the code. This will
| avoid the compiler compiling it more than once.
+---------------

Or simply wrap a LAMBDA around the generated code, eval *that*
[thus compiling it], and then FUNCALL the compiled LAMBDA multiple
times inside the timing loop, thus avoiding polluting the global
namespace with things like GENERATED...

Not that since COMPILE is is allow to (and usually will) return
the same object when given an already-compiled object, if you
further wrap a COMPILE around the EVAL (or the LAMBDA, not sure
it matters much which), you get a version that will "do the same thing"
on both compile-all-the-time and interpret-unless-told-to-compile
implementations (e.g., SBCL vs. CMUCL).


-Rob

-----
Rob Warnock <rp...@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607

Dr Jon D Harrop

unread,
Oct 30, 2005, 3:11:00 PM10/30/05
to
Rainer Joswig wrote:
> Am 29.10.2005 13:16 Uhr schrieb "Dr Jon D Harrop" unter
> <j...@ffconsultancy.com> in
> 1130584570....@g44g2000cwa.googlegroups.com:
> > Not if you state that the test was specifically designed to emphasise
> > the benefits of efficient run-time code generation. IMHO, many people
> > believe that such a test cannot exist.
>
> Who?

Basically everyone that I know of. I am not sure if it can be done.

> > I think they would be very
> > interested to see if it can be created.
>
> Why not enter "run-time code generation" and "benchmark" into
> the Google search field and press return?
>
> Or go to comp.benchmark and ask there?

I've already searched for existing benchmarks. There are many out
there, of course, and I have studied quite a few. However, most Lisp
benchmarks are either out of date, compare only to Java/C# or use poor
implementations written in other languages.

I have studied all of the run-time code generation benchmarks that come
with MetaOCaml. Some of those are probably suitable (I'll look into
this in more detail). However, the ordinary OCaml implementations of
the benchmarks that are used for comparison are typically written in
the style of MetaOCaml, which is much more verbose and less efficient.
When rewritten, I rarely found a significant speed improvement from
MetaOCaml.

Perhaps I should take whichever MetaOCaml benchmark showed the biggest
performance improvement from run-time code generation and port it to
Lisp.

Cheers,
Jon.

Pascal Costanza

unread,
Oct 30, 2005, 3:46:57 PM10/30/05
to
Dr Jon D Harrop wrote:
> Rainer Joswig wrote:
>
>>Am 29.10.2005 13:16 Uhr schrieb "Dr Jon D Harrop" unter
>><j...@ffconsultancy.com> in
>>1130584570....@g44g2000cwa.googlegroups.com:
>>
>>>Not if you state that the test was specifically designed to emphasise
>>>the benefits of efficient run-time code generation. IMHO, many people
>>>believe that such a test cannot exist.
>>
>>Who?
>
> Basically everyone that I know of. I am not sure if it can be done.

The people you know are apparently not very smart.

Virtual machines rely heavily on runtime code generation, because it is
clearly better to compile bytecodes to machine code before executing
them instead of just interpreting them. There exists a whole body of
literature on benchmarks for virtual machines.

In the case of Common Lisp, for example CLOS relies on runtime code
generation. Cf. the section on user-defined method combinations in ANSI
Common Lisp, where you can see that a method combination is basically a
macro expansion process. Since CLOS allows method redefinition at
runtime, this macro expansion process has to be performed at runtime.
Again, there exist a number of papers that discuss performance
characteristics of CLOS, and there are also benchmarks out there for
testing performance of CLOS.

There is also the related field of partial evaluation which is of
interest in this regard. Basically, the implementations of virtual
machines, CLOS, etc., employ (ad-hoc or principled) partial evaluation
to distinguish between program fragments that can and cannot change at
runtime, in order to efficiently compile away the static aspects of such
code. This is related because one can also make optimistic guesses wrt
to what is static about a code fragment if one is also able to undo
optimizations and redo the analysis once the assumptions don't hold
anymore. This is, by definition, a runtime code generation approach.

The people who have implemented Self have put a lot of work into such
issues, and again you can find a lot of literature here.

Jon Harrop

unread,
Oct 31, 2005, 1:06:14 AM10/31/05
to
Pascal Costanza wrote:
> Virtual machines rely heavily on runtime code generation, because it is
> clearly better to compile bytecodes to machine code before executing
> them instead of just interpreting them. There exists a whole body of
> literature on benchmarks for virtual machines.
>
> In the case of Common Lisp, for example CLOS relies on runtime code
> generation. Cf. the section on user-defined method combinations in ANSI
> Common Lisp, where you can see that a method combination is basically a
> macro expansion process. Since CLOS allows method redefinition at
> runtime, this macro expansion process has to be performed at runtime.
> Again, there exist a number of papers that discuss performance
> characteristics of CLOS, and there are also benchmarks out there for
> testing performance of CLOS.
>
> There is also the related field of partial evaluation which is of
> interest in this regard. Basically, the implementations of virtual
> machines, CLOS, etc., employ (ad-hoc or principled) partial evaluation
> to distinguish between program fragments that can and cannot change at
> runtime, in order to efficiently compile away the static aspects of such
> code. This is related because one can also make optimistic guesses wrt
> to what is static about a code fragment if one is also able to undo
> optimizations and redo the analysis once the assumptions don't hold
> anymore. This is, by definition, a runtime code generation approach.

Those are all sound theoretical reasons why Java should be faster than C++.
That does not provide any evidence that Java implementations are actually
any faster than C++ implementations. Indeed, measurements mostly point to
the contrary.

--
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com

Pascal Costanza

unread,
Oct 31, 2005, 1:18:37 AM10/31/05
to
Jon Harrop wrote:

> Those are all sound theoretical reasons why Java should be faster than C++.
> That does not provide any evidence that Java implementations are actually
> any faster than C++ implementations. Indeed, measurements mostly point to
> the contrary.

I haven't claimed otherwise, and this was not the topic at hand.

Rob Thorpe

unread,
Oct 31, 2005, 4:18:54 AM10/31/05
to
Rob Warnock wrote:
> Rob Thorpe <robert...@antenova.com> wrote:
> +---------------
> | If you write a program that generates some lisp code in CMUCL or GCL
> | you could execute the code by evaling it. In SBCL it may be more
> | appropriate to evaluate something like "(defun generated (args)
> | (...code...))", then call "generated" later in the code. This will
> | avoid the compiler compiling it more than once.
> +---------------
>
> Or simply wrap a LAMBDA around the generated code, eval *that*
> [thus compiling it], and then FUNCALL the compiled LAMBDA multiple
> times inside the timing loop, thus avoiding polluting the global
> namespace with things like GENERATED...
>
> Not that since COMPILE is is allow to (and usually will) return
> the same object when given an already-compiled object, if you
> further wrap a COMPILE around the EVAL (or the LAMBDA, not sure
> it matters much which), you get a version that will "do the same thing"
> on both compile-all-the-time and interpret-unless-told-to-compile
> implementations (e.g., SBCL vs. CMUCL).

Good idea.

Pascal Costanza

unread,
Oct 31, 2005, 7:36:33 AM10/31/05
to

It's important to note that (compile nil `(lambda () (eval
,some-expression))) is not necessarily more efficient than just (eval
some-expression). If you perform compilation at runtime, you have to
take into account that the compilation process itself costs time and
memory resources. So if the expression you want to evaluate is
computationally inexpensive and you use it only for one-shot
computations, then it will probably not pay off to compile it, because
it is likely that (> (+ (time compilation) (time execution)) (time
evalutation)). Only if you are reusing the compiled code later on, or if
it is an expensive computation, the overhead of compilation can be
compensated for.

BTW, that's the main reason why the performance characteristics of
runtime code generation cannot be easily shown with small toy benchmarks.

Rob Thorpe

unread,
Oct 31, 2005, 8:38:32 AM10/31/05
to

Sure. My point to Jon was that this doesn't work very well on SBCL,
and using that implementation there's nothing to be lost in compiling
the code since it will be compiled anyway if you use eval. And, if
it's kept around it may be useful in the future.

Richard J. Fateman

unread,
Nov 10, 2005, 8:28:49 PM11/10/05
to
In addition to this code being clumsy, if you are trying to make
it fast, wouldn't you use ...(safety 0) ...?

If you want to compute the derivative of an expression at a point,
you do not have to cons up the symbolic expression at all.

You could compute (f 2 g) at g=3
and its derivative with respect to g at that point
in approximately 0ms.

<value, deriv> =<4.434264882430378d+38 , 1.0793576867959292d+41>

I just stuck this definition in to a suitably augmented CL
(generic arithmetic) with g = < 3 , 1>

>
> (define (f n g)
> (if (= n 0) g `(expt ,(f (- n 1) g) ,(f (- n 1) g))))
>
>
>

0 new messages