peps/pep-0669/index.html

741 lines
57 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="color-scheme" content="light dark">
<title>PEP 669 Low Impact Monitoring for CPython | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-0669/">
<link rel="stylesheet" href="../_static/style.css" type="text/css">
<link rel="stylesheet" href="../_static/mq.css" type="text/css">
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" media="(prefers-color-scheme: light)" id="pyg-light">
<link rel="stylesheet" href="../_static/pygments_dark.css" type="text/css" media="(prefers-color-scheme: dark)" id="pyg-dark">
<link rel="alternate" type="application/rss+xml" title="Latest PEPs" href="https://peps.python.org/peps.rss">
<meta property="og:title" content='PEP 669 Low Impact Monitoring for CPython | peps.python.org'>
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-0669/">
<meta property="og:site_name" content="Python Enhancement Proposals (PEPs)">
<meta property="og:image" content="https://peps.python.org/_static/og-image.png">
<meta property="og:image:alt" content="Python PEPs">
<meta property="og:image:width" content="200">
<meta property="og:image:height" content="200">
<meta name="description" content="Python Enhancement Proposals (PEPs)">
<meta name="theme-color" content="#3776ab">
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all">
<title>Following system colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="9"></circle>
<path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path>
</svg>
</symbol>
<symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all">
<title>Selected dark colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path>
</svg>
</symbol>
<symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all">
<title>Selected light colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="5"></circle>
<line x1="12" y1="1" x2="12" y2="3"></line>
<line x1="12" y1="21" x2="12" y2="23"></line>
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
<line x1="1" y1="12" x2="3" y2="12"></line>
<line x1="21" y1="12" x2="23" y2="12"></line>
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
</svg>
</symbol>
</svg>
<script>
document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto"
</script>
<section id="pep-page-section">
<header>
<h1>Python Enhancement Proposals</h1>
<ul class="breadcrumbs">
<li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> &raquo; </li>
<li><a href="../pep-0000/">PEP Index</a> &raquo; </li>
<li>PEP 669</li>
</ul>
<button id="colour-scheme-cycler" onClick="setColourScheme(nextColourScheme())">
<svg aria-hidden="true" class="colour-scheme-icon-when-auto"><use href="#svg-sun-half"></use></svg>
<svg aria-hidden="true" class="colour-scheme-icon-when-dark"><use href="#svg-moon"></use></svg>
<svg aria-hidden="true" class="colour-scheme-icon-when-light"><use href="#svg-sun"></use></svg>
<span class="visually-hidden">Toggle light / dark / auto colour theme</span>
</button>
</header>
<article>
<section id="pep-content">
<h1 class="page-title">PEP 669 Low Impact Monitoring for CPython</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">Mark Shannon &lt;mark&#32;&#97;t&#32;hotpy.org&gt;</dd>
<dt class="field-even">Discussions-To<span class="colon">:</span></dt>
<dd class="field-even"><a class="reference external" href="https://discuss.python.org/t/pep-669-low-impact-monitoring-for-cpython/13018/">Discourse thread</a></dd>
<dt class="field-odd">Status<span class="colon">:</span></dt>
<dd class="field-odd"><abbr title="Accepted and implementation complete, or no longer active">Final</abbr></dd>
<dt class="field-even">Type<span class="colon">:</span></dt>
<dd class="field-even"><abbr title="Normative PEP with a new feature for Python, implementation change for CPython or interoperability standard for the ecosystem">Standards Track</abbr></dd>
<dt class="field-odd">Created<span class="colon">:</span></dt>
<dd class="field-odd">18-Aug-2021</dd>
<dt class="field-even">Python-Version<span class="colon">:</span></dt>
<dd class="field-even">3.12</dd>
<dt class="field-odd">Post-History<span class="colon">:</span></dt>
<dd class="field-odd"><a class="reference external" href="https://mail.python.org/archives/list/python-dev&#64;python.org/thread/VNSD4TSAM2BM64FJNIQPAOPNEGNX4MDX/" title="Python-Dev thread">07-Dec-2021</a>,
<a class="reference external" href="https://discuss.python.org/t/pep-669-low-impact-monitoring-for-cpython/13018" title="Discourse thread">10-Jan-2022</a></dd>
<dt class="field-even">Resolution<span class="colon">:</span></dt>
<dd class="field-even"><a class="reference external" href="https://discuss.python.org/t/pep-669-low-impact-monitoring-for-cpython/13018/42">Discourse message</a></dd>
</dl>
<hr class="docutils" />
<section id="contents">
<details><summary>Table of Contents</summary><ul class="simple">
<li><a class="reference internal" href="#abstract">Abstract</a></li>
<li><a class="reference internal" href="#motivation">Motivation</a></li>
<li><a class="reference internal" href="#rationale">Rationale</a></li>
<li><a class="reference internal" href="#specification">Specification</a><ul>
<li><a class="reference internal" href="#events">Events</a><ul>
<li><a class="reference internal" href="#local-events">Local events</a></li>
<li><a class="reference internal" href="#ancilliary-events">Ancilliary events</a></li>
<li><a class="reference internal" href="#other-events">Other events</a></li>
<li><a class="reference internal" href="#the-stop-iteration-event">The STOP_ITERATION event</a></li>
</ul>
</li>
<li><a class="reference internal" href="#tool-identifiers">Tool identifiers</a></li>
<li><a class="reference internal" href="#setting-events-globally">Setting events globally</a></li>
<li><a class="reference internal" href="#per-code-object-events">Per code object events</a></li>
<li><a class="reference internal" href="#register-callback-functions">Register callback functions</a><ul>
<li><a class="reference internal" href="#callback-function-arguments">Callback function arguments</a></li>
</ul>
</li>
<li><a class="reference internal" href="#events-in-callback-functions">Events in callback functions</a></li>
<li><a class="reference internal" href="#order-of-events">Order of events</a></li>
<li><a class="reference internal" href="#the-call-event-group">The “call” event group</a></li>
<li><a class="reference internal" href="#attributes-of-the-sys-monitoring-namespace">Attributes of the <code class="docutils literal notranslate"><span class="pre">sys.monitoring</span></code> namespace</a></li>
<li><a class="reference internal" href="#access-to-debug-only-features">Access to “debug only” features</a></li>
</ul>
</li>
<li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a><ul>
<li><a class="reference internal" href="#performance">Performance</a><ul>
<li><a class="reference internal" href="#memory-consumption">Memory Consumption</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#security-implications">Security Implications</a></li>
<li><a class="reference internal" href="#implementation">Implementation</a></li>
<li><a class="reference internal" href="#implementing-tools">Implementing tools</a><ul>
<li><a class="reference internal" href="#debuggers">Debuggers</a><ul>
<li><a class="reference internal" href="#inserting-breakpoints">Inserting breakpoints</a></li>
<li><a class="reference internal" href="#stepping">Stepping</a></li>
<li><a class="reference internal" href="#attaching">Attaching</a></li>
</ul>
</li>
<li><a class="reference internal" href="#coverage-tools">Coverage Tools</a></li>
<li><a class="reference internal" href="#profilers">Profilers</a><ul>
<li><a class="reference internal" href="#line-based-profilers">Line based profilers</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#rejected-ideas">Rejected ideas</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
</details></section>
<div class="pep-banner canonical-doc sticky-banner admonition important">
<p class="admonition-title">Important</p>
<p>This PEP is a historical document. The up-to-date, canonical documentation can now be found at <a class="reference external" href="https://docs.python.org/3/library/sys.monitoring.html#module-sys.monitoring" title="(in Python v3.12)"><code class="docutils literal notranslate"><span class="pre">sys.monitoring</span></code></a>.</p>
<p class="close-button">×</p>
<p>See <a class="pep reference internal" href="../pep-0001/" title="PEP 1 PEP Purpose and Guidelines">PEP 1</a> for how to propose changes.</p>
</div>
<section id="abstract">
<h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2>
<p>Using a profiler or debugger in CPython can have a severe impact on
performance. Slowdowns by an order of magnitude are common.</p>
<p>This PEP proposes an API for monitoring Python programs running
on CPython that will enable monitoring at low cost.</p>
<p>Although this PEP does not specify an implementation, it is expected that
it will be implemented using the quickening step of
<a class="pep reference internal" href="../pep-0659/" title="PEP 659 Specializing Adaptive Interpreter">PEP 659</a>.</p>
<p>A <code class="docutils literal notranslate"><span class="pre">sys.monitoring</span></code> namespace will be added, which will contain
the relevant functions and constants.</p>
</section>
<section id="motivation">
<h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2>
<p>Developers should not have to pay an unreasonable cost to use debuggers,
profilers and other similar tools.</p>
<p>C++ and Java developers expect to be able to run a program at full speed
(or very close to it) under a debugger.
Python developers should expect that too.</p>
</section>
<section id="rationale">
<h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2>
<p>The quickening mechanism provided by <a class="pep reference internal" href="../pep-0659/" title="PEP 659 Specializing Adaptive Interpreter">PEP 659</a> provides a way to dynamically
modify executing Python bytecode. These modifications have little cost beyond
the parts of the code that are modified and a relatively low cost to those
parts that are modified. We can leverage this to provide an efficient
mechanism for monitoring that was not possible in 3.10 or earlier.</p>
<p>By using quickening, we expect that code run under a debugger on 3.12
should outperform code run without a debugger on 3.11.
Profiling will still slow down execution, but by much less than in 3.11.</p>
</section>
<section id="specification">
<h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2>
<p>Monitoring of Python programs is done by registering callback functions
for events and by activating a set of events.</p>
<p>Activating events and registering callback functions are independent of each other.</p>
<p>Both registering callbacks and activating events are done on a per-tool basis.
It is possible to have multiple tools that respond to different sets of events.</p>
<p>Note that, unlike <code class="docutils literal notranslate"><span class="pre">sys.settrace()</span></code>, events and callbacks are per interpreter, not per thread.</p>
<section id="events">
<h3><a class="toc-backref" href="#events" role="doc-backlink">Events</a></h3>
<p>As a code object executes various events occur that might be of interest
to tools. By activating events and by registering callback functions
tools can respond to these events in any way that suits them.
Events can be set globally, or for individual code objects.</p>
<p>For 3.12, CPython will support the following events:</p>
<ul class="simple">
<li>PY_START: Start of a Python function (occurs immediately after the call, the callees frame will be on the stack)</li>
<li>PY_RESUME: Resumption of a Python function (for generator and coroutine functions), except for throw() calls.</li>
<li>PY_THROW: A Python function is resumed by a throw() call.</li>
<li>PY_RETURN: Return from a Python function (occurs immediately before the return, the callees frame will be on the stack).</li>
<li>PY_YIELD: Yield from a Python function (occurs immediately before the yield, the callees frame will be on the stack).</li>
<li>PY_UNWIND: Exit from a Python function during exception unwinding.</li>
<li>CALL: A call in Python code (event occurs before the call).</li>
<li>C_RETURN: Return from any callable, except Python functions (event occurs after the return).</li>
<li>C_RAISE: Exception raised from any callable, except Python functions (event occurs after the exit).</li>
<li>RAISE: An exception is raised, except those that cause a <code class="docutils literal notranslate"><span class="pre">STOP_ITERATION</span></code> event.</li>
<li>EXCEPTION_HANDLED: An exception is handled.</li>
<li>LINE: An instruction is about to be executed that has a different line number from the preceding instruction.</li>
<li>INSTRUCTION A VM instruction is about to be executed.</li>
<li>JUMP An unconditional jump in the control flow graph is made.</li>
<li>BRANCH A conditional branch is taken (or not).</li>
<li>STOP_ITERATION An artificial <code class="docutils literal notranslate"><span class="pre">StopIteration</span></code> is raised;
see <a class="reference internal" href="#the-stop-iteration-event">the STOP_ITERATION event</a>.</li>
</ul>
<p>More events may be added in the future.</p>
<p>All events will be attributes of the <code class="docutils literal notranslate"><span class="pre">events</span></code> namespace in <code class="docutils literal notranslate"><span class="pre">sys.monitoring</span></code>.
All events will represented by a power of two integer, so that they can be combined
with the <code class="docutils literal notranslate"><span class="pre">|</span></code> operator.</p>
<p>Events are divided into three groups:</p>
<section id="local-events">
<h4><a class="toc-backref" href="#local-events" role="doc-backlink">Local events</a></h4>
<p>Local events are associated with normal execution of the program and happen
at clearly defined locations. All local events can be disabled.
The local events are:</p>
<ul class="simple">
<li>PY_START</li>
<li>PY_RESUME</li>
<li>PY_RETURN</li>
<li>PY_YIELD</li>
<li>CALL</li>
<li>LINE</li>
<li>INSTRUCTION</li>
<li>JUMP</li>
<li>BRANCH</li>
<li>STOP_ITERATION</li>
</ul>
</section>
<section id="ancilliary-events">
<h4><a class="toc-backref" href="#ancilliary-events" role="doc-backlink">Ancilliary events</a></h4>
<p>Ancillary events can be monitored like other events, but are controlled
by another event:</p>
<ul class="simple">
<li>C_RAISE</li>
<li>C_RETURN</li>
</ul>
<p>The <code class="docutils literal notranslate"><span class="pre">C_RETURN</span></code> and <code class="docutils literal notranslate"><span class="pre">C_RAISE</span></code> events are are controlled by the <code class="docutils literal notranslate"><span class="pre">CALL</span></code>
event. <code class="docutils literal notranslate"><span class="pre">C_RETURN</span></code> and <code class="docutils literal notranslate"><span class="pre">C_RAISE</span></code> events will only be seen if the
corresponding <code class="docutils literal notranslate"><span class="pre">CALL</span></code> event is being monitored.</p>
</section>
<section id="other-events">
<h4><a class="toc-backref" href="#other-events" role="doc-backlink">Other events</a></h4>
<p>Other events are not necessarily tied to a specific location in the
program and cannot be individually disabled.</p>
<p>The other events that can be monitored are:</p>
<ul class="simple">
<li>PY_THROW</li>
<li>PY_UNWIND</li>
<li>RAISE</li>
<li>EXCEPTION_HANDLED</li>
</ul>
</section>
<section id="the-stop-iteration-event">
<h4><a class="toc-backref" href="#the-stop-iteration-event" role="doc-backlink">The STOP_ITERATION event</a></h4>
<p><a class="pep reference internal" href="../pep-0380/#use-of-stopiteration-to-return-values" title="PEP 380 Syntax for Delegating to a Subgenerator § Use of StopIteration to return values">PEP 380</a>
specifies that a <code class="docutils literal notranslate"><span class="pre">StopIteration</span></code> exception is raised when returning a value
from a generator or coroutine. However, this is a very inefficient way to
return a value, so some Python implementations, notably CPython 3.12+, do not
raise an exception unless it would be visible to other code.</p>
<p>To allow tools to monitor for real exceptions without slowing down generators
and coroutines, the <code class="docutils literal notranslate"><span class="pre">STOP_ITERATION</span></code> event is provided.
<code class="docutils literal notranslate"><span class="pre">STOP_ITERATION</span></code> can be locally disabled, unlike <code class="docutils literal notranslate"><span class="pre">RAISE</span></code>.</p>
</section>
</section>
<section id="tool-identifiers">
<h3><a class="toc-backref" href="#tool-identifiers" role="doc-backlink">Tool identifiers</a></h3>
<p>The VM can support up to 6 tools at once.
Before registering or activating events, a tool should choose an identifier.
Identifiers are integers in the range 0 to 5.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">sys</span><span class="o">.</span><span class="n">monitoring</span><span class="o">.</span><span class="n">use_tool_id</span><span class="p">(</span><span class="nb">id</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span><span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span>
<span class="n">sys</span><span class="o">.</span><span class="n">monitoring</span><span class="o">.</span><span class="n">free_tool_id</span><span class="p">(</span><span class="nb">id</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span>
<span class="n">sys</span><span class="o">.</span><span class="n">monitoring</span><span class="o">.</span><span class="n">get_tool</span><span class="p">(</span><span class="nb">id</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span>
</pre></div>
</div>
<p><code class="docutils literal notranslate"><span class="pre">sys.monitoring.use_tool_id</span></code> raises a <code class="docutils literal notranslate"><span class="pre">ValueError</span></code> if <code class="docutils literal notranslate"><span class="pre">id</span></code> is in use.
<code class="docutils literal notranslate"><span class="pre">sys.monitoring.get_tool</span></code> returns the name of the tool if <code class="docutils literal notranslate"><span class="pre">id</span></code> is in use,
otherwise it returns <code class="docutils literal notranslate"><span class="pre">None</span></code>.</p>
<p>All IDs are treated the same by the VM with regard to events, but the
following IDs are pre-defined to make co-operation of tools easier:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">sys</span><span class="o">.</span><span class="n">monitoring</span><span class="o">.</span><span class="n">DEBUGGER_ID</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">sys</span><span class="o">.</span><span class="n">monitoring</span><span class="o">.</span><span class="n">COVERAGE_ID</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">sys</span><span class="o">.</span><span class="n">monitoring</span><span class="o">.</span><span class="n">PROFILER_ID</span> <span class="o">=</span> <span class="mi">2</span>
<span class="n">sys</span><span class="o">.</span><span class="n">monitoring</span><span class="o">.</span><span class="n">OPTIMIZER_ID</span> <span class="o">=</span> <span class="mi">5</span>
</pre></div>
</div>
<p>There is no obligation to set an ID, nor is there anything preventing a tool
from using an ID even it is already in use.
However, tools are encouraged to use a unique ID and respect other tools.</p>
<p>For example, if a debugger were attached and <code class="docutils literal notranslate"><span class="pre">DEBUGGER_ID</span></code> were in use, it
should report an error, rather than carrying on regardless.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">OPTIMIZER_ID</span></code> is provided for tools like Cinder or PyTorch
that want to optimize Python code, but need to decide what to
optimize in a way that depends on some wider context.</p>
</section>
<section id="setting-events-globally">
<h3><a class="toc-backref" href="#setting-events-globally" role="doc-backlink">Setting events globally</a></h3>
<p>Events can be controlled globally by modifying the set of events being monitored:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">sys.monitoring.get_events(tool_id:int)-&gt;int</span></code>
Returns the <code class="docutils literal notranslate"><span class="pre">int</span></code> representing all the active events.</li>
<li><code class="docutils literal notranslate"><span class="pre">sys.monitoring.set_events(tool_id:int,</span> <span class="pre">event_set:</span> <span class="pre">int)</span></code>
Activates all events which are set in <code class="docutils literal notranslate"><span class="pre">event_set</span></code>.
Raises a <code class="docutils literal notranslate"><span class="pre">ValueError</span></code> if <code class="docutils literal notranslate"><span class="pre">tool_id</span></code> is not in use.</li>
</ul>
<p>No events are active by default.</p>
</section>
<section id="per-code-object-events">
<h3><a class="toc-backref" href="#per-code-object-events" role="doc-backlink">Per code object events</a></h3>
<p>Events can also be controlled on a per code object basis:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">sys.monitoring.get_local_events(tool_id:int,</span> <span class="pre">code:</span> <span class="pre">CodeType)-&gt;int</span></code>
Returns all the local events for <code class="docutils literal notranslate"><span class="pre">code</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">sys.monitoring.set_local_events(tool_id:int,</span> <span class="pre">code:</span> <span class="pre">CodeType,</span> <span class="pre">event_set:</span> <span class="pre">int)</span></code>
Activates all the local events for <code class="docutils literal notranslate"><span class="pre">code</span></code> which are set in <code class="docutils literal notranslate"><span class="pre">event_set</span></code>.
Raises a <code class="docutils literal notranslate"><span class="pre">ValueError</span></code> if <code class="docutils literal notranslate"><span class="pre">tool_id</span></code> is not in use.</li>
</ul>
<p>Local events add to global events, but do not mask them.
In other words, all global events will trigger for a code object,
regardless of the local events.</p>
</section>
<section id="register-callback-functions">
<h3><a class="toc-backref" href="#register-callback-functions" role="doc-backlink">Register callback functions</a></h3>
<p>To register a callable for events call:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">sys</span><span class="o">.</span><span class="n">monitoring</span><span class="o">.</span><span class="n">register_callback</span><span class="p">(</span><span class="n">tool_id</span><span class="p">:</span><span class="nb">int</span><span class="p">,</span> <span class="n">event</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">func</span><span class="p">:</span> <span class="n">Callable</span> <span class="o">|</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Callable</span> <span class="o">|</span> <span class="kc">None</span>
</pre></div>
</div>
<p>If another callback was registered for the given <code class="docutils literal notranslate"><span class="pre">tool_id</span></code> and <code class="docutils literal notranslate"><span class="pre">event</span></code>,
it is unregistered and returned.
Otherwise <code class="docutils literal notranslate"><span class="pre">register_callback</span></code> returns <code class="docutils literal notranslate"><span class="pre">None</span></code>.</p>
<p>Functions can be unregistered by calling
<code class="docutils literal notranslate"><span class="pre">sys.monitoring.register_callback(tool_id,</span> <span class="pre">event,</span> <span class="pre">None)</span></code>.</p>
<p>Callback functions can be registered and unregistered at any time.</p>
<p>Registering or unregistering a callback function will generate a <code class="docutils literal notranslate"><span class="pre">sys.audit</span></code> event.</p>
<section id="callback-function-arguments">
<h4><a class="toc-backref" href="#callback-function-arguments" role="doc-backlink">Callback function arguments</a></h4>
<p>When an active event occurs, the registered callback function is called.
Different events will provide the callback function with different arguments, as follows:</p>
<ul>
<li><code class="docutils literal notranslate"><span class="pre">PY_START</span></code> and <code class="docutils literal notranslate"><span class="pre">PY_RESUME</span></code>:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">func</span><span class="p">(</span><span class="n">code</span><span class="p">:</span> <span class="n">CodeType</span><span class="p">,</span> <span class="n">instruction_offset</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">DISABLE</span> <span class="o">|</span> <span class="n">Any</span>
</pre></div>
</div>
</li>
<li><code class="docutils literal notranslate"><span class="pre">PY_RETURN</span></code> and <code class="docutils literal notranslate"><span class="pre">PY_YIELD</span></code>:<blockquote>
<div><code class="docutils literal notranslate"><span class="pre">func(code:</span> <span class="pre">CodeType,</span> <span class="pre">instruction_offset:</span> <span class="pre">int,</span> <span class="pre">retval:</span> <span class="pre">object)</span> <span class="pre">-&gt;</span> <span class="pre">DISABLE</span> <span class="pre">|</span> <span class="pre">Any</span></code></div></blockquote>
</li>
<li><code class="docutils literal notranslate"><span class="pre">CALL</span></code>, <code class="docutils literal notranslate"><span class="pre">C_RAISE</span></code> and <code class="docutils literal notranslate"><span class="pre">C_RETURN</span></code>:<blockquote>
<div><code class="docutils literal notranslate"><span class="pre">func(code:</span> <span class="pre">CodeType,</span> <span class="pre">instruction_offset:</span> <span class="pre">int,</span> <span class="pre">callable:</span> <span class="pre">object,</span> <span class="pre">arg0:</span> <span class="pre">object</span> <span class="pre">|</span> <span class="pre">MISSING)</span> <span class="pre">-&gt;</span> <span class="pre">DISABLE</span> <span class="pre">|</span> <span class="pre">Any</span></code><p>If there are no arguments, <code class="docutils literal notranslate"><span class="pre">arg0</span></code> is set to <code class="docutils literal notranslate"><span class="pre">MISSING</span></code>.</p>
</div></blockquote>
</li>
<li><code class="docutils literal notranslate"><span class="pre">RAISE</span></code> and <code class="docutils literal notranslate"><span class="pre">EXCEPTION_HANDLED</span></code>:<blockquote>
<div><code class="docutils literal notranslate"><span class="pre">func(code:</span> <span class="pre">CodeType,</span> <span class="pre">instruction_offset:</span> <span class="pre">int,</span> <span class="pre">exception:</span> <span class="pre">BaseException)</span> <span class="pre">-&gt;</span> <span class="pre">DISABLE</span> <span class="pre">|</span> <span class="pre">Any</span></code></div></blockquote>
</li>
<li><code class="docutils literal notranslate"><span class="pre">LINE</span></code>:<blockquote>
<div><code class="docutils literal notranslate"><span class="pre">func(code:</span> <span class="pre">CodeType,</span> <span class="pre">line_number:</span> <span class="pre">int)</span> <span class="pre">-&gt;</span> <span class="pre">DISABLE</span> <span class="pre">|</span> <span class="pre">Any</span></code></div></blockquote>
</li>
<li><code class="docutils literal notranslate"><span class="pre">BRANCH</span></code>:<blockquote>
<div><code class="docutils literal notranslate"><span class="pre">func(code:</span> <span class="pre">CodeType,</span> <span class="pre">instruction_offset:</span> <span class="pre">int,</span> <span class="pre">destination_offset:</span> <span class="pre">int)</span> <span class="pre">-&gt;</span> <span class="pre">DISABLE</span> <span class="pre">|</span> <span class="pre">Any</span></code></div></blockquote>
<p>Note that the <code class="docutils literal notranslate"><span class="pre">destination_offset</span></code> is where the code will next execute.
For an untaken branch this will be the offset of the instruction following
the branch.</p>
</li>
<li><code class="docutils literal notranslate"><span class="pre">INSTRUCTION</span></code>:<blockquote>
<div><code class="docutils literal notranslate"><span class="pre">func(code:</span> <span class="pre">CodeType,</span> <span class="pre">instruction_offset:</span> <span class="pre">int)</span> <span class="pre">-&gt;</span> <span class="pre">DISABLE</span> <span class="pre">|</span> <span class="pre">Any</span></code></div></blockquote>
</li>
</ul>
<p>If a callback function returns <code class="docutils literal notranslate"><span class="pre">DISABLE</span></code>, then that function will no longer
be called for that <code class="docutils literal notranslate"><span class="pre">(code,</span> <span class="pre">instruction_offset)</span></code> until
<code class="docutils literal notranslate"><span class="pre">sys.monitoring.restart_events()</span></code> is called.
This feature is provided for coverage and other tools that are only interested
seeing an event once.</p>
<p>Note that <code class="docutils literal notranslate"><span class="pre">sys.monitoring.restart_events()</span></code> is not specific to one tool,
so tools must be prepared to receive events that they have chosen to DISABLE.</p>
</section>
</section>
<section id="events-in-callback-functions">
<h3><a class="toc-backref" href="#events-in-callback-functions" role="doc-backlink">Events in callback functions</a></h3>
<p>Events are suspended in callback functions and their callees for the tool
that registered that callback.</p>
<p>That means that other tools will see events in the callback functions for other
tools. This could be useful for debugging a profiling tool, but would produce
misleading profiles, as the debugger tool would show up in the profile.</p>
</section>
<section id="order-of-events">
<h3><a class="toc-backref" href="#order-of-events" role="doc-backlink">Order of events</a></h3>
<p>If an instructions triggers several events they occur in the following order:</p>
<ul class="simple">
<li>LINE</li>
<li>INSTRUCTION</li>
<li>All other events (only one of these events can occur per instruction)</li>
</ul>
<p>Each event is delivered to tools in ascending order of ID.</p>
</section>
<section id="the-call-event-group">
<h3><a class="toc-backref" href="#the-call-event-group" role="doc-backlink">The “call” event group</a></h3>
<p>Most events are independent; setting or disabling one event has no effect on the others.
However, the <code class="docutils literal notranslate"><span class="pre">CALL</span></code>, <code class="docutils literal notranslate"><span class="pre">C_RAISE</span></code> and <code class="docutils literal notranslate"><span class="pre">C_RETURN</span></code> events form a group.
If any of those events are set or disabled, then all events in the group are.
Disabling a <code class="docutils literal notranslate"><span class="pre">CALL</span></code> event will not disable the matching <code class="docutils literal notranslate"><span class="pre">C_RAISE</span></code> or <code class="docutils literal notranslate"><span class="pre">C_RETURN</span></code>,
but will disable all subsequent events.</p>
</section>
<section id="attributes-of-the-sys-monitoring-namespace">
<h3><a class="toc-backref" href="#attributes-of-the-sys-monitoring-namespace" role="doc-backlink">Attributes of the <code class="docutils literal notranslate"><span class="pre">sys.monitoring</span></code> namespace</a></h3>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">def</span> <span class="pre">use_tool_id(id)-&gt;None</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">def</span> <span class="pre">free_tool_id(id)-&gt;None</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">def</span> <span class="pre">get_events(tool_id:</span> <span class="pre">int)-&gt;int</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">def</span> <span class="pre">set_events(tool_id:</span> <span class="pre">int,</span> <span class="pre">event_set:</span> <span class="pre">int)-&gt;None</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">def</span> <span class="pre">get_local_events(tool_id:</span> <span class="pre">int,</span> <span class="pre">code:</span> <span class="pre">CodeType)-&gt;int</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">def</span> <span class="pre">set_local_events(tool_id:</span> <span class="pre">int,</span> <span class="pre">code:</span> <span class="pre">CodeType,</span> <span class="pre">event_set:</span> <span class="pre">int)-&gt;None</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">def</span> <span class="pre">register_callback(tool_id:</span> <span class="pre">int,</span> <span class="pre">event:</span> <span class="pre">int,</span> <span class="pre">func:</span> <span class="pre">Callable)-&gt;Optional[Callable]</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">def</span> <span class="pre">restart_events()-&gt;None</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">DISABLE:</span> <span class="pre">object</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">MISSING:</span> <span class="pre">object</span></code></li>
</ul>
</section>
<section id="access-to-debug-only-features">
<h3><a class="toc-backref" href="#access-to-debug-only-features" role="doc-backlink">Access to “debug only” features</a></h3>
<p>Some features of the standard library are not accessible to normal code,
but are accessible to debuggers. For example, setting local variables, or
the line number.</p>
<p>These features will be available to callback functions.</p>
</section>
</section>
<section id="backwards-compatibility">
<h2><a class="toc-backref" href="#backwards-compatibility" role="doc-backlink">Backwards Compatibility</a></h2>
<p>This PEP is mostly backwards compatible.</p>
<p>There are some compatibility issues with <a class="pep reference internal" href="../pep-0523/" title="PEP 523 Adding a frame evaluation API to CPython">PEP 523</a>, as the behavior
of <a class="pep reference internal" href="../pep-0523/" title="PEP 523 Adding a frame evaluation API to CPython">PEP 523</a> plugins is outside of the VMs control.
It is up to <a class="pep reference internal" href="../pep-0523/" title="PEP 523 Adding a frame evaluation API to CPython">PEP 523</a> plugins to ensure that they respect the semantics
of this PEP. Simple plugins that do not change the state of the VM, and
defer execution to <code class="docutils literal notranslate"><span class="pre">_PyEval_EvalFrameDefault()</span></code> should continue to work.</p>
<p><a class="reference external" href="https://docs.python.org/3/library/sys.html#sys.settrace" title="(in Python v3.12)"><code class="xref py py-func docutils literal notranslate"><span class="pre">sys.settrace()</span></code></a> and <a class="reference external" href="https://docs.python.org/3/library/sys.html#sys.setprofile" title="(in Python v3.12)"><code class="xref py py-func docutils literal notranslate"><span class="pre">sys.setprofile()</span></code></a> will act as if they were tools
6 and 7 respectively, so can be used alongside this PEP.</p>
<p>This means that <a class="reference external" href="https://docs.python.org/3/library/sys.html#sys.settrace" title="(in Python v3.12)"><code class="xref py py-func docutils literal notranslate"><span class="pre">sys.settrace()</span></code></a> and <a class="reference external" href="https://docs.python.org/3/library/sys.html#sys.setprofile" title="(in Python v3.12)"><code class="xref py py-func docutils literal notranslate"><span class="pre">sys.setprofile()</span></code></a> may not work
correctly with all <a class="pep reference internal" href="../pep-0523/" title="PEP 523 Adding a frame evaluation API to CPython">PEP 523</a> plugins. Although, simple <a class="pep reference internal" href="../pep-0523/" title="PEP 523 Adding a frame evaluation API to CPython">PEP 523</a>
plugins, as described above, should be fine.</p>
<section id="performance">
<h3><a class="toc-backref" href="#performance" role="doc-backlink">Performance</a></h3>
<p>If no events are active, this PEP should have a small positive impact on
performance. Experiments show between 1 and 2% speedup from not supporting
<a class="reference external" href="https://docs.python.org/3/library/sys.html#sys.settrace" title="(in Python v3.12)"><code class="xref py py-func docutils literal notranslate"><span class="pre">sys.settrace()</span></code></a> directly.</p>
<p>The performance of <a class="reference external" href="https://docs.python.org/3/library/sys.html#sys.settrace" title="(in Python v3.12)"><code class="xref py py-func docutils literal notranslate"><span class="pre">sys.settrace()</span></code></a> will be about the same.
The performance of <a class="reference external" href="https://docs.python.org/3/library/sys.html#sys.setprofile" title="(in Python v3.12)"><code class="xref py py-func docutils literal notranslate"><span class="pre">sys.setprofile()</span></code></a> should be better.
However, tools relying on <a class="reference external" href="https://docs.python.org/3/library/sys.html#sys.settrace" title="(in Python v3.12)"><code class="xref py py-func docutils literal notranslate"><span class="pre">sys.settrace()</span></code></a> and
<a class="reference external" href="https://docs.python.org/3/library/sys.html#sys.setprofile" title="(in Python v3.12)"><code class="xref py py-func docutils literal notranslate"><span class="pre">sys.setprofile()</span></code></a> can be made a lot faster by using the
API provided by this PEP.</p>
<p>If a small set of events are active, e.g. for a debugger, then the overhead
of callbacks will be orders of magnitudes less than for <a class="reference external" href="https://docs.python.org/3/library/sys.html#sys.settrace" title="(in Python v3.12)"><code class="xref py py-func docutils literal notranslate"><span class="pre">sys.settrace()</span></code></a>
and much cheaper than using <a class="pep reference internal" href="../pep-0523/" title="PEP 523 Adding a frame evaluation API to CPython">PEP 523</a>.</p>
<p>Coverage tools can be implemented at very low cost,
by returning <code class="docutils literal notranslate"><span class="pre">DISABLE</span></code> in all callbacks.</p>
<p>For heavily instrumented code, e.g. using <code class="docutils literal notranslate"><span class="pre">LINE</span></code>, performance should be
better than <code class="docutils literal notranslate"><span class="pre">sys.settrace</span></code>, but not by that much as performance will be
dominated by the time spent in callbacks.</p>
<p>For optimizing virtual machines, such as future versions of CPython
(and <code class="docutils literal notranslate"><span class="pre">PyPy</span></code> should they choose to support this API), changes to the set
active events in the midst of a long running program could be quite
expensive, possibly taking hundreds of milliseconds as it triggers
de-optimizations. Once such de-optimization has occurred, performance should
recover as the VM can re-optimize the instrumented code.</p>
<p>In general these operations can be considered to be fast:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">def</span> <span class="pre">get_events(tool_id:</span> <span class="pre">int)-&gt;int</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">def</span> <span class="pre">get_local_events(tool_id:</span> <span class="pre">int,</span> <span class="pre">code:</span> <span class="pre">CodeType)-&gt;int</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">def</span> <span class="pre">register_callback(tool_id:</span> <span class="pre">int,</span> <span class="pre">event:</span> <span class="pre">int,</span> <span class="pre">func:</span> <span class="pre">Callable)-&gt;Optional[Callable]</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">def</span> <span class="pre">get_tool(tool_id)</span> <span class="pre">-&gt;</span> <span class="pre">str</span> <span class="pre">|</span> <span class="pre">None</span></code></li>
</ul>
<p>These operations are slower, but not especially so:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">def</span> <span class="pre">set_local_events(tool_id:</span> <span class="pre">int,</span> <span class="pre">code:</span> <span class="pre">CodeType,</span> <span class="pre">event_set:</span> <span class="pre">int)-&gt;None</span></code></li>
</ul>
<p>And these operations should be regarded as slow:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">def</span> <span class="pre">use_tool_id(id,</span> <span class="pre">name:str)-&gt;None</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">def</span> <span class="pre">free_tool_id(id)-&gt;None</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">def</span> <span class="pre">set_events(tool_id:</span> <span class="pre">int,</span> <span class="pre">event_set:</span> <span class="pre">int)-&gt;None</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">def</span> <span class="pre">restart_events()-&gt;None</span></code></li>
</ul>
<p>How slow the slow operations are depends on when they happen.
If done early in the program, before modules are loaded,
they should be fairly inexpensive.</p>
<section id="memory-consumption">
<h4><a class="toc-backref" href="#memory-consumption" role="doc-backlink">Memory Consumption</a></h4>
<p>When not in use, this PEP will have a negligible change on memory consumption.</p>
<p>How memory is used is very much an implementation detail.
However, we expect that for 3.12 the additional memory consumption per
code object will be <strong>roughly</strong> as follows:</p>
<table class="docutils align-default">
<thead>
<tr class="row-odd"><th class="head" colspan="2"></th>
<th class="head" colspan="2">Events</th>
</tr>
<tr class="row-even"><th class="head">Tools</th>
<th class="head">Others</th>
<th class="head">LINE</th>
<th class="head">INSTRUCTION</th>
</tr>
</thead>
<tbody>
<tr class="row-odd"><td>One</td>
<td>None</td>
<td>≈40%</td>
<td>≈80%</td>
</tr>
<tr class="row-even"><td rowspan="2">Two or more</td>
<td rowspan="2">≈40%</td>
<td rowspan="2">≈120%</td>
<td rowspan="2">≈200%</td>
</tr>
<tr class="row-odd"></tr>
</tbody>
</table>
</section>
</section>
</section>
<section id="security-implications">
<h2><a class="toc-backref" href="#security-implications" role="doc-backlink">Security Implications</a></h2>
<p>Allowing modification of running code has some security implications,
but no more than the ability to generate and call new code.</p>
<p>All the new functions listed above will trigger audit hooks.</p>
</section>
<section id="implementation">
<h2><a class="toc-backref" href="#implementation" role="doc-backlink">Implementation</a></h2>
<p>This outlines the proposed implementation for CPython 3.12. The actual
implementation for later versions of CPython and other Python implementations
may differ considerably.</p>
<p>The proposed implementation of this PEP will be built on top of the quickening
step of CPython 3.11, as described in <a class="pep reference internal" href="../pep-0659/#quickening" title="PEP 659 Specializing Adaptive Interpreter § Quickening">PEP 659</a>.
Instrumentation works in much the same way as quickening, bytecodes are
replaced with instrumented ones as needed.</p>
<p>For example, if the <code class="docutils literal notranslate"><span class="pre">CALL</span></code> event is turned on,
then all call instructions will be
replaced with a <code class="docutils literal notranslate"><span class="pre">INSTRUMENTED_CALL</span></code> instruction.</p>
<p>Note that this will interfere with specialization, which will result in some
performance degradation in addition to the overhead of calling the
registered callable.</p>
<p>When the set of active events changes, the VM will immediately update
all code objects present on the call stack of any thread. It will also set in
place traps to ensure that all code objects are correctly instrumented when
called. Consequently changing the set of active events should be done as
infrequently as possible, as it could be quite an expensive operation.</p>
<p>Other events, such as <code class="docutils literal notranslate"><span class="pre">RAISE</span></code> can be turned on or off cheaply,
as they do not rely on code instrumentation, but runtime checks when the
underlying event occurs.</p>
<p>The exact set of events that require instrumentation is an implementation detail,
but for the current design, the following events will require instrumentation:</p>
<ul class="simple">
<li>PY_START</li>
<li>PY_RESUME</li>
<li>PY_RETURN</li>
<li>PY_YIELD</li>
<li>CALL</li>
<li>LINE</li>
<li>INSTRUCTION</li>
<li>JUMP</li>
<li>BRANCH</li>
</ul>
<p>Each instrumented bytecode will require an additional 8 bits of information to
note which tool the instrumentation applies to.
<code class="docutils literal notranslate"><span class="pre">LINE</span></code> and <code class="docutils literal notranslate"><span class="pre">INSTRUCTION</span></code> events require additional information, as they
need to store the original instruction, or even the instrumented instruction
if they overlap other instrumentation.</p>
</section>
<section id="implementing-tools">
<h2><a class="toc-backref" href="#implementing-tools" role="doc-backlink">Implementing tools</a></h2>
<p>It is the philosophy of this PEP that it should be possible for third-party monitoring
tools to achieve high-performance, not that it should be easy for them to do so.</p>
<p>Converting events into data that is meaningful to the users is
the responsibility of the tool.</p>
<p>All events have a cost, and tools should attempt to the use set of events
that trigger the least often and still provide the necessary information.</p>
<section id="debuggers">
<h3><a class="toc-backref" href="#debuggers" role="doc-backlink">Debuggers</a></h3>
<section id="inserting-breakpoints">
<h4><a class="toc-backref" href="#inserting-breakpoints" role="doc-backlink">Inserting breakpoints</a></h4>
<p>Breakpoints can be inserted setting per code object events, either <code class="docutils literal notranslate"><span class="pre">LINE</span></code> or <code class="docutils literal notranslate"><span class="pre">INSTRUCTION</span></code>,
and returning <code class="docutils literal notranslate"><span class="pre">DISABLE</span></code> for any events not matching a breakpoint.</p>
</section>
<section id="stepping">
<h4><a class="toc-backref" href="#stepping" role="doc-backlink">Stepping</a></h4>
<p>Debuggers usually offer the ability to step execution by a
single instruction or line.</p>
<p>Like breakpoints, stepping can be implemented by setting per code object events.
As soon as normal execution is to be resumed, the local events can be unset.</p>
</section>
<section id="attaching">
<h4><a class="toc-backref" href="#attaching" role="doc-backlink">Attaching</a></h4>
<p>Debuggers can use the <code class="docutils literal notranslate"><span class="pre">PY_START</span></code> and <code class="docutils literal notranslate"><span class="pre">PY_RESUME</span></code> events to be informed
when a code object is first encountered, so that any necessary breakpoints
can be inserted.</p>
</section>
</section>
<section id="coverage-tools">
<h3><a class="toc-backref" href="#coverage-tools" role="doc-backlink">Coverage Tools</a></h3>
<p>Coverage tools need to track which parts of the control graph have been
executed. To do this, they need to register for the <code class="docutils literal notranslate"><span class="pre">PY_</span></code> events,
plus <code class="docutils literal notranslate"><span class="pre">JUMP</span></code> and <code class="docutils literal notranslate"><span class="pre">BRANCH</span></code>.</p>
<p>This information can be then be converted back into a line based report
after execution has completed.</p>
</section>
<section id="profilers">
<h3><a class="toc-backref" href="#profilers" role="doc-backlink">Profilers</a></h3>
<p>Simple profilers need to gather information about calls.
To do this profilers should register for the following events:</p>
<ul class="simple">
<li>PY_START</li>
<li>PY_RESUME</li>
<li>PY_THROW</li>
<li>PY_RETURN</li>
<li>PY_YIELD</li>
<li>PY_UNWIND</li>
<li>CALL</li>
<li>C_RAISE</li>
<li>C_RETURN</li>
</ul>
<section id="line-based-profilers">
<h4><a class="toc-backref" href="#line-based-profilers" role="doc-backlink">Line based profilers</a></h4>
<p>Line based profilers can use the <code class="docutils literal notranslate"><span class="pre">LINE</span></code> and <code class="docutils literal notranslate"><span class="pre">JUMP</span></code> events.
Implementers of profilers should be aware that instrumenting <code class="docutils literal notranslate"><span class="pre">LINE</span></code>
events will have a large impact on performance.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Instrumenting profilers have significant overhead and will distort
the results of profiling. Unless you need exact call counts,
consider using a statistical profiler.</p>
</div>
</section>
</section>
</section>
<section id="rejected-ideas">
<h2><a class="toc-backref" href="#rejected-ideas" role="doc-backlink">Rejected ideas</a></h2>
<p>A draft version of this PEP proposed making the user responsible
for inserting the monitoring instructions, rather than have VM do it.
However, that puts too much of a burden on the tools, and would make
attaching a debugger nearly impossible.</p>
<p>An earlier version of this PEP, proposed storing events as <code class="docutils literal notranslate"><span class="pre">enums</span></code>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Event</span><span class="p">(</span><span class="n">enum</span><span class="o">.</span><span class="n">IntFlag</span><span class="p">):</span>
<span class="n">PY_START</span> <span class="o">=</span> <span class="o">...</span>
</pre></div>
</div>
<p>However, that would prevent monitoring of code before the <code class="docutils literal notranslate"><span class="pre">enum</span></code> module was
loaded and could cause unnecessary overhead.</p>
</section>
<section id="copyright">
<h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2>
<p>This document is placed in the public domain or under the
CC0-1.0-Universal license, whichever is more permissive.</p>
</section>
</section>
<hr class="docutils" />
<p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0669.rst">https://github.com/python/peps/blob/main/peps/pep-0669.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0669.rst">2024-02-07 11:51:52 GMT</a></p>
</article>
<nav id="pep-sidebar">
<h2>Contents</h2>
<ul>
<li><a class="reference internal" href="#abstract">Abstract</a></li>
<li><a class="reference internal" href="#motivation">Motivation</a></li>
<li><a class="reference internal" href="#rationale">Rationale</a></li>
<li><a class="reference internal" href="#specification">Specification</a><ul>
<li><a class="reference internal" href="#events">Events</a><ul>
<li><a class="reference internal" href="#local-events">Local events</a></li>
<li><a class="reference internal" href="#ancilliary-events">Ancilliary events</a></li>
<li><a class="reference internal" href="#other-events">Other events</a></li>
<li><a class="reference internal" href="#the-stop-iteration-event">The STOP_ITERATION event</a></li>
</ul>
</li>
<li><a class="reference internal" href="#tool-identifiers">Tool identifiers</a></li>
<li><a class="reference internal" href="#setting-events-globally">Setting events globally</a></li>
<li><a class="reference internal" href="#per-code-object-events">Per code object events</a></li>
<li><a class="reference internal" href="#register-callback-functions">Register callback functions</a><ul>
<li><a class="reference internal" href="#callback-function-arguments">Callback function arguments</a></li>
</ul>
</li>
<li><a class="reference internal" href="#events-in-callback-functions">Events in callback functions</a></li>
<li><a class="reference internal" href="#order-of-events">Order of events</a></li>
<li><a class="reference internal" href="#the-call-event-group">The “call” event group</a></li>
<li><a class="reference internal" href="#attributes-of-the-sys-monitoring-namespace">Attributes of the <code class="docutils literal notranslate"><span class="pre">sys.monitoring</span></code> namespace</a></li>
<li><a class="reference internal" href="#access-to-debug-only-features">Access to “debug only” features</a></li>
</ul>
</li>
<li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a><ul>
<li><a class="reference internal" href="#performance">Performance</a><ul>
<li><a class="reference internal" href="#memory-consumption">Memory Consumption</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#security-implications">Security Implications</a></li>
<li><a class="reference internal" href="#implementation">Implementation</a></li>
<li><a class="reference internal" href="#implementing-tools">Implementing tools</a><ul>
<li><a class="reference internal" href="#debuggers">Debuggers</a><ul>
<li><a class="reference internal" href="#inserting-breakpoints">Inserting breakpoints</a></li>
<li><a class="reference internal" href="#stepping">Stepping</a></li>
<li><a class="reference internal" href="#attaching">Attaching</a></li>
</ul>
</li>
<li><a class="reference internal" href="#coverage-tools">Coverage Tools</a></li>
<li><a class="reference internal" href="#profilers">Profilers</a><ul>
<li><a class="reference internal" href="#line-based-profilers">Line based profilers</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#rejected-ideas">Rejected ideas</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
<br>
<a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0669.rst">Page Source (GitHub)</a>
</nav>
</section>
<script src="../_static/colour_scheme.js"></script>
<script src="../_static/wrap_tables.js"></script>
<script src="../_static/sticky_banner.js"></script>
</body>
</html>