From 8dd402b7a92004794f7c65035b876b4c1816b3de Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 10 Aug 2020 14:33:33 +0100 Subject: [PATCH] PEP 626:Guarantee stability of line table during release and define API for out-of-process tools. (#1555) * Guarantee stability of line table during release and implement API for out-of-process tools. --- pep-0626.rst | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/pep-0626.rst b/pep-0626.rst index cf5f052fc..27e3d3070 100644 --- a/pep-0626.rst +++ b/pep-0626.rst @@ -183,6 +183,57 @@ Access to the ``f_lineno`` attribute of frame objects through C API functions is Accessing ``f_lineno`` directly through the underlying data structure is forbidden. +Out of process debuggers and profilers +'''''''''''''''''''''''''''''''''''''' + +Out of process tools, such as py-spy [1]_, cannot use the C-API, and must parse the line number table themselves. +Although the line number table format may change without warning, +it will not change during a release unless absolutely necessary for a bug fix. + +To reduce the work required to implement these tools, the following C struct and utility functions are provided. +Note that these functions are not part of the C-API, so will be need to be linked into any code that needs to use them. + +:: + + typedef struct addressrange { + int ar_start; + int ar_end; + int ar_line; + int opaque1; + void *opaque2; + } PyCodeAddressRange; + + void PyLineTable_InitAddressRange(char *linetable, int firstlineno, PyCodeAddressRange *range); + int PyLineTable_NextAddressRange(PyCodeAddressRange *range); + int PyLineTable_PreviousAddressRange(PyCodeAddressRange *range); + +``PyLineTable_InitAddressRange`` initializes the ``PyCodeAddressRange`` struct from the line number table and first line number. + +``PyLineTable_NextAddressRange`` advances the range to the next entry, returning non-zero if valid. + +``PyLineTable_PreviousAddressRange`` retreats the range to the previous entry, returning non-zero if valid. + +For example, the following code prints out all the address ranges: + +:: + + void print_address_ranges(char *linetable, int firstlineno) + { + PyCodeAddressRange range; + PyLineTable_InitAddressRange(linetable, firstlineno, &range); + while (PyLineTable_NextAddressRange(&range)) { + printf("Bytecodes from %d (inclusive) to %d (exclusive) ", + range.start, range.end); + if (range.line < 0) { + /* line < 0 means no line number */ + printf("have no line number\n"); + } + else { + printf("have line number %d\n", range.line); + } + } + } + Performance Implications ======================== @@ -194,7 +245,7 @@ Code with long sequences of ``pass`` statements will probably become a bit slowe Reference Implementation ======================== -Under development. +https://github.com/markshannon/cpython/tree/new-linetable-format-version-2 Copyright ========= @@ -202,6 +253,12 @@ Copyright This document is placed in the public domain or under the CC0-1.0-Universal license, whichever is more permissive. +References +========== + +.. [1] py-spy: Sampling profiler for Python programs + (https://github.com/benfred/py-spy) + ..