Hello,

Having given a talk on precisely this topic at Clojure/West, I may be
able to give you a couple of hints and explanations.  You can find the
slides at
<https://github.com/strangeloop/clojurewest2012-slides/raw/master/Solano-G%C3%B3mez-Crunching-Numbers-with-Clojure.pdf>,
and I am planning on writing a more detailed set of blog posts over the
next few months.


On Mon Mar 26 13:37 2012, Sergey Didenko wrote:
> Hi,
> 
> I believe I've heard claims that nothing stops Clojure 1.3 code to be
> made very close to Java in terms of execution speed.
> 
> However when trying to match the speed of ad-hoc Heapsort
> implementation I have faced essential obstacles.
> 
> Setting type hints and coercions was quite easy. A bit harder was to
> realize that "aset" is much faster than "aset-int" and that "(int -1)"
> inside "if" condition can be faster than "-1".

You can best understand why these things happen by looking at the
examining the bytecode generated by the Clojure compiler.  Just
AOT-compile the code and look at the output of 'javap -c'.

One of the things you're battling with in your code is Clojure's
64-bit primitives.  If using longs in your application isn't a
deal-breaker, consider making all your primitives 64-bit.  This will
eliminate the need of having to do a lot of casting back and forth
between 32-bit and 64-bit integers.

One additional benefit to using longs is that you can replace all of
your (unchecked-op-int) calls to the plain arithmetic function.  For
example, instead of (unchecked-add-int), you can just do (+).  When you
set *unchecked-math* to true during compile time, you get the unchecked
long operations.

> However I'm still far from the Java speed ( 1.5 times slower on a cut
> code - first part of the Heapsort ).
> 
> What I can't understand now is why inlining the following function
> makes a noticeable speedup (~20%). Isn't it supposed to be solved in
> 1.3?

What you're running into is the overhead of get the root value of vars
like swap! and move-up!.  The only way to avoid this is use something
like definline.

> (defn move-up! [^long pos]
>   (let [array (ints array)]
>     (loop [pos pos ppos (unchecked-divide-int pos 2)]
>       (if (or (= pos 0)
>               (>= (aget array ppos) (aget array pos)))
>         nil
>         (do ;(swap! array ppos pos)
>           (recur ppos (unchecked-divide-int ppos 2)))))))
> 
> I'm attaching the full sources if anyone is interested to measure the
> difference.

I don't have the time to run your example code, but I hope some of the
above pointers help.

Sincerely,

Daniel

Attachment: signature.asc
Description: Digital signature

Reply via email to