Skip to content

Commit 8b515f6

Browse files
authored
GH-103082: Document PEP-669: Low Impact Monitoring for CPython (GH-107772)
1 parent b4c8cce commit 8b515f6

File tree

4 files changed

+323
-0
lines changed

4 files changed

+323
-0
lines changed

Doc/library/python.rst

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ overview:
1212
.. toctree::
1313

1414
sys.rst
15+
sys.monitoring.rst
1516
sysconfig.rst
1617
builtins.rst
1718
__main__.rst

Doc/library/sys.monitoring.rst

+300
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,300 @@
1+
:mod:`sys.monitoring` --- Execution event monitoring
2+
====================================================
3+
4+
.. module:: sys.monitoring
5+
:synopsis: Access and control event monitoring
6+
7+
-----------------
8+
9+
.. note::
10+
11+
``sys.monitoring`` is a namespace within the ``sys`` module,
12+
not an independent module, so there is no need to
13+
``import sys.monitoring``, simply ``import sys`` and then use
14+
``sys.monitoring``.
15+
16+
17+
This namespace provides access to the functions and constants necessary to
18+
activate and control event monitoring.
19+
20+
As programs execute, events occur that might be of interest to tools that
21+
monitor execution. The :mod:`!sys.monitoring` namespace provides means to
22+
receive callbacks when events of interest occur.
23+
24+
The monitoring API consists of three components:
25+
26+
* Tool identifiers
27+
* Events
28+
* Callbacks
29+
30+
Tool identifiers
31+
----------------
32+
33+
A tool identifier is an integer and associated name.
34+
Tool identifiers are used to discourage tools from interfering with each
35+
other and to allow multiple tools to operate at the same time.
36+
Currently tools are completely independent and cannot be used to
37+
monitor each other. This restriction may be lifted in the future.
38+
39+
Before registering or activating events, a tool should choose an identifier.
40+
Identifiers are integers in the range 0 to 5.
41+
42+
Registering and using tools
43+
'''''''''''''''''''''''''''
44+
45+
.. function:: use_tool_id(id: int, name: str) -> None
46+
47+
Must be called before ``id`` can be used.
48+
``id`` must be in the range 0 to 5 inclusive.
49+
Raises a ``ValueError`` if ``id`` is in use.
50+
51+
.. function:: free_tool_id(id: int) -> None
52+
53+
Should be called once a tool no longer requires ``id``.
54+
55+
.. function:: get_tool(id: int) -> str | None
56+
57+
Returns the name of the tool if ``id`` is in use,
58+
otherwise it returns ``None``.
59+
``id`` must be in the range 0 to 5 inclusive.
60+
61+
All IDs are treated the same by the VM with regard to events, but the
62+
following IDs are pre-defined to make co-operation of tools easier::
63+
64+
sys.monitoring.DEBUGGER_ID = 0
65+
sys.monitoring.COVERAGE_ID = 1
66+
sys.monitoring.PROFILER_ID = 2
67+
sys.monitoring.OPTIMIZER_ID = 5
68+
69+
There is no obligation to set an ID, nor is there anything preventing a tool
70+
from using an ID even it is already in use.
71+
However, tools are encouraged to use a unique ID and respect other tools.
72+
73+
Events
74+
------
75+
76+
The following events are supported:
77+
78+
BRANCH
79+
A conditional branch is taken (or not).
80+
CALL
81+
A call in Python code (event occurs before the call).
82+
C_RAISE
83+
Exception raised from any callable, except Python functions (event occurs after the exit).
84+
C_RETURN
85+
Return from any callable, except Python functions (event occurs after the return).
86+
EXCEPTION_HANDLED
87+
An exception is handled.
88+
INSTRUCTION
89+
A VM instruction is about to be executed.
90+
JUMP
91+
An unconditional jump in the control flow graph is made.
92+
LINE
93+
An instruction is about to be executed that has a different line number from the preceding instruction.
94+
PY_RESUME
95+
Resumption of a Python function (for generator and coroutine functions), except for throw() calls.
96+
PY_RETURN
97+
Return from a Python function (occurs immediately before the return, the callee's frame will be on the stack).
98+
PY_START
99+
Start of a Python function (occurs immediately after the call, the callee's frame will be on the stack)
100+
PY_THROW
101+
A Python function is resumed by a throw() call.
102+
PY_UNWIND
103+
Exit from a Python function during exception unwinding.
104+
PY_YIELD
105+
Yield from a Python function (occurs immediately before the yield, the callee's frame will be on the stack).
106+
RAISE
107+
An exception is raised, except those that cause a ``STOP_ITERATION`` event.
108+
RERAISE
109+
An exception is re-raised, for example at the end of a ``finally`` block.
110+
STOP_ITERATION
111+
An artificial ``StopIteration`` is raised; see `the STOP_ITERATION event`_.
112+
113+
More events may be added in the future.
114+
115+
These events are attributes of the :mod:`!sys.monitoring.events` namespace.
116+
Each event is represented as a power-of-2 integer constant.
117+
To define a set of events, simply bitwise or the individual events together.
118+
For example, to specify both ``PY_RETURN`` and ``PY_START`` events, use the
119+
expression ``PY_RETURN | PY_START``.
120+
121+
Events are divided into three groups:
122+
123+
Local events
124+
''''''''''''
125+
126+
Local events are associated with normal execution of the program and happen
127+
at clearly defined locations. All local events can be disabled.
128+
The local events are:
129+
130+
* PY_START
131+
* PY_RESUME
132+
* PY_RETURN
133+
* PY_YIELD
134+
* CALL
135+
* LINE
136+
* INSTRUCTION
137+
* JUMP
138+
* BRANCH
139+
* STOP_ITERATION
140+
141+
Ancillary events
142+
''''''''''''''''
143+
144+
Ancillary events can be monitored like other events, but are controlled
145+
by another event:
146+
147+
* C_RAISE
148+
* C_RETURN
149+
150+
The ``C_RETURN`` and ``C_RAISE`` events are are controlled by the ``CALL``
151+
event. ``C_RETURN`` and ``C_RAISE`` events will only be seen if the
152+
corresponding ``CALL`` event is being monitored.
153+
154+
Other events
155+
''''''''''''
156+
157+
Other events are not necessarily tied to a specific location in the
158+
program and cannot be individually disabled.
159+
160+
The other events that can be monitored are:
161+
162+
* PY_THROW
163+
* PY_UNWIND
164+
* RAISE
165+
* EXCEPTION_HANDLED
166+
167+
168+
The STOP_ITERATION event
169+
''''''''''''''''''''''''
170+
171+
:pep:`PEP 380 <380#use-of-stopiteration-to-return-values>`
172+
specifies that a ``StopIteration`` exception is raised when returning a value
173+
from a generator or coroutine. However, this is a very inefficient way to
174+
return a value, so some Python implementations, notably CPython 3.12+, do not
175+
raise an exception unless it would be visible to other code.
176+
177+
To allow tools to monitor for real exceptions without slowing down generators
178+
and coroutines, the ``STOP_ITERATION`` event is provided.
179+
``STOP_ITERATION`` can be locally disabled, unlike ``RAISE``.
180+
181+
182+
Turning events on and off
183+
-------------------------
184+
185+
In order to monitor an event, it must be turned on and a callback registered.
186+
Events can be turned on or off by setting the events either globally or
187+
for a particular code object.
188+
189+
190+
Setting events globally
191+
'''''''''''''''''''''''
192+
193+
Events can be controlled globally by modifying the set of events being monitored.
194+
195+
.. function:: get_events(tool_id: int) -> int
196+
197+
Returns the ``int`` representing all the active events.
198+
199+
.. function:: set_events(tool_id: int, event_set: int)
200+
201+
Activates all events which are set in ``event_set``.
202+
Raises a ``ValueError`` if ``tool_id`` is not in use.
203+
204+
No events are active by default.
205+
206+
Per code object events
207+
''''''''''''''''''''''
208+
209+
Events can also be controlled on a per code object basis.
210+
211+
.. function:: get_local_events(tool_id: int, code: CodeType) -> int
212+
213+
Returns all the local events for ``code``
214+
215+
.. function:: set_local_events(tool_id: int, code: CodeType, event_set: int)
216+
217+
Activates all the local events for ``code`` which are set in ``event_set``.
218+
Raises a ``ValueError`` if ``tool_id`` is not in use.
219+
220+
Local events add to global events, but do not mask them.
221+
In other words, all global events will trigger for a code object,
222+
regardless of the local events.
223+
224+
225+
Disabling events
226+
''''''''''''''''
227+
228+
Local events can be disabled for a specific code location by returning
229+
``sys.monitoring.DISABLE`` from a callback function. This does not change
230+
which events are set, or any other code locations for the same event.
231+
232+
Disabling events for specific locations is very important for high
233+
performance monitoring. For example, a program can be run under a
234+
debugger with no overhead if the debugger disables all monitoring
235+
except for a few breakpoints.
236+
237+
238+
Registering callback functions
239+
------------------------------
240+
241+
To register a callable for events call
242+
243+
.. function:: register_callback(tool_id: int, event: int, func: Callable | None) -> Callable | None
244+
245+
Registers the callable ``func`` for the ``event`` with the given ``tool_id``
246+
247+
If another callback was registered for the given ``tool_id`` and ``event``,
248+
it is unregistered and returned.
249+
Otherwise ``register_callback`` returns ``None``.
250+
251+
252+
Functions can be unregistered by calling
253+
``sys.monitoring.register_callback(tool_id, event, None)``.
254+
255+
Callback functions can be registered and unregistered at any time.
256+
257+
Registering or unregistering a callback function will generate a ``sys.audit`` event.
258+
259+
260+
Callback function arguments
261+
'''''''''''''''''''''''''''
262+
263+
When an active event occurs, the registered callback function is called.
264+
Different events will provide the callback function with different arguments, as follows:
265+
266+
* ``PY_START`` and ``PY_RESUME``::
267+
268+
func(code: CodeType, instruction_offset: int) -> DISABLE | Any
269+
270+
* ``PY_RETURN`` and ``PY_YIELD``:
271+
272+
``func(code: CodeType, instruction_offset: int, retval: object) -> DISABLE | Any``
273+
274+
* ``CALL``, ``C_RAISE`` and ``C_RETURN``:
275+
276+
``func(code: CodeType, instruction_offset: int, callable: object, arg0: object | MISSING) -> DISABLE | Any``
277+
278+
If there are no arguments, ``arg0`` is set to ``MISSING``.
279+
280+
* ``RAISE``, ``RERAISE``, ``EXCEPTION_HANDLED``, ``PY_UNWIND``, ``PY_THROW`` and ``STOP_ITERATION``:
281+
282+
``func(code: CodeType, instruction_offset: int, exception: BaseException) -> DISABLE | Any``
283+
284+
* ``LINE``:
285+
286+
``func(code: CodeType, line_number: int) -> DISABLE | Any``
287+
288+
* ``BRANCH`` and ``JUMP``:
289+
290+
``func(code: CodeType, instruction_offset: int, destination_offset: int) -> DISABLE | Any``
291+
292+
Note that the ``destination_offset`` is where the code will next execute.
293+
For an untaken branch this will be the offset of the instruction following
294+
the branch.
295+
296+
* ``INSTRUCTION``:
297+
298+
``func(code: CodeType, instruction_offset: int) -> DISABLE | Any``
299+
300+

