From: Lowell
Subject: lisp's speed
Date: 
Message-ID: <bhh4jh$iie$1@mughi.cs.ubc.ca>
I read everywhere that Lisp is fast. Much faster than Java. But from a 
simple test that I've done, Java seems much faster. It's just a trivial 
loop which is executed ten million times. It takes 47 ms in Java and 3.7 
seconds in CL. This is almost 100 times slower!! Am I missing the point? 
Here is the code:

CL:
(defun test-fn ()
   (declaim (optimize speed))
   (let ((x nil))
     (dotimes (i 10000000)
       (setq x (not x)))))
(compile 'test-fn)
(time (test-fn))


Java:
public class delme {
     public static void main (String[] args) {
	long start = System.currentTimeMillis();
	boolean x = false;
	for(int i = 0; i < 10000000; i++)
	    x = !x;
	System.out.println(System.currentTimeMillis() - start);
}}


Lowell

From: Lowell
Subject: Re: lisp's speed
Date: 
Message-ID: <bhh7ho$j8v$1@mughi.cs.ubc.ca>
By the way, I'm using Clisp 2.30 on Windows and am using Java 1.4.2

Lowell

Lowell wrote:

> I read everywhere that Lisp is fast. Much faster than Java. ...
From: Kaz Kylheku
Subject: Re: lisp's speed
Date: 
Message-ID: <cf333042.0308150312.3707da95@posting.google.com>
Lowell <······@cs.ubc.ca> wrote in message news:<············@mughi.cs.ubc.ca>...
> By the way, I'm using Clisp 2.30 on Windows and am using Java 1.4.2

Yet you are making claims about Lisp and Java, the languages.

CLISP compiles to byte code, not native code.

Despite that lack of optimization, it has many redeeming qualities.
For example, it has very nice performance on bignum integers, and has
a small memory footprint.

In the Java program, you had to declare the type of your loop counter.
If you increment its value beyond the largest signed 64 bit integer,
too bad! What will happen? Will the program die with an arithmetic
overflow? Will the value silently wrap to the greatest negative
number? Will the program handle it?

In the Lisp program, this type of thing isn't a problem. Integers
behave like mathematical integers, rather than machine-language
integers.

Type declarations play their proper role in Lisp: they are
optimization devices, which introduce representational compromises for
the sake of performance. Their effects can be nicely confined to
pockets of the program that contain performance hotspots.

This makes Lisp a much better language than Java for writing reliable
software that won't suddenly bail when it hits some corner case that
exists only because some data representation was forced to fit the
machine rather than the other way around.

Try your test with a Lisp implementation that produces native code.
Declare not only that you want speed, but also indicate that safety is
not important---just like you do implicitly every time you bang out a
Java program! Also indicate the types of the relevant variables, and
the result types of expressions where necessary.

Use the DISASSEMBLE function to see how your function is being
compiled, and what effects the declarations are having on the
translation.
From: Howard Ding <······@hading.dnsalias.com>
Subject: Re: lisp's speed
Date: 
Message-ID: <m365kzq056.fsf@frisell.localdomain>
Lowell <······@cs.ubc.ca> writes:

> I read everywhere that Lisp is fast. Much faster than Java. But from a
> simple test that I've done, Java seems much faster. It's just a
> trivial loop which is executed ten million times. It takes 47 ms in
> Java and 3.7 seconds in CL. This is almost 100 times slower!! Am I
> missing the point? Here is the code:
>
> CL:
> (defun test-fn ()
>    (declaim (optimize speed))
>    (let ((x nil))
>      (dotimes (i 10000000)
>        (setq x (not x)))))
> (compile 'test-fn)
> (time (test-fn))
>
>
> Java:
> public class delme {
>      public static void main (String[] args) {
> 	long start = System.currentTimeMillis();
> 	boolean x = false;
> 	for(int i = 0; i < 10000000; i++)
> 	    x = !x;
> 	System.out.println(System.currentTimeMillis() - start);
> }}
>

Perhaps you're using a slow Lisp implementation (CLISP, perhaps?)

You can also do the declarations better.

With CMUCL 18c and the test function:
(defun test-fn ()
   (declare (optimize (speed 3)))
   (let ((x nil)) 
     (declare (boolean x))
     (dotimes (i 10000000)
       (declare (fixnum i))
       (setq x (not x)))))

after compiling and running I get something like:


-- (time (test-fn))
Compiling LAMBDA NIL: 
Compiling Top-Level Form: 

Evaluation took:
  0.21 seconds of real time
  0.19 seconds of user run time
  0.0 seconds of system run time
  0 page faults and
  0 bytes consed.

The java version gives me:
······@Frisell ~/tmp 30> java delme
247

(I believe that the java on my machine is a 1.3 version)

At any rate, they seem pretty close once you give Lisp the same type
of type information that java has.

Howard Ding
<······@hading.dnsalias.com>
From: Peter Seibel
Subject: Re: lisp's speed
Date: 
Message-ID: <m37k5frdmx.fsf@javamonkey.com>
Lowell <······@cs.ubc.ca> writes:

> I read everywhere that Lisp is fast. Much faster than Java. But from a
> simple test that I've done, Java seems much faster. It's just a
> trivial loop which is executed ten million times. It takes 47 ms in
> Java and 3.7 seconds in CL. This is almost 100 times slower!! Am I
> missing the point? Here is the code:
> 
> CL:
> (defun test-fn ()
>    (declaim (optimize speed))
>    (let ((x nil))
>      (dotimes (i 10000000)
>        (setq x (not x)))))
> (compile 'test-fn)
> (time (test-fn))
> 
> 
> Java:
> public class delme {
>      public static void main (String[] args) {
> 	long start = System.currentTimeMillis();
> 	boolean x = false;
> 	for(int i = 0; i < 10000000; i++)
> 	    x = !x;
> 	System.out.println(System.currentTimeMillis() - start);
> }}


So, there are a bunch of things to say about this.

 - What implementation of Common Lisp are you using? Not every
   implementation is the same. FWIW, on my dual xeon GNU/Linux box
   your Java code ran in Sun's 1.4.1 JDK in ~ 40ms while your Lisp
   code (with DECLAIM changed to DECLARE) ran in Allegro Common Lisp
   6.2 in ~ 40ms. i.e. a dead heat.

 - It's not clear that a micro benchmark like this is going to tell
   you a lot--in theory, either the Java or Lisp compiler could
   optimze away almost all the code. The java version, in particular,
   could be optimized to essentailly nothing since all the loop does
   is diddle a variable that is never referenced after the loop. Not
   that I suspect that is what's happening but it's possible. More
   relevant are the various (large) bits of noise: the cost of
   starting the Java VM, the cost a function call in the Lisp version
   vs measuring in the function. Etc.

 - While I didn't observe that it made any difference in Allegro
   Common Lisp, but in theory you ought to declare the type of x. As
   it stands the Java compiler has more (explicit) information than
   the Lisp compiler: it knows x is a boolean. (I guess a really smart
   Lisp compiler could figure out that x will always be a boolean, but
   a really smart compiler would figure out that it doesn't need to
   run the loop to compute the value of x.) In order to give Lisp a
   fair chance to optimize you'd want to write something like:

    (defun test-fn ()
      (declare (optimize speed))
      (let ((x nil))
        (declare (type boolean x))
        (dotimes (i 100000000)
          (setq x (not x)))))

   As I said, that declaration didn't make any difference in ACL, but
   in general one of the principles of Lisp optimization is you use
   declarations when you have to, to give the compiler information
   (such as type information) it can use to generate more efficient
   code. As opposed to Java where you *always* have to provide that
   information, even when you don't care about optimization.

Other optimization guru's can probably give you more specific advice
about optimization techniques but I suspect nobody is going to really
go to town on such an artificial benchmark as this.

If you want to take a look at some more realistic benchmarks, you
might want to look at the Great Computer Language Shootout. You can
get both Lisp and Java source code for various benchmarks. (Note,
however, that they used CMUCL, a particular CL implementation--the
source code may run faster or slower on other CL implementations.)

 <http://www.bagley.org/~doug/shootout/lang/cmucl/>
 <http://www.bagley.org/~doug/shootout/lang/java/>

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Rayiner Hashem
Subject: Re: lisp's speed
Date: 
Message-ID: <a3995c0d.0308150631.1926ed12@posting.google.com>
These very mini-microbenchmarks are useless. With a sufficiently
aggressive optimizer (both GCC and Intel C++ compiler a C version of
that loop to absolutely nothing, since the variable is never
referenced again), all languages should be able to hit the same speed
in a benchmark like that. Far more interesting are benchmarks that are
realistic, but difficult for the optimizer to reduce completely.

For example, take the cost of classes. In C++, you can create a vector
integer class (that incorporates inline ASM to use the vector units on
modern processors) that perform as fast as native integer types. Even
CMUCL will not do that for the equivilent CLOS code. On the other
hand, there are optimizations that a high-level language compiler can
do that a C++ compiler cannot. For example, C++ compilers cannot
implement any optimizations that change the in-memory representation
of a value, because C++ makes certain guarentees about the exact
memory arrangement of data structures.

Excercising these sorts of performance characteristics would be much
more interesting IMHO
From: Pascal Costanza
Subject: Re: lisp's speed
Date: 
Message-ID: <bhir48$n0i$1@f1node01.rhrz.uni-bonn.de>
Exactly!

Rayiner Hashem wrote:
> These very mini-microbenchmarks are useless. With a sufficiently
> aggressive optimizer (both GCC and Intel C++ compiler a C version of
> that loop to absolutely nothing, since the variable is never
> referenced again), all languages should be able to hit the same speed
> in a benchmark like that. Far more interesting are benchmarks that are
> realistic, but difficult for the optimizer to reduce completely.
> 
> For example, take the cost of classes. In C++, you can create a vector
> integer class (that incorporates inline ASM to use the vector units on
> modern processors) that perform as fast as native integer types. Even
> CMUCL will not do that for the equivilent CLOS code. On the other
> hand, there are optimizations that a high-level language compiler can
> do that a C++ compiler cannot. For example, C++ compilers cannot
> implement any optimizations that change the in-memory representation
> of a value, because C++ makes certain guarentees about the exact
> memory arrangement of data structures.
> 
> Excercising these sorts of performance characteristics would be much
> more interesting IMHO


-- 
Pascal Costanza               University of Bonn
···············@web.de        Institute of Computer Science III
http://www.pascalcostanza.de  R�merstr. 164, D-53117 Bonn (Germany)
From: Edi Weitz
Subject: Re: lisp's speed
Date: 
Message-ID: <87znibn7cn.fsf@bird.agharta.de>
On Thu, 14 Aug 2003 16:05:22 -0700, Lowell <······@cs.ubc.ca> wrote:

> I read everywhere that Lisp is fast. Much faster than Java. But from
> a simple test that I've done, Java seems much faster. It's just a
> trivial loop which is executed ten million times. It takes 47 ms in
> Java and 3.7 seconds in CL. This is almost 100 times slower!! Am I
> missing the point? Here is the code:
> 
> CL:
> (defun test-fn ()
>    (declaim (optimize speed))
>    (let ((x nil))
>      (dotimes (i 10000000)
>        (setq x (not x)))))
> (compile 'test-fn)
> (time (test-fn))
> 
> 
> Java:
> public class delme {
>      public static void main (String[] args) {
> 	long start = System.currentTimeMillis();
> 	boolean x = false;
> 	for(int i = 0; i < 10000000; i++)
> 	    x = !x;
> 	System.out.println(System.currentTimeMillis() - start);
> }}

It's DECLARE, not DECLAIM.

What implementation did you try? Probably CLISP which doesn't compile
to native code? I ran this on my laptop and got around 65 milliseconds
with Sun's Java 1.4.2 and less than 0.05 seconds of real time with
CMUCL 18e. To me this looks like CMUCL is faster unless Java is using
some American meaning of 'milliseconds' that I don't know of.

Now replace 10000000 with 10000000000:

  ···@bird:/tmp > /opt/sun-jdk-1.4.2/bin/javac delme.java
  delme.java:5: integer number too large: 10000000000
                          for(int i = 0; i < 10000000000; i++)
                                           ^
  1 error

Ooops... Try the same with Lisp.

Edi.
From: pete kirkham
Subject: Re: lisp's speed
Date: 
Message-ID: <3f3c3b3a$0$15035$cc9e4d1f@news.dial.pipex.com>
Edi Weitz wrote:

> Now replace 10000000 with 10000000000:
> 
>   ···@bird:/tmp > /opt/sun-jdk-1.4.2/bin/javac delme.java
>   delme.java:5: integer number too large: 10000000000
>                           for(int i = 0; i < 10000000000; i++)
>                                            ^
>   1 error
> 
> Ooops... Try the same with Lisp.

for example:

(defun test-fn ()
     (declaim (optimize speed))
     (let ((x nil))
       (dotimes (i 1-some-equally-syntacticly-incorrect-numerical-literal-0)
         (setq x (not x)))))
  (compile 'test-fn)
  (time (test-fn))

; While compiling TEST-FN:
Warning: Free reference to undeclared variable
          1-SOME-EQUALLY-SYNTACTICLY-INCORRECT-NUMERICAL-LITERAL-0
          assumed special.
TEST-FN
T
T
CL-USER(6): Error: `("Unbound Value")' is not of the expected type `REAL'
   [condition type: TYPE-ERROR]

Pete
From: Peter Seibel
Subject: Re: lisp's speed
Date: 
Message-ID: <m33cg3r7lw.fsf@javamonkey.com>
pete kirkham <············@cafemosaic.co.uk> writes:

> Edi Weitz wrote:
> 
> > Now replace 10000000 with 10000000000:
> >   ···@bird:/tmp > /opt/sun-jdk-1.4.2/bin/javac delme.java
> >   delme.java:5: integer number too large: 10000000000
> >                           for(int i = 0; i < 10000000000; i++)
> >                                            ^
> >   1 error
> > Ooops... Try the same with Lisp.
> 
> for example:
> 
> (defun test-fn ()
>      (declaim (optimize speed))
>      (let ((x nil))
>        (dotimes (i 1-some-equally-syntacticly-incorrect-numerical-literal-0)
>          (setq x (not x)))))
>   (compile 'test-fn)
>   (time (test-fn))

Well, 10000000000 is not syntactically incorrect in Java. It's
*semantically* incorrect. Which was, of course, Edi's point.

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: pete kirkham
Subject: Re: lisp's speed
Date: 
Message-ID: <3f3cb687$0$18492$cc9e4d1f@news.dial.pipex.com>
Peter Seibel wrote:
> Well, 10000000000 is not syntactically incorrect in Java. It's
> *semantically* incorrect. Which was, of course, Edi's point.

According to the language specification, the compiler's _parser_ will 
complain if a literal of type int excedes 2^31. That is why it produced 
the error and failed to compile. Most numeric literal parsers for Java 
will use a 64 bit accumulator that starts at zero. For each digit 
multiply and accumulator by ten, read a digit, and add the equivalent 
integer to the accumulator. If any bits 31-62 of the accumulator are set 
and the integral literal is not terminated by an 'L', or if at any time 
bit 63 gets set, then the error is signalled (there also are mechanics 
for '.', 'E' and 'F' which signal floating point, octal, hex etc.).

At no point in the process of parsing an numeric literal is it necessary 
to make a comparison on the symantic value that we would attach to the 
symbols made, not even at the level of a '>' instruction.

Lisp will do the same if you violate its syntax with representations of 
integral numbers that are symantically correct in normal usage but 
syntactically incorrect in Lisp:

  (defun test-fn ()
        (declaim (optimize speed))
        (let ((x nil))
          (dotimes (i 10,000,000,000)
            (setq x (not x)))))
     (compile 'test-fn)
     (time (test-fn))

Generates 'Comma not in backquote' which is a syntax error, even though 
10,000,000,000 has the same symantic value as 10000000000 in normal 
(British) usage.

If you want to demonstrate Java's discrepency with the semantics of 
idealiased integer mathematics, you can only demonstrate that with 
respect to results of operators, not literals, something like:

         int ten = 10;
         int thousand = 1000;
         int million =  thousand * thousand;

         for(int i = 0; i < ten * thousand * million; i++) {
  	    x = !x;
  	}

Which is syntactically correct but semantically wrong, whereas:

         for(long i = 0; i < 10000000000L; i++) {
           x ^= true;
         }

Is correct, but the literal has a word length indicating suffix which 
doesn't quite match the naive hope that computer languages share both 
the symantics and representations of human ones.


Pete

(I'm away for a long weekend so probably won't follow up for a few days)
From: Programmer Dude
Subject: Re: lisp's speed
Date: 
Message-ID: <3F3D1029.AB3D3896@mmm.com>
pete kirkham wrote:

> According to the language specification, the compiler's _parser_
> will complain if a literal of type int excedes 2^31. That is why
> it produced the error and failed to compile. Most numeric literal
> parsers for Java will use a 64 bit accumulator that starts at
> zero. For each digit multiply and accumulator by ten, read a digit,
> and add the equivalent integer to the accumulator.

Isn't that process creating the *semantic* value of the text?
And when it fails, doesn't it fail for semantic reasons?

-- 
|_ CJSonnack <·····@Sonnack.com> _____________| How's my programming? |
|_ http://www.Sonnack.com/ ___________________| Call: 1-800-DEV-NULL  |
|_____________________________________________|_______________________|
From: pete kirkham
Subject: Re: lisp's speed
Date: 
Message-ID: <3f3fe01b$0$18488$cc9e4d1f@news.dial.pipex.com>
Programmer Dude wrote:
> pete kirkham wrote:
> 
> 
>>According to the language specification, the compiler's _parser_
>>will complain if a literal of type int excedes 2^31. That is why
>>it produced the error and failed to compile. Most numeric literal
>>parsers for Java will use a 64 bit accumulator that starts at
>>zero. For each digit multiply and accumulator by ten, read a digit,
>>and add the equivalent integer to the accumulator.
> 
> 
> Isn't that process creating the *semantic* value of the text?
> And when it fails, doesn't it fail for semantic reasons?
> 
No, in Java the *semantic* value of that bit sequence will be negative.

Pete
From: Peter Seibel
Subject: Re: lisp's speed
Date: 
Message-ID: <m3y8xuq5zs.fsf@javamonkey.com>
pete kirkham <············@cafemosaic.co.uk> writes:

> Peter Seibel wrote:
> > Well, 10000000000 is not syntactically incorrect in Java. It's
> > *semantically* incorrect. Which was, of course, Edi's point.
> 
> According to the language specification, the compiler's _parser_
> will complain if a literal of type int excedes 2^31. That is why it
> produced the error and failed to compile.

From Java Language Specificiation 3.10.1:

  IntegerLiteral:
    DecimalIntegerLiteral
    HexIntegerLiteral
    OctalIntegerLiteral

  DecimialIntegerLiteral:
    DecimalNumeral IntegerTypeSuffix(opt)

  IntegerTypeSuffix: (one of)
    l L

  DecimalNumeral:
    0
    NonZeroDigit Digits(opt)

  Digits:
    Digit
    Digits Digit

  Digit:
    0
    NonZeroDigit

  NonZeroDigit: one of
    1 2 3 4 5 6 7 8 9


That's the *syntax* of a integer literal. 10000000000 matches that
grammar but is not a valid integer because of a semantic constraint.
Just because the compiler is required to detect the error doesn't make
it a syntactic error. In fact you can see this distinction in the
errors generated by javac: For a number that's too big it says:

  Foo.java:14: integer number too large: 10000000000

I.e. it managed to recognize that '10000000000' is an integer but then
realized it's too big. Whereas if we change the 10000000000 to
something that doesn't parse at all like: 10000y000000 then we get a
different error:

  Foo.java:14: ';' expected

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: pete kirkham
Subject: Re: lisp's speed
Date: 
Message-ID: <3f3fe487$0$18496$cc9e4d1f@news.dial.pipex.com>
Peter Seibel wrote:
> From Java Language Specificiation 3.10.1:
The productions in the java specification text are self declared to be 
informal. Read the explanitory paragraph following the production. It 
gives the values for the maxium representable integers.

Certainly for the javac compiler, which is written in Java an doesn't 
support unsigned integer representations, you cannot make the required 
test based on the semantic value of the generated bit sequence. Any 
sequence of 32 bits interpreted as a signed 32 bit integer will be less 
than or equal to the maximum signed integer representable in 32 bits. 
(you can make the test interpreting it as 64 bit, but then you have a 
problem making the test on the 64 bit literal overflow).

As to whether you interpret elementary machine operations as being 
semantic or syntactic before the resulting bit sequence is interpreted 
as representing something, that borders on religion and I won't argue 
with you.

But the final test is based on whether the value matches the syntax of 
the positive integer representation of the appropriate length, not 
whether the value of the integer value represented by the bit sequence 
is greater than the largest representable value for a bit sequence of 
that length.


Pete
From: Peter Seibel
Subject: Re: lisp's speed
Date: 
Message-ID: <m3k79croxu.fsf@javamonkey.com>
pete kirkham <············@cafemosaic.co.uk> writes:

> Peter Seibel wrote:
> > From Java Language Specificiation 3.10.1:

> The productions in the java specification text are self declared to
> be informal. Read the explanitory paragraph following the
> production. It gives the values for the maxium representable
> integers.

Well, to me if we're talking about *values* we're talking about
semantics. That those values have to be specified in prose, rather
than in the grammar is exactly what makes them a semantic restriction,
not a syntactic one. But maybe that's just me.

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: pete kirkham
Subject: Re: lisp's speed
Date: 
Message-ID: <3f4090c6$0$964$cc9e4d1f@news.dial.pipex.com>
Peter Seibel wrote:

> Well, to me if we're talking about *values* we're talking about
> semantics. That those values have to be specified in prose, rather
> than in the grammar is exactly what makes them a semantic restriction,
> not a syntactic one. But maybe that's just me.

That they chose to express the language that is accepted by that part of 
the parse in prose instead of using:

  (non-zero-digit [ digit [ digit [ digit [ digit
  [digit [ digit [ digit [ digit ]]]]]]]]) |
  ( '1' digit digit digit digit digit digit digit digit digit ) |
  ( '2' ('0' digit digit digit digit digit digit digit digit ) |
        ('1' ( ('0'|'1'|'2'|'3)
               digit digit digit digit digit digit digit)) |
             ( '4' ( ('0'|'1'|'2'|'3'|'4'|'5'|'6')
                       digit digit digit digit digit digit ) |
                  ( '7' ( ('0'|'1'|'2'|'3')
                           digit digit digit digit digit )|
                        ( '4' ( ('0'|'1'|'2'|'3'|'4'|'5'|'6'|'7') ETC.

to me indicates nothing about whether the basis of the language is 
semantic, only that the authors are concerned with communicating with 
humans.

To me anything that can be parsed with an automata without refererence 
to any 'outside world knowledge' is syntactic, and as such there cannot 
be any semantic restrictions to the input language of a parser.

But I suspect that's just me.


Pete
From: Pascal Costanza
Subject: Re: lisp's speed
Date: 
Message-ID: <bhie2t$10o4$1@f1node01.rhrz.uni-bonn.de>
Peter Seibel wrote:

> Well, 10000000000 is not syntactically incorrect in Java. It's
> *semantically* incorrect. Which was, of course, Edi's point.

No, I don't think that's the main point. The main point is that the 
original poster compared apples to oranges.

The semantically equivalent Java program of the original Lisp code is this:

import java.math.*;

public class delme {
   public static void main (String[] args) {
     long start = System.currentTimeMillis();
     boolean x = false;
     for (BigInteger i = BigInteger.valueOf(0);
          i.compareTo(BigInteger.valueOf(10000000)) < 0;
          i = i.add(BigInteger(1)))
       x = !x;
     System.out.println(System.currentTimeMillis() - start);
}}

You should compare the runtime of the original Lisp code to this Java 
code to get a fair comparison!

(Note: I haven't tested the Java code above by myself, but you get the 
idea...)

Pascal

-- 
Pascal Costanza               University of Bonn
···············@web.de        Institute of Computer Science III
http://www.pascalcostanza.de  R�merstr. 164, D-53117 Bonn (Germany)
From: pete kirkham
Subject: Re: lisp's speed
Date: 
Message-ID: <3f3cc551$0$18486$cc9e4d1f@news.dial.pipex.com>
Pascal Costanza wrote:
> No, I don't think that's the main point. The main point is that the 
> original poster compared apples to oranges.

Strictly speaking, an optimising compiler for the Lisp code should 
detect that the loop iteration variable is only ever set to a fixnum and 
create code equivalent to the original Java.

Similarly, some of the better Java compilers will detect a variable 
whose value is set but not used, and systematically remove all side 
effect free operations on that variable until the last use.

So the compiler detects that b is unused, making the semantically 
equivalent Java code:

   public class delme {
     public static void main (String[] args) {
     long start = System.currentTimeMillis();
     for(int i = 0; i < 10000000; i++) {
     }
     System.out.println(System.currentTimeMillis() - start);
   }}

at which point the compiler reduces the empty loop:
   public class delme {
     public static void main (String[] args) {
     long start = System.currentTimeMillis();
     int i = 10000000;
     System.out.println(System.currentTimeMillis() - start);
   }}

and then performs unused variable elision:
   public class delme {
     public static void main (String[] args) {
     long start = System.currentTimeMillis();
     System.out.println(System.currentTimeMillis() - start);
   }}

Which is far as it can go, as currentTimeMillis() is not idempotent.
(and even if it were, as you can't tag a function as idempotent and side 
effect free in Java, so you're stuck with it)

I do know that Jikes will do some of this, but I don't know if it will 
understand to remove b = !b when b is unused elsewhere.


Pete
From: Pascal Costanza
Subject: Re: lisp's speed
Date: 
Message-ID: <bhih99$n7c$1@f1node01.rhrz.uni-bonn.de>
pete kirkham wrote:
> Pascal Costanza wrote:
> 
>> No, I don't think that's the main point. The main point is that the 
>> original poster compared apples to oranges.
> 
> Strictly speaking, an optimising compiler for the Lisp code should 
> detect that the loop iteration variable is only ever set to a fixnum and 
> create code equivalent to the original Java.
> 
> Similarly, some of the better Java compilers will detect a variable 
> whose value is set but not used, and systematically remove all side 
> effect free operations on that variable until the last use.

Strictly strictly speaking, such code is useless and would never occur 
in real programs. ;)

And before a compiler removes all such code, I would rather see a 
warning issued that I have written useless code.

In a benchmark, you want the code to be still there in the resulting 
program, otherwise the benchmark wouldn't make any sense at all.


Pascal

-- 
Pascal Costanza               University of Bonn
···············@web.de        Institute of Computer Science III
http://www.pascalcostanza.de  R�merstr. 164, D-53117 Bonn (Germany)
From: pete kirkham
Subject: Re: lisp's speed
Date: 
Message-ID: <3f3cdb35$0$18487$cc9e4d1f@news.dial.pipex.com>
Pascal Costanza wrote:
> In a benchmark, you want the code to be still there in the resulting 
> program, otherwise the benchmark wouldn't make any sense at all.

Speed benchmarks only make sense when you are comparing compilers which 
are using all the speed optimisations they know. My car is faster that a 
McLaren if you don't press the McLaren's accelerator.

To ensure that the equivalent code is generated, you simply have to 
encapsulate the code in a method which returns b.

Of course, if your compiler has facilities for tagging symmetric 
functions and uses a double-or-nothing rewrite strategy:

   (defun test-fn ()
     (let ((x nil))
       (dotimes (i 10000000)
         (setq x (not x)))))

double-or-nothing ->
   (defun test-fn ()
     (let ((x nil))
       (do ((i 0))
         ((>= i 10000000) x)
         (setq x (not x))
         (setf i (+ i 1))
         (setq x (not x))
         (setf i (+ i 1))))

evaluate-just-in-time ->
   (defun test-fn ()
     (let ((x nil))
       (do ((i 0))
         ((>= i 10000000) x)
         (setq x (not x))
         (setq x (not x))
         (setf i (+ i 1))
         (setf i (+ i 1))))

combine-store-load-store ->
   (defun test-fn ()
     (let ((x nil))
       (do ((i 0))
         ((>= i 10000000) x)
         (setq x (not (not x)))
         (setf i (+ (+ i 1) 1))))

symmetric-function-elision ->
   (defun test-fn ()
     (let ((x nil))
       (do ((i 0))
         ((>= i 10000000) x)
         (setq x x)
         (setf i (+ (+ i 1) 1))))

non-operation-elision ->
   (defun test-fn ()
     (let ((x nil))
       (do ((i 0))
         ((>= i 10000000) x)
         (setf i (+ (+ i 1) 1))))

unused-variable-elision ->
   (defun test-fn ()
     (let ((x nil)) x)

constant-value-replace-variable ->
   (defun test-fn () nil)

If your functions are, for example tan(x) and atan(x) and you are 
benchmarking a real life example where the symmetric calls are seperated 
by a few thousand lines of math, having a compiler that does this 
rewrite can make improvements of a few tens of percent (in the class of 
problem I work on a 10% improvment means saving half a CPU day to run 
the data set to test a different algorithm).

One of lisp's main selling ponts to me is the ability to perform 
automatic rewrite on the code. The internals of Java's compilers are not 
as accessible, nor are they optimised for intensive numeric work.


Pete
From: Janis Dzerins
Subject: Re: lisp's speed
Date: 
Message-ID: <twk7k5fxbax.fsf@gulbis.latnet.lv>
Pascal Costanza <········@web.de> writes:

> The semantically equivalent Java program of the original Lisp code is this:
> 
> import java.math.*;
> 
> public class delme {
>    public static void main (String[] args) {
>      long start = System.currentTimeMillis();
>      boolean x = false;
>      for (BigInteger i = BigInteger.valueOf(0);
>           i.compareTo(BigInteger.valueOf(10000000)) < 0;
>           i = i.add(BigInteger(1)))
>        x = !x;
>      System.out.println(System.currentTimeMillis() - start);
> }}

One should also make "boolean x = false;" be "object x = false;" (or
something similar that makes the compiler happy.)

And let's not forget that language *ipmlementations* are being
compared.

-- 
Janis Dzerins

  Common Lisp -- you get more than what you see.
From: Kaz Kylheku
Subject: Re: lisp's speed
Date: 
Message-ID: <cf333042.0308151434.554d2499@posting.google.com>
pete kirkham <············@cafemosaic.co.uk> wrote in message news:<·························@news.dial.pipex.com>...
> Edi Weitz wrote:
> 
> > Now replace 10000000 with 10000000000:
> > 
> >   ···@bird:/tmp > /opt/sun-jdk-1.4.2/bin/javac delme.java
> >   delme.java:5: integer number too large: 10000000000
> >                           for(int i = 0; i < 10000000000; i++)
> >                                            ^
> >   1 error
> > 
> > Ooops... Try the same with Lisp.
> 
> for example:
> 
> (defun test-fn ()
>      (declaim (optimize speed))
>      (let ((x nil))
>        (dotimes (i 1-some-equally-syntacticly-incorrect-numerical-literal-0)

Pointless nitpick. Replace 10000000...0000 with 10 * 10 * 10 * 10 ...
* 10 in the Java program and with (* 10 10 10 10 ...) in the Lisp
version.

Then it's clearly no longer a matter of syntax.
From: Frode Vatvedt Fjeld
Subject: Re: lisp's speed
Date: 
Message-ID: <2h4r0j6bl7.fsf@vserver.cs.uit.no>
Lowell <······@cs.ubc.ca> writes:

> I read everywhere that Lisp is fast. Much faster than Java. But from
> a simple test that I've done, Java seems much faster. It's just a
> trivial loop which is executed ten million times.

Benchmarking is difficult. And a language as such has no speed, only
particular implementations do. So asking your question without giving
details about the system you use, is rather pointless.

Don't expect lisp systems to do meaningless things very fast. Still,
on my (not particularly fast, but with 10000000 in the fixnum range)
system, your test-fn took about 100 ms, after I changed your mistaken
"declaim" to "declare". Presumably, you have a lisp whose
most-positive-fixnum is below ten million, and with a not-so-clever
dotimes, so that millions of bignum objects were created and most
likely also garbage-collected within those 3.7 seconds you measured.

Or... you could be using a lisp that compiles to a 9-bit virtual
machine running in Visual Basic, for all I know.

-- 
Frode Vatvedt Fjeld
From: Joe Marshall
Subject: Re: lisp's speed
Date: 
Message-ID: <ekzm6h40.fsf@ccs.neu.edu>
Lowell <······@cs.ubc.ca> writes:

> I read everywhere that Lisp is fast. Much faster than Java. But from a
> simple test that I've done, Java seems much faster. It's just a
> trivial loop which is executed ten million times. It takes 47 ms in
> Java and 3.7 seconds in CL. This is almost 100 times slower!! Am I
> missing the point? 

Depends.  If you want to sit in a loop and do nothing useful,
then Java is definitely for you!
From: Coby Beck
Subject: Re: lisp's speed
Date: 
Message-ID: <bhjnsl$dbk$1@otis.netspace.net.au>
"Joe Marshall" <···@ccs.neu.edu> wrote in message
·················@ccs.neu.edu...
> Lowell <······@cs.ubc.ca> writes:
>
> > I read everywhere that Lisp is fast. Much faster than Java. But from a
> > simple test that I've done, Java seems much faster. It's just a
> > trivial loop which is executed ten million times. It takes 47 ms in
> > Java and 3.7 seconds in CL. This is almost 100 times slower!! Am I
> > missing the point?
>
> Depends.  If you want to sit in a loop and do nothing useful,
> then Java is definitely for you!

LOL!  My vote for most succinct answer of the thread!
From: Wade Humeniuk
Subject: Re: lisp's speed
Date: 
Message-ID: <Rj5%a.22656$zE1.22623@edtnps84>
"Lowell" <······@cs.ubc.ca> wrote in message ·················@mughi.cs.ubc.ca...
> I read everywhere that Lisp is fast. Much faster than Java. But from a 
> simple test that I've done, Java seems much faster. It's just a trivial 
> loop which is executed ten million times. It takes 47 ms in Java and 3.7 
> seconds in CL. This is almost 100 times slower!! Am I missing the point? 
> Here is the code:
> 
> CL:
> (defun test-fn ()
>    (declaim (optimize speed))
>    (let ((x nil))
>      (dotimes (i 10000000)
>        (setq x (not x)))))
> (compile 'test-fn)
> (time (test-fn))

Just for the fun of it rewrite test-fn, like so :)

(defun test-fn ()
   (declaim (optimize speed))
   #.(let ((x nil))
     (dotimes (i 10000000)
       (setq x (not x)))))
(compile 'test-fn)
(time (test-fn))

Wade
From: Wade Humeniuk
Subject: Re: lisp's speed
Date: 
Message-ID: <qS7%a.6367$L6.89232@news2.telusplanet.net>
"Wade Humeniuk" <····@nospam.nowhere> wrote in message ··························@edtnps84...
> Just for the fun of it rewrite test-fn, like so :)
> 
> (defun test-fn ()
>    (declaim (optimize speed))
>    #.(let ((x nil))
>      (dotimes (i 10000000)
>        (setq x (not x)))))

Change that declaim to a declare.  The call to declaim is
taking way too much time. ;) 

BTW, in this case the read time evaluation can be seen as 
a compiler declaration.

Wade