Comparing clojure speed to java speed

115 views
Skip to first unread message

Jarl Haggerty

unread,
Mar 10, 2011, 10:39:52 PM3/10/11
to Clojure
I've been benchmarking java and clojure programs and wanted to make
sure I was doing this right. I made two fairly similar programs that
manipulated Vec2 objects from the JBox2D library. At first clojure
was performing pretty poorly, then I tried compiling my clojure
script, and then replacing the inner doseq with a loop. But java is
still 5x faster and I hear that clojure should be able to run as fast
as java and I wondered if there's any options in clojure I'm not using

Java:

package test;

import org.jbox2d.common.Vec2;

public class Main {
static long w = 0;
public static void main(String[] args) {
for(int q = 0;q < 5;q++){
Vec2 a = new Vec2(1, 2), b = new Vec2(3, 4);
long start = System.currentTimeMillis();
for(int d = 0;d < 1e9;d++){
a.addLocal(b);
}
long stop = System.currentTimeMillis();
System.out.println((stop - start)/1000.0);
}
}
}

Clojure:

(ns hello.test
(import org.jbox2d.common.Vec2)
(:gen-class))

(defn -main [& args]
(doseq [q (range 5)]
(let [a (Vec2. 1 2)
b (Vec2. 3 4)]
(time (loop [x (int 0)]
(when (< x 1e9)
(.addLocal a b)
(recur (unchecked-inc x))))))))

Vec2(if anyone cares):

http://code.google.com/p/jbox2d/source/browse/trunk/jbox2d/src/org/jbox2d/common/Vec2.java

Jarl Haggerty

unread,
Mar 10, 2011, 10:47:08 PM3/10/11
to Clojure
I should readjust my 5x statement, it's more like 2.25x.
> http://code.google.com/p/jbox2d/source/browse/trunk/jbox2d/src/org/jb...

Mark Engelberg

unread,
Mar 10, 2011, 11:02:53 PM3/10/11
to clo...@googlegroups.com
Try typehinting the a and b in the let.

David Nolen

unread,
Mar 10, 2011, 11:04:57 PM3/10/11
to clo...@googlegroups.com
On Thu, Mar 10, 2011 at 10:39 PM, Jarl Haggerty <jarlha...@gmail.com> wrote:
I've been benchmarking java and clojure programs and wanted to make
sure I was doing this right.  I made two fairly similar programs that
manipulated Vec2 objects from the JBox2D library.  At first clojure
was performing pretty poorly, then I tried compiling my clojure
script, and then replacing the inner doseq with a loop.  But java is
still 5x faster and I hear that clojure should be able to run as fast
as java and I wondered if there's any options in clojure I'm not using

Try replacing doseq w/ dotimes. You need to cast 1e9 to int, just like you do w/ 0 if you're using Clojure <= 1.2.0. How long is it taking for you in Clojure and Java?

David 

David Nolen

unread,
Mar 10, 2011, 11:11:29 PM3/10/11
to clo...@googlegroups.com
On Thu, Mar 10, 2011 at 10:39 PM, Jarl Haggerty <jarlha...@gmail.com> wrote:
I've been benchmarking java and clojure programs and wanted to make
sure I was doing this right.  I made two fairly similar programs that
manipulated Vec2 objects from the JBox2D library.  At first clojure
was performing pretty poorly, then I tried compiling my clojure
script, and then replacing the inner doseq with a loop.  But java is
still 5x faster and I hear that clojure should be able to run as fast
as java and I wondered if there's any options in clojure I'm not using

Try:

(ns box2d.core
 (import org.jbox2d.common.Vec2)
 (:gen-class))

(defn -main [& args]
  (dotimes [_ 5]
    (let [a (Vec2. 1 2)
          b (Vec2. 3 4)]
      (time (dotimes [x 1e9]
              (.addLocal a b))))))
 

Jarl Haggerty

unread,
Mar 10, 2011, 11:26:09 PM3/10/11
to Clojure
Hmm, I should have thought of that.

New Clojure:

(ns hello.test
(import org.jbox2d.common.Vec2)
(:gen-class))

