caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* announce: callbacks-0.1
@ 2005-09-08 16:31 Christophe Raffalli
       [not found] ` <4320A68E.1060608@xs4all.nl>
  0 siblings, 1 reply; 8+ messages in thread
From: Christophe Raffalli @ 2005-09-08 16:31 UTC (permalink / raw)
  To: caml-list

link: third item of:

http://www.lama.univ-savoie.fr/~raffalli/?page=soft&lang=en

comment and idea are welcome !

-----------
MOTIVATION
-----------

callbacks are problematic when writting OCaml bindings for C
library. Indeed, a C function waits for a function respecting C
calling conventions as argument, and OCaml functions do not respect the
C conventions.

Then in a library you only have a limited number of the C functions and
in fact ideally, it is the user of the library that should often write 
the C function that needs to be passed in arguments to other C functions.

This is too hard for the average user ... this is why I wrote this package


Here is an example on how to use it (see the README file for a more 
detailled doc)

--------------
in glut.mli:
--------------

open Direct_callback
...
val reshapeFunc: cb:(w:int->h:int->unit) callback->unit
...

-------------
in a programm using lablGlut
-------------

let doReshape ~w ~h =
   ...

c_wrapper doReshape_cb for  doReshape : w:int->h:int->unit
...

ReshapeFunc doReshape_cb
...


-------------
in glut.ml
-------------

open Direct_callback
...
external reshapeFunc : cb:(w:int->h:int->unit) callback->unit = 
"ml_glutReshapeFunc"
...

-------------
in wrapglut.c
-------------

...
ML_1(glutReshapeFunc,Callback2)
...

which expends to

...
CAMLprim value ml_glutReshapeFunc (value arg1) \
{ glutReshapeFunc ((void (*)(int,int))(arg1)); return Val_unit; }
...



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Caml-list] announce: callbacks-0.1
       [not found] ` <4320A68E.1060608@xs4all.nl>
@ 2005-09-08 21:24   ` Christophe Raffalli
  2005-09-08 23:31     ` Bardur Arantsson
  0 siblings, 1 reply; 8+ messages in thread
From: Christophe Raffalli @ 2005-09-08 21:24 UTC (permalink / raw)
  To: Maas-Maarten Zeeman, caml-list

Maas-Maarten Zeeman a écrit :
> 
> Hello,
> 
>> link: third item of:
>>
>> http://www.lama.univ-savoie.fr/~raffalli/?page=soft&lang=en
>>
>> comment and idea are welcome !
>>
> 
> Sounds like a nice idea. As the author of ocaml-expat a binding I've 
> also worked with c -> ocaml callbacks.
> 
> It is not really clear to me what problem you are trying to solve. It is 
> not very difficult for somebody writing a Ocaml binding to come up with 
> a solution which is easy to call an ocaml function value from c.
> 
> What I did was create one fixed c-callback functions which:
> 
> receive c-parameters
> transform them to ocaml-values
> lookup the ocaml callback "cb" in a tuple (set earlier from ocaml),

This is that step I want to avoid ... not mainly for performance, but 
because there are some cases where you do not know which callback you 
should call (this was the case for one of the glut callback, I don't 
recall which one, and it was a bit tricky for glutTimer). It happens 
that in glut, the current window or current menu is properly set before 
calling the callback ... but there may be other library, more purely 
functional, with no concept of "current window" ...

The other reason, is that it makes it easier to writte the bindings for 
the library (no thinking required and therefore less bug) ! and does not 
make it that much complex for the user.

If you really need "dynamic" callback with arbitrary closure, then you 
can implement your trick above mine in OCaml.

By expending my work, we could write and use bindings for a C library 
like glut without writing a line of C, except to convert data structure 
from C to OCaml if you really need that.

This could divide the size of the glut binding by a factor 2 or 3 ...
which is important !

