Re: Performance of calling primitive type hinted functions passed as arguments

2013-04-25 Thread Gunnar Völkel
Some time ago I dug into primitive type hints and how the Clojure compiler 
uses them.
When the compiler finds primitive type hints on a function, say (defn f 
[^long n] ...), the generated class for that function implements a 
primitive interface, IFn$LO in this case,
and generates appropriate code in the interface's only method Object 
invokePrim(long arg0).

For a defn which is used as symbol in code the compiler detects the 
primitive interface and generates code using invokePrim if the infered type 
of the parameters matches.
Long story short, currently the compiler is not able to use primitive 
invocation for higher order functions automatically because it would need 
to generate code that checks at runtime.

You can fix this with Java interop. I implemented an `invoke-primitive` 
macro over here: https://gist.github.com/guv/5458038
It could be used like follows: 
(defn calc [^long n] ...)
(defn dosomething [f, ^long n]
  (invoke-primitive O [L] f n))

The macro expands to (.invokePrim ^IFn$LO f n) using several checks at 
compile time.


Am Mittwoch, 24. April 2013 19:15:49 UTC+2 schrieb Alice:

 So, is there a way to type hint on cb that it has a function accepting 
 a long argument? 

 On Apr 25, 12:55 am, Stuart Sierra the.stuart.sie...@gmail.com 
 wrote: 
  I'm taking a guess here: The compiler doesn't know the type signature of 
  `cb` when compiling `foo`, so it's going to use the IFn.invoke(Object) 
  signature. Clojure's type inference is only local, and it won't assume 
 that 
  a primitive-type signature is available for an arbitrary function. 
  
  So there's probably some extra typecasting going on when `fn` is 
  type-hinted to a primitive. 
  
  In general, type-hinting to primitive types doesn't do you any good in 
 the 
  presence of higher-order functions like `map`. 
  
  -S 
  
  
  
  
  
  
  
  On Wednesday, April 24, 2013 11:35:11 AM UTC-4, Alice wrote: 
  
   (defn foo [^long l cb] (cb l)) 
  
   (time 
 (dotimes [n 100] 
   (foo n (fn [l] nil 
  
   (time 
 (dotimes [n 100] 
   (foo n (fn [^long l] nil 
  
   Elapsed time: 7.861 msecs 
   Elapsed time: 11.770973 msecs 
  
   Why is the latter slower? 


-- 
-- 
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: Performance of calling primitive type hinted functions passed as arguments

2013-04-25 Thread Alice
Wow! That's awesome. It's even faster! Thanks.

(defn foo1 [^long l cb] (cb l))
(defn foo2 [^long l cb] (invoke-primitive O [L] cb l))

(time
  (dotimes [n 100]
(foo1 n (fn [l] nil

(time
  (dotimes [n 100]
(foo2 n (fn [^long l] nil

Elapsed time: 7.622627 msecs
Elapsed time: 5.341534 msecs

On Apr 25, 4:17 pm, Gunnar Völkel gunnar.voel...@googlemail.com
wrote:
 Some time ago I dug into primitive type hints and how the Clojure compiler
 uses them.
 When the compiler finds primitive type hints on a function, say (defn f
 [^long n] ...), the generated class for that function implements a
 primitive interface, IFn$LO in this case,
 and generates appropriate code in the interface's only method Object
 invokePrim(long arg0).

 For a defn which is used as symbol in code the compiler detects the
 primitive interface and generates code using invokePrim if the infered type
 of the parameters matches.
 Long story short, currently the compiler is not able to use primitive
 invocation for higher order functions automatically because it would need
 to generate code that checks at runtime.

 You can fix this with Java interop. I implemented an `invoke-primitive`
 macro over here:https://gist.github.com/guv/5458038
 It could be used like follows:
 (defn calc [^long n] ...)
 (defn dosomething [f, ^long n]
   (invoke-primitive O [L] f n))

 The macro expands to (.invokePrim ^IFn$LO f n) using several checks at
 compile time.

 Am Mittwoch, 24. April 2013 19:15:49 UTC+2 schrieb Alice:









  So, is there a way to type hint on cb that it has a function accepting
  a long argument?

  On Apr 25, 12:55 am, Stuart Sierra the.stuart.sie...@gmail.com
  wrote:
   I'm taking a guess here: The compiler doesn't know the type signature of
   `cb` when compiling `foo`, so it's going to use the IFn.invoke(Object)
   signature. Clojure's type inference is only local, and it won't assume
  that
   a primitive-type signature is available for an arbitrary function.

   So there's probably some extra typecasting going on when `fn` is
   type-hinted to a primitive.

   In general, type-hinting to primitive types doesn't do you any good in
  the
   presence of higher-order functions like `map`.

   -S

   On Wednesday, April 24, 2013 11:35:11 AM UTC-4, Alice wrote:

(defn foo [^long l cb] (cb l))

(time
  (dotimes [n 100]
    (foo n (fn [l] nil

(time
  (dotimes [n 100]
    (foo n (fn [^long l] nil

Elapsed time: 7.861 msecs
Elapsed time: 11.770973 msecs

Why is the latter slower?

-- 
-- 
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: Performance of calling primitive type hinted functions passed as arguments

2013-04-25 Thread Alice
The reason foo2 is faster is that foo1 is passing a primitive long
value to cb, which caused boxing. Without that, the performance seems
to be exactly the same, which it should be!

On Apr 25, 6:50 pm, Alice dofflt...@gmail.com wrote:
 Wow! That's awesome. It's even faster! Thanks.

 (defn foo1 [^long l cb] (cb l))
 (defn foo2 [^long l cb] (invoke-primitive O [L] cb l))

 (time
   (dotimes [n 100]
     (foo1 n (fn [l] nil

 (time
   (dotimes [n 100]
     (foo2 n (fn [^long l] nil

 Elapsed time: 7.622627 msecs
 Elapsed time: 5.341534 msecs

 On Apr 25, 4:17 pm, Gunnar Völkel gunnar.voel...@googlemail.com
 wrote:







  Some time ago I dug into primitive type hints and how the Clojure compiler
  uses them.
  When the compiler finds primitive type hints on a function, say (defn f
  [^long n] ...), the generated class for that function implements a
  primitive interface, IFn$LO in this case,
  and generates appropriate code in the interface's only method Object
  invokePrim(long arg0).

  For a defn which is used as symbol in code the compiler detects the
  primitive interface and generates code using invokePrim if the infered type
  of the parameters matches.
  Long story short, currently the compiler is not able to use primitive
  invocation for higher order functions automatically because it would need
  to generate code that checks at runtime.

  You can fix this with Java interop. I implemented an `invoke-primitive`
  macro over here:https://gist.github.com/guv/5458038
  It could be used like follows:
  (defn calc [^long n] ...)
  (defn dosomething [f, ^long n]
    (invoke-primitive O [L] f n))

  The macro expands to (.invokePrim ^IFn$LO f n) using several checks at
  compile time.

  Am Mittwoch, 24. April 2013 19:15:49 UTC+2 schrieb Alice:

   So, is there a way to type hint on cb that it has a function accepting
   a long argument?

   On Apr 25, 12:55 am, Stuart Sierra the.stuart.sie...@gmail.com
   wrote:
I'm taking a guess here: The compiler doesn't know the type signature of
`cb` when compiling `foo`, so it's going to use the IFn.invoke(Object)
signature. Clojure's type inference is only local, and it won't assume
   that
a primitive-type signature is available for an arbitrary function.

So there's probably some extra typecasting going on when `fn` is
type-hinted to a primitive.

In general, type-hinting to primitive types doesn't do you any good in
   the
presence of higher-order functions like `map`.

-S

On Wednesday, April 24, 2013 11:35:11 AM UTC-4, Alice wrote:

 (defn foo [^long l cb] (cb l))

 (time
   (dotimes [n 100]
     (foo n (fn [l] nil

 (time
   (dotimes [n 100]
     (foo n (fn [^long l] nil

 Elapsed time: 7.861 msecs
 Elapsed time: 11.770973 msecs

 Why is the latter slower?

-- 
-- 
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: Performance of calling primitive type hinted functions passed as arguments

2013-04-24 Thread Jim

On 24/04/13 16:35, Alice wrote:

(defn foo [^long l cb] (cb l))

(time
   (dotimes [n 100]
 (foo n (fn [l] nil

(time
   (dotimes [n 100]
 (foo n (fn [^long l] nil

Elapsed time: 7.861 msecs
Elapsed time: 11.770973 msecs


Why is the latter slower?

You should be getting very similar timings from these 2 versions as the 
type-hinted arg 'l' is never used anywhere - you're just returning nil...


Jim

--
--
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: Performance of calling primitive type hinted functions passed as arguments

2013-04-24 Thread Alice
I tested several times, but the latter is always slower.

On Apr 25, 12:38 am, Jim jimpil1...@gmail.com wrote:
 On 24/04/13 16:35, Alice wrote:







  (defn foo [^long l cb] (cb l))

  (time
     (dotimes [n 100]
       (foo n (fn [l] nil

  (time
     (dotimes [n 100]
       (foo n (fn [^long l] nil

  Elapsed time: 7.861 msecs
  Elapsed time: 11.770973 msecs

  Why is the latter slower?

 You should be getting very similar timings from these 2 versions as the
 type-hinted arg 'l' is never used anywhere - you're just returning nil...

 Jim

-- 
-- 
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: Performance of calling primitive type hinted functions passed as arguments

2013-04-24 Thread Stuart Sierra
I'm taking a guess here: The compiler doesn't know the type signature of 
`cb` when compiling `foo`, so it's going to use the IFn.invoke(Object) 
signature. Clojure's type inference is only local, and it won't assume that 
a primitive-type signature is available for an arbitrary function.

So there's probably some extra typecasting going on when `fn` is 
type-hinted to a primitive.

In general, type-hinting to primitive types doesn't do you any good in the 
presence of higher-order functions like `map`.

-S


On Wednesday, April 24, 2013 11:35:11 AM UTC-4, Alice wrote:

 (defn foo [^long l cb] (cb l)) 

 (time 
   (dotimes [n 100] 
 (foo n (fn [l] nil 

 (time 
   (dotimes [n 100] 
 (foo n (fn [^long l] nil 

 Elapsed time: 7.861 msecs 
 Elapsed time: 11.770973 msecs 


 Why is the latter slower? 


-- 
-- 
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: Performance of calling primitive type hinted functions passed as arguments

2013-04-24 Thread Softaddicts
I am not convinced that this test is representative.
If you are not using l but still hinting it's type, you may have extra
code generated in the function body to handle the type hint.

4 milliseconds divided by a million is a very low overhead IMHO.
I would hardly qualify this as being inefficient.

I would expect to see a gain if you had some calls done on the argument to 
qualify how much you save by avoiding reflection.

I did not open the cover of the byte code generated by the compiler however.
It could be an edge case not optimized yet. On the other hand if the argument 
is not
used at all, why bother with such an edge case ?

Luc P.

 On 24/04/13 16:35, Alice wrote:
  (defn foo [^long l cb] (cb l))
 
  (time
 (dotimes [n 100]
   (foo n (fn [l] nil
 
  (time
 (dotimes [n 100]
   (foo n (fn [^long l] nil
 
  Elapsed time: 7.861 msecs
  Elapsed time: 11.770973 msecs
 
 
  Why is the latter slower?
 
 You should be getting very similar timings from these 2 versions as the 
 type-hinted arg 'l' is never used anywhere - you're just returning nil...
 
 Jim
 
 -- 
 -- 
 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.
 
 
 
--
Softaddictslprefonta...@softaddicts.ca sent by ibisMail from my ipad!

-- 
-- 
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: Performance of calling primitive type hinted functions passed as arguments

2013-04-24 Thread Alice
I'm writing some low-level byte manipulation library and want it to be
as efficient as possible, so I just want to know the cost of trivial
things like this before designing the API. It can be negligible as you
said, but I wanted to know why it is slow and what's happening under
the hood anyway.

On Apr 25, 12:55 am, Softaddicts lprefonta...@softaddicts.ca wrote:
 I am not convinced that this test is representative.
 If you are not using l but still hinting it's type, you may have extra
 code generated in the function body to handle the type hint.

 4 milliseconds divided by a million is a very low overhead IMHO.
 I would hardly qualify this as being inefficient.

 I would expect to see a gain if you had some calls done on the argument to
 qualify how much you save by avoiding reflection.

 I did not open the cover of the byte code generated by the compiler however.
 It could be an edge case not optimized yet. On the other hand if the argument 
 is not
 used at all, why bother with such an edge case ?

 Luc P.









  On 24/04/13 16:35, Alice wrote:
   (defn foo [^long l cb] (cb l))

   (time
      (dotimes [n 100]
        (foo n (fn [l] nil

   (time
      (dotimes [n 100]
        (foo n (fn [^long l] nil

   Elapsed time: 7.861 msecs
   Elapsed time: 11.770973 msecs

   Why is the latter slower?

  You should be getting very similar timings from these 2 versions as the
  type-hinted arg 'l' is never used anywhere - you're just returning nil...

  Jim

  --
  --
  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, visithttps://groups.google.com/groups/opt_out.

 --
 Softaddictslprefonta...@softaddicts.ca sent by ibisMail from my ipad!

-- 
-- 
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: Performance of calling primitive type hinted functions passed as arguments

2013-04-24 Thread Alice
So, is there a way to type hint on cb that it has a function accepting
a long argument?

On Apr 25, 12:55 am, Stuart Sierra the.stuart.sie...@gmail.com
wrote:
 I'm taking a guess here: The compiler doesn't know the type signature of
 `cb` when compiling `foo`, so it's going to use the IFn.invoke(Object)
 signature. Clojure's type inference is only local, and it won't assume that
 a primitive-type signature is available for an arbitrary function.

 So there's probably some extra typecasting going on when `fn` is
 type-hinted to a primitive.

 In general, type-hinting to primitive types doesn't do you any good in the
 presence of higher-order functions like `map`.

 -S







 On Wednesday, April 24, 2013 11:35:11 AM UTC-4, Alice wrote:

  (defn foo [^long l cb] (cb l))

  (time
    (dotimes [n 100]
      (foo n (fn [l] nil

  (time
    (dotimes [n 100]
      (foo n (fn [^long l] nil

  Elapsed time: 7.861 msecs
  Elapsed time: 11.770973 msecs

  Why is the latter slower?

-- 
-- 
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: Performance of calling primitive type hinted functions passed as arguments

2013-04-24 Thread Jason Wolfe
^clojure.lang.IFn$LO should work, although my guess is that this is 
considered an implementation detail and subject to change with new versions 
of Clojure.

On Wednesday, April 24, 2013 10:15:49 AM UTC-7, Alice wrote:

 So, is there a way to type hint on cb that it has a function accepting 
 a long argument? 

 On Apr 25, 12:55 am, Stuart Sierra the.stuart.sie...@gmail.com 
 wrote: 
  I'm taking a guess here: The compiler doesn't know the type signature of 
  `cb` when compiling `foo`, so it's going to use the IFn.invoke(Object) 
  signature. Clojure's type inference is only local, and it won't assume 
 that 
  a primitive-type signature is available for an arbitrary function. 
  
  So there's probably some extra typecasting going on when `fn` is 
  type-hinted to a primitive. 
  
  In general, type-hinting to primitive types doesn't do you any good in 
 the 
  presence of higher-order functions like `map`. 
  
  -S 
  
  
  
  
  
  
  
  On Wednesday, April 24, 2013 11:35:11 AM UTC-4, Alice wrote: 
  
   (defn foo [^long l cb] (cb l)) 
  
   (time 
 (dotimes [n 100] 
   (foo n (fn [l] nil 
  
   (time 
 (dotimes [n 100] 
   (foo n (fn [^long l] nil 
  
   Elapsed time: 7.861 msecs 
   Elapsed time: 11.770973 msecs 
  
   Why is the latter slower? 


-- 
-- 
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: Performance of calling primitive type hinted functions passed as arguments

2013-04-24 Thread Mikera
The second one is slower because the (cb l) call is going via (fn [Object]) 
which then delegates to (fn [long]) rather than using (fn [Object]) 
directly. I believe it may be doing an extra cast as well, which would 
explain the extra 3ns of overhead.

In general, I've found primitive functions are very tricky to get working 
at maximum performance within higher order functions: they are mostly 
useful for direct calls with known arguments. 

If you really care about performance then you might find that using Java 
interfaces or abstract base classes works better: there are easier to type 
hint, it can give you a bit more control and doesn't have as many 
restrictions / strange edge cases. Also they work nicely for protocol 
dispatch. I use this technique quite a lot within vectorz-clj to squeeze 
the maximum performance out or low-level vector/matrix operations. Downside 
it that it isn't idiomatic Clojure. but currently you have to live with 
that if you want maximum performance.

On Wednesday, 24 April 2013 23:35:11 UTC+8, Alice wrote:

 (defn foo [^long l cb] (cb l)) 

 (time 
   (dotimes [n 100] 
 (foo n (fn [l] nil 

 (time 
   (dotimes [n 100] 
 (foo n (fn [^long l] nil 

 Elapsed time: 7.861 msecs 
 Elapsed time: 11.770973 msecs 


 Why is the latter slower? 


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