Clojure count and get functions much faster on strings than direct interop with .length and .charAt

2013-02-17 Thread Geo
I am writing an expensive algorithms in Clojure and while trying to 
optimize the code I discovered something that puzzled me. Clojure count and 
get functions are much faster on strings than direct interop with .length 
and .charAt. On my machine I get the following:

(def sss (apply str (repeat 1000 \a)))

I execute each of the following tests a few times:

(time (dotimes [_ 1000] (count sss)))
"Elapsed time: 0.56 msecs"
"Elapsed time: 0.539 msecs"
"Elapsed time: 0.551 msecs"
"Elapsed time: 0.453 msecs"
"Elapsed time: 0.612 msecs"

(time (dotimes [_ 1000] (.length sss)))
"Elapsed time: 170.819 msecs"
"Elapsed time: 114.892 msecs"
"Elapsed time: 10.111 msecs"
"Elapsed time: 32.106 msecs"
"Elapsed time: 10.803 msecs"

Even after something under the hood warms up (feel free to enlighten me :). 
.length is still significantly slower.

(time (dotimes [_ 1000] (get sss (rand-int 1000
"Elapsed time: 4.651 msecs"
"Elapsed time: 3.699 msecs"
"Elapsed time: 3.672 msecs"
"Elapsed time: 4.561 msecs"
"Elapsed time: 3.742 msecs"

(time (dotimes [_ 1000] (.charAt sss (rand-int 1000
"Elapsed time: 13.211 msecs"
"Elapsed time: 14.874 msecs"
"Elapsed time: 32.044 msecs"
"Elapsed time: 13.849 msecs"
"Elapsed time: 39.493 msecs"

.charAt is also significantly slower than get.

By replacing .length with count and .charAt with get I was able to reduce 
the running time of my algo by orders of magnitude.

These results are surprising and puzzling. You'd think direct interop with 
Java would be the faster. Can anyone venture a guess or explain what's 
going on here?

-- 
-- 
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.




Re: Clojure count and get functions much faster on strings than direct interop with .length and .charAt

2013-02-17 Thread Nicola Mometto

Try to set! *warn-on-reflection* to true and you'll find out that
there's a lot of reflection going on when using direct java interop.

Try benchmarking (.length ^String sss) and you'll see the difference

Geo writes:

> I am writing an expensive algorithms in Clojure and while trying to
> optimize the code I discovered something that puzzled me. Clojure count and
> get functions are much faster on strings than direct interop with .length
> and .charAt. On my machine I get the following:
>
> (def sss (apply str (repeat 1000 \a)))
>
> I execute each of the following tests a few times:
>
> (time (dotimes [_ 1000] (count sss)))
> "Elapsed time: 0.56 msecs"
> "Elapsed time: 0.539 msecs"
> "Elapsed time: 0.551 msecs"
> "Elapsed time: 0.453 msecs"
> "Elapsed time: 0.612 msecs"
>
> (time (dotimes [_ 1000] (.length sss)))
> "Elapsed time: 170.819 msecs"
> "Elapsed time: 114.892 msecs"
> "Elapsed time: 10.111 msecs"
> "Elapsed time: 32.106 msecs"
> "Elapsed time: 10.803 msecs"
>
> Even after something under the hood warms up (feel free to enlighten me :).
> .length is still significantly slower.
>
> (time (dotimes [_ 1000] (get sss (rand-int 1000
> "Elapsed time: 4.651 msecs"
> "Elapsed time: 3.699 msecs"
> "Elapsed time: 3.672 msecs"
> "Elapsed time: 4.561 msecs"
> "Elapsed time: 3.742 msecs"
>
> (time (dotimes [_ 1000] (.charAt sss (rand-int 1000
> "Elapsed time: 13.211 msecs"
> "Elapsed time: 14.874 msecs"
> "Elapsed time: 32.044 msecs"
> "Elapsed time: 13.849 msecs"
> "Elapsed time: 39.493 msecs"
>
> .charAt is also significantly slower than get.
>
> By replacing .length with count and .charAt with get I was able to reduce
> the running time of my algo by orders of magnitude.
>
> These results are surprising and puzzling. You'd think direct interop with
> Java would be the faster. Can anyone venture a guess or explain what's
> going on here?
>
> --

-- 
-- 
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.




Re: Clojure count and get functions much faster on strings than direct interop with .length and .charAt

2013-02-17 Thread Akhil Wali
Tried it out.

user> (time (dotimes [_ 1000] (.length ^String sss)))
"Elapsed time: 0.341035 msecs"
user> (time (dotimes [_ 1000] (.length ^String sss)))
"Elapsed time: 0.341105 msecs"
user> (time (dotimes [_ 1000] (.length ^String sss)))
"Elapsed time: 0.356121 msecs"
user> (time (dotimes [_ 1000] (.length ^String sss)))
"Elapsed time: 0.341035 msecs"



On Sun, Feb 17, 2013 at 7:51 PM, Nicola Mometto  wrote:

>
> Try to set! *warn-on-reflection* to true and you'll find out that
> there's a lot of reflection going on when using direct java interop.
>
> Try benchmarking (.length ^String sss) and you'll see the difference
>
> Geo writes:
>
> > I am writing an expensive algorithms in Clojure and while trying to
> > optimize the code I discovered something that puzzled me. Clojure count
> and
> > get functions are much faster on strings than direct interop with .length
> > and .charAt. On my machine I get the following:
> >
> > (def sss (apply str (repeat 1000 \a)))
> >
> > I execute each of the following tests a few times:
> >
> > (time (dotimes [_ 1000] (count sss)))
> > "Elapsed time: 0.56 msecs"
> > "Elapsed time: 0.539 msecs"
> > "Elapsed time: 0.551 msecs"
> > "Elapsed time: 0.453 msecs"
> > "Elapsed time: 0.612 msecs"
> >
> > (time (dotimes [_ 1000] (.length sss)))
> > "Elapsed time: 170.819 msecs"
> > "Elapsed time: 114.892 msecs"
> > "Elapsed time: 10.111 msecs"
> > "Elapsed time: 32.106 msecs"
> > "Elapsed time: 10.803 msecs"
> >
> > Even after something under the hood warms up (feel free to enlighten me
> :).
> > .length is still significantly slower.
> >
> > (time (dotimes [_ 1000] (get sss (rand-int 1000
> > "Elapsed time: 4.651 msecs"
> > "Elapsed time: 3.699 msecs"
> > "Elapsed time: 3.672 msecs"
> > "Elapsed time: 4.561 msecs"
> > "Elapsed time: 3.742 msecs"
> >
> > (time (dotimes [_ 1000] (.charAt sss (rand-int 1000
> > "Elapsed time: 13.211 msecs"
> > "Elapsed time: 14.874 msecs"
> > "Elapsed time: 32.044 msecs"
> > "Elapsed time: 13.849 msecs"
> > "Elapsed time: 39.493 msecs"
> >
> > .charAt is also significantly slower than get.
> >
> > By replacing .length with count and .charAt with get I was able to reduce
> > the running time of my algo by orders of magnitude.
> >
> > These results are surprising and puzzling. You'd think direct interop
> with
> > Java would be the faster. Can anyone venture a guess or explain what's
> > going on here?
> >
> > --
>
> --
> --
> 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.
>
>
>


-- 
Akhil Wali

# http://github.com/darth10 
# http://darth10.github.com

-- 
-- 
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.




Re: Clojure count and get functions much faster on strings than direct interop with .length and .charAt

2013-02-17 Thread Geo
Thank you!

Adding type hints solves the problem. The interop now slightly outperforms 
Clojure's get and count.

So how come Clojure's get and count don't incur the reflection penalty?

On Sunday, February 17, 2013 9:17:55 AM UTC-5, Geo wrote:
>
> I am writing an expensive algorithms in Clojure and while trying to 
> optimize the code I discovered something that puzzled me. Clojure count and 
> get functions are much faster on strings than direct interop with .length 
> and .charAt. On my machine I get the following:
>
> (def sss (apply str (repeat 1000 \a)))
>
> I execute each of the following tests a few times:
>
> (time (dotimes [_ 1000] (count sss)))
> "Elapsed time: 0.56 msecs"
> "Elapsed time: 0.539 msecs"
> "Elapsed time: 0.551 msecs"
> "Elapsed time: 0.453 msecs"
> "Elapsed time: 0.612 msecs"
>
> (time (dotimes [_ 1000] (.length sss)))
> "Elapsed time: 170.819 msecs"
> "Elapsed time: 114.892 msecs"
> "Elapsed time: 10.111 msecs"
> "Elapsed time: 32.106 msecs"
> "Elapsed time: 10.803 msecs"
>
> Even after something under the hood warms up (feel free to enlighten me 
> :). .length is still significantly slower.
>
> (time (dotimes [_ 1000] (get sss (rand-int 1000
> "Elapsed time: 4.651 msecs"
> "Elapsed time: 3.699 msecs"
> "Elapsed time: 3.672 msecs"
> "Elapsed time: 4.561 msecs"
> "Elapsed time: 3.742 msecs"
>
> (time (dotimes [_ 1000] (.charAt sss (rand-int 1000
> "Elapsed time: 13.211 msecs"
> "Elapsed time: 14.874 msecs"
> "Elapsed time: 32.044 msecs"
> "Elapsed time: 13.849 msecs"
> "Elapsed time: 39.493 msecs"
>
> .charAt is also significantly slower than get.
>
> By replacing .length with count and .charAt with get I was able to reduce 
> the running time of my algo by orders of magnitude.
>
> These results are surprising and puzzling. You'd think direct interop with 
> Java would be the faster. Can anyone venture a guess or explain what's 
> going on here?
>
>

-- 
-- 
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.




Re: Clojure count and get functions much faster on strings than direct interop with .length and .charAt

2013-02-17 Thread Herwig Hochleitner
2013/2/17 Geo 

> So how come Clojure's get and count don't incur the reflection penalty?


Clojure's collection functions do a typeof dispatch for JVM types. In a
bootstrapped clojure, that would be solved with protocols.

E.g.
https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/RT.java#L527

-- 
-- 
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.




Re: Clojure count and get functions much faster on strings than direct interop with .length and .charAt

2013-02-17 Thread AtKaaZ
and in the case of String, this happens:
https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/RT.java#L547

else if(o instanceof CharSequence)
return ((CharSequence) o).length();

=> (dorun (map println (supers (class "a string here"
java.lang.Object
java.lang.Comparable
java.io.Serializable
java.lang.*CharSequence*
nil



On Sun, Feb 17, 2013 at 6:08 PM, Herwig Hochleitner
wrote:

> 2013/2/17 Geo 
>
>> So how come Clojure's get and count don't incur the reflection penalty?
>
>
> Clojure's collection functions do a typeof dispatch for JVM types. In a
> bootstrapped clojure, that would be solved with protocols.
>
> E.g.
> https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/RT.java#L527
>
>  --
> --
> 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.
>
>
>



-- 
Please correct me if I'm wrong or incomplete,
even if you think I'll subconsciously hate it.

-- 
-- 
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.




Re: Clojure count and get functions much faster on strings than direct interop with .length and .charAt

2013-02-17 Thread Akhil Wali
What's happening is a classic example of "Functional Lisp FTW" :P


On Sun, Feb 17, 2013 at 7:47 PM, Geo  wrote:

> I am writing an expensive algorithms in Clojure and while trying to
> optimize the code I discovered something that puzzled me. Clojure count and
> get functions are much faster on strings than direct interop with .length
> and .charAt. On my machine I get the following:
>
> (def sss (apply str (repeat 1000 \a)))
>
> I execute each of the following tests a few times:
>
> (time (dotimes [_ 1000] (count sss)))
> "Elapsed time: 0.56 msecs"
> "Elapsed time: 0.539 msecs"
> "Elapsed time: 0.551 msecs"
> "Elapsed time: 0.453 msecs"
> "Elapsed time: 0.612 msecs"
>
> (time (dotimes [_ 1000] (.length sss)))
> "Elapsed time: 170.819 msecs"
> "Elapsed time: 114.892 msecs"
> "Elapsed time: 10.111 msecs"
> "Elapsed time: 32.106 msecs"
> "Elapsed time: 10.803 msecs"
>
> Even after something under the hood warms up (feel free to enlighten me
> :). .length is still significantly slower.
>
> (time (dotimes [_ 1000] (get sss (rand-int 1000
> "Elapsed time: 4.651 msecs"
> "Elapsed time: 3.699 msecs"
> "Elapsed time: 3.672 msecs"
> "Elapsed time: 4.561 msecs"
> "Elapsed time: 3.742 msecs"
>
> (time (dotimes [_ 1000] (.charAt sss (rand-int 1000
> "Elapsed time: 13.211 msecs"
> "Elapsed time: 14.874 msecs"
> "Elapsed time: 32.044 msecs"
> "Elapsed time: 13.849 msecs"
> "Elapsed time: 39.493 msecs"
>
> .charAt is also significantly slower than get.
>
> By replacing .length with count and .charAt with get I was able to reduce
> the running time of my algo by orders of magnitude.
>
> These results are surprising and puzzling. You'd think direct interop with
> Java would be the faster. Can anyone venture a guess or explain what's
> going on here?
>
>  --
> --
> 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.
>
>
>



-- 
Akhil Wali

# http://github.com/darth10 
# http://darth10.github.com

-- 
-- 
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.




Re: Clojure count and get functions much faster on strings than direct interop with .length and .charAt

2013-02-17 Thread Geo
Clojure is full of pleasant surprises :)

>
>

-- 
-- 
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.