Hi All,

I stuck with performance problem using Clojure.
It seems that when all the optimisation hints are used,
Clojure data processing is still much slower than Java.

In my simple test I sum up 16M of random integers 0 < n < 10.
The code is as follows (see below Java and C code, and the test
script and output):

(def *N* (* 1024 1024 16))
(def *a* (make-array Integer/TYPE *N*))

(dotimes [i *N*] (aset ^ints *a* i (int (* 10 (rand 1.0)))))

(set! *warn-on-reflection* true)

(defn sum [arr]
  (loop [i (int 0) s (int 0)]
    (if (= i *N*) s
      (recur (inc i) (+ s (aget ^ints arr i))))))

(println "Clojure:" *clojure-version*)
(dotimes [_ 5] (time (println "sum =" (sum *a*))))

(set! *warn-on-reflection* false)

In this test Clojure is ~15 times slower than the same test in plain
Java.
(The best result is for Clojure 1.2, it's slower for the 1.3-alpha
version,
see the output log below.)

I didn't use there unchecked-inc, unchecked-add, but it doesn't help
much
either. Actually, this is even not about access to the Java array,
because
the sum of constants (1+1+1... ) is evaluated at nearly the same time
(30% more quick, ~10 time slower than the original test in Java).

It's rather surprising, having in mind that Clojure code is compiled
to the bytecode, pretty much the same as Java code is.

I do realize that Java demonstrates an extremely powerful JIT technic
there, since the loop is executed in just ~1 nanosecond which is
~3 CPU cycles on my PC. (Clojure's best result shows ~16ns = ~50 CPU
cycles.)
Although, the same slowdown I observed with more sophisticated tests,
therefore it seems to be a general trend.

Thanks in advance, I would appreciate very much any suggestions or
comments.

Best wishes,
  Dmitriy

P.S. The code for Java/Clojure/C languages, test script, and its
output:

### Sum.java  ###############################################

package Test;
import java.util.Random;

public class Sum {
  public static void main(String args[]) {
    int N = 1024*1024*16;
    int a[] = new int[N];
    int i, cs = 0;

    Random r = new Random();

    for(i = 0; i < N; i++) {
        int r_int = r.nextInt();
        a[i] = (r_int > 0 ? r_int : -r_int) % 10;
    }

    for(int l = 0; l < 5; l++) {
        long start = System.currentTimeMillis();
        cs = 0;
        for(i = 0; i < N; i++) {
            cs += a[i];
        }
        System.out.printf("Elapsed time (Java): %1$d msecs\n",
            System.currentTimeMillis() - start);
    }

    System.out.printf("sum = %1$d\n", cs);
  }
}

### sum.clj  ###############################################

(def *N* (* 1024 1024 16))
(def *a* (make-array Integer/TYPE *N*))

(dotimes [i *N*] (aset ^ints *a* i (int (* 10 (rand 1.0)))))

(set! *warn-on-reflection* true)

(defn sum [arr]
  (loop [i (int 0) s (int 0)]
    (if (= i *N*) s
      (recur (inc i) (+ s (aget ^ints arr i))))))

(println "Clojure:" *clojure-version*)
(dotimes [_ 5] (time (println "sum =" (sum *a*))))

(set! *warn-on-reflection* false)

### sum.c  ###############################################

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <sys/time.h>

#define N (1024*1024*16)
int a[N];

int main()
{
    int i, cs = 0;
    struct timeval t1, t2;

    srand(23);
    for(i = 0; i < N; i++) {
        int rn = rand();
        a[i] = rn % 10;
    }

    gettimeofday(&t1, NULL);
    for(i = 0; i < N; i++) {
        cs += a[i];
    }
    gettimeofday(&t2, NULL);
    printf("Elapsed time (C): %d msecs\n",
           (t2.tv_sec - t1.tv_sec) * 1000
            + (t2.tv_usec - t1.tv_usec) / 1000);

    printf("sum = %d\n", cs);
}

### test-sum.sh  ###############################################

#! /bin/bash

echo System info:
cat /proc/cpuinfo | grep 'model name' | tail -1
uname -rs

# C
echo
gcc --version
gcc -O2 -o sum sum.c
./sum

# Java
echo
javac -6 Test/Sum.java
java -version
java -server -cp . Test.Sum

# Clojure 1.2 alpha
echo
java -server -cp .:clojure.jar clojure.main sum.clj

# Clojure 1.3 alpha
echo
java -server -cp .:clojure-1.3a.jar clojure.main sum.clj

# clean
rm sum Test/Sum.class

### The output:  ###############################################

System info:
model name      : Intel(R) Core(TM)2 Duo CPU     E8600  @ 3.33GHz
Linux 2.6.27.19-170.2.35.fc10.i686

gcc (GCC) 4.3.2 20081105 (Red Hat 4.3.2-7)
Copyright (C) 2008 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There
is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.

Elapsed time (C): 14 msecs
sum = 75480349

java version "1.6.0_0"
OpenJDK Runtime Environment (IcedTea6 1.6) (fedora-23.b16.fc10-i386)
OpenJDK Server VM (build 14.0-b16, mixed mode)
Elapsed time (Java): 17 msecs
Elapsed time (Java): 19 msecs
Elapsed time (Java): 14 msecs
Elapsed time (Java): 17 msecs
Elapsed time (Java): 18 msecs
sum = 75490326

Clojure: {:major 1, :minor 2, :incremental 0, :qualifier }
sum = 75488840
"Elapsed time: 568.937934 msecs"
sum = 75488840
"Elapsed time: 285.198714 msecs"
sum = 75488840
"Elapsed time: 293.939893 msecs"
sum = 75488840
"Elapsed time: 291.059807 msecs"
sum = 75488840
"Elapsed time: 299.875087 msecs"

Clojure: {:major 1, :minor 3, :incremental 0, :qualifier alpha1}
sum = 75479971
"Elapsed time: 683.505713 msecs"
sum = 75479971
"Elapsed time: 528.660321 msecs"
sum = 75479971
"Elapsed time: 499.890406 msecs"
sum = 75479971
"Elapsed time: 485.581542 msecs"
sum = 75479971
"Elapsed time: 474.028165 msecs"


-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to