(defn -main [& args]
(dotimes [q 5]
(let [#^Vec2 a (Vec2. 1 2)
#^Vec2 b (Vec2. 3 4)]
(time (loop [x (int 0)]
(when (< x (int 1e9))
(.addLocal a b)
(recur (unchecked-inc x))))))))

Old Clojure Output:
"Elapsed time: 11437.687558 msecs"
"Elapsed time: 10863.527399 msecs"
"Elapsed time: 11863.44317 msecs"
"Elapsed time: 11861.23116 msecs"
"Elapsed time: 11870.92791 msecs"
New Clojure Output:
"Elapsed time: 2492.033705 msecs"
"Elapsed time: 1489.316185 msecs"
"Elapsed time: 1484.606724 msecs"
"Elapsed time: 1480.983085 msecs"
"Elapsed time: 1486.435446 msecs"

This is the result of the Java code I posted,

Java Output:
2.263
4.471
4.484
4.452
4.409

I thought it was strange that the first iteration ran so fast, so I
changed 1e9 to (int)1e9 and the speed got better, but I still wonder
why the first iteration before was so fast, the JIT is supposed to
make it faster isn't it?

Old Java Output:
1.513
1.495
1.96
1.47
1.475

On Mar 10, 9:04 pm, David Nolen <dnolen.li...@gmail.com> wrote:

Chouser

unread,
Mar 11, 2011, 9:05:10 AM3/11/11
to clo...@googlegroups.com
On Thu, Mar 10, 2011 at 11:26 PM, Jarl Haggerty <jarlha...@gmail.com> wrote:
> Hmm, I should have thought of that.
>
> New Clojure:
>
> (ns hello.test
>  (import org.jbox2d.common.Vec2)
>  (:gen-class))
>
> (defn -main [& args]
>  (dotimes [q 5]
>    (let [#^Vec2 a (Vec2. 1 2)
>          #^Vec2 b (Vec2. 3 4)]
>      (time (loop [x (int 0)]
>              (when (< x (int 1e9))
>                (.addLocal a b)
>                (recur (unchecked-inc x))))))))

I think if you turn on reflection warnings and remove those type
hints, you'll find those hints aren't useful. In which case I'd
recommend leaving them out.

--Chouser

Jarl Haggerty

unread,
Mar 19, 2011, 12:26:32 AM3/19/11
to Clojure
Is there a reason I can't get this clojure program to compare with the
java one?

The following code:

for(int q = 0;q < 5;q++){
Point2D.Float a = new Point2D.Float(1, 2), b = new
Point2D.Float(3, 4);
long start = System.currentTimeMillis();
for(int d = 0;d < (int)1e9;d++){
a.getX();
}
long stop = System.currentTimeMillis();
System.out.println(stop - start);
}

prints this:

7
6
0
0
0

And this code:

(set! *warn-on-reflection* true)
(import 'java.awt.geom.Point2D$Float)
(dotimes [_ 5]
(let [q (Point2D$Float. 1 2)]
(time (dotimes [_ (int 1e9)]
(.getX q)))))

prints this:

"Elapsed time: 2220.368412 msecs"
"Elapsed time: 2214.941962 msecs"
"Elapsed time: 2168.259558 msecs"
"Elapsed time: 2162.655501 msecs"
"Elapsed time: 2172.560098 msecs"

On Mar 11, 7:05 am, Chouser <chou...@gmail.com> wrote:

David Nolen

unread,
Mar 19, 2011, 1:08:00 AM3/19/11
to clo...@googlegroups.com
On Sat, Mar 19, 2011 at 12:26 AM, Jarl Haggerty <jarlha...@gmail.com> wrote:
Is there a reason I can't get this clojure program to compare with the
java one?

The following code:

for(int q = 0;q < 5;q++){
   Point2D.Float a = new Point2D.Float(1, 2), b = new
Point2D.Float(3, 4);
   long start = System.currentTimeMillis();
   for(int d = 0;d < (int)1e9;d++){
       a.getX();
   }
   long stop = System.currentTimeMillis();
   System.out.println(stop - start);
}

prints this:

7
6
0
0
0

That's 1 billion operations getting JITed away. Not really useful for profiling real programs, eh? :)

David 

Jarl Haggerty

unread,
Mar 19, 2011, 3:40:29 AM3/19/11
to Clojure
Ok, I changed the java version to add x to an accumulator and now it
runs just a little slower than clojure, probably because of the extra
adding. And if you don't mind one more trivial example...

Should I be able assign to the members of an object in Clojure just as
fast as I could in Java? I have two forms below, one calls the
setLocation of a Point2D object, and the other does the assignment in
Clojure and is about 3 times slower.

(dotimes [_ 5]
(let [a (Point2D$Double. 1 2)
b (Point2D$Double. 2 3)
add (fn [^Point2D a ^Point2D b]
(.setLocation a
(+ (.getX a) (.getX b))
(+ (.getY a) (.getY b))))]
(time (dotimes [_ (int 1e9)]
(add a b)))))
(dotimes [_ 5]
(let [a (Point2D$Double. 1 2)
b (Point2D$Double. 2 3)
add (fn [^Point2D$Double a ^Point2D$Double b]
(set! (.x a) (+ (.x a) (.x b)))
(set! (.y a) (+ (.y a) (.y b))))]
(time (dotimes [_ (int 1e9)]
(add a b)))))

On Mar 18, 10:08 pm, David Nolen <dnolen.li...@gmail.com> wrote:
Reply all
Reply to author
Forward
0 new messages