Skip to content

Commit 65e1bb2

Browse files
committed
📝 Update performance measurements section
* Add cProfile/profiling.tracing * Add tprof
1 parent 1eb625d commit 65e1bb2

File tree

3 files changed

+136
-5
lines changed

3 files changed

+136
-5
lines changed

docs/performance/index.rst

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,18 +67,28 @@ Performance-Messungen
6767

6868
Wenn ihr erst einmal mit eurem Code gearbeitet habt, kann es nützlich sein, die
6969
Effizienz genauer zu untersuchen. Hierfür kann :abbr:`z. B. (zum Beispiel)`
70-
`cProfile <https://docs.python.org/3.14/library/profile.html#module-cProfile>`_,
71-
:doc:`ipython-profiler` oder :doc:`scalene` genutzt werden.
70+
:doc:`cProfile <tracing>`, :doc:`ipython-profiler`, :doc:`scalene` oder
71+
:doc:`tprof` genutzt werden. Bisher führe ich meist die folgenden Schritte aus:
72+
73+
#. Ich profilierte das gesamte Programm mit :doc:`cProfile <tracing>` oder
74+
`py-spy <https://github.com/benfred/py-spy>`_, um langsame Funktionen zu
75+
finden.
76+
#. Anschließend optimiertee ich eine langsame Funktion.
77+
#. Schließlich erstellte ich ein neues Profil und filterte das Ergebnis meiner
78+
optimierten Version heraus um die Ergebnisse vergleichen zu können.
79+
80+
:mod:`sys.monitoring` in Python 3.12 vereinfachte das Monitoring bestimmter
81+
Funktionen. :doc:`tprof` nutzt dies, sodass im letzten Schritt nur noch das
82+
Profil für die optimierte Funktion erstellt werden muss.
7283

7384
.. versionadded:: Python3.15
7485
Mit :pep:`799` wird ein spezielles Profiling-Modul zur Verfügung stehen, das
7586
die in Python integrierten Profiling-Tools unter einem einheitlichen
7687
Namespace organisiert. Dieses Modul enthält:
7788

7889
:mod:`profiling.tracing`
79-
deterministische Funktionsaufrufverfolgung, die aus `cProfile
80-
<https://docs.python.org/3.14/library/profile.html#module-cProfile>`_
81-
verschoben wurde.
90+
deterministische Funktionsaufrufverfolgung, die aus :doc:`cProfile
91+
<tracing>` verschoben wurde.
8292
:mod:`profiling.sampling`
8393
der neue statistische Sampling-Profiler :doc:`tachyon`.
8494

@@ -96,8 +106,10 @@ Effizienz genauer zu untersuchen. Hierfür kann :abbr:`z. B. (zum Beispiel)`
96106
:titlesonly:
97107
:maxdepth: 0
98108

109+
tracing
99110
ipython-profiler.ipynb
100111
scalene.ipynb
112+
tprof
101113
tachyon
102114

103115
Suche nach bestehenden Implementierungen