> apply cb to the ocaml-values,
> etc, etc
> 
> The ocaml programmer just has to deal with normal ocaml callback 
> function values (which can be partially applied, unnamed, etc). These 
> will be stored via c in a tuple. The value pointing to this tuple is 
> registered as 1 global root. If you have large amounts of callbacks it 
> would probably work with a simple hash table too. Then you only have to 
> write/generate 1 c-callback function (per c-signature) which takes care 
> of calling an unlimited amount of caml callbacks.
> 
> Its interesting to have the c-wrapper function generated as it would 
> prevent hard to debug gc problems.
> 
> Regards,
> 
> Maas


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: announce: callbacks-0.1
  2005-09-08 21:24   ` [Caml-list] " Christophe Raffalli
@ 2005-09-08 23:31     ` Bardur Arantsson
  2005-09-09  6:30       ` Bardur Arantsson
  0 siblings, 1 reply; 8+ messages in thread
From: Bardur Arantsson @ 2005-09-08 23:31 UTC (permalink / raw)
  To: caml-list

Christophe Raffalli wrote:
> Maas-Maarten Zeeman a écrit :
> 
>>
>> Hello,
>>
>>> link: third item of:
>>>
>>> http://www.lama.univ-savoie.fr/~raffalli/?page=soft&lang=en
>>>
>>> comment and idea are welcome !
>>>
>>
>> Sounds like a nice idea. As the author of ocaml-expat a binding I've 
>> also worked with c -> ocaml callbacks.
>>
>> It is not really clear to me what problem you are trying to solve. It 
>> is not very difficult for somebody writing a Ocaml binding to come up 
>> with a solution which is easy to call an ocaml function value from c.
>>
>> What I did was create one fixed c-callback functions which:
>>
>> receive c-parameters
>> transform them to ocaml-values
>> lookup the ocaml callback "cb" in a tuple (set earlier from ocaml),
> 
> 
> This is that step I want to avoid ... not mainly for performance, 

Now, I'll freely admit that I haven't tested it specifically, but I 
suspect performance will be worse when using register_global_root () to 
register callback closures instead of just using a mapping from "int" 
(or whatever type your callback identifier would be on the C side) to 
closures "stored" on the OCaml side. There was a post on this list not 
too long ago which exposed efficiency issues with register_global_root 
when registering lots and lots of roots.

 >but
> because there are some cases where you do not know which callback you 
> should call (this was the case for one of the glut callback, I don't 
> recall which one, and it was a bit tricky for glutTimer). It happens 
> that in glut, the current window or current menu is properly set before 
> calling the callback ... but there may be other library, more purely 
> functional, with no concept of "current window" ...
> 

For any C library using callbacks there will *always* be *some* way to 
distinguish which event/object caused the callback. The reason is 
simple: Creating callback functions/closures on the fly is impossible(*) 
in C, or, in other words the callback function itself can't possibly 
carry enough information to distinguish callbacks from different 
events/objects. If there isn't enough information to distinguish what 
caused the callback, the callback would be pointless.

(*) Well, you can generate machine code on the fly, but no sane library 
will force you to do this.

-- 
Bardur Arantsson
<bardur@imada.sdu.dk>
<bardur@scientician.net>

- In my weaker moments I almost pity them, but then I remind
myself: They want to teach.
                                      Bart Simpson, 'The Simpsons'


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: announce: callbacks-0.1
  2005-09-08 23:31     ` Bardur Arantsson
@ 2005-09-09  6:30       ` Bardur Arantsson
  2005-09-10  7:04         ` [Caml-list] " Xavier Leroy
  0 siblings, 1 reply; 8+ messages in thread
From: Bardur Arantsson @ 2005-09-09  6:30 UTC (permalink / raw)
  To: caml-list

On Fri, Sep 09, 2005 at 07:53:17AM +0200, Christophe Raffalli wrote:

>> Now, I'll freely admit that I haven't tested it specifically, but I
>>  suspect performance will be worse when using register_global_root
>>  to register callback closures instead of just using a mapping from
>>  "int" (or whatever type your callback identifier would be on the C
>>  side) to closures "stored" on the OCaml side. There was a post on
>>  this list not too long ago which exposed efficiency issues with 
>> register_global_root when registering lots and lots of roots.

> anyway, there should not be that many callbacks ?

