"""Sieve of Eratosthenes - find all primes up to limit."""
+
+
+
+
39
+
+
+
+
is_prime = [True] * (limit + 1)
+
+
+
+
40
+
+
+
+
is_prime[0] = is_prime[1] = False
+
+
+
+
41
+
+
+
+
+
+
+
+
42
+
+
+
+
for num in range(2, int(limit ** 0.5) + 1):
+
+
+
+
43
+
+
+
+
if is_prime[num]:
+
+
+
+
44
+
1
+
1
+
+
for multiple in range(num * num, limit + 1, num):
+
+
+
+
+
45
+
+
+
+
is_prime[multiple] = False
+
+
+
+
46
+
+
+
+
+
+
+
+
47
+
2
+
2
+
+
return [num for num, prime in enumerate(is_prime) if prime]
+
+
+
+
+
48
+
+
+
+
+
+
+
+
49
+
+
+
+
+
+
+
+
50
+
+
+
+
def string_processing(iterations):
+
+
+
+
51
+
+
+
+
"""String operations - concatenation and formatting."""
+
+
+
+
52
+
+
+
+
for _ in range(iterations):
+
+
+
+
53
+
+
+
+
result = ""
+
+
+
+
54
+
+
+
+
for i in range(50):
+
+
+
+
55
+
91
+
91
+
+
result += f"item_{i}_"
+
+
+
+
+
56
+
22
+
22
+
+
parts = result.split("_")
+
+
+
+
+
57
+
10
+
10
+
+
joined = "-".join(parts)
+
+
+
+
+
58
+
+
+
+
+
+
+
+
59
+
+
+
+
+
+
+
+
60
+
+
+
+
def list_operations(iterations):
+
+
+
+
61
+
+
+
+
"""List comprehensions and operations."""
+
+
+
+
62
+
+
+
+
for _ in range(iterations):
+
+
+
+
63
+
118
+
118
+
+
squares = [x ** 2 for x in range(500)]
+
+
+
+
+
64
+
119
+
119
+
+
evens = [x for x in squares if x % 2 == 0]
+
+
+
+
+
65
+
12
+
12
+
+
total = sum(evens)
+
+
+
+
+
66
+
+
+
+
+
+
+
+
67
+
+
+
+
+
+
+
+
68
+
+
+
+
def dict_operations(iterations):
+
+
+
+
69
+
+
+
+
"""Dictionary creation and lookups."""
+
+
+
+
70
+
+
+
+
for _ in range(iterations):
+
+
+
+
71
+
206
+
206
+
+
data = {f"key_{i}": i ** 2 for i in range(200)}
+
+
+
+
+
72
+
158
+
158
+
+
values = [data[f"key_{i}"] for i in range(200)]
+
+
+
+
+
73
+
5
+
5
+
+
total = sum(values)
+
+
+
+
+
74
+
+
+
+
+
+
+
+
75
+
+
+
+
+
+
+
+
76
+
+
+
+
def compute_heavy():
+
+
+
+
77
+
+
+
+
"""CPU-intensive computation section."""
+
+
+
+
78
+
1
+
301
+
+
fibonacci(30)
+
+
+
+
+
79
+
+
+
+
+
+
+
+
80
+
+
+
+
size = 60
+
+
+
+
81
+
+
+
+
a = [[i + j for j in range(size)] for i in range(size)]
+
+
+
+
82
+
+
+
+
b = [[i * j for j in range(size)] for i in range(size)]
+
+
+
+
83
+
+
+
+
matrix_multiply(a, b)
+
+
+
+
84
+
+
+
+
+
+
+
+
85
+
+
+
+
prime_sieve(10000)
+
+
+
+
86
+
+
+
+
+
+
+
+
87
+
+
+
+
+
+
+
+
88
+
+
+
+
def data_processing():
+
+
+
+
89
+
+
+
+
"""Data structure operations."""
+
+
+
+
90
+
+
753
+
+
string_processing(2000)
+
+
+
+
+
91
+
+
+
+
list_operations(1500)
+
+
+
+
92
+
+
+
+
dict_operations(1000)
+
+
+
+
93
+
+
+
+
+
+
+
+
94
+
+
+
+
data = list(range(800))
+
+
+
+
95
+
+
+
+
for _ in range(3):
+
+
+
+
96
+
+
+
+
data = data[::-1]
+
+
+
+
97
+
+
+
+
bubble_sort(data[:200])
+
+
+
+
98
+
+
+
+
+
+
+
+
99
+
+
+
+
+
+
+
+
100
+
+
+
+
def main():
+
+
+
+
101
+
+
+
+
"""Main entry point."""
+
+
+
+
102
+
+
1,054
+
+
compute_heavy()
+
+
+
+
+
103
+
+
+
+
data_processing()
+
+
+
+
104
+
+
+
+
+
+
+
+
105
+
+
+
+
+
+
+
+
106
+
+
+
+
if __name__ == "__main__":
+
+
+
+
107
+
+
1,054
+
+
main()
+
+
+
+
+
+
+
+
+
+
diff --git a/Doc/conf.py b/Doc/conf.py
index a4275835059efa..f6efc5ff22a5e1 100644
--- a/Doc/conf.py
+++ b/Doc/conf.py
@@ -436,7 +436,12 @@
epub_author = 'Python Documentation Authors'
epub_publisher = 'Python Software Foundation'
-epub_exclude_files = ('index.xhtml', 'download.xhtml')
+epub_exclude_files = (
+ 'index.xhtml',
+ 'download.xhtml',
+ '_static/tachyon-example-flamegraph.html',
+ '_static/tachyon-example-heatmap.html',
+)
# index pages are not valid xhtml
# https://github.com/sphinx-doc/sphinx/issues/12359
diff --git a/Doc/library/profiling.sampling.rst b/Doc/library/profiling.sampling.rst
index a05adf8c3da20e..e0e583d00500f7 100644
--- a/Doc/library/profiling.sampling.rst
+++ b/Doc/library/profiling.sampling.rst
@@ -406,12 +406,12 @@ and the base instruction.
Opcode information appears in several output formats:
-- **Live mode**: An opcode panel shows instruction-level statistics for the
- selected function, accessible via keyboard navigation
-- **Flame graphs**: Nodes display opcode information when available, helping
- identify which instructions consume the most time
+- **Flame graphs**: Hovering over a frame displays a tooltip with a bytecode
+ instruction breakdown, showing which opcodes consumed time in that function
- **Heatmap**: Expandable bytecode panels per source line show instruction
breakdown with specialization percentages
+- **Live mode**: An opcode panel shows instruction-level statistics for the
+ selected function, accessible via keyboard navigation
- **Gecko format**: Opcode transitions are emitted as interval markers in the
Firefox Profiler timeline
@@ -679,6 +679,14 @@ deterministic profilers generate. This is the default output format::
python -m profiling.sampling run script.py
python -m profiling.sampling run --pstats script.py
+.. figure:: tachyon-pstats.png
+ :alt: Tachyon pstats terminal output
+ :align: center
+ :width: 100%
+
+ The pstats format displays profiling results in a color-coded table showing
+ function hotspots, sample counts, and timing estimates.
+
Output appears on stdout by default::
Profile Stats (Mode: wall):
@@ -780,6 +788,19 @@ an interactive flame graph visualization::
python -m profiling.sampling run --flamegraph script.py
python -m profiling.sampling run --flamegraph -o profile.html script.py
+.. figure:: tachyon-flamegraph.png
+ :alt: Tachyon interactive flame graph
+ :align: center
+ :width: 100%
+
+ The flame graph visualization shows call stacks as nested rectangles, with
+ width proportional to time spent. The sidebar displays runtime statistics,
+ GIL metrics, and hotspot functions.
+
+.. only:: html
+
+ `Try the interactive example <../_static/tachyon-example-flamegraph.html>`__!
+
If no output file is specified, the profiler generates a filename based on
the process ID (for example, ``flamegraph.12345.html``).
@@ -850,6 +871,33 @@ Firefox Profiler timeline:
For this reason, the :option:`--mode` option is not available with Gecko format;
all relevant data is captured automatically.
+.. figure:: tachyon-gecko-calltree.png
+ :alt: Firefox Profiler Call Tree view
+ :align: center
+ :width: 100%
+
+ The Call Tree view shows the complete call hierarchy with sample counts
+ and percentages. The sidebar displays detailed statistics for the
+ selected function including running time and sample distribution.
+
+.. figure:: tachyon-gecko-flamegraph.png
+ :alt: Firefox Profiler Flame Graph view
+ :align: center
+ :width: 100%
+
+ The Flame Graph visualization shows call stacks as nested rectangles.
+ Functions names are visible in the call hierarchy.
+
+.. figure:: tachyon-gecko-opcodes.png
+ :alt: Firefox Profiler Marker Chart with opcodes
+ :align: center
+ :width: 100%
+
+ The Marker Chart displays interval markers including CPU state, GIL
+ status, and opcodes. With ``--opcodes`` enabled, bytecode instructions
+ like ``BINARY_OP_ADD_FLOAT``, ``CALL_PY_EXACT_ARGS``, and
+ ``CALL_LIST_APPEND`` appear as markers showing execution over time.
+
Heatmap format
--------------
@@ -860,6 +908,15 @@ showing sample counts at the source line level::
python -m profiling.sampling run --heatmap script.py
python -m profiling.sampling run --heatmap -o my_heatmap script.py
+.. figure:: tachyon-heatmap.png
+ :alt: Tachyon heatmap visualization
+ :align: center
+ :width: 100%
+
+ The heatmap overlays sample counts directly on your source code. Lines are
+ color-coded from cool (few samples) to hot (many samples). Navigation
+ buttons (▲▼) let you jump between callers and callees.
+
Unlike other formats that produce a single file, heatmap output creates a
directory containing HTML files for each profiled source file. If no output
path is specified, the directory is named ``heatmap_PID``.
@@ -886,6 +943,22 @@ The heatmap interface provides several interactive features:
- **Dark/light theme**: toggle with preference saved across sessions
- **Line linking**: click line numbers to create shareable URLs
+When opcode-level profiling is enabled with :option:`--opcodes`, each hot line
+can be expanded to show which bytecode instructions consumed time:
+
+.. figure:: tachyon-heatmap-with-opcodes.png
+ :alt: Heatmap with expanded bytecode panel
+ :align: center
+ :width: 100%
+
+ Expanding a hot line reveals the bytecode instructions executed, including
+ specialized variants. The panel shows sample counts per instruction and the
+ overall specialization percentage for the line.
+
+.. only:: html
+
+ `Try the interactive example <../_static/tachyon-example-heatmap.html>`__!
+
Heatmaps are especially useful when you know which file contains a performance
issue but need to identify the specific lines. Many developers prefer this
format because it maps directly to their source code, making it easy to read
@@ -903,6 +976,14 @@ data, similar to the ``top`` command for system processes::
python -m profiling.sampling run --live script.py
python -m profiling.sampling attach --live 12345
+.. figure:: tachyon-live-mode-2.gif
+ :alt: Tachyon live mode showing all threads
+ :align: center
+ :width: 100%
+
+ Live mode displays real-time profiling statistics, showing combined
+ data from multiple threads in a multi-threaded application.
+
The display updates continuously as new samples arrive, showing the current
hottest functions. This mode requires the :mod:`curses` module, which is
available on Unix-like systems but not on Windows. The terminal must be at
@@ -918,6 +999,14 @@ main table, showing instruction-level statistics for the currently selected
function. This panel displays which bytecode instructions are executing most
frequently, including specialized variants and their base opcodes.
+.. figure:: tachyon-live-mode-1.gif
+ :alt: Tachyon live mode with opcode panel
+ :align: center
+ :width: 100%
+
+ Live mode with ``--opcodes`` enabled shows an opcode panel with a bytecode
+ instruction breakdown for the selected function.
+
Keyboard commands
-----------------
diff --git a/Doc/library/tachyon-flamegraph.png b/Doc/library/tachyon-flamegraph.png
new file mode 100644
index 00000000000000..a17cd304f8bb28
Binary files /dev/null and b/Doc/library/tachyon-flamegraph.png differ
diff --git a/Doc/library/tachyon-gecko-calltree.png b/Doc/library/tachyon-gecko-calltree.png
new file mode 100644
index 00000000000000..71b096940e8fcd
Binary files /dev/null and b/Doc/library/tachyon-gecko-calltree.png differ
diff --git a/Doc/library/tachyon-gecko-flamegraph.png b/Doc/library/tachyon-gecko-flamegraph.png
new file mode 100644
index 00000000000000..d427ed85ac04e7
Binary files /dev/null and b/Doc/library/tachyon-gecko-flamegraph.png differ
diff --git a/Doc/library/tachyon-gecko-opcodes.png b/Doc/library/tachyon-gecko-opcodes.png
new file mode 100644
index 00000000000000..9741eb659120b8
Binary files /dev/null and b/Doc/library/tachyon-gecko-opcodes.png differ
diff --git a/Doc/library/tachyon-heatmap-with-opcodes.png b/Doc/library/tachyon-heatmap-with-opcodes.png
new file mode 100644
index 00000000000000..5ad67d131548e4
Binary files /dev/null and b/Doc/library/tachyon-heatmap-with-opcodes.png differ
diff --git a/Doc/library/tachyon-heatmap.png b/Doc/library/tachyon-heatmap.png
new file mode 100644
index 00000000000000..47ac1119f4e572
Binary files /dev/null and b/Doc/library/tachyon-heatmap.png differ
diff --git a/Doc/library/tachyon-live-mode-1.gif b/Doc/library/tachyon-live-mode-1.gif
new file mode 100644
index 00000000000000..2d58e807d6a7c1
Binary files /dev/null and b/Doc/library/tachyon-live-mode-1.gif differ
diff --git a/Doc/library/tachyon-live-mode-2.gif b/Doc/library/tachyon-live-mode-2.gif
new file mode 100644
index 00000000000000..bbc2163fe603eb
Binary files /dev/null and b/Doc/library/tachyon-live-mode-2.gif differ
diff --git a/Doc/library/tachyon-logo.png b/Doc/library/tachyon-logo.png
index fddeaafe7e09a5..bf0901ec9f313e 100644
Binary files a/Doc/library/tachyon-logo.png and b/Doc/library/tachyon-logo.png differ
diff --git a/Doc/library/tachyon-pstats.png b/Doc/library/tachyon-pstats.png
new file mode 100644
index 00000000000000..d0281ade660914
Binary files /dev/null and b/Doc/library/tachyon-pstats.png differ