| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -8,10 +8,11 @@ Python support for the Linux ``perf`` profiler | |||
| 8 | 8 | ||
| 9 | 9 | :author: Pablo Galindo | |
| 10 | 10 | ||
| 11 | - The Linux ``perf`` profiler is a very powerful tool that allows you to profile and | ||
| 12 | - obtain information about the performance of your application. ``perf`` also has | ||
| 13 | - a very vibrant ecosystem of tools that aid with the analysis of the data that it | ||
| 14 | - produces. | ||
| 11 | + `The Linux perf profiler <https://perf.wiki.kernel.org>`_ | ||
| 12 | + is a very powerful tool that allows you to profile and obtain | ||
| 13 | + information about the performance of your application. | ||
| 14 | + ``perf`` also has a very vibrant ecosystem of tools | ||
| 15 | + that aid with the analysis of the data that it produces. | ||
| 15 | 16 | ||
| 16 | 17 | The main problem with using the ``perf`` profiler with Python applications is that | |
| 17 | 18 | ``perf`` only allows to get information about native symbols, this is, the names of | |
@@ -25,7 +26,7 @@ fly before the execution of every Python function and it will teach ``perf`` the | |||
| 25 | 26 | relationship between this piece of code and the associated Python function using | |
| 26 | 27 | `perf map files`_. | |
| 27 | 28 | ||
| 28 | - .. warning:: | ||
| 29 | + .. note:: | ||
| 29 | 30 | ||
| 30 | 31 | Support for the ``perf`` profiler is only currently available for Linux on | |
| 31 | 32 | selected architectures. Check the output of the configure build step or | |
@@ -51,11 +52,11 @@ For example, consider the following script: | |||
| 51 | 52 | if __name__ == "__main__": | |
| 52 | 53 | baz(1000000) | |
| 53 | 54 | ||
| 54 | - We can run perf to sample CPU stack traces at 9999 Hertz: | ||
| 55 | + We can run ``perf`` to sample CPU stack traces at 9999 Hertz:: | ||
| 55 | 56 | ||
| 56 | 57 | $ perf record -F 9999 -g -o perf.data python my_script.py | |
| 57 | 58 | ||
| 58 | - Then we can use perf report to analyze the data: | ||
| 59 | + Then we can use ``perf`` report to analyze the data: | ||
| 59 | 60 | ||
| 60 | 61 | .. code-block:: shell-session | |
| 61 | 62 | ||
@@ -101,7 +102,7 @@ As you can see here, the Python functions are not shown in the output, only ``_P | |||
| 101 | 102 | functions use the same C function to evaluate bytecode so we cannot know which Python function corresponds to which | |
| 102 | 103 | bytecode-evaluating function. | |
| 103 | 104 | ||
| 104 | - Instead, if we run the same experiment with perf support activated we get: | ||
| 105 | + Instead, if we run the same experiment with ``perf`` support enabled we get: | ||
| 105 | 106 | ||
| 106 | 107 | .. code-block:: shell-session | |
| 107 | 108 | ||
@@ -147,52 +148,58 @@ Instead, if we run the same experiment with perf support activated we get: | |||
| 147 | 148 | ||
| 148 | 149 | ||
| 149 | 150 | ||
| 150 | - Enabling perf profiling mode | ||
| 151 | - ---------------------------- | ||
| 151 | + How to enable ``perf`` profiling support | ||
| 152 | + ---------------------------------------- | ||
| 152 | 153 | ||
| 153 | - There are two main ways to activate the perf profiling mode. If you want it to be | ||
| 154 | - active since the start of the Python interpreter, you can use the ``-Xperf`` option: | ||
| 154 | + ``perf`` profiling support can either be enabled from the start using | ||
| 155 | + the environment variable :envvar:`PYTHONPERFSUPPORT` or the | ||
| 156 | + :option:`-X perf <-X>` option, | ||
| 157 | + or dynamically using :func:`sys.activate_stack_trampoline` and | ||
| 158 | + :func:`sys.deactivate_stack_trampoline`. | ||
| 155 | 159 | ||
| 156 | - $ python -Xperf my_script.py | ||
| 160 | + The :mod:`!sys` functions take precedence over the :option:`!-X` option, | ||
| 161 | + the :option:`!-X` option takes precedence over the environment variable. | ||
| 157 | 162 | ||
| 158 | - You can also set the :envvar:`PYTHONPERFSUPPORT` to a nonzero value to actiavate perf | ||
| 159 | - profiling mode globally. | ||
| 163 | + Example, using the environment variable:: | ||
| 160 | 164 | ||
| 161 | - There is also support for dynamically activating and deactivating the perf | ||
| 162 | - profiling mode by using the APIs in the :mod:`sys` module: | ||
| 165 | + $ PYTHONPERFSUPPORT=1 | ||
| 166 | + $ python script.py | ||
| 167 | + $ perf report -g -i perf.data | ||
| 163 | 168 | ||
| 164 | - .. code-block:: python | ||
| 165 | - | ||
| 166 | - import sys | ||
| 167 | - sys.activate_stack_trampoline("perf") | ||
| 169 | + Example, using the :option:`!-X` option:: | ||
| 168 | 170 | ||
| 169 | - # Run some code with Perf profiling active | ||
| 171 | + $ python -X perf script.py | ||
| 172 | + $ perf report -g -i perf.data | ||
| 170 | 173 | ||
| 171 | - sys.deactivate_stack_trampoline() | ||
| 174 | + Example, using the :mod:`sys` APIs in file :file:`example.py`: | ||
| 172 | 175 | ||
| 173 | - # Perf profiling is not active anymore | ||
| 176 | + .. code-block:: python | ||
| 174 | 177 | ||
| 175 | - These APIs can be handy if you want to activate/deactivate profiling mode in | ||
| 176 | - response to a signal or other communication mechanism with your process. | ||
| 178 | + import sys | ||
| 177 | 179 | ||
| 180 | + sys.activate_stack_trampoline("perf") | ||
| 181 | + do_profiled_stuff() | ||
| 182 | + sys.deactivate_stack_trampoline() | ||
| 178 | 183 | ||
| 184 | + non_profiled_stuff() | ||
| 179 | 185 | ||
| 180 | - Now we can analyze the data with ``perf report``: | ||
| 186 | + ...then:: | ||
| 181 | 187 | ||
| 182 | - $ perf report -g -i perf.data | ||
| 188 | + $ python ./example.py | ||
| 189 | + $ perf report -g -i perf.data | ||
| 183 | 190 | ||
| 184 | 191 | ||
| 185 | 192 | How to obtain the best results | |
| 186 | - ------------------------------- | ||
| 193 | + ------------------------------ | ||
| 187 | 194 | ||
| 188 | 195 | For the best results, Python should be compiled with | |
| 189 | 196 | ``CFLAGS="-fno-omit-frame-pointer -mno-omit-leaf-frame-pointer"`` as this allows | |
| 190 | 197 | profilers to unwind using only the frame pointer and not on DWARF debug | |
| 191 | - information. This is because as the code that is interposed to allow perf | ||
| 198 | + information. This is because as the code that is interposed to allow ``perf`` | ||
| 192 | 199 | support is dynamically generated it doesn't have any DWARF debugging information | |
| 193 | 200 | available. | |
| 194 | 201 | ||
| 195 | - You can check if you system has been compiled with this flag by running: | ||
| 202 | + You can check if your system has been compiled with this flag by running:: | ||
| 196 | 203 | ||
| 197 | 204 | $ python -m sysconfig | grep 'no-omit-frame-pointer' | |
| 198 | 205 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1555,6 +1555,38 @@ always available. | |||
| 1555 | 1555 | This function has been added on a provisional basis (see :pep:`411` | |
| 1556 | 1556 | for details.) Use it only for debugging purposes. | |
| 1557 | 1557 | ||
| 1558 | + .. function:: activate_stack_trampoline(backend, /) | ||
| 1559 | + | ||
| 1560 | + Activate the stack profiler trampoline *backend*. | ||
| 1561 | + The only supported backend is ``"perf"``. | ||
| 1562 | + | ||
| 1563 | + .. availability:: Linux. | ||
| 1564 | + | ||
| 1565 | + .. versionadded:: 3.12 | ||
| 1566 | + | ||
| 1567 | + .. seealso:: | ||
| 1568 | + | ||
| 1569 | + * :ref:`perf_profiling` | ||
| 1570 | + * https://perf.wiki.kernel.org | ||
| 1571 | + | ||
| 1572 | + .. function:: deactivate_stack_trampoline() | ||
| 1573 | + | ||
| 1574 | + Deactivate the current stack profiler trampoline backend. | ||
| 1575 | + | ||
| 1576 | + If no stack profiler is activated, this function has no effect. | ||
| 1577 | + | ||
| 1578 | + .. availability:: Linux. | ||
| 1579 | + | ||
| 1580 | + .. versionadded:: 3.12 | ||
| 1581 | + | ||
| 1582 | + .. function:: is_stack_trampoline_active() | ||
| 1583 | + | ||
| 1584 | + Return ``True`` if a stack profiler trampoline is active. | ||
| 1585 | + | ||
| 1586 | + .. availability:: Linux. | ||
| 1587 | + | ||
| 1588 | + .. versionadded:: 3.12 | ||
| 1589 | + | ||
| 1558 | 1590 | .. function:: _enablelegacywindowsfsencoding() | |
| 1559 | 1591 | ||
| 1560 | 1592 | Changes the :term:`filesystem encoding and error handler` to 'mbcs' and | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -538,12 +538,11 @@ Miscellaneous options | |||
| 538 | 538 | development (running from the source tree) then the default is "off". | |
| 539 | 539 | Note that the "importlib_bootstrap" and "importlib_bootstrap_external" | |
| 540 | 540 | frozen modules are always used, even if this flag is set to "off". | |
| 541 | - * ``-X perf`` to activate compatibility mode with the ``perf`` profiler. | ||
| 542 | - When this option is activated, the Linux ``perf`` profiler will be able to | ||
| 541 | + * ``-X perf`` enables support for the Linux ``perf`` profiler. | ||
| 542 | + When this option is provided, the ``perf`` profiler will be able to | ||
| 543 | 543 | report Python calls. This option is only available on some platforms and | |
| 544 | 544 | will do nothing if is not supported on the current system. The default value | |
| 545 | - is "off". See also :envvar:`PYTHONPERFSUPPORT` and :ref:`perf_profiling` | ||
| 546 | - for more information. | ||
| 545 | + is "off". See also :envvar:`PYTHONPERFSUPPORT` and :ref:`perf_profiling`. | ||
| 547 | 546 | ||
| 548 | 547 | It also allows passing arbitrary values and retrieving them through the | |
| 549 | 548 | :data:`sys._xoptions` dictionary. | |
@@ -1048,9 +1047,13 @@ conflict. | |||
| 1048 | 1047 | ||
| 1049 | 1048 | .. envvar:: PYTHONPERFSUPPORT | |
| 1050 | 1049 | ||
| 1051 | - If this variable is set to a nonzero value, it activates compatibility mode | ||
| 1052 | - with the ``perf`` profiler so Python calls can be detected by it. See the | ||
| 1053 | - :ref:`perf_profiling` section for more information. | ||
| 1050 | + If this variable is set to a nonzero value, it enables support for | ||
| 1051 | + the Linux ``perf`` profiler so Python calls can be detected by it. | ||
| 1052 | + | ||
| 1053 | + If set to ``0``, disable Linux ``perf`` profiler support. | ||
| 1054 | + | ||
| 1055 | + See also the :option:`-X perf <-X>` command-line option | ||
| 1056 | + and :ref:`perf_profiling`. | ||
| 1054 | 1057 | ||
| 1055 | 1058 | .. versionadded:: 3.12 | |
| 1056 | 1059 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -74,6 +74,15 @@ Important deprecations, removals or restrictions: | |||
| 74 | 74 | New Features | |
| 75 | 75 | ============ | |
| 76 | 76 | ||
| 77 | + * Add :ref:`perf_profiling` through the new | ||
| 78 | + environment variable :envvar:`PYTHONPERFSUPPORT`, | ||
| 79 | + the new command-line option :option:`-X perf <-X>`, | ||
| 80 | + as well as the new :func:`sys.activate_stack_trampoline`, | ||
| 81 | + :func:`sys.deactivate_stack_trampoline`, | ||
| 82 | + and :func:`sys.is_stack_trampoline_active` APIs. | ||
| 83 | + (Design by Pablo Galindo. Contributed by Pablo Galindo and Christian Heimes | ||
| 84 | + with contributions from Gregory P. Smith [Google] and Mark Shannon | ||
| 85 | + in :gh:`96123`.) | ||
| 77 | 86 | ||
| 78 | 87 | ||
| 79 | 88 | Other Language Changes | |
@@ -194,6 +203,19 @@ tempfile | |||
| 194 | 203 | The :class:`tempfile.NamedTemporaryFile` function has a new optional parameter | |
| 195 | 204 | *delete_on_close* (Contributed by Evgeny Zorin in :gh:`58451`.) | |
| 196 | 205 | ||
| 206 | + sys | ||
| 207 | + --- | ||
| 208 | + | ||
| 209 | + * Add :func:`sys.activate_stack_trampoline` and | ||
| 210 | + :func:`sys.deactivate_stack_trampoline` for activating and deactivating | ||
| 211 | + stack profiler trampolines, | ||
| 212 | + and :func:`sys.is_stack_trampoline_active` for querying if stack profiler | ||
| 213 | + trampolines are active. | ||
| 214 | + (Contributed by Pablo Galindo and Christian Heimes | ||
| 215 | + with contributions from Gregory P. Smith [Google] and Mark Shannon | ||
| 216 | + in :gh:`96123`.) | ||
| 217 | + | ||
| 218 | + | ||
| 197 | 219 | Optimizations | |
| 198 | 220 | ============= | |
| 199 | 221 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2127,12 +2127,12 @@ sys.activate_stack_trampoline | |||
| 2127 | 2127 | backend: str | |
| 2128 | 2128 | / | |
| 2129 | 2129 | ||
| 2130 | - Activate the perf profiler trampoline. | ||
| 2130 | + Activate stack profiler trampoline *backend*. | ||
| 2131 | 2131 | [clinic start generated code]*/ | |
| 2132 | 2132 | ||
| 2133 | 2133 | static PyObject * | |
| 2134 | 2134 | sys_activate_stack_trampoline_impl(PyObject *module, const char *backend) | |
| 2135 | - /*[clinic end generated code: output=5783cdeb51874b43 input=b09020e3a17c78c5]*/ | ||
| 2135 | + /*[clinic end generated code: output=5783cdeb51874b43 input=a12df928758a82b4]*/ | ||
| 2136 | 2136 | { | |
| 2137 | 2137 | #ifdef PY_HAVE_PERF_TRAMPOLINE | |
| 2138 | 2138 | if (strcmp(backend, "perf") == 0) { | |
@@ -2163,12 +2163,14 @@ sys_activate_stack_trampoline_impl(PyObject *module, const char *backend) | |||
| 2163 | 2163 | /*[clinic input] | |
| 2164 | 2164 | sys.deactivate_stack_trampoline | |
| 2165 | 2165 | ||
| 2166 | - Dectivate the perf profiler trampoline. | ||
| 2166 | + Deactivate the current stack profiler trampoline backend. | ||
| 2167 | + | ||
| 2168 | + If no stack profiler is activated, this function has no effect. | ||
| 2167 | 2169 | [clinic start generated code]*/ | |
| 2168 | 2170 | ||
| 2169 | 2171 | static PyObject * | |
| 2170 | 2172 | sys_deactivate_stack_trampoline_impl(PyObject *module) | |
| 2171 | - /*[clinic end generated code: output=b50da25465df0ef1 input=491f4fc1ed615736]*/ | ||
| 2173 | + /*[clinic end generated code: output=b50da25465df0ef1 input=9f629a6be9fe7fc8]*/ | ||
| 2172 | 2174 | { | |
| 2173 | 2175 | if (_PyPerfTrampoline_Init(0) < 0) { | |
| 2174 | 2176 | return NULL; | |
@@ -2179,12 +2181,12 @@ sys_deactivate_stack_trampoline_impl(PyObject *module) | |||
| 2179 | 2181 | /*[clinic input] | |
| 2180 | 2182 | sys.is_stack_trampoline_active | |
| 2181 | 2183 | ||
| 2182 | - Returns *True* if the perf profiler trampoline is active. | ||
| 2184 | + Return *True* if a stack profiler trampoline is active. | ||
| 2183 | 2185 | [clinic start generated code]*/ | |
| 2184 | 2186 | ||
| 2185 | 2187 | static PyObject * | |
| 2186 | 2188 | sys_is_stack_trampoline_active_impl(PyObject *module) | |
| 2187 | - /*[clinic end generated code: output=ab2746de0ad9d293 input=061fa5776ac9dd59]*/ | ||
| 2189 | + /*[clinic end generated code: output=ab2746de0ad9d293 input=29616b7bf6a0b703]*/ | ||
| 2188 | 2190 | { | |
| 2189 | 2191 | #ifdef PY_HAVE_PERF_TRAMPOLINE | |
| 2190 | 2192 | if (_PyIsPerfTrampolineActive()) { | |
| Back | FazBrowse Home | New Git URL |
0 commit comments