JIT will probably remove unnecessary checkcast instructions. What looks suspicious to me is that i and asize are converted to longs (notice i2l opcodes). I noticed earlier that loops with long counters are measurably slower for the same number of iterations (probably, HotSpot does not apply some optimizations in this case).
Leon Barrett <lbarr...@climate.com> writes: > 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. > > -- Mikhail
pgpHYSTT9m844.pgp
Description: PGP signature