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
signature.asc
Description: Digital signature