Thinking about it, this actually happens because of boxing and the
relation between macros and functions.

If you look at the 1-d case in the original code, it is inlined.
In the 2-d case in the original code, it is not inlined.

This means that when you coerce the indexs to int in the 2-d code, it
goes through a function call, meaning it gets boxed and would have to
be re-coerced to an int.

In the 1-d code, it is a macroexpansion, meaning that the coerced int
gets passed directly to the clojure.lang.RT aget primitive.

In the version I gave you, I added the coercion into the macro
version, because it seemed like a fairly reasonable thing to do,
however, I am no longer sure it is (it is really only required for the
function invocation, as coercing to int when the code has been inlined
actually works, and you can therefore avoid coercing twice).

I'm not sure, it is a very tricky subject, and probably not worth
worrying about for the minimal speed difference that it makes.

Interesting though,

-Jon.


On Sep 28, 2:45 am, Jonathan Smith <[email protected]> wrote:
> On Sep 27, 9:17 am, Timothy Pratley <[email protected]> wrote:
>
>
>
> > As far as I can tell there is currently no way to hint 2d array access
> > fast
> > (def a (make-array Double/TYPE 100 100))
> > (time (doseq [i (range 100), j (range 100)] (aget a (int i) (int j))))
> > "Elapsed time: 836.800335 msecs"
> > I can't find any combination of type hinting to speed it up.
>
> > However with a trivial change to core.clj [just added (int idx) in the
> > multi-arg case]:>   (apply aget (aget array (int idx)) idxs)))
>
> > (time (doseq [i (range 100), j (range 100)] (aget a i j)))
> > "Elapsed time: 40.162875 msecs"
> > It is fast! Yay!
>
> > That's great, almost as fast as a 1d array:
> > (def b (make-array Double/TYPE 10000))
> > (time (doseq [i (range 100), j (range 100)] (aget b (int (+ i (* j
> > 100))))))
> > "Elapsed time: 27.701047 msecs"
> > But still it seems for maximum speed you would go with a 1d array.
>
> > Now for 1d arrays, the index also cannot be anything other than an
> > integer, so we could do the same thing [just added (int ~i)]:
> >   {:inline (fn [a i] `(. clojure.lang.RT (aget ~a (int ~i))))
>
> > (time (doseq [i (range 100), j (range 100)] (aget b (+ i (* j 100)))))
> > "Elapsed time: 27.701047 msecs"
> > Great, it is just as fast as when we had to coerce to int.
>
> > But the coercion comes at a small cost when we don't need it:
> > (time (amap b idx ret (aset ret idx (inc (aget b idx)))))
> > original:  "Elapsed time: 23.06673 msecs"
> > modified: "Elapsed time: 27.457263 msecs"  <-- slower :( :( :(
>
> > So for the 1d case for maximum speed it appears better to leave it to
> > the user to coerce when necessary. The index must be an integer - is
> > there any way to have this fast in both cases? If not another
> > alternative would be to have an aget* and aget be a macro that
> > coerces, to allow both forms.
>
> Hello friend,
>
> The time difference you are seeing between the 2-d version and the 1-d
> version is actually due to in-lining...
> If you try, for example:
>
> (defn aget
>        "Returns the value at the index/indices. Works on Java arrays
> of all
>   types."
>        {:inline (fn ([a i] `(. clojure.lang.RT (aget ~a ~i)))
>                   ([a i & idxs]
>                      (reduce (fn [inner idx] `(aget ~inner (int ~idx)))
>                              `(aget ~a (int ~i)) idxs)))
>         :inline-arities #{2 3 4 5 6 7} ;; actually i used a special 'all-
> arities' set here
>        ([array idx]
>           (clojure.lang.Reflector/prepRet (. Array (get array (int idx)))))
>        ([array idx & idxs]
>           (apply aget (aget array (int idx)) idxs)))
> and rebuild core...
>
> I got results like so:
>
> (time (doseq [i (range 100), j (range 100)] (aget a i j)))
> "Elapsed time: 27.410739 msecs"
>
> (time (doseq [i (range 100), j (range 100)] (aget b (int (+ i (* j
> 100))))))
> "Elapsed time: 28.009345 msecs"
>
> I don't really have any idea about the other stuff.
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to