I read that there are ways to persuade the Clojure compiler to create code that compares the performance of similar Java code, at least for code that is already very similar to the Java code that you want it to turn into. This sounds reasonable to me: idiomatic, high-level Clojure code may have stadium performance of what I use from CPython or MRI, but ugly Java-like code works more or less like Java. This is a tradeoff that I appreciate in Haskell, for example. Haskell code is low with mutable arrays, loops, and something that doesn't run under GHC, with corresponding compiler flags, about as fast as in C (and then some high-tech libraries can sometimes compress similar performance from a more beautiful higher-level code).
I want to help find out how to make Clojure Java code run as fast as it does in Java. Take this example:
(defn f [x y z n]
(+ (* 2 (+ (* x y) (+ (* y z) (* x z))))
(* 4 (+ x y z n -2) (- n 1))))
(defmacro from [[var ini cnd] & body]
`(loop [~var ~ini]
(when ~cnd
~@body
(recur (inc ~var)))))
(defn g [n]
(let [c (long-array (inc n))]
(from [x 1 (<= (f x x x 1) n)]
(from [y x (<= (f x y y 1) n)]
(from [z y (<= (f x y z 1) n)]
(from [k 1 (<= (f x y z k) n)]
(let [l (f x y z k)]
(aset c l (inc (aget c l))))))))
c))
(defn h [x]
(loop [n 1000]
(let [^longs c (g n)]
(if-let [k (some #(when (= x (aget c %)) %)
(range 1 (inc n)))]
k
(recur (* 2 n))))))
(time (print (h 1000)))
It takes about 85 seconds using Clojure 1.6 on my (admittedly) slow machine. Equivalent code in Java runs after about 0.4 seconds. I'm not greedy, I just want to get the Clojure code to run, say, about 2 seconds.
The first thing I did was turn it on *warn-on-reflection*, but unfortunately there are no more warnings with this hint of a lone type. What am I doing wrong?
This method contains both Java versions and Clojure code.
source
share