Re: [MLton] cost of _export

Matthew Fluet <[email protected]> Mon, 8 Dec 2014 14:50:36 -0500
Newsgroups gmane.comp.lang.ml.mlton.devel
Message-ID <CAMrhFL75VAt=nyMAnRFEQn_3MtV7L_eTTHYuErWVDOS-fow7=g@mail.gmail.com>
On Fri, Dec 5, 2014 at 10:57 AM, Bernard Berthomieu <[email protected]> wrote:
> I'd like to use the "_export" feature of mlton ffi to call SML functions
> from C, but I'm surprised by its cost in terms of allocations.
> The following simple example illustrates this.
>
> The files x.sml and x.c are attached. I'm creating application x by:
>
>     mlton -default-ann 'allowFFI true' -export-header x.h -stop tc x.sml
>     gcc -c x.c
>     mlton -default-ann 'allowFFI true' x.sml x.o
>
>
> Then, running `x @MLton gc-summary -- 1000000` prints:
>
> done
> GC type        time ms     number          bytes          bytes/sec
> -------------    -------    -------    --------------- ---------------
> copying            146      4,348         55,184,904 377,978,794
> mark-compact          0          0                  0               -
> minor              0          0                  0 -
> total time: 3,009 ms
> total GC time: 1,382 ms (45.9%)
> max pause time: 0 ms
> total bytes allocated: 762,041,120 bytes
> max bytes live: 12,772 bytes
> max heap size: 188,416 bytes
> max stack size: 296 bytes
> num cards marked: 0
> bytes scanned: 0 bytes
> bytes hash consed: 0 bytes
>
>
> The actual application may call SML from C that many times or even more.
> Can somebody explain me the reason for the amount of bytes allocated;
> where does it come from ?

The short answer is that each call of an _export-ed SML function
results in a new ML thread being created to service the call.
However, it is possible to cache a worker thread to service the calls
of _export-ed functions, so that in the common case of no deep mutual
calls between SML and C only a single new ML thread is created.  Read
more at: https://github.com/MatthewFluet/mlton/commit/97c2bdf.  With
that patch applied, for your example application, I get:

[mtf@fenrir tmp]$ ./x @MLton gc-summary -- 1000000
done
GC type time ms number  bytes      bytes/sec
------------- ------- ------- --------------- ---------------
copying      0      0              0              -
mark-compact      0      0              0              -
minor      0      0              0              -
total time: 121 ms
total GC time: 0 ms (0.0%)
max pause time: 0 ms
total bytes allocated: 22,312 bytes
max bytes live: 0 bytes
max heap size: 122,880 bytes
max stack size: 624 bytes
num cards marked: 0
bytes scanned: 0 bytes
bytes hash consed: 0 bytes

You should be able to apply that patch to the most recent MLton
release without issues.  If you rebuild from that commit, then for
your example application, you will need to change
    let val sum = _import "C_add" private : int * int -> int;
to
    let val sum = _import "C_add" runtime private : int * int -> int;
in order to indicate that the _import-ed function is actually a
reentrant function (read more at:
https://github.com/MLton/mlton/issues/88).

------------------------------------------------------------------------------
Download BIRT iHub F-Type - The Free Enterprise-Grade BIRT Server
from Actuate! Instantly Supercharge Your Business Reports and Dashboards
with Interactivity, Sharing, Native Excel Exports, App Integration & more
Get technology previously reserved for billion-dollar corporations, FREE
http://pubads.g.doubleclick.net/gampad/clk?id=164703151&iu=/4140/ostg.clktrk