Why is Clojure much faster than mit-scheme for equivalent functions?

clojure, mit-scheme, scheme

Solution

Modern incarnations of the Java Virtual Machine have extremely good performance when compared to interpreted languages. A significant amount of engineering resource has gone into the JVM, in particular the hotspot JIT compiler, highly tuned garbage collection and so on.

I suspect the difference you are seeing is primarily down to that. For example if you look Are the Java programs faster? you can see a comparison of java vs ruby which shows that java outperforms by a factor of 220 on one of the benchmarks.

You don't say what JVM options you are running your clojure benchmark with. Try running java with the `-Xint` flag which runs in pure interpreted mode and see what the difference is.

Also, it's possible that your example is too small to really warm-up the JIT compiler. Using a larger example may yield an even larger performance difference.

To give you an idea of how much Hotspot is helping you. I ran your code on my MBP 2011 (quad core 2.2Ghz), using java 1.6.0_31 with default opts (-server hotspot) and interpreted mode (-Xint) and see a large difference

; with -server hotspot (best of 10 runs)
>(time (reduce + 0 (sieve 5000000)))
"Elapsed time: 282.322 msecs"
838596693108

; in interpreted mode using -Xint cmdline arg
> (time (reduce + 0 (sieve 5000000)))
"Elapsed time: 3268.823 msecs"
838596693108

Problem

I found this code in Clojure to sieve out first n prime numbers: ``` (defn sieve [n] (let [n (int n)] "Returns a list of all primes from 2 to n" (let [root (int (Math/round (Math/floor (Math/sqrt n))))] (loop [i (int 3) a (int-array n) result (list 2)] (if (>= i n) (reverse result) (recur (+ i (int 2)) (if (< i root) (loop [arr a inc (+ i i) j (* i i)] (if (>= j n) arr (recur (do (aset arr j (int 1)) arr) inc (+ j inc)))) a) (if (zero? (aget a i)) (conj result i) result))))))) ``` Then I wrote the equivalent (I think) code in Scheme (I use mit-scheme) ``` (define (sieve n) (let ((root (round (sqrt n))) (a (make-vector n))) (define (cross-out t to dt) (cond ((> t to) 0) (else (vector-set! a t #t) (cross-out (+ t dt) to dt) ))) (define (iter i result) (cond ((>= i n) (reverse result)) (else (if (< i root) (cross-out (* i i) (- n 1) (+ i i))) (iter (+ i 2) (if (vector-ref a i) result (cons i result)))))) (iter 3 (list 2)))) ``` The timing results are: For Clojure: ``` (time (reduce + 0 (sieve 5000000))) "Elapsed time: 168.01169 msecs" ``` For mit-scheme: ``` (time (fold + 0 (sieve 5000000))) "Elapsed time: 3990 msecs" ``` Can anyone tell me why mit-scheme is more than 20 times slower? update: "the difference was in iterpreted/compiled mode. After I compiled the mit-scheme code, it was running comparably fast. – abo-abo Apr 30 '12 at 15:43"

Original source