That depends hugely on what kind of library you're wrapping. I did a
wrapper for libevent (events on file descriptors and other similar stuff
like alarms, etc.) and what ended up happening was that a 1) lot of the
time a relatively large amount of callbacks were registered, orm 2)
callbacks would be registered/unregistered a lot. I did try using
*_global_roots in my libevent wrapper, but the performance was awful
until I changed it to use an (fd->callback) hashtable on the OCaml side.

(In the case of file descriptors or similar objects you can try to be
more clever and just use an array of callbacks and use the file
descriptor as the index; I didn't bother with this in my wrapper library
since the performance was OK as it was).

> Moreover, I suspect (but may be wrong) that register_global_root () 
> is or could be optimized for closure on closed functions, and this 
> will be the case of most closure with my approach.

 From the implementation in globroots.c it would seem that
register_global_root is at least O(n) in the number of roots, and that
it has a large constant overhead compared to e.g. adding something to a
hashtable. So it may not be the fact that a closure may keep things
alive that's slowing it down, but rather just a slow implementation of 
register_global_root itself.

[--snip--]

-- 
Bardur Arantsson
<bardur@imada.sdu.dk>
<bardur@scientician.net>

- There are a thousand forms of subversion, all of them
interesting. But few, in my opinion, can equal the convenience
and immediacy of the cream pie.
                                                        Noël Godin


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Caml-list] Re: announce: callbacks-0.1
  2005-09-09  6:30       ` Bardur Arantsson
@ 2005-09-10  7:04         ` Xavier Leroy
  2005-09-10  7:31           ` Bardur Arantsson
                             ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Xavier Leroy @ 2005-09-10  7:04 UTC (permalink / raw)
  To: Bardur Arantsson; +Cc: caml-list

> From the implementation in globroots.c it would seem that
> register_global_root is at least O(n) in the number of roots, and that
> it has a large constant overhead compared to e.g. adding something to a
> hashtable.

You should look harder.  register_global_root is insertion in a skip
list, which is probabilistic O(log n) with a low constant.  I don't
think a hash table would perform significantly better for the mix of
operations we need to do on the set of global roots (insertion,
deletion, and enumeration for the GC).

> That depends hugely on what kind of library you're wrapping. I did a
> wrapper for libevent (events on file descriptors and other similar stuff
> like alarms, etc.) and what ended up happening was that a 1) lot of the
> time a relatively large amount of callbacks were registered, orm 2)
> callbacks would be registered/unregistered a lot. I did try using
> *_global_roots in my libevent wrapper, but the performance was awful
> until I changed it to use an (fd->callback) hashtable on the OCaml side.

I would have been very interested in a profiling of your initial
implementation.  The only reason why the Caml hashtable can beat the
global roots is that the latter are not generational: since the
contents of registered global roots can change at any time without
notifying the GC, all global roots must be scanned at every minor
collection.

- Xavier Leroy


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: announce: callbacks-0.1
  2005-09-10  7:04         ` [Caml-list] " Xavier Leroy
