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

Reply via email to