[MLton-user] Questions on MLton

Stephen Weeks sweeks@sweeks.com
Fri, 3 Oct 2003 22:46:31 -0700


Hi Olin.  Thanks for the questions.

> 1. I see there are ways to do unsafe vector accesses.
>    Is there a way to do unsafe list processing.

No.

> 2. Is there a way to control the choice of GC? I am timing some
>    ML code, and it does a *lot* of side effects to refs, and I'd
>    like to run without a write barrier -- i.e., simple stop&copy,
>    with no generational gc.

There are a couple of (undocumented) ways to do this.  FYI, you can
see the undocumented "expert" options with "mlton -expert true -z"
(-expert is purposely undocumented as well).

Anyways, if you compile with -mark-cards false, the code generator
won't insert the write barrier stuff, and the runtime will know not to
allocate the card map and will not use generational GC.

In case you didn't know, MLton automatically switches between using
copying, mark-compact, and generational GC.  If it is able to obtain a
large enough live ratio, then it will use copying only.  This is the
usual scenario.  Only if the live ratio drops below a certain point
will MLton resort to generational or mark-compact.  If you already
have an executable compiled with -mark-cards true, you can prevent the
runtime from using generational GC by setting this ratio using @MLton
copy-generational-ratio 1.0 --.  This ratio, with default value 4.0,
controls what the liveness ratio has to drop below before MLton
resorts to generational gc.

Also, the write barrier in MLton is very cheap.  First off, we use
card marking, which is only a few instructions.  Second, because MLton
has the whole program and knows the types of everything, it doesn't
have to insert card marks at every ref update, only at pointer
updates.  That cuts it down on the number of writes.

I did some experiments in August 2002 when I put in the generational
GC that showed that both the code size impact and the time impact of
card marking were negligible.

Unless your application is tight for memory, I'd be surprised if you
see a significant difference in code size or run time among

1. the original application
2. the application compiled -mark-cards true, but run with
   copy-generational-ratio 1.0.
3. the application compiled -mark-cards false.

I would expect (1) and (2) to be similar because the runtime will
always decide to use copying.  I would expect (2) and (3) to be
similar because the write barrier is so cheap.

I'd be interested to find what you learn with your application.

> 3. Is there a way simply to time code? The profiler seems like a very
>    hairy thing, and I essentially just want to have a little timer
>    that I can click on & off when I run the function being timed.
>    Or am I fighting the system, and should just suck it up & figure
>    out how to extract this functionality from the profiler?

You can use the Timer structure from the basis library to do timing in
source code.

However, I think you can get what you want easily from the profiler.
If you want the total amount of time spent in a function and all of
its callees, you do the following three steps.

	% mlton -profile true -profile-stack true z.sml
	% z
	% mlprof -raw true z mlmon.out

Then, look for the line with the function you want in the output of
mlprof.

I would also guess that the profiler would perturb the program less
than using Timer would.