@ 2005-09-10  7:31           ` Bardur Arantsson
  2005-09-10 13:04           ` [Caml-list] " Yaron Minsky
  2005-09-10 21:02           ` caml_register_unmutable_global_root Christophe Raffalli
  2 siblings, 0 replies; 8+ messages in thread
From: Bardur Arantsson @ 2005-09-10  7:31 UTC (permalink / raw)
  To: caml-list

Xavier Leroy wrote:
>>From the implementation in globroots.c it would seem that
>>register_global_root is at least O(n) in the number of roots, and that
>>it has a large constant overhead compared to e.g. adding something to a
>>hashtable.
> 
> 
> You should look harder.  register_global_root is insertion in a skip
> list, which is probabilistic O(log n) with a low constant.  I don't
> think a hash table would perform significantly better for the mix of
> operations we need to do on the set of global roots (insertion,
> deletion, and enumeration for the GC).
>

D'oh, don't know how I could have missed that... Sorry for the 
misinformation.

> 
>>That depends hugely on what kind of library you're wrapping. I did a
>>wrapper for libevent (events on file descriptors and other similar stuff
>>like alarms, etc.) and what ended up happening was that a 1) lot of the
>>time a relatively large amount of callbacks were registered, orm 2)
>>callbacks would be registered/unregistered a lot. I did try using
>>*_global_roots in my libevent wrapper, but the performance was awful
>>until I changed it to use an (fd->callback) hashtable on the OCaml side.
> 
> 
> I would have been very interested in a profiling of your initial
> implementation.  The only reason why the Caml hashtable can beat the
> global roots is that the latter are not generational: since the
> contents of registered global roots can change at any time without
> notifying the GC, all global roots must be scanned at every minor
> collection.
> 

Unfortunately I haven't kept any of the benchmark results. Of course I 
don't have old source to compile from either since this was before I put 
it into version control :(. I supposed there's a lesson in there somewhere.

I'm not really motivated to attempt to reconstruct a benchmark for this 
as 1) I've since moved to an event library which only uses short-lived 
callbacks at the C/OCaml interface. 2) I just don't have the time.

Cheers,

-- 
Bardur Arantsson
<bardur@imada.sdu.dk>
<bardur@scientician.net>

- I'm a well-wisher... in that I don't wish you any *specific*
harm.
                                               Moe, 'The Simpsons'


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Caml-list] Re: announce: callbacks-0.1
  2005-09-10  7:04         ` [Caml-list] " Xavier Leroy
  2005-09-10  7:31           ` Bardur Arantsson
@ 2005-09-10 13:04           ` Yaron Minsky
  2005-09-10 21:02           ` caml_register_unmutable_global_root Christophe Raffalli
  2 siblings, 0 replies; 8+ messages in thread
From: Yaron Minsky @ 2005-09-10 13:04 UTC (permalink / raw)
  To: Xavier Leroy; +Cc: Bardur Arantsson, caml-list

On 9/10/05, Xavier Leroy <Xavier.Leroy@inria.fr> wrote:

> I would have been very interested in a profiling of your initial
> implementation.  The only reason why the Caml hashtable can beat the
> global roots is that the latter are not generational: since the
> contents of registered global roots can change at any time without
> notifying the GC, all global roots must be scanned at every minor
> collection.

Yeah, we ran into this problem.  We had an application where we ended
up registering about 200,000 global roots (most of which were
callbacks.)  The application spent around 15% of the CPU all the time
just scanning global roots as part of minor collections.  The
callbacks were moved into a hashtbl,and these problems went away
completely.

Yaron


^ permalink raw reply	[flat|nested] 8+ messages in thread

* caml_register_unmutable_global_root
  2005-09-10  7:04         ` [Caml-list] " Xavier Leroy
  2005-09-10  7:31           ` Bardur Arantsson
  2005-09-10 13:04           ` [Caml-list] " Yaron Minsky
@ 2005-09-10 21:02           ` Christophe Raffalli
  2 siblings, 0 replies; 8+ messages in thread
From: Christophe Raffalli @ 2005-09-10 21:02 UTC (permalink / raw)
  To: Xavier Leroy; +Cc: Bardur Arantsson, caml-list


> 
> I would have been very interested in a profiling of your initial
> implementation.  The only reason why the Caml hashtable can beat the
> global roots is that the latter are not generational: since the
> contents of registered global roots can change at any time without
> notifying the GC, all global roots must be scanned at every minor
> collection.
> 

why not add a caml_register_unmutable_global_root() ?

For callback this should be ok in most cases ...

> - Xavier Leroy
> 
> _______________________________________________
> Caml-list mailing list. Subscription management:
> http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list
> Archives: http://caml.inria.fr
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2005-09-10 21:02 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-09-08 16:31 announce: callbacks-0.1 Christophe Raffalli
     [not found] ` <4320A68E.1060608@xs4all.nl>
2005-09-08 21:24   ` [Caml-list] " Christophe Raffalli
2005-09-08 23:31     ` Bardur Arantsson
2005-09-09  6:30       ` Bardur Arantsson
2005-09-10  7:04         ` [Caml-list] " Xavier Leroy
2005-09-10  7:31           ` Bardur Arantsson
2005-09-10 13:04           ` [Caml-list] " Yaron Minsky
2005-09-10 21:02           ` caml_register_unmutable_global_root Christophe Raffalli

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).