Thursday, 21 August 2008

Tip: Calling C functions directly with "noalloc"

In OCaml you can call a C function by writing:

external call_1 : float -> float = "call_1"
then just using call_1. However these calls are not direct. They go via an OCaml runtime function called caml_c_call. This is a tiny bit of assembler, so the overhead isn't large, but it does use a computed jump which on many processors is quite slow.

Luckily this indirection is only needed in order to set up the garbage collector. If your C function won't perform any OCaml allocations, then you don't need this, and you can tell OCaml to jump directly to your C function like this:

external call_2 : float -> float = "call_2" "noalloc"

Let's compare the generated assembly code for the calls in both cases:


Normal "noalloc"

pushl %eax pushl %eax
movl $call_1, %eax call call_2
call caml_c_call addl $4, %esp
addl $4, %esp
...
caml_c_call:
movl (%esp), %edx
movl %edx, G(caml_last_return_address)
leal 4(%esp), %edx
movl %edx, G(caml_bottom_of_stack)
jmp *%eax


As you can see, the "noalloc" version is much shorter.

3 comments:

Hezekiah Carty said...

There is also "float" which allows calling C functions with floats completely unboxed. As I understand, though, all values involved must be floats for this to work.

A message from Xavier Leroy on the mailing list is here:

http://groups.google.com/group/fa.caml/msg/977d7ccaaf61b223?hl=en

alermo said...

Cool!

Richard, but where do you find out about this feature? The documentation, I found nothing about it.

Richard Jones said...

alermo:

"noalloc", and "float" as mentioned by Hezekiah, are not documented in the manual, but are both widely used in the stdlib and in external libraries.