Hi. I've been working with people at Prismatic to optimize some simple math 
code in Clojure. However, it seems that Clojure generates an unnecessary 
type check that slows our (otherwise-optimized) code by 50%. Is there a 
good way to avoid this, is it a bug in Clojure 1.5.1, or something else? 
What should I do to work around this?

Here's my example. The aget seems to generate an unnecessary checkcastbytecode. 
I used Jasper and Jasmin to decompile and recompile Bar.class 
into Bar_EDITED.class, without that bytecode. The edited version takes 
about 2/3 the time.

(ns demo
  (:import demo.Bar_EDITED))

(definterface Foo
  (arraysum ^double [^doubles a ^int i ^int asize ^double sum]))

(deftype Bar []
  Foo
  (arraysum ^double [this ^doubles a ^int i ^int asize ^double sum]
    (if (< i asize)
      (recur a (unchecked-inc-int i) asize (+ sum (aget a i)))
      sum)))

(defn -main [& args]
  (let [bar (Bar.)
        bar-edited (Bar_EDITED.)
        asize 10000
        a (double-array asize)
        i 0
        ntimes 10000]
    (time

      (dotimes [iter ntimes]
        (.arraysum bar a i asize 0)))
    (time
      (dotimes [iter ntimes]
        (.arraysum bar-edited a i asize 0)))))


;; $ lein2 run -m demo
;; Compiling demo
;; "Elapsed time: 191.015885 msecs"
;; "Elapsed time: 129.332 msecs"


Here's the bytecode for Bar.arraysum:

  public java.lang.Object arraysum(double[], int, int, double);
    Code:
       0: iload_2       
       1: i2l           
       2: iload_3       
       3: i2l           
       4: lcmp          
       5: ifge          39
       8: aload_1       
       9: iload_2       
      10: iconst_1      
      11: iadd          
      12: iload_3       
      13: dload         4
      15: aload_1       
      16: aconst_null   
      17: astore_1      
      18: checkcast     #60                 // class "[D"
      21: iload_2       
      22: invokestatic  #64                 // Method 
clojure/lang/RT.intCast:(I)I
      25: daload        
      26: dadd          
      27: dstore        4
      29: istore_3      
      30: istore_2      
      31: astore_1      
      32: goto          0
      35: goto          44
      38: pop           
      39: dload         4
      41: invokestatic  #70                 // Method 
java/lang/Double.valueOf:(D)Ljava/lang/Double;
      44: areturn       


As far as I can tell, Clojure generated a checkcast opcode that tests on 
every loop to make sure the double array is really a double array. When I 
remove that checkcast, I get a 1/3 speedup (meaning it's a 50% overhead).

Can someone help me figure out how to avoid this overhead?

Thanks.

- Leon Barrett

-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to