## MLton 20241230

# ProfilingTime

With MLton and `mlprof`, you can profile your program to find out how much time is spent in each function over an entire run of the program. To do so, compile your program with `-profile time`. For example, suppose that `tak.sml` contains the following.

    structure Tak =
       struct
          fun tak1 (x, y, z) =
             let
                fun tak2 (x, y, z) =
                   if y >= x
                      then z
                   else
                      tak1 (tak2 (x - 1, y, z),
                            tak2 (y - 1, z, x),
                            tak2 (z - 1, x, y))
             in
                if y >= x
                   then z
                else
                   tak1 (tak2 (x - 1, y, z),
                         tak2 (y - 1, z, x),
                         tak2 (z - 1, x, y))
             end
       end

    val rec f =
       fn 0 => ()
        | ~1 => print "this branch is not taken\n"
        | n => (Tak.tak1 (18, 12, 6) ; f (n-1))

    val _ = f 5000

    fun uncalled () = ()

Compile with time profiling and run the program.

    % mlton -profile time tak.sml
    % ./tak

Display the profiling data.

    % mlprof tak mlmon.out
    6.00 seconds of CPU time (0.00 seconds GC)
    function     cur
    ------------- -----
    Tak.tak1.tak2 75.8%
    Tak.tak1      24.2%

This example shows how `mlprof` indicates lexical nesting: as a sequence of period-separated names indicating the structures and functions in which a function definition is nested. The profiling data shows that roughly three-quarters of the time is spent in the `Tak.tak1.tak2` function, while the rest is spent in `Tak.tak1`.

Display raw counts in addition to percentages with `-raw true`.

    % mlprof -raw true tak mlmon.out
    6.00 seconds of CPU time (0.00 seconds GC)
      function     cur    raw
    ------------- ----- -------
    Tak.tak1.tak2 75.8% (4.55s)
    Tak.tak1      24.2% (1.45s)

Display the file name and line number for each function in addition to its name with `-show-line true`.

    % mlprof -show-line true tak mlmon.out
    6.00 seconds of CPU time (0.00 seconds GC)
            function           cur
    ------------------------- -----
    Tak.tak1.tak2  tak.sml: 5 75.8%
    Tak.tak1  tak.sml: 3      24.2%

Time profiling is designed to have a very small performance impact. However, in some cases there will be a run-time performance cost, which may perturb the results.

You can also compile with `-profile time -profile-branch true` to find out how much time is spent in each branch of a function; see ProfilingCounts for more details on `-profile-branch`.

## Caveats

With `-profile time`, use of the following in your program will cause a run-time error, since they would interfere with the profiler signal handler.

- `MLton.Itimer.set (MLton.Itimer.Prof, …​)`

- `MLton.Signal.setHandler (MLton.Signal.prof, …​)`

Also, because of the random sampling used to implement `-profile time`, it is best to have a long running program (at least tens of seconds) in order to get reasonable time