One has to be very careful with this kind of
micro-benchmarking on the JVM. Dead-code elimination can
easily make something seem fast simply because it's not
doing anything. For example, in Java:
https://gist.github.com/stuartsierra/5807356

Being careful not to have dead code, I get about the same
results: 9 microseconds to sum an array of 10000 doubles in
Java.

Getting back to Clojure, I notice a large difference between
Clojure 1.2.1 and 1.5.1 to sum an array. But looking more
closely, that difference is entirely due to dead-code
elimination:
https://gist.github.com/stuartsierra/5807676

With a loop doing real work, my tests show Clojure's
performance on this task is virtually indistinguishable from
Java. The performance hasn't changed since 1.2, although the
syntax has. (I get the same result with `areduce`.)

Also beware of this "helpful" Leiningen 2.1+ feature: it
disables some JVM optimizations to get faster start-up time.
https://github.com/technomancy/leiningen/wiki/Faster#tiered-compilation

To avoid this, you need to add the following to your
`project.clj` file:

    :jvm-opts ^:replace []

The `^:replace` is critical.

Whenever I'm uncertain about a benchmark, I run it without
Leiningen to make sure I know what's going on.

-S


On Thursday, June 13, 2013 4:50:48 PM UTC-4, Jason Wolfe wrote:
>
> Taking a step back, the core problem we're trying to solve is just to sum 
> an array's values as quickly as in Java. (We really want to write a fancier 
> macro that allows arbitrary computations beyond summing that can't be 
> achieved by just calling into Java, but this simpler task gets at the crux 
> of our performance issues).
>
> This Java code:
>
>   public static double asum_noop_indexed(double[] arr) {
>     double s = 0;
>     for (int i = 0; i < arr.length; i++) {
>       s += arr[i];
>     }
>     return s;
>   }
>
> can run on an array with 10k elements in about 8 microseconds. In 
> contrast, this Clojure code (which I believe used to be as fast as the Java 
> in a previous Clojure version):
>
> (defn asum-identity [^doubles a]
>   (let [len (long (alength a))]
>     (loop [sum 0.0
>            idx 0]
>       (if (< idx len)
>         (let [ai (aget a idx)]
>           (recur (+ sum ai) (unchecked-inc idx)))
>         sum))))
>
> executes on the same array in about 40 microseconds normally, or 14 
> microseconds with *unchecked-math* set to true.  (We weren't using 
> unchecked-math properly until today, which is why we were doing the hacky 
> interface stuff above, please disregard that -- but I think the core point 
> about an extra cast is still correct).  
>
> For reference, (areduce a1 i r 0.0 (+ (aget a1 i) r)) takes about 23 ms to 
> do the same computation (with unchecked-math true).
>
> Does anyone have ideas for how to achieve parity with Java on this task? 
>  They'd be much appreciated! 
>

-- 
-- 
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