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 [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en