signature MLTON_PROFILE = sig structure Data: sig type t val equals: t * t -> bool val free: t -> unit val malloc: unit -> t val write: t * string -> unit end val isOn: bool val withData: Data.t * (unit -> 'a) -> 'a end
MLton.Profile provides Profiling control from within the program, allowing you to profile individual portions of your program. With MLton.Profile, you can create many units of profiling data (essentially, mappings from functions to counts) during a run of a program, switch between them while the program is running, and output multiple mlmon.out files.
-
isOn
a compile-time constant that is false only when compiling -profile no. -
type Data.t
the type of a unit of profiling data. In order to most efficiently execute non-profiled programs, when compiling -profile no (the default), Data.t is equivalent to unit ref. -
Data.equals (x, y)
returns true if the x and y are the same unit of profiling data. -
Data.free x
frees the memory associated with the unit of profiling data x. It is an error to free the current unit of profiling data or to free a previously freed unit of profiling data. When compiling -profile no, Data.free x is a no-op. -
Data.malloc ()
returns a new unit of profiling data. Each unit of profiling data is allocated from the process address space (but is not in the MLton heap) and consumes memory proportional to the number of source functions. When compiling -profile no, Data.malloc () is equivalent to allocating a new unit ref. -
write (x, f)
writes the accumulated ticks in the unit of profiling data x to file f. It is an error to write a previously freed unit of profiling data. When compiling -profile no, write (x, f) is a no-op. A profiled program will always write the current unit of profiling data at program exit to a file named mlmon.out. -
withData (d, f)
runs f with d as the unit of profiling data, and returns the result of f after restoring the current unit of profiling data. When compiling -profile no, withData (d, f) is equivalent to f ().
Example
Here is an example, taken from the examples/profiling directory, showing how to profile the executions of the fib and tak functions separately. Suppose that fib-tak.sml contains the following.
structure Profile = MLton.Profile val fibData = Profile.Data.malloc () val takData = Profile.Data.malloc () fun wrap (f, d) x = Profile.withData (d, fn () => f x) val rec fib = fn 0 => 0 | 1 => 1 | n => fib (n - 1) + fib (n - 2) val fib = wrap (fib, fibData) fun tak (x,y,z) = if not (y < x) then z else tak (tak (x - 1, y, z), tak (y - 1, z, x), tak (z - 1, x, y)) val tak = wrap (tak, takData) val rec f = fn 0 => () | n => (fib 38; f (n-1)) val _ = f 2 val rec g = fn 0 => () | n => (tak (18,12,6); g (n-1)) val _ = g 500 fun done (data, file) = (Profile.Data.write (data, file) ; Profile.Data.free data) val _ = done (fibData, "mlmon.fib.out") val _ = done (takData, "mlmon.tak.out")
Compile and run the program.
% mlton -profile time fib-tak.sml % ./fib-tak
Separately display the profiling data for fib
% mlprof fib-tak mlmon.fib.out 5.77 seconds of CPU time (0.00 seconds GC) function cur --------- ----- fib 96.9% <unknown> 3.1%
and for tak
% mlprof fib-tak mlmon.tak.out 0.68 seconds of CPU time (0.00 seconds GC) function cur -------- ------ tak 100.0%
Combine the data for fib and tak by calling mlprof with multiple mlmon.out files.
% mlprof fib-tak mlmon.fib.out mlmon.tak.out mlmon.out 6.45 seconds of CPU time (0.00 seconds GC) function cur --------- ----- fib 86.7% tak 10.5% <unknown> 2.8%