docs/performance/tprof.rst

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
.. SPDX-FileCopyrightText: 2026 Veit Schiele
2+
..
3+
.. SPDX-License-Identifier: BSD-3-Clause
4+
5+
``tprof``
6+
=========
7+
8+
`tprof <https://github.com/adamchainz/tprof>`_ misst die Zeit, die beim
9+
Ausführen eines Moduls in bestimmten Funktionen verbracht wird. Im Gegensatz zu
10+
anderen Profilern verfolgt es nur die angegebenen Funktionen mit
11+
:mod:`sys.monitoring`, wodurch man sich das Filtern sparen kann.
12+
13+
``tprof`` unterstützt die Verwendung als Befehlszeilenprogramm und mit einer
14+
Python-Schnittstelle:
15+
16+
:samp:`uv run tprof -t {MODULE}:{FUNCTION} (-m {MODULE} | {PATH/TO/SCRIPT})`
17+
Angenommen, ihr habt festgestellt, dass die Erstellung von
18+
:class:`pathlib.Path`-Objekten im :mod:`main`-Modul euren Code verlangsamt.
19+
So könnt ihr dies mit ``tprof`` messen:
20+
21+
.. code-block:: console
22+
23+
$ uv run tprof -t pathlib:Path.open -m main
24+
🎯 tprof results:
25+
function calls total mean ± σ min … max
26+
pathlib:Path.open() 1 93μs 93μs 93μs … 93μs
27+
28+
Mit der ``-x``-Option könnt ihr auch zwei Funktionen miteinander
29+
vergleichen:
30+
31+
.. code-block:: console
32+
33+
$ uv run tprof -x -t old -m main -t new -m main
34+
🎯 tprof results:
35+
function calls total mean ± σ min … max delta
36+
main:old() 1 41μs 41μs 41μs … 41μs -
37+
main:new() 1 20μs 20μs 20μs … 20μs -50.67%
38+
39+
``tprof(*targets, label: str | None = None, compare: bool = False)``
40+
verwendet diesen Code als :doc:`Kontextmanager
41+
<python-basics:control-flow/with>` in eurem Code, um ein Profil in einem
42+
bestimmten Block zu erstellen. Der Bericht wird jedes Mal ausgegeben,
43+
wenn der Block durchlaufen wurde.
44+
45+
``*targets``
46+
sind aufrufbare Elemente zum Profiling oder Referenzen zu Elementen, die
47+
mit :func:`pkgutil.resolve_name` aufgelöst werden.
48+
``label``
49+
ist eine optionale Zeichenfolge, die als Kopfzeile dem Bericht
50+
hinzugefügt werden kann.
51+
``compare``
52+
auf ``True`` gesetzt, wird der Vergleichsmodus aktiviert.
53+
54+
Beispiel:
55+
56+
.. code-block:: Python
57+
58+
from pathlib import Path
59+
60+
from tprof import tprof
61+
62+
with tprof(Path.open):
63+
p = Path("docs", "save-data", "myfile.txt")
64+
f = p.open()
65+
66+
.. code-block:: console
67+
68+
$ uv run python main.py
69+
🎯 tprof results:
70+
function calls total mean ± σ min … max
71+
pathlib:Path.open() 1 82μs 82μs 82μs … 82μs

docs/performance/tracing.rst

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
.. SPDX-FileCopyrightText: 2026 Veit Schiele
2+
..
3+
.. SPDX-License-Identifier: BSD-3-Clause
4+
5+
cProfile/profiling.tracing
6+
==========================
7+
8+
Üblicherweise wird in der Kommandozeile mit `cProfile
9+
<https://docs.python.org/3.14/library/profile.html#module-cProfile>`_ oder ab
10+
Python 3.15 mit :mod:`profiling.tracing` ein Profil erstellt, das anschließend
11+
dessen Profilstatistiken anzeigt. Dies kann jedoch schnell sehr mühsam sein,
12+
insbesondere beim Lesen umfangreicher Profile oder beim Sortieren der Daten.
13+
Flexibler ist, die Profildaten stattdessen in einer Datei zu speichern, die dann
14+
mit dem :mod:`pstats`-Modul gelesen werden kann:
15+
16+
#. :samp:`uv run python -m cProfile -o {PROFILE} ({SCRIPT} | {-m {MODULE})`
17+
führt `cProfile
18+
<https://docs.python.org/3.14/library/profile.html#module-cProfile>`_ zum
19+
Profilerstellung eures Script oder eures Moduls aus und speichert die
20+
Ergebnisse in einer Datei, die durch die Option ``-o`` angegeben wird.
21+
22+
#. :samp:`uv run python -m (cProfile | profiling.tracing) -o profile ({SCRIPT} |
23+
-m {MODULE}) <<< $'sort cumtime\nstats 100' | less` übergibt die folgenden
24+
beiden Befehle an das :mod:`pstats`-Modul, wobei die ``$``-Syntax verwendet
25+
wird.
26+
27+
``sort cumtime``
28+
sortiert die Ausgabe nach kumulativer Zeit, beginnend mit der größten.
29+
30+
Um nach anderen Metriken zu sortieren, könnt ihr ``cumtime`` einfach
31+
durch einen Wert aus :meth:`pstats.Stats.sort_stats` ersetzen.
32+
33+
``stats 100``
34+
zeigt die ersten 100 Zeilen des Profils an.
35+
36+
Die Ausgabe wird an ``less`` übergeben, sodass ihr euch die Ergebnisse
37+
anschauen könnt. Drückt :kbd:`q`, um den Vorgang zu beenden, wenn ihr fertig
38+
seid.
39+
40+
#. Vor und nach der Optimierung lassen sich einfach vergleichen, :abbr:`z. B.
41+
(zum Beispiel)` mit:
42+
43+
.. code-block:: console
44+
45+
$ uv run python -m cProfile -o before.profile main.py
46+
$ git switch -c main_optimisation
47+
...
48+
$ uv run python -m cProfile -o after.profile main.py

0 commit comments

Comments
 (0)