mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-01-04 19:10:37 -08:00
396 lines
No EOL
31 KiB
HTML
396 lines
No EOL
31 KiB
HTML
|
|
|
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
|
|
|
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
|
|
<title>3. The critical path — Memory Pool System 1.111.0 documentation</title>
|
|
|
|
<link rel="stylesheet" href="../_static/mps.css" type="text/css" />
|
|
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
|
|
|
|
<script type="text/javascript">
|
|
var DOCUMENTATION_OPTIONS = {
|
|
URL_ROOT: '../',
|
|
VERSION: '1.111.0',
|
|
COLLAPSE_INDEX: false,
|
|
FILE_SUFFIX: '.html',
|
|
HAS_SOURCE: true
|
|
};
|
|
</script>
|
|
<script type="text/javascript" src="../_static/jquery.js"></script>
|
|
<script type="text/javascript" src="../_static/underscore.js"></script>
|
|
<script type="text/javascript" src="../_static/doctools.js"></script>
|
|
<link rel="copyright" title="Copyright" href="../copyright.html" />
|
|
<link rel="top" title="Memory Pool System 1.111.0 documentation" href="../index.html" />
|
|
<link rel="up" title="Internals" href="internals.html" />
|
|
<link rel="next" title="Introduction to memory management" href="../mmref/index.html" />
|
|
<link rel="prev" title="2. Platforms" href="platform.html" />
|
|
</head>
|
|
<body>
|
|
<div class="related">
|
|
<h3>Navigation</h3>
|
|
<ul>
|
|
<li class="right" style="margin-right: 10px">
|
|
<a href="../genindex.html" title="General Index"
|
|
accesskey="I">index</a></li>
|
|
<li class="right" >
|
|
<a href="../mmref/index.html" title="Introduction to memory management"
|
|
accesskey="N">next</a> |</li>
|
|
<li class="right" >
|
|
<a href="platform.html" title="2. Platforms"
|
|
accesskey="P">previous</a> |</li>
|
|
<li><a href="../index.html">Memory Pool System 1.111.0 documentation</a> »</li>
|
|
<li><a href="internals.html" accesskey="U">Internals</a> »</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="document">
|
|
<div class="documentwrapper">
|
|
<div class="bodywrapper">
|
|
<div class="body">
|
|
|
|
<div class="section" id="the-critical-path">
|
|
<span id="topic-critical"></span><span id="index-0"></span><h1>3. The critical path<a class="headerlink" href="#the-critical-path" title="Permalink to this headline">¶</a></h1>
|
|
<p>The critical path is a key concept in the design of the Memory Pool
|
|
System. Code on the critical path is usually executed more than any
|
|
other code in the process. A change of just one instruction on the
|
|
critical path can make as much as a 1% difference in overall run-time.
|
|
The MPS is designed to make the critical path as short and fast as
|
|
possible.</p>
|
|
<div class="section" id="what-makes-the-critical-path-critical">
|
|
<h2>3.1. What makes the critical path critical<a class="headerlink" href="#what-makes-the-critical-path-critical" title="Permalink to this headline">¶</a></h2>
|
|
<p>In order to determine which objects can be recycled, the <a class="reference internal" href="../glossary/g.html#term-garbage-collector"><em class="xref std std-term">garbage
|
|
collector</em></a> has to frequently examine a very large number of pointers
|
|
in the program’s objects. It does this by <a class="reference internal" href="../glossary/s.html#term-scan"><em class="xref std std-term">scanning</em></a>
|
|
memory, both allocated objects and <a class="reference internal" href="../glossary/r.html#term-root"><em class="xref std std-term">roots</em></a> (such as the
|
|
<a class="reference internal" href="../glossary/t.html#term-thread"><em class="xref std std-term">threads’</em></a> <a class="reference internal" href="../glossary/c.html#term-control-stack"><em class="xref std std-term">control stacks</em></a>).</p>
|
|
<p>This means that the scanning functions must loop over pretty much
|
|
<em>every word in memory</em> sooner or later. The MPS takes great pains to
|
|
avoid scanning memory which does not need scanning, but to get good
|
|
performance, scanning must be highly optimised.</p>
|
|
<p>What’s more, the scanning functions apply an operation called “fix” to
|
|
every <a class="reference internal" href="../glossary/r.html#term-reference"><em class="xref std std-term">reference</em></a> (or potential reference) that they find in the
|
|
objects in memory. Fixing also attempts to eliminate uninteresting
|
|
pointers as fast as possible, but it has to do some work on every
|
|
object that is being considered for recycling, and that can be a large
|
|
proportion of the objects in existence. The path through fixing must
|
|
also be highly optimised, especially in the early stages.</p>
|
|
</div>
|
|
<div class="section" id="how-the-mps-avoids-scanning-and-fixing">
|
|
<h2>3.2. How the MPS avoids scanning and fixing<a class="headerlink" href="#how-the-mps-avoids-scanning-and-fixing" title="Permalink to this headline">¶</a></h2>
|
|
<p>Firstly, the MPS must occasionally decide which objects to try to
|
|
recycle. It does this using various facts it knows about the objects,
|
|
primarily their age and whether they’ve survived previous attempts at
|
|
recycling them. It then <a class="reference internal" href="../glossary/c.html#term-condemned-set"><em class="xref std std-term">condemns</em></a> a large
|
|
number of objects at once, and each of these objects must be
|
|
“preserved” by fixing references to them.</p>
|
|
<p>When the MPS condemns objects it chooses sets of objects in a small
|
|
set of “zones” in memory (preferably a single zone). The zone of an
|
|
object can be determined quickly from its address, without looking at
|
|
the object or any other data structure.</p>
|
|
<p>The MPS arranges that objects which it predicts will die at about the
|
|
same time are in the same zones.</p>
|
|
<p>The MPS allocates in “segments”. Each segment is of the order of one
|
|
“tract” of memory (generally the same as the operating system
|
|
<a class="reference internal" href="../glossary/p.html#term-page"><em class="xref std std-term">page</em></a> size, usually 4 KiB or 8 KiB) but may be larger if there
|
|
are large objects inside. The MPS maintains a “summary” of the zones
|
|
pointed to by all the pointers in a segment from previous scans.</p>
|
|
<p>So, once the MPS has decided what to condemn, it can quickly eliminate
|
|
all segments which definitely do not point to anything in those zones.
|
|
This avoids a large amount of scanning. It is an implementation of a
|
|
<a class="reference internal" href="../glossary/r.html#term-remembered-set"><em class="xref std std-term">remembered set</em></a>, though it is unlike that in most other
|
|
collectors.</p>
|
|
<p>In addition, the <a class="reference internal" href="../glossary/f.html#term-fix"><em class="xref std std-term">fix</em></a> operation can quickly ignore pointers to
|
|
the wrong zones. This is called the “zone check” and is a
|
|
<a class="reference internal" href="../glossary/b.html#term-bibop"><em class="xref std std-term">BIBOP</em></a> technique.</p>
|
|
<p>Even if a pointer passes the zone check, it may still not point to a
|
|
segment containing condemned objects. The next stage of the fix
|
|
operation is to look up the segment pointed to by the pointer and see
|
|
if it was condemned. This is a fast lookup.</p>
|
|
<p>After that, each pool class must decide whether the pointer is to a
|
|
condemned object and do something to preserve it. This code is still
|
|
critical. The MPS will have tried to condemn objects that are dead,
|
|
but those objects are still likely to be in segments with other
|
|
objects that must be preserved. The pool class fix method must quickly
|
|
distinguish between them.</p>
|
|
<p>Furthermore, many objects will be preserved at least once in their
|
|
lifetime, so even the code that preserves an object needs to be highly
|
|
efficient. (Programs in languages like <a class="reference internal" href="../mmref/lang.html#term-ml"><em class="xref std std-term">ML</em></a> might not preserve
|
|
95% of their objects even once, but programs in many other languages
|
|
tend to preserve nearly all of theirs many times.)</p>
|
|
</div>
|
|
<div class="section" id="where-to-find-the-critical-path">
|
|
<h2>3.3. Where to find the critical path<a class="headerlink" href="#where-to-find-the-critical-path" title="Permalink to this headline">¶</a></h2>
|
|
<p>Very briefly, the critical path consists of five stages:</p>
|
|
<ol class="arabic">
|
|
<li><p class="first">The scanner, which iterates over pointers in objects. The MPS has
|
|
several internal scanners, but the most important ones will be the
|
|
<a class="reference internal" href="../glossary/s.html#term-scan-method"><em class="xref std std-term">scan methods</em></a> in the client program’s
|
|
<a class="reference internal" href="../glossary/o.html#term-object-format"><em class="xref std std-term">object formats</em></a>. See <a class="reference internal" href="scanning.html#topic-scanning"><em>Scanning</em></a>.</p>
|
|
</li>
|
|
<li><p class="first">The first-stage fix, which filters out pointers inline in the
|
|
scanner. This is implemented in the <a class="reference internal" href="scanning.html#MPS_FIX1" title="MPS_FIX1"><tt class="xref c c-func docutils literal"><span class="pre">MPS_FIX1()</span></tt></a> macro.</p>
|
|
</li>
|
|
<li><p class="first">The second-stage fix, which filters out pointers using general
|
|
information about segments. This is implemented by the
|
|
<a class="reference internal" href="scanning.html#MPS_FIX2" title="MPS_FIX2"><tt class="xref c c-func docutils literal"><span class="pre">MPS_FIX2()</span></tt></a> macro, which calls <tt class="docutils literal"><span class="pre">_mps_fix</span></tt> in <tt class="docutils literal"><span class="pre">trace.c</span></tt>.</p>
|
|
</li>
|
|
<li><p class="first">The third-stage fix, which filters out pointers using pool-specific
|
|
information. Implemented in pool class functions called <tt class="docutils literal"><span class="pre">AMCFix</span></tt>,
|
|
<tt class="docutils literal"><span class="pre">LOFix</span></tt>, and so on in <tt class="docutils literal"><span class="pre">pool*.c</span></tt>.</p>
|
|
</li>
|
|
<li><p class="first">Preserving the object, which might entail:</p>
|
|
<ul class="simple">
|
|
<li><a class="reference internal" href="../glossary/m.html#term-marking"><em class="xref std std-term">marking</em></a> it to prevent it being recycled; and/or</li>
|
|
<li><a class="reference internal" href="../glossary/c.html#term-copying-garbage-collection"><em class="xref std std-term">copying</em></a> it and updating the
|
|
original pointer (or just updating the pointer, if the object has
|
|
previously been copied); and/or</li>
|
|
<li>adding it to a queue of objects to be scanned later, if it
|
|
contains pointers.</li>
|
|
</ul>
|
|
<p>Found in or near the pool class fix functions.</p>
|
|
</li>
|
|
</ol>
|
|
</div>
|
|
<div class="section" id="the-format-scanner">
|
|
<h2>3.4. The format scanner<a class="headerlink" href="#the-format-scanner" title="Permalink to this headline">¶</a></h2>
|
|
<p>The critical path starts when an <a class="reference internal" href="../glossary/o.html#term-object-format"><em class="xref std std-term">object format’s</em></a> <a class="reference internal" href="../glossary/s.html#term-scan-method"><em class="xref std std-term">scan method</em></a> is called. That is a call from the MPS to
|
|
a client function of type <a class="reference internal" href="format.html#mps_fmt_scan_t" title="mps_fmt_scan_t"><tt class="xref c c-type docutils literal"><span class="pre">mps_fmt_scan_t</span></tt></a> registered with one
|
|
of the format creation functions. (See <a class="reference internal" href="format.html#topic-format"><em>Object formats</em></a>.)</p>
|
|
<p>Here is an example of part of a format scanner for scanning contiguous
|
|
runs of pointers, from <tt class="docutils literal"><span class="pre">fmtdy.c</span></tt>, the scanner for the <a class="reference external" href="http://opendylan.org/">Open Dylan</a> runtime:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="k">static</span> <span class="n">mps_res_t</span> <span class="nf">dylan_scan_contig</span><span class="p">(</span><span class="n">mps_ss_t</span> <span class="n">mps_ss</span><span class="p">,</span>
|
|
<span class="n">mps_addr_t</span> <span class="o">*</span><span class="n">base</span><span class="p">,</span> <span class="n">mps_addr_t</span> <span class="o">*</span><span class="n">limit</span><span class="p">)</span>
|
|
<span class="p">{</span>
|
|
<span class="n">mps_res_t</span> <span class="n">res</span><span class="p">;</span>
|
|
<span class="n">mps_addr_t</span> <span class="o">*</span><span class="n">p</span><span class="p">;</span> <span class="cm">/* reference cursor */</span>
|
|
<span class="n">mps_addr_t</span> <span class="n">r</span><span class="p">;</span> <span class="cm">/* reference to be fixed */</span>
|
|
|
|
<span class="n">MPS_SCAN_BEGIN</span><span class="p">(</span><span class="n">mps_ss</span><span class="p">)</span> <span class="p">{</span>
|
|
<span class="n">p</span> <span class="o">=</span> <span class="n">base</span><span class="p">;</span>
|
|
<span class="nl">loop:</span> <span class="k">if</span><span class="p">(</span><span class="n">p</span> <span class="o">>=</span> <span class="n">limit</span><span class="p">)</span> <span class="k">goto</span> <span class="n">out</span><span class="p">;</span>
|
|
<span class="n">r</span> <span class="o">=</span> <span class="o">*</span><span class="n">p</span><span class="o">++</span><span class="p">;</span>
|
|
<span class="k">if</span><span class="p">(((</span><span class="n">mps_word_t</span><span class="p">)</span><span class="n">r</span><span class="o">&</span><span class="mi">3</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="cm">/* pointers tagged with 0 */</span>
|
|
<span class="k">goto</span> <span class="n">loop</span><span class="p">;</span> <span class="cm">/* not a pointer */</span>
|
|
<span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">MPS_FIX1</span><span class="p">(</span><span class="n">mps_ss</span><span class="p">,</span> <span class="n">r</span><span class="p">))</span> <span class="k">goto</span> <span class="n">loop</span><span class="p">;</span>
|
|
<span class="n">res</span> <span class="o">=</span> <span class="n">MPS_FIX2</span><span class="p">(</span><span class="n">mps_ss</span><span class="p">,</span> <span class="n">p</span><span class="o">-</span><span class="mi">1</span><span class="p">);</span>
|
|
<span class="k">if</span><span class="p">(</span><span class="n">res</span> <span class="o">==</span> <span class="n">MPS_RES_OK</span><span class="p">)</span> <span class="k">goto</span> <span class="n">loop</span><span class="p">;</span>
|
|
<span class="k">return</span> <span class="n">res</span><span class="p">;</span>
|
|
<span class="nl">out:</span> <span class="n">assert</span><span class="p">(</span><span class="n">p</span> <span class="o">==</span> <span class="n">limit</span><span class="p">);</span>
|
|
<span class="p">}</span> <span class="n">MPS_SCAN_END</span><span class="p">(</span><span class="n">mps_ss</span><span class="p">);</span>
|
|
|
|
<span class="k">return</span> <span class="n">MPS_RES_OK</span><span class="p">;</span>
|
|
<span class="p">}</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>(To help with understanding optimisation of this code, it’s written in a
|
|
pseudo-assembler style, with one line roughly corresponding to each
|
|
instruction of an idealized intermediate code.)</p>
|
|
<p>The MPS C interface provides macros to try to help optimise this code.
|
|
The first parameter, of type <a class="reference internal" href="scanning.html#mps_ss_t" title="mps_ss_t"><tt class="xref c c-type docutils literal"><span class="pre">mps_ss_t</span></tt></a>, is a <a class="reference internal" href="../glossary/s.html#term-scan-state"><em class="xref std std-term">scan
|
|
state</em></a> and contains data that is used to eliminate uninteresting
|
|
pointers now, and record information which will be used to reduce
|
|
scanning in future by maintaining the remembered set.</p>
|
|
<p>The macros <a class="reference internal" href="scanning.html#MPS_SCAN_BEGIN" title="MPS_SCAN_BEGIN"><tt class="xref c c-func docutils literal"><span class="pre">MPS_SCAN_BEGIN()</span></tt></a> and <a class="reference internal" href="scanning.html#MPS_SCAN_END" title="MPS_SCAN_END"><tt class="xref c c-func docutils literal"><span class="pre">MPS_SCAN_END()</span></tt></a> load
|
|
key data from the scan state into local variables, and hopefully into
|
|
processor registers. This avoids aliasing values that we know won’t
|
|
change when calls are made to <a class="reference internal" href="scanning.html#MPS_FIX2" title="MPS_FIX2"><tt class="xref c c-func docutils literal"><span class="pre">MPS_FIX2()</span></tt></a> later, and so allows
|
|
the compiler to keep the scan loop small and avoid unnecessary memory
|
|
references.</p>
|
|
<p>This scanner knows that words not ending in <tt class="docutils literal"><span class="pre">0b00</span></tt> aren’t pointers
|
|
to objects, so it eliminates them straight away. This is a <a class="reference internal" href="../glossary/t.html#term-tag"><em class="xref std std-term">tag</em></a>
|
|
chosen by the client program for its object representation.</p>
|
|
<p>Next, the pointer is tested using <a class="reference internal" href="scanning.html#MPS_FIX1" title="MPS_FIX1"><tt class="xref c c-func docutils literal"><span class="pre">MPS_FIX1()</span></tt></a>. This performs
|
|
fast tests on the pointer without using any other memory. In
|
|
particular, it does the “zone check” described above. If a pointer
|
|
fails these tests, it isn’t interesting and can be skipped. It is very
|
|
important to proceed to the next pointer as fast as possible in this
|
|
case.</p>
|
|
<p>Having passed these tests, we need to fix the pointer using other data
|
|
in memory, and possibly call the MPS to preserve the object. This is
|
|
what <a class="reference internal" href="scanning.html#MPS_FIX2" title="MPS_FIX2"><tt class="xref c c-func docutils literal"><span class="pre">MPS_FIX2()</span></tt></a> does. The important distinction here is that
|
|
<a class="reference internal" href="scanning.html#MPS_FIX2" title="MPS_FIX2"><tt class="xref c c-func docutils literal"><span class="pre">MPS_FIX2()</span></tt></a> can fail and return an error code, which must be
|
|
propagated without ado by returning from the scanner. Separating
|
|
<a class="reference internal" href="scanning.html#MPS_FIX1" title="MPS_FIX1"><tt class="xref c c-func docutils literal"><span class="pre">MPS_FIX1()</span></tt></a> from <a class="reference internal" href="scanning.html#MPS_FIX2" title="MPS_FIX2"><tt class="xref c c-func docutils literal"><span class="pre">MPS_FIX2()</span></tt></a> helps keep the error
|
|
handling code away from the tight loop with the zone check.</p>
|
|
<p>The macro/inline parts of the fix operation are referred to as “fix
|
|
stage 1” or “the first stage fix” in other documents and comments.</p>
|
|
<p>If these inline checks pass, <tt class="docutils literal"><span class="pre">_mps_fix2</span></tt> is called. If the MPS has
|
|
been built as a separate object file or library, this is where the
|
|
function call out of the scan loop happens. Since version 1.110 of the
|
|
MPS, we encourage clients to compile the MPS in the same translation
|
|
unit as their format code, so that the compiler can be intelligent
|
|
about inlining parts of <tt class="docutils literal"><span class="pre">_mps_fix2</span></tt> in the format scanner. See <a class="reference internal" href="../guide/build.html#guide-build"><em>Building the Memory Pool System</em></a>.</p>
|
|
</div>
|
|
<div class="section" id="the-second-stage-fix">
|
|
<h2>3.5. The second stage fix<a class="headerlink" href="#the-second-stage-fix" title="Permalink to this headline">¶</a></h2>
|
|
<p>If a pointer gets past the first-stage fix filters, it is passed to
|
|
<tt class="docutils literal"><span class="pre">_mps_fix2</span></tt>, the “second stage fix”. The second stage can filter out
|
|
yet more pointers using information about segments before it has to
|
|
consult the pool class.</p>
|
|
<p>The first test applied is the “tract test”. The MPS looks up the tract
|
|
containing the address in the tract table, which is a simple linear
|
|
table indexed by the address shifted: a kind of flat <a class="reference internal" href="../glossary/p.html#term-page-table"><em class="xref std std-term">page
|
|
table</em></a>.</p>
|
|
<p>Note that if the arena has been extended, the tract table becomes less
|
|
simple, and this test may involved looking in more than one table.
|
|
This will cause a considerable slow-down in garbage collection
|
|
scanning. This is the reason that it’s important to reserve an address
|
|
space that is several times larger than (a good estimate of) your peak
|
|
memory usage when you initialize a <a class="reference internal" href="../glossary/v.html#term-virtual-memory-arena"><em class="xref std std-term">virtual memory arena</em></a>.</p>
|
|
<p>The pointer might not even be in the arena (and so not in any tract).
|
|
The first stage fix doesn’t guarantee it. So we eliminate any pointers
|
|
not in the arena at this stage.</p>
|
|
<p>If the pointer is in an allocated tract, then the table also contains
|
|
a cache of the “white set”, the set of garbage collection traces for
|
|
which the tract is “interesting”. If a tract isn’t interesting, then
|
|
we know that it contains no condemned objects, and we can filter out
|
|
the pointer.</p>
|
|
<p>If the tract is interesting them it’s part of a segment containing
|
|
objects that have been condemned. The MPM can’t know anything about
|
|
the internal layout of the segment, so at this point we dispatch to
|
|
the third stage fix.</p>
|
|
<p>This dispatch is slightly subtle. We have a cache of the function to
|
|
dispatch to in the <a class="reference internal" href="../glossary/s.html#term-scan-state"><em class="xref std std-term">scan state</em></a>, which has recently been looked
|
|
at and is with luck still in the processor cache. The reason there is
|
|
a dispatch at all is to allow for a fast changeover to emergency
|
|
garbage collection, or overriding of garbage collection with extra
|
|
operations. Those are beyond the scope of this document. Normally,
|
|
<tt class="docutils literal"><span class="pre">ss->fix</span></tt> points at <tt class="docutils literal"><span class="pre">PoolFix</span></tt>, and we rely somewhat on modern
|
|
processor <a class="reference external" href="https://en.wikipedia.org/wiki/Branch_target_predictor">branch target prediction</a>. <tt class="docutils literal"><span class="pre">PoolFix</span></tt>
|
|
is passed the pool, which is fetched from the tract table entry, and
|
|
that should be in the cache.</p>
|
|
<p><tt class="docutils literal"><span class="pre">PoolFix</span></tt> itself dispatches to the pool class. Normally, a dispatch
|
|
to a pool class would indirect through the pool class object. That
|
|
would be a double indirection from the tract, so instead we have a
|
|
cache of the pool’s fix method in the pool object. This also allows a
|
|
pool class to vary its fix method per pool instance, a fact that is
|
|
exploited to optimize fixing in <a class="reference internal" href="../pool/amc.html#pool-amc"><em>AMC (Automatic Mostly-Copying)</em></a>, depending on what
|
|
kind of object format it is managing.</p>
|
|
</div>
|
|
<div class="section" id="the-third-stage-fix-in-the-pool-class">
|
|
<h2>3.6. The third stage fix in the pool class<a class="headerlink" href="#the-third-stage-fix-in-the-pool-class" title="Permalink to this headline">¶</a></h2>
|
|
<p>The final stage of fixing is entirely dependent on the <a class="reference internal" href="../glossary/p.html#term-pool-class"><em class="xref std std-term">pool
|
|
class</em></a>. The Memory Pool Manager can’t, in general, know how the
|
|
objects within a pool are arranged, so this is pool class specific
|
|
code.</p>
|
|
<p>Furthermore, the pool class must make decisions based on the
|
|
<a class="reference internal" href="../glossary/r.html#term-rank"><em class="xref std std-term">reference rank</em></a> of the pointer. If a pointer is
|
|
<a class="reference internal" href="../glossary/a.html#term-ambiguous-reference"><em class="xref std std-term">ambiguous</em></a> then it can’t be changed, so
|
|
even a <a class="reference internal" href="../glossary/c.html#term-copying-garbage-collection"><em class="xref std std-term">copying</em></a> pool class can’t
|
|
move an object. On the other hand, if the pointer is <a class="reference internal" href="../glossary/w.html#term-weak-reference-1"><em class="xref std std-term">weak</em></a> then the pool fix method shouldn’t preserve the object
|
|
at all, even if it’s condemned.</p>
|
|
<p>The exact details of the logic that the pool fix must implement in
|
|
order to co-operate with the MPM and other pools are beyond the scope
|
|
of this document, which is about the critical path. Since it is on the
|
|
critical path, it’s important that whatever the pool fix does is
|
|
simple and fast and returns to scanning as soon as possible.</p>
|
|
<p>The first step, though, is to further filter out pointers which aren’t
|
|
to objects, if that’s its policy. Then, it may preserve the object,
|
|
according to its policy, and possibly ensure that the object gets
|
|
scanned at some point in the future, if it contains more pointers.</p>
|
|
<p>If the object is moved to preserve it (for instance, if the pool class
|
|
implements copying garbage collection), or was already moved when
|
|
fixing a previous reference to it, the reference being fixed must be
|
|
updated (this is the origin of the term “fix”).</p>
|
|
<p>As a simple example, <tt class="docutils literal"><span class="pre">LOFix</span></tt> is the pool fix method for the
|
|
<a class="reference internal" href="../pool/lo.html#pool-lo"><em>LO (Leaf Object)</em></a> pool class. It implements a <a class="reference internal" href="../glossary/m.html#term-marking"><em class="xref std std-term">marking</em></a> garbage
|
|
collector, and does not have to worry about scanning preserved objects
|
|
because it is used to store objects that don’t contain pointers. (It
|
|
is used in compiler run-time systems to store binary data such as
|
|
character strings, thus avoiding any scanning, decoding, or remembered
|
|
set overhead for them.)</p>
|
|
<p><tt class="docutils literal"><span class="pre">LOFix</span></tt> filters any ambiguous pointers that aren’t aligned, since
|
|
they can’t point to objects it allocated. Otherwise it subtracts the
|
|
segment base address and shifts the result to get an index into a mark
|
|
bit table. If the object wasn’t marked and the pointer is weak, then
|
|
it sets the pointer to zero, since the object is about to be recycled.
|
|
Otherwise, the mark bit is set, which preserves the object from
|
|
recycling when <tt class="docutils literal"><span class="pre">LOReclaim</span></tt> is called later on. <tt class="docutils literal"><span class="pre">LOFix</span></tt> illustrates
|
|
about the minimum and most efficient thing a pool fix method can do.</p>
|
|
</div>
|
|
<div class="section" id="other-considerations">
|
|
<h2>3.7. Other considerations<a class="headerlink" href="#other-considerations" title="Permalink to this headline">¶</a></h2>
|
|
<p>So far this document has described the ways in which the garbage
|
|
collector is designed around optimising the critical path. There are a
|
|
few other things that the MPS does that are important.</p>
|
|
<p>Firstly, inlining is very important. The first stage fix is inlined
|
|
into the format scanner by being implemented in macros in <tt class="docutils literal"><span class="pre">mps.h</span></tt>.
|
|
And to get even better inlining, we recommend that the whole MPS is
|
|
compiled in a single translation unit with the client format and that
|
|
strong global optimisation is applied. See <a class="reference internal" href="../guide/build.html#guide-build"><em>Building the Memory Pool System</em></a>.</p>
|
|
<p>Secondly, we are very careful with code annotations on the critical
|
|
path. Assertions, statistics, and telemetry are all disabled on the
|
|
critical path in <a class="reference internal" href="../glossary/h.html#term-hot"><em class="xref std std-term">hot</em></a> (production) builds. (In fact, it’s
|
|
because the critical path is critical that we can afford to leave
|
|
annotations switched on elsewhere.)</p>
|
|
<p>Last, but by no means least, we pay a lot of brainpower and
|
|
measurement to the critical path, and are very very careful about
|
|
changing it. Code review around the critical path is especially
|
|
vigilant.</p>
|
|
<p>And we write long documents about it.</p>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sphinxsidebar">
|
|
<div class="sphinxsidebarwrapper">
|
|
<p class="logo"><a href="../index.html">
|
|
<img class="logo" src="../_static/logo.png" alt="Logo"/>
|
|
</a></p>
|
|
<h3><a href="../index.html">Table Of Contents</a></h3>
|
|
<ul>
|
|
<li><a class="reference internal" href="#">3. The critical path</a><ul>
|
|
<li><a class="reference internal" href="#what-makes-the-critical-path-critical">3.1. What makes the critical path critical</a></li>
|
|
<li><a class="reference internal" href="#how-the-mps-avoids-scanning-and-fixing">3.2. How the MPS avoids scanning and fixing</a></li>
|
|
<li><a class="reference internal" href="#where-to-find-the-critical-path">3.3. Where to find the critical path</a></li>
|
|
<li><a class="reference internal" href="#the-format-scanner">3.4. The format scanner</a></li>
|
|
<li><a class="reference internal" href="#the-second-stage-fix">3.5. The second stage fix</a></li>
|
|
<li><a class="reference internal" href="#the-third-stage-fix-in-the-pool-class">3.6. The third stage fix in the pool class</a></li>
|
|
<li><a class="reference internal" href="#other-considerations">3.7. Other considerations</a></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
|
|
<h4>Previous topic</h4>
|
|
<p class="topless"><a href="platform.html"
|
|
title="previous chapter">2. Platforms</a></p>
|
|
<h4>Next topic</h4>
|
|
<p class="topless"><a href="../mmref/index.html"
|
|
title="next chapter">Introduction to memory management</a></p><h4>Contact us</h4>
|
|
|
|
<p class="topless"><a href="mailto:mps-questions@ravenbrook.com">mps-questions@ravenbrook.com</a></p>
|
|
</div>
|
|
</div>
|
|
<div class="clearer"></div>
|
|
</div>
|
|
<div class="related">
|
|
<h3>Navigation</h3>
|
|
<ul>
|
|
<li class="right" style="margin-right: 10px">
|
|
<a href="../genindex.html" title="General Index"
|
|
>index</a></li>
|
|
<li class="right" >
|
|
<a href="../mmref/index.html" title="Introduction to memory management"
|
|
>next</a> |</li>
|
|
<li class="right" >
|
|
<a href="platform.html" title="2. Platforms"
|
|
>previous</a> |</li>
|
|
<li><a href="../index.html">Memory Pool System 1.111.0 documentation</a> »</li>
|
|
<li><a href="internals.html" >Internals</a> »</li>
|
|
</ul>
|
|
</div>
|
|
<div class="footer">
|
|
© <a href="../copyright.html">Copyright</a> 2012, Ravenbrook Limited.
|
|
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3.
|
|
</div>
|
|
</body>
|
|
</html> |