On Feb 10, 2011, at 4:49 PM, Andy Fingerhut wrote:
I've published that program at the link below. It contains comments
marking two lines in the function gen-random-fast where the Hotspot
JVM profiler tells me that the CPU is spending lots of time in
java.lang.Integer.valueOf (Clojure 1.2.0). I can't seem to get rid
of these calls to Integer.valueOf even after trying about half a
dozen different variations of type-hinting. Can anyone else see a
way to change the program to avoid those calls?
http://github.com/jafingerhut/clojure-benchmarks/blob/master/fasta/fasta.clj-10.clj
Here is something a little odd. I've looked at the disassembly of the
Java bytecode produced for this Clojure function:
(def random-seed (int-array [42]))
(let [scale (double (/ *lookup-size* 139968))]
(defn gen-random-fast []
(let [^ints random-seed random-seed
IM (int 139968)
IA (int 3877)
IC (int 29573)
zero (int 0)
new-seed (int (unchecked-remainder
(unchecked-add
(unchecked-multiply
(aget random-seed zero) IA) IC) IM))]
(aset random-seed zero new-seed) ;; <--- this line produces
odd Java bytecode
(int (* new-seed scale)))))
The marked line produces bytecodes for pushing the args on the stack,
then calling aset, and then it calls Integer.valueOf to take the int
returned by aset (which is just the value of new-seed assigned to the
array element) and convert it to an Integer, then it pops it off the
stack, discarding that Integer value. Strange. Apparently java -
server was not able to optimize away that wasted work, but I don't yet
know why the Clojure compiler generated the call in the first place.
The second call to Integer.valueOf() from the last line of the
function makes sense to me now: the int return value must be boxed
into an Integer before being returned as the value of function gen-
random-fast, since all Clojure 1.2 function arguments and returns
values must be Objects.
Given the wasted bytecode instructions mentioned above, on a hunch I
decided to assign the return value of aset to a symbol via let -- one
that is never used again. This actually produces faster code:
(def random-seed (int-array [42]))
(let [scale (double (/ *lookup-size* 139968))]
(defn gen-random-fast []
(let [^ints random-seed random-seed
IM (int 139968)
IA (int 3877)
IC (int 29573)
zero (int 0)
new-seed (int (unchecked-remainder
(unchecked-add
(unchecked-multiply
(aget random-seed zero) IA) IC) IM))
throwaway-val (int (aset random-seed zero new-seed))]
<-- this is the only changed line
(int (* new-seed scale)))))
Hmmmm. I hope such wasted instructions are rare.
Andy
--
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