<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="Asciidoctor 2.0.23">
<title>HowProfilingWorks</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700">
<link rel="stylesheet" href="./asciidoctor.css">
<link rel="stylesheet" href="./rouge-github.css">
<link rel="stylesheet" href="./mlton.css">

</head>
<body class="article">
<div id="mlton-header">
<div id="mlton-header-text">
<h2>
<a href="./Home">
MLton
20241230
</a>
</h2>
</div>
</div>
<div id="header">
<h1>HowProfilingWorks</h1>
</div>
<div id="content">
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Here&#8217;s how <a href="Profiling">Profiling</a> works.  If profiling is on, the front end
(elaborator) inserts <code>Enter</code> and <code>Leave</code> statements into the source
program for function entry and exit.  For example,</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="sml"><span class="kr">fun</span> <span class="nf">f</span> <span class="n">n</span> <span class="p">=</span> <span class="kr">if</span> <span class="n">n</span> <span class="p">=</span> <span class="mi">0</span> <span class="kr">then</span> <span class="mi">0</span> <span class="kr">else</span> <span class="mi">1</span> <span class="n">+</span> <span class="n">f</span> <span class="p">(</span><span class="n">n</span> <span class="n">-</span> <span class="mi">1</span><span class="p">)</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>becomes</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="sml"><span class="kr">fun</span> <span class="nf">f</span> <span class="n">n</span> <span class="p">=</span>
   <span class="kr">let</span>
      <span class="kr">val</span> <span class="p">()</span> <span class="nv">=</span> <span class="n">Enter</span> <span class="s2">"f"</span>
      <span class="kr">val</span> <span class="nv">res</span> <span class="p">=</span> <span class="p">(</span><span class="kr">if</span> <span class="n">n</span> <span class="p">=</span> <span class="mi">0</span> <span class="kr">then</span> <span class="mi">0</span> <span class="kr">else</span> <span class="mi">1</span> <span class="n">+</span> <span class="n">f</span> <span class="p">(</span><span class="n">n</span> <span class="n">-</span> <span class="mi">1</span><span class="p">))</span>
                <span class="kr">handle</span> <span class="n">e</span> <span class="p">=&gt;</span> <span class="p">(</span><span class="n">Leave</span> <span class="s2">"f"</span><span class="p">;</span> <span class="kr">raise</span> <span class="n">e</span><span class="p">)</span>
      <span class="kr">val</span> <span class="p">()</span> <span class="nv">=</span> <span class="n">Leave</span> <span class="s2">"f"</span>
   <span class="kr">in</span>
      <span class="n">res</span>
   <span class="kr">end</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Actually there is a bit more information than just the source function
name; there is also lexical nesting and file position.</p>
</div>
<div class="paragraph">
<p>Most of the middle of the compiler ignores, but preserves, <code>Enter</code> and
<code>Leave</code>.  However, so that profiling preserves tail calls, the
<a href="Shrink">SSA shrinker</a> has an optimization that notices when the only
operations that cause a call to be a nontail call are profiling
operations, and if so, moves them before the call, turning it into a
tail call. If you observe a program that has a tail call that appears
to be turned into a nontail when compiled with profiling, please
<a href="Bug">report a bug</a>.</p>
</div>
<div class="paragraph">
<p>There is the <code>checkProf</code> function in
<a href="https://github.com/MLton/mlton/blob/master/mlton/ssa/type-check.fun"><code>type-check.fun</code></a>, which checks that
the <code>Enter</code>/<code>Leave</code> statements match up.</p>
</div>
<div class="paragraph">
<p>In the backend, just before translating to the <a href="Machine">Machine IL</a>,
the profiler uses the <code>Enter</code>/<code>Leave</code> statements to infer the "local"
portion of the control stack at each program point.  The profiler then
removes the <code>Enter</code>s/<code>Leave</code>s and inserts different information
depending on which kind of profiling is happening.  For time
profiling, the profiler inserts code that sets a global field that
records the local control stack.  For allocation profiling, the
profiler inserts calls to a C function that will maintain byte counts.
With stack profiling, the profiler also inserts a call to a C function
at each nontail call in order to maintain information at runtime about
what SML functions are on the stack.</p>
</div>
<div class="paragraph">
<p>At run time, the profiler associates counters (either clock ticks or
byte counts) with source functions.  When the program finishes, the
profiler writes the counts out to the <code>mlmon.out</code> file.  Then,
<code>mlprof</code> uses source information stored in the executable to
associate the counts in the <code>mlmon.out</code> file with source
functions.</p>
</div>
<div class="paragraph">
<p>For time profiling, the profiler catches the <code>SIGPROF</code> signal 100
times per second and increments the appropriate counter, determined by
looking at the global field that records the local control stack and
mapping that to the current source function.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_caveats">Caveats</h2>
<div class="sectionbody">
<div class="paragraph">
<p>There may be a few missed clock ticks or bytes allocated at the very
end of the program after the data is written.</p>
</div>
<div class="paragraph">
<p>Profiling has not been tested with signals or threads.  In particular,
stack profiling may behave strangely.</p>
</div>
</div>
</div>
</div>
<div id="mlton-footer">
<div id="mlton-footer-text">
<div>
Last updated Thu Oct 21 15:53:06 2021 -0400 by Matthew Fluet.
<a href="https://github.com/MLton/mlton/commits/master/doc/guide/src/HowProfilingWorks.adoc">Log</a>
<a href="https://github.com/MLton/mlton/edit/master/doc/guide/src/HowProfilingWorks.adoc">Edit</a>
</div>
</div>
</body>
</html>