Doc/library/sys.rst

+7
Original file line numberDiff line numberDiff line change
@@ -1953,6 +1953,13 @@ always available.
19531953
.. availability:: Windows.
19541954

19551955

1956+
.. data:: monitoring
1957+
:noindex:
1958+
1959+
Namespace containing functions and constants for register callbacks
1960+
and controlling monitoring events.
1961+
See :mod:`sys.monitoring` for details.
1962+
19561963
.. data:: _xoptions
19571964

19581965
A dictionary of the various implementation-specific flags passed through

Doc/whatsnew/3.12.rst

+15
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ Interpreter improvements:
7373

7474
* :ref:`whatsnew312-pep684`
7575

76+
* :ref:`whatsnew312-pep669`
77+
7678
New typing features:
7779

7880
* :ref:`whatsnew312-pep688`
@@ -312,6 +314,19 @@ A Python API is anticipated for 3.13. (See :pep:`554`.)
312314

313315
(Contributed by Eric Snow in :gh:`104210`, etc.)
314316

317+
.. _whatsnew312-pep669:
318+
319+
PEP 669: Low impact monitoring for CPython
320+
------------------------------------------
321+
322+
CPython 3.12 now supports the ability to monitor calls,
323+
returns, lines, exceptions and other events using instrumentation.
324+
This means that you only pay for what you use, providing support
325+
for near-zero overhead debuggers and coverage tools.
326+
327+
See :mod:`sys.monitoring` for details.
328+
329+
315330
New Features Related to Type Hints
316331
==================================
317332

0 commit comments

Comments
 (0)