17db96d56Sopenharmony_ci.. highlight:: shell-session
27db96d56Sopenharmony_ci
37db96d56Sopenharmony_ci.. _instrumentation:
47db96d56Sopenharmony_ci
57db96d56Sopenharmony_ci===============================================
67db96d56Sopenharmony_ciInstrumenting CPython with DTrace and SystemTap
77db96d56Sopenharmony_ci===============================================
87db96d56Sopenharmony_ci
97db96d56Sopenharmony_ci:author: David Malcolm
107db96d56Sopenharmony_ci:author: Łukasz Langa
117db96d56Sopenharmony_ci
127db96d56Sopenharmony_ciDTrace and SystemTap are monitoring tools, each providing a way to inspect
137db96d56Sopenharmony_ciwhat the processes on a computer system are doing.  They both use
147db96d56Sopenharmony_cidomain-specific languages allowing a user to write scripts which:
157db96d56Sopenharmony_ci
167db96d56Sopenharmony_ci  - filter which processes are to be observed
177db96d56Sopenharmony_ci  - gather data from the processes of interest
187db96d56Sopenharmony_ci  - generate reports on the data
197db96d56Sopenharmony_ci
207db96d56Sopenharmony_ciAs of Python 3.6, CPython can be built with embedded "markers", also
217db96d56Sopenharmony_ciknown as "probes", that can be observed by a DTrace or SystemTap script,
227db96d56Sopenharmony_cimaking it easier to monitor what the CPython processes on a system are
237db96d56Sopenharmony_cidoing.
247db96d56Sopenharmony_ci
257db96d56Sopenharmony_ci.. impl-detail::
267db96d56Sopenharmony_ci
277db96d56Sopenharmony_ci   DTrace markers are implementation details of the CPython interpreter.
287db96d56Sopenharmony_ci   No guarantees are made about probe compatibility between versions of
297db96d56Sopenharmony_ci   CPython. DTrace scripts can stop working or work incorrectly without
307db96d56Sopenharmony_ci   warning when changing CPython versions.
317db96d56Sopenharmony_ci
327db96d56Sopenharmony_ci
337db96d56Sopenharmony_ciEnabling the static markers
347db96d56Sopenharmony_ci---------------------------
357db96d56Sopenharmony_ci
367db96d56Sopenharmony_cimacOS comes with built-in support for DTrace.  On Linux, in order to
377db96d56Sopenharmony_cibuild CPython with the embedded markers for SystemTap, the SystemTap
387db96d56Sopenharmony_cidevelopment tools must be installed.
397db96d56Sopenharmony_ci
407db96d56Sopenharmony_ciOn a Linux machine, this can be done via::
417db96d56Sopenharmony_ci
427db96d56Sopenharmony_ci   $ yum install systemtap-sdt-devel
437db96d56Sopenharmony_ci
447db96d56Sopenharmony_cior::
457db96d56Sopenharmony_ci
467db96d56Sopenharmony_ci   $ sudo apt-get install systemtap-sdt-dev
477db96d56Sopenharmony_ci
487db96d56Sopenharmony_ci
497db96d56Sopenharmony_ciCPython must then be :option:`configured with the --with-dtrace option
507db96d56Sopenharmony_ci<--with-dtrace>`:
517db96d56Sopenharmony_ci
527db96d56Sopenharmony_ci.. code-block:: none
537db96d56Sopenharmony_ci
547db96d56Sopenharmony_ci   checking for --with-dtrace... yes
557db96d56Sopenharmony_ci
567db96d56Sopenharmony_ciOn macOS, you can list available DTrace probes by running a Python
577db96d56Sopenharmony_ciprocess in the background and listing all probes made available by the
587db96d56Sopenharmony_ciPython provider::
597db96d56Sopenharmony_ci
607db96d56Sopenharmony_ci   $ python3.6 -q &
617db96d56Sopenharmony_ci   $ sudo dtrace -l -P python$!  # or: dtrace -l -m python3.6
627db96d56Sopenharmony_ci
637db96d56Sopenharmony_ci      ID   PROVIDER            MODULE                          FUNCTION NAME
647db96d56Sopenharmony_ci   29564 python18035        python3.6          _PyEval_EvalFrameDefault function-entry
657db96d56Sopenharmony_ci   29565 python18035        python3.6             dtrace_function_entry function-entry
667db96d56Sopenharmony_ci   29566 python18035        python3.6          _PyEval_EvalFrameDefault function-return
677db96d56Sopenharmony_ci   29567 python18035        python3.6            dtrace_function_return function-return
687db96d56Sopenharmony_ci   29568 python18035        python3.6                           collect gc-done
697db96d56Sopenharmony_ci   29569 python18035        python3.6                           collect gc-start
707db96d56Sopenharmony_ci   29570 python18035        python3.6          _PyEval_EvalFrameDefault line
717db96d56Sopenharmony_ci   29571 python18035        python3.6                 maybe_dtrace_line line
727db96d56Sopenharmony_ci
737db96d56Sopenharmony_ciOn Linux, you can verify if the SystemTap static markers are present in
747db96d56Sopenharmony_cithe built binary by seeing if it contains a ".note.stapsdt" section.
757db96d56Sopenharmony_ci
767db96d56Sopenharmony_ci::
777db96d56Sopenharmony_ci
787db96d56Sopenharmony_ci   $ readelf -S ./python | grep .note.stapsdt
797db96d56Sopenharmony_ci   [30] .note.stapsdt        NOTE         0000000000000000 00308d78
807db96d56Sopenharmony_ci
817db96d56Sopenharmony_ciIf you've built Python as a shared library
827db96d56Sopenharmony_ci(with the :option:`--enable-shared` configure option), you
837db96d56Sopenharmony_cineed to look instead within the shared library.  For example::
847db96d56Sopenharmony_ci
857db96d56Sopenharmony_ci   $ readelf -S libpython3.3dm.so.1.0 | grep .note.stapsdt
867db96d56Sopenharmony_ci   [29] .note.stapsdt        NOTE         0000000000000000 00365b68
877db96d56Sopenharmony_ci
887db96d56Sopenharmony_ciSufficiently modern readelf can print the metadata::
897db96d56Sopenharmony_ci
907db96d56Sopenharmony_ci    $ readelf -n ./python
917db96d56Sopenharmony_ci
927db96d56Sopenharmony_ci    Displaying notes found at file offset 0x00000254 with length 0x00000020:
937db96d56Sopenharmony_ci        Owner                 Data size          Description
947db96d56Sopenharmony_ci        GNU                  0x00000010          NT_GNU_ABI_TAG (ABI version tag)
957db96d56Sopenharmony_ci            OS: Linux, ABI: 2.6.32
967db96d56Sopenharmony_ci
977db96d56Sopenharmony_ci    Displaying notes found at file offset 0x00000274 with length 0x00000024:
987db96d56Sopenharmony_ci        Owner                 Data size          Description
997db96d56Sopenharmony_ci        GNU                  0x00000014          NT_GNU_BUILD_ID (unique build ID bitstring)
1007db96d56Sopenharmony_ci            Build ID: df924a2b08a7e89f6e11251d4602022977af2670
1017db96d56Sopenharmony_ci
1027db96d56Sopenharmony_ci    Displaying notes found at file offset 0x002d6c30 with length 0x00000144:
1037db96d56Sopenharmony_ci        Owner                 Data size          Description
1047db96d56Sopenharmony_ci        stapsdt              0x00000031          NT_STAPSDT (SystemTap probe descriptors)
1057db96d56Sopenharmony_ci            Provider: python
1067db96d56Sopenharmony_ci            Name: gc__start
1077db96d56Sopenharmony_ci            Location: 0x00000000004371c3, Base: 0x0000000000630ce2, Semaphore: 0x00000000008d6bf6
1087db96d56Sopenharmony_ci            Arguments: -4@%ebx
1097db96d56Sopenharmony_ci        stapsdt              0x00000030          NT_STAPSDT (SystemTap probe descriptors)
1107db96d56Sopenharmony_ci            Provider: python
1117db96d56Sopenharmony_ci            Name: gc__done
1127db96d56Sopenharmony_ci            Location: 0x00000000004374e1, Base: 0x0000000000630ce2, Semaphore: 0x00000000008d6bf8
1137db96d56Sopenharmony_ci            Arguments: -8@%rax
1147db96d56Sopenharmony_ci        stapsdt              0x00000045          NT_STAPSDT (SystemTap probe descriptors)
1157db96d56Sopenharmony_ci            Provider: python
1167db96d56Sopenharmony_ci            Name: function__entry
1177db96d56Sopenharmony_ci            Location: 0x000000000053db6c, Base: 0x0000000000630ce2, Semaphore: 0x00000000008d6be8
1187db96d56Sopenharmony_ci            Arguments: 8@%rbp 8@%r12 -4@%eax
1197db96d56Sopenharmony_ci        stapsdt              0x00000046          NT_STAPSDT (SystemTap probe descriptors)
1207db96d56Sopenharmony_ci            Provider: python
1217db96d56Sopenharmony_ci            Name: function__return
1227db96d56Sopenharmony_ci            Location: 0x000000000053dba8, Base: 0x0000000000630ce2, Semaphore: 0x00000000008d6bea
1237db96d56Sopenharmony_ci            Arguments: 8@%rbp 8@%r12 -4@%eax
1247db96d56Sopenharmony_ci
1257db96d56Sopenharmony_ciThe above metadata contains information for SystemTap describing how it
1267db96d56Sopenharmony_cican patch strategically placed machine code instructions to enable the
1277db96d56Sopenharmony_citracing hooks used by a SystemTap script.
1287db96d56Sopenharmony_ci
1297db96d56Sopenharmony_ci
1307db96d56Sopenharmony_ciStatic DTrace probes
1317db96d56Sopenharmony_ci--------------------
1327db96d56Sopenharmony_ci
1337db96d56Sopenharmony_ciThe following example DTrace script can be used to show the call/return
1347db96d56Sopenharmony_cihierarchy of a Python script, only tracing within the invocation of
1357db96d56Sopenharmony_cia function called "start". In other words, import-time function
1367db96d56Sopenharmony_ciinvocations are not going to be listed:
1377db96d56Sopenharmony_ci
1387db96d56Sopenharmony_ci.. code-block:: none
1397db96d56Sopenharmony_ci
1407db96d56Sopenharmony_ci    self int indent;
1417db96d56Sopenharmony_ci
1427db96d56Sopenharmony_ci    python$target:::function-entry
1437db96d56Sopenharmony_ci    /copyinstr(arg1) == "start"/
1447db96d56Sopenharmony_ci    {
1457db96d56Sopenharmony_ci            self->trace = 1;
1467db96d56Sopenharmony_ci    }
1477db96d56Sopenharmony_ci
1487db96d56Sopenharmony_ci    python$target:::function-entry
1497db96d56Sopenharmony_ci    /self->trace/
1507db96d56Sopenharmony_ci    {
1517db96d56Sopenharmony_ci            printf("%d\t%*s:", timestamp, 15, probename);
1527db96d56Sopenharmony_ci            printf("%*s", self->indent, "");
1537db96d56Sopenharmony_ci            printf("%s:%s:%d\n", basename(copyinstr(arg0)), copyinstr(arg1), arg2);
1547db96d56Sopenharmony_ci            self->indent++;
1557db96d56Sopenharmony_ci    }
1567db96d56Sopenharmony_ci
1577db96d56Sopenharmony_ci    python$target:::function-return
1587db96d56Sopenharmony_ci    /self->trace/
1597db96d56Sopenharmony_ci    {
1607db96d56Sopenharmony_ci            self->indent--;
1617db96d56Sopenharmony_ci            printf("%d\t%*s:", timestamp, 15, probename);
1627db96d56Sopenharmony_ci            printf("%*s", self->indent, "");
1637db96d56Sopenharmony_ci            printf("%s:%s:%d\n", basename(copyinstr(arg0)), copyinstr(arg1), arg2);
1647db96d56Sopenharmony_ci    }
1657db96d56Sopenharmony_ci
1667db96d56Sopenharmony_ci    python$target:::function-return
1677db96d56Sopenharmony_ci    /copyinstr(arg1) == "start"/
1687db96d56Sopenharmony_ci    {
1697db96d56Sopenharmony_ci            self->trace = 0;
1707db96d56Sopenharmony_ci    }
1717db96d56Sopenharmony_ci
1727db96d56Sopenharmony_ciIt can be invoked like this::
1737db96d56Sopenharmony_ci
1747db96d56Sopenharmony_ci  $ sudo dtrace -q -s call_stack.d -c "python3.6 script.py"
1757db96d56Sopenharmony_ci
1767db96d56Sopenharmony_ciThe output looks like this:
1777db96d56Sopenharmony_ci
1787db96d56Sopenharmony_ci.. code-block:: none
1797db96d56Sopenharmony_ci
1807db96d56Sopenharmony_ci    156641360502280  function-entry:call_stack.py:start:23
1817db96d56Sopenharmony_ci    156641360518804  function-entry: call_stack.py:function_1:1
1827db96d56Sopenharmony_ci    156641360532797  function-entry:  call_stack.py:function_3:9
1837db96d56Sopenharmony_ci    156641360546807 function-return:  call_stack.py:function_3:10
1847db96d56Sopenharmony_ci    156641360563367 function-return: call_stack.py:function_1:2
1857db96d56Sopenharmony_ci    156641360578365  function-entry: call_stack.py:function_2:5
1867db96d56Sopenharmony_ci    156641360591757  function-entry:  call_stack.py:function_1:1
1877db96d56Sopenharmony_ci    156641360605556  function-entry:   call_stack.py:function_3:9
1887db96d56Sopenharmony_ci    156641360617482 function-return:   call_stack.py:function_3:10
1897db96d56Sopenharmony_ci    156641360629814 function-return:  call_stack.py:function_1:2
1907db96d56Sopenharmony_ci    156641360642285 function-return: call_stack.py:function_2:6
1917db96d56Sopenharmony_ci    156641360656770  function-entry: call_stack.py:function_3:9
1927db96d56Sopenharmony_ci    156641360669707 function-return: call_stack.py:function_3:10
1937db96d56Sopenharmony_ci    156641360687853  function-entry: call_stack.py:function_4:13
1947db96d56Sopenharmony_ci    156641360700719 function-return: call_stack.py:function_4:14
1957db96d56Sopenharmony_ci    156641360719640  function-entry: call_stack.py:function_5:18
1967db96d56Sopenharmony_ci    156641360732567 function-return: call_stack.py:function_5:21
1977db96d56Sopenharmony_ci    156641360747370 function-return:call_stack.py:start:28
1987db96d56Sopenharmony_ci
1997db96d56Sopenharmony_ci
2007db96d56Sopenharmony_ciStatic SystemTap markers
2017db96d56Sopenharmony_ci------------------------
2027db96d56Sopenharmony_ci
2037db96d56Sopenharmony_ciThe low-level way to use the SystemTap integration is to use the static
2047db96d56Sopenharmony_cimarkers directly.  This requires you to explicitly state the binary file
2057db96d56Sopenharmony_cicontaining them.
2067db96d56Sopenharmony_ci
2077db96d56Sopenharmony_ciFor example, this SystemTap script can be used to show the call/return
2087db96d56Sopenharmony_cihierarchy of a Python script:
2097db96d56Sopenharmony_ci
2107db96d56Sopenharmony_ci.. code-block:: none
2117db96d56Sopenharmony_ci
2127db96d56Sopenharmony_ci   probe process("python").mark("function__entry") {
2137db96d56Sopenharmony_ci        filename = user_string($arg1);
2147db96d56Sopenharmony_ci        funcname = user_string($arg2);
2157db96d56Sopenharmony_ci        lineno = $arg3;
2167db96d56Sopenharmony_ci
2177db96d56Sopenharmony_ci        printf("%s => %s in %s:%d\\n",
2187db96d56Sopenharmony_ci               thread_indent(1), funcname, filename, lineno);
2197db96d56Sopenharmony_ci   }
2207db96d56Sopenharmony_ci
2217db96d56Sopenharmony_ci   probe process("python").mark("function__return") {
2227db96d56Sopenharmony_ci       filename = user_string($arg1);
2237db96d56Sopenharmony_ci       funcname = user_string($arg2);
2247db96d56Sopenharmony_ci       lineno = $arg3;
2257db96d56Sopenharmony_ci
2267db96d56Sopenharmony_ci       printf("%s <= %s in %s:%d\\n",
2277db96d56Sopenharmony_ci              thread_indent(-1), funcname, filename, lineno);
2287db96d56Sopenharmony_ci   }
2297db96d56Sopenharmony_ci
2307db96d56Sopenharmony_ciIt can be invoked like this::
2317db96d56Sopenharmony_ci
2327db96d56Sopenharmony_ci   $ stap \
2337db96d56Sopenharmony_ci     show-call-hierarchy.stp \
2347db96d56Sopenharmony_ci     -c "./python test.py"
2357db96d56Sopenharmony_ci
2367db96d56Sopenharmony_ciThe output looks like this:
2377db96d56Sopenharmony_ci
2387db96d56Sopenharmony_ci.. code-block:: none
2397db96d56Sopenharmony_ci
2407db96d56Sopenharmony_ci   11408 python(8274):        => __contains__ in Lib/_abcoll.py:362
2417db96d56Sopenharmony_ci   11414 python(8274):         => __getitem__ in Lib/os.py:425
2427db96d56Sopenharmony_ci   11418 python(8274):          => encode in Lib/os.py:490
2437db96d56Sopenharmony_ci   11424 python(8274):          <= encode in Lib/os.py:493
2447db96d56Sopenharmony_ci   11428 python(8274):         <= __getitem__ in Lib/os.py:426
2457db96d56Sopenharmony_ci   11433 python(8274):        <= __contains__ in Lib/_abcoll.py:366
2467db96d56Sopenharmony_ci
2477db96d56Sopenharmony_ciwhere the columns are:
2487db96d56Sopenharmony_ci
2497db96d56Sopenharmony_ci  - time in microseconds since start of script
2507db96d56Sopenharmony_ci
2517db96d56Sopenharmony_ci  - name of executable
2527db96d56Sopenharmony_ci
2537db96d56Sopenharmony_ci  - PID of process
2547db96d56Sopenharmony_ci
2557db96d56Sopenharmony_ciand the remainder indicates the call/return hierarchy as the script executes.
2567db96d56Sopenharmony_ci
2577db96d56Sopenharmony_ciFor a :option:`--enable-shared` build of CPython, the markers are contained within the
2587db96d56Sopenharmony_cilibpython shared library, and the probe's dotted path needs to reflect this. For
2597db96d56Sopenharmony_ciexample, this line from the above example:
2607db96d56Sopenharmony_ci
2617db96d56Sopenharmony_ci.. code-block:: none
2627db96d56Sopenharmony_ci
2637db96d56Sopenharmony_ci   probe process("python").mark("function__entry") {
2647db96d56Sopenharmony_ci
2657db96d56Sopenharmony_cishould instead read:
2667db96d56Sopenharmony_ci
2677db96d56Sopenharmony_ci.. code-block:: none
2687db96d56Sopenharmony_ci
2697db96d56Sopenharmony_ci   probe process("python").library("libpython3.6dm.so.1.0").mark("function__entry") {
2707db96d56Sopenharmony_ci
2717db96d56Sopenharmony_ci(assuming a :ref:`debug build <debug-build>` of CPython 3.6)
2727db96d56Sopenharmony_ci
2737db96d56Sopenharmony_ci
2747db96d56Sopenharmony_ciAvailable static markers
2757db96d56Sopenharmony_ci------------------------
2767db96d56Sopenharmony_ci
2777db96d56Sopenharmony_ci.. object:: function__entry(str filename, str funcname, int lineno)
2787db96d56Sopenharmony_ci
2797db96d56Sopenharmony_ci   This marker indicates that execution of a Python function has begun.
2807db96d56Sopenharmony_ci   It is only triggered for pure-Python (bytecode) functions.
2817db96d56Sopenharmony_ci
2827db96d56Sopenharmony_ci   The filename, function name, and line number are provided back to the
2837db96d56Sopenharmony_ci   tracing script as positional arguments, which must be accessed using
2847db96d56Sopenharmony_ci   ``$arg1``, ``$arg2``, ``$arg3``:
2857db96d56Sopenharmony_ci
2867db96d56Sopenharmony_ci       * ``$arg1`` : ``(const char *)`` filename, accessible using ``user_string($arg1)``
2877db96d56Sopenharmony_ci
2887db96d56Sopenharmony_ci       * ``$arg2`` : ``(const char *)`` function name, accessible using
2897db96d56Sopenharmony_ci         ``user_string($arg2)``
2907db96d56Sopenharmony_ci
2917db96d56Sopenharmony_ci       * ``$arg3`` : ``int`` line number
2927db96d56Sopenharmony_ci
2937db96d56Sopenharmony_ci.. object:: function__return(str filename, str funcname, int lineno)
2947db96d56Sopenharmony_ci
2957db96d56Sopenharmony_ci   This marker is the converse of :c:func:`function__entry`, and indicates that
2967db96d56Sopenharmony_ci   execution of a Python function has ended (either via ``return``, or via an
2977db96d56Sopenharmony_ci   exception).  It is only triggered for pure-Python (bytecode) functions.
2987db96d56Sopenharmony_ci
2997db96d56Sopenharmony_ci   The arguments are the same as for :c:func:`function__entry`
3007db96d56Sopenharmony_ci
3017db96d56Sopenharmony_ci.. object:: line(str filename, str funcname, int lineno)
3027db96d56Sopenharmony_ci
3037db96d56Sopenharmony_ci   This marker indicates a Python line is about to be executed.  It is
3047db96d56Sopenharmony_ci   the equivalent of line-by-line tracing with a Python profiler.  It is
3057db96d56Sopenharmony_ci   not triggered within C functions.
3067db96d56Sopenharmony_ci
3077db96d56Sopenharmony_ci   The arguments are the same as for :c:func:`function__entry`.
3087db96d56Sopenharmony_ci
3097db96d56Sopenharmony_ci.. object:: gc__start(int generation)
3107db96d56Sopenharmony_ci
3117db96d56Sopenharmony_ci   Fires when the Python interpreter starts a garbage collection cycle.
3127db96d56Sopenharmony_ci   ``arg0`` is the generation to scan, like :func:`gc.collect()`.
3137db96d56Sopenharmony_ci
3147db96d56Sopenharmony_ci.. object:: gc__done(long collected)
3157db96d56Sopenharmony_ci
3167db96d56Sopenharmony_ci   Fires when the Python interpreter finishes a garbage collection
3177db96d56Sopenharmony_ci   cycle. ``arg0`` is the number of collected objects.
3187db96d56Sopenharmony_ci
3197db96d56Sopenharmony_ci.. object:: import__find__load__start(str modulename)
3207db96d56Sopenharmony_ci
3217db96d56Sopenharmony_ci   Fires before :mod:`importlib` attempts to find and load the module.
3227db96d56Sopenharmony_ci   ``arg0`` is the module name.
3237db96d56Sopenharmony_ci
3247db96d56Sopenharmony_ci   .. versionadded:: 3.7
3257db96d56Sopenharmony_ci
3267db96d56Sopenharmony_ci.. object:: import__find__load__done(str modulename, int found)
3277db96d56Sopenharmony_ci
3287db96d56Sopenharmony_ci   Fires after :mod:`importlib`'s find_and_load function is called.
3297db96d56Sopenharmony_ci   ``arg0`` is the module name, ``arg1`` indicates if module was
3307db96d56Sopenharmony_ci   successfully loaded.
3317db96d56Sopenharmony_ci
3327db96d56Sopenharmony_ci   .. versionadded:: 3.7
3337db96d56Sopenharmony_ci
3347db96d56Sopenharmony_ci
3357db96d56Sopenharmony_ci.. object:: audit(str event, void *tuple)
3367db96d56Sopenharmony_ci
3377db96d56Sopenharmony_ci   Fires when :func:`sys.audit` or :c:func:`PySys_Audit` is called.
3387db96d56Sopenharmony_ci   ``arg0`` is the event name as C string, ``arg1`` is a :c:type:`PyObject`
3397db96d56Sopenharmony_ci   pointer to a tuple object.
3407db96d56Sopenharmony_ci
3417db96d56Sopenharmony_ci   .. versionadded:: 3.8
3427db96d56Sopenharmony_ci
3437db96d56Sopenharmony_ci
3447db96d56Sopenharmony_ciSystemTap Tapsets
3457db96d56Sopenharmony_ci-----------------
3467db96d56Sopenharmony_ci
3477db96d56Sopenharmony_ciThe higher-level way to use the SystemTap integration is to use a "tapset":
3487db96d56Sopenharmony_ciSystemTap's equivalent of a library, which hides some of the lower-level
3497db96d56Sopenharmony_cidetails of the static markers.
3507db96d56Sopenharmony_ci
3517db96d56Sopenharmony_ciHere is a tapset file, based on a non-shared build of CPython:
3527db96d56Sopenharmony_ci
3537db96d56Sopenharmony_ci.. code-block:: none
3547db96d56Sopenharmony_ci
3557db96d56Sopenharmony_ci    /*
3567db96d56Sopenharmony_ci       Provide a higher-level wrapping around the function__entry and
3577db96d56Sopenharmony_ci       function__return markers:
3587db96d56Sopenharmony_ci     \*/
3597db96d56Sopenharmony_ci    probe python.function.entry = process("python").mark("function__entry")
3607db96d56Sopenharmony_ci    {
3617db96d56Sopenharmony_ci        filename = user_string($arg1);
3627db96d56Sopenharmony_ci        funcname = user_string($arg2);
3637db96d56Sopenharmony_ci        lineno = $arg3;
3647db96d56Sopenharmony_ci        frameptr = $arg4
3657db96d56Sopenharmony_ci    }
3667db96d56Sopenharmony_ci    probe python.function.return = process("python").mark("function__return")
3677db96d56Sopenharmony_ci    {
3687db96d56Sopenharmony_ci        filename = user_string($arg1);
3697db96d56Sopenharmony_ci        funcname = user_string($arg2);
3707db96d56Sopenharmony_ci        lineno = $arg3;
3717db96d56Sopenharmony_ci        frameptr = $arg4
3727db96d56Sopenharmony_ci    }
3737db96d56Sopenharmony_ci
3747db96d56Sopenharmony_ciIf this file is installed in SystemTap's tapset directory (e.g.
3757db96d56Sopenharmony_ci``/usr/share/systemtap/tapset``), then these additional probepoints become
3767db96d56Sopenharmony_ciavailable:
3777db96d56Sopenharmony_ci
3787db96d56Sopenharmony_ci.. object:: python.function.entry(str filename, str funcname, int lineno, frameptr)
3797db96d56Sopenharmony_ci
3807db96d56Sopenharmony_ci   This probe point indicates that execution of a Python function has begun.
3817db96d56Sopenharmony_ci   It is only triggered for pure-Python (bytecode) functions.
3827db96d56Sopenharmony_ci
3837db96d56Sopenharmony_ci.. object:: python.function.return(str filename, str funcname, int lineno, frameptr)
3847db96d56Sopenharmony_ci
3857db96d56Sopenharmony_ci   This probe point is the converse of ``python.function.return``, and
3867db96d56Sopenharmony_ci   indicates that execution of a Python function has ended (either via
3877db96d56Sopenharmony_ci   ``return``, or via an exception).  It is only triggered for pure-Python
3887db96d56Sopenharmony_ci   (bytecode) functions.
3897db96d56Sopenharmony_ci
3907db96d56Sopenharmony_ci
3917db96d56Sopenharmony_ciExamples
3927db96d56Sopenharmony_ci--------
3937db96d56Sopenharmony_ciThis SystemTap script uses the tapset above to more cleanly implement the
3947db96d56Sopenharmony_ciexample given above of tracing the Python function-call hierarchy, without
3957db96d56Sopenharmony_cineeding to directly name the static markers:
3967db96d56Sopenharmony_ci
3977db96d56Sopenharmony_ci.. code-block:: none
3987db96d56Sopenharmony_ci
3997db96d56Sopenharmony_ci    probe python.function.entry
4007db96d56Sopenharmony_ci    {
4017db96d56Sopenharmony_ci      printf("%s => %s in %s:%d\n",
4027db96d56Sopenharmony_ci             thread_indent(1), funcname, filename, lineno);
4037db96d56Sopenharmony_ci    }
4047db96d56Sopenharmony_ci
4057db96d56Sopenharmony_ci    probe python.function.return
4067db96d56Sopenharmony_ci    {
4077db96d56Sopenharmony_ci      printf("%s <= %s in %s:%d\n",
4087db96d56Sopenharmony_ci             thread_indent(-1), funcname, filename, lineno);
4097db96d56Sopenharmony_ci    }
4107db96d56Sopenharmony_ci
4117db96d56Sopenharmony_ci
4127db96d56Sopenharmony_ciThe following script uses the tapset above to provide a top-like view of all
4137db96d56Sopenharmony_cirunning CPython code, showing the top 20 most frequently entered bytecode
4147db96d56Sopenharmony_ciframes, each second, across the whole system:
4157db96d56Sopenharmony_ci
4167db96d56Sopenharmony_ci.. code-block:: none
4177db96d56Sopenharmony_ci
4187db96d56Sopenharmony_ci    global fn_calls;
4197db96d56Sopenharmony_ci
4207db96d56Sopenharmony_ci    probe python.function.entry
4217db96d56Sopenharmony_ci    {
4227db96d56Sopenharmony_ci        fn_calls[pid(), filename, funcname, lineno] += 1;
4237db96d56Sopenharmony_ci    }
4247db96d56Sopenharmony_ci
4257db96d56Sopenharmony_ci    probe timer.ms(1000) {
4267db96d56Sopenharmony_ci        printf("\033[2J\033[1;1H") /* clear screen \*/
4277db96d56Sopenharmony_ci        printf("%6s %80s %6s %30s %6s\n",
4287db96d56Sopenharmony_ci               "PID", "FILENAME", "LINE", "FUNCTION", "CALLS")
4297db96d56Sopenharmony_ci        foreach ([pid, filename, funcname, lineno] in fn_calls- limit 20) {
4307db96d56Sopenharmony_ci            printf("%6d %80s %6d %30s %6d\n",
4317db96d56Sopenharmony_ci                pid, filename, lineno, funcname,
4327db96d56Sopenharmony_ci                fn_calls[pid, filename, funcname, lineno]);
4337db96d56Sopenharmony_ci        }
4347db96d56Sopenharmony_ci        delete fn_calls;
4357db96d56Sopenharmony_ci    }
4367db96d56Sopenharmony_ci
437