Hi all,

I am doing some (naive and trivial) performance tests before deciding 
whether and how to use Clojure for some performance critical number 
cruching and I wanted help understanding the behaviour.

I am defining an array inside a function, setting the contents to be 1 and 
then summing them up (by areducing) them (I chose 1 instead of a random 
number for consistency, obviously the contents will be different otherwise 
it would all reduce to (n) :)).  If I 'let' the array then it is factors of 
10 faster than if I def the array.

The relevant code 
(https://github.com/yatesco/clojure-perf/blob/master/src/inc.clj):

[code]
(ns inc
  (:gen-class))

(defn- inc-atom [n]
  (def x (atom 0))
  (dotimes [n n] (swap! x inc))
  @x)

(defn- array-let [n]
  (let [a (int-array n)]
    (dotimes [n n] (aset-int a n 1))
    (areduce a i ret 0
             (+ ret (aget a i)))))

(defn- array-def [n]
  (def a (int-array n))
  (dotimes [n n] (aset-int a n 1))
  (areduce a i ret 0
           (+ ret (aget a i))))

(defn- run-test [subject n]
  (time (do (def x (subject n)) (println x))))

(defn -main [& args]
  (let [n 1000000]
    (println "inc atom")
    (run-test inc-atom n)
    (println "array with let")
    (run-test array-let n)
    (println "array with def")
    (run-test array-def n))
)
[/code]

Interestingly, if I refactored an 'execute-on-array' def which array-let 
and array-def delegated to then they had the same performance which seems 
to imply it is about scoping, but the array in both array-let and array-def 
have exactly the same scope...  Setting the autoboxing warning to true 
didn't point out anything either.

The output (from my VM, so a bit slow):
[code]
inc atom
1000000
"Elapsed time: 213.214118 msecs"
array with let
1000000
"Elapsed time: 75.302602 msecs"
array with def
1000000
"Elapsed time: 12868.970203 msecs"
[/code]

For comparison, the following java code:

[code]
package perf;

public class Inc {
    public static void main(String[] args) {
        int n = 1000000;
        int counter = 0;
        long start = System.currentTimeMillis();
        for (int i=0; i<n; i++) counter++;
        long end  = System.currentTimeMillis();         
        System.out.println ("Naive " + (end - start) + " ms, counter is " + 
counter);

        counter = 0;
        int[] arr = new int[n];
        start = System.currentTimeMillis();
        for (int i=0; i<arr.length; i++) arr[i]=1;
        for (int i=0; i<arr.length; i++) counter = counter + arr[i];
        end  = System.currentTimeMillis();         
        System.out.println ("Array " + (end - start) + " ms, counter is " + 
counter);     
                                           }
}    
[/code]

produces the (as expected, much faster) results :

[code]
Naive 3 ms, counter is 1000000
Array 6 ms, counter is 1000000
[/code]

I am not surprised that the atom/inc takes much longer than 3 ms, but I 
don't understand why the array solution is so much more expensive in 
Clojure?

On a related point - can anyone provide a faster implementation of summing 
up the contents of an array?

A lein project can be found https://github.com/yatesco/clojure-perf, 'lein 
uberjar; java -jar target/*.jar should demonstrate the output.

-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to