Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
7dd836b
Add binary I/O header for sampling profiler
pablogsal Dec 15, 2025
83603c7
Add binary writer for sampling profiler
pablogsal Dec 15, 2025
7a58811
Add binary reader for sampling profiler
pablogsal Dec 15, 2025
e3ea7a4
Build: add binary I/O files to Unix build
pablogsal Dec 15, 2025
8931b4a
Build: add binary I/O files to Windows build
pablogsal Dec 15, 2025
18287f4
Add Python bindings for binary writer and reader
pablogsal Dec 15, 2025
1f7737e
Add BinaryCollector for sampling profiler
pablogsal Dec 15, 2025
2965eff
Add BinaryReader for sampling profiler replay
pablogsal Dec 15, 2025
427f846
Add --binary and replay command to sampling profiler CLI
pablogsal Dec 15, 2025
1437629
Update collector interface for binary replay support
pablogsal Dec 15, 2025
e75513b
Add tests for binary format
pablogsal Dec 15, 2025
a520ac1
Add internal documentation for binary format
pablogsal Dec 15, 2025
3ad7a3d
Document binary format and replay command
pablogsal Dec 15, 2025
cd4f412
Fix CI
pablogsal Dec 15, 2025
596af7f
Add NEWS entry
pablogsal Dec 15, 2025
1e2400b
Regen and simplify
pablogsal Dec 15, 2025
b90e37c
Merge upstream/main into file-output
pablogsal Dec 15, 2025
788c565
Speed up general case
pablogsal Dec 15, 2025
51b3b09
Small fixes
pablogsal Dec 20, 2025
81a8f2d
Merge branch 'main' into file-output
pablogsal Dec 20, 2025
0ccea49
Address Laszlo's review
pablogsal Dec 20, 2025
dfc0d31
More fixes from review
pablogsal Dec 20, 2025
b9fc778
Fixes and more tests
pablogsal Dec 20, 2025
191458a
Fix c analizer
pablogsal Dec 22, 2025
63c6f50
Update docs
pablogsal Dec 22, 2025
046fe55
Update cli
pablogsal Dec 22, 2025
f88c01f
Fixes
pablogsal Dec 22, 2025
ed63156
Merge upstream/main
pablogsal Dec 22, 2025
c880f85
Fix big endian
pablogsal Dec 22, 2025
ad7891c
Fix big endian
pablogsal Dec 22, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 100 additions & 3 deletions Doc/library/profiling.sampling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,36 @@ On most systems, attaching to another process requires appropriate permissions.
See :ref:`profiling-permissions` for platform-specific requirements.


.. _replay-command:

The ``replay`` command
----------------------

The ``replay`` command converts binary profile files to other output formats::

python -m profiling.sampling replay profile.bin
python -m profiling.sampling replay --flamegraph -o profile.html profile.bin

This command is useful when you have captured profiling data in binary format
and want to analyze it later or convert it to a visualization format. Binary
profiles can be replayed multiple times to different formats without
re-profiling.

::

# Convert binary to pstats (default, prints to stdout)
python -m profiling.sampling replay profile.bin

# Convert binary to flame graph
python -m profiling.sampling replay --flamegraph -o output.html profile.bin

# Convert binary to gecko format for Firefox Profiler
python -m profiling.sampling replay --gecko -o profile.json profile.bin

# Convert binary to heatmap
python -m profiling.sampling replay --heatmap -o my_heatmap profile.bin


Profiling in production
-----------------------

Expand Down Expand Up @@ -1041,6 +1071,59 @@ intuitive view that shows exactly where time is spent without requiring
interpretation of hierarchical visualizations.


Binary format
-------------

Binary format (:option:`--binary`) produces a compact binary file for efficient
storage of profiling data::

python -m profiling.sampling run --binary -o profile.bin script.py
python -m profiling.sampling attach --binary -o profile.bin 12345

The :option:`--compression` option controls data compression:

- ``auto`` (default): Use zstd compression if available, otherwise no
compression
- ``zstd``: Force zstd compression (requires :mod:`compression.zstd` support)
- ``none``: Disable compression

::

python -m profiling.sampling run --binary --compression=zstd -o profile.bin script.py

To analyze binary profiles, use the :ref:`replay-command` to convert them to
other formats like flame graphs or pstats output.


Record and replay workflow
==========================

The binary format combined with the replay command enables a record-and-replay
workflow that separates data capture from analysis. Rather than generating
visualizations during profiling, you capture raw data to a compact binary file
and convert it to different formats later.

This approach has three main benefits:

- Sampling runs faster because the work of building data structures for
visualization is deferred until replay.
- A single binary capture can be converted to multiple output formats
without re-profiling: pstats for a quick overview, flame graph for visual
exploration, heatmap for line-level detail.
- Binary files are compact and easy to share with colleagues who can convert
them to their preferred format.

A typical workflow::

# Capture profile in production or during tests
python -m profiling.sampling attach --binary -o profile.bin 12345

# Later, analyze with different formats
python -m profiling.sampling replay profile.bin
python -m profiling.sampling replay --flamegraph -o profile.html profile.bin
python -m profiling.sampling replay --heatmap -o heatmap profile.bin


Live mode
=========

Expand Down Expand Up @@ -1252,6 +1335,10 @@ Global options

Attach to and profile a running process by PID.

.. option:: replay

Convert a binary profile file to another output format.


Sampling options
----------------
Expand Down Expand Up @@ -1335,12 +1422,22 @@ Output options

Generate HTML heatmap with line-level sample counts.

.. option:: --binary

Generate high-performance binary format for later conversion with the
``replay`` command.

.. option:: --compression <type>

Compression for binary format: ``auto`` (use zstd if available, default),
``zstd``, or ``none``.

.. option:: -o <path>, --output <path>

Output file or directory path. Default behavior varies by format:
``--pstats`` writes to stdout, ``--flamegraph`` and ``--gecko`` generate
files like ``flamegraph.PID.html``, and ``--heatmap`` creates a directory
named ``heatmap_PID``.
:option:`--pstats` writes to stdout, while other formats generate a file
named ``<format>_<PID>.<ext>`` (for example, ``flamegraph_12345.html``).
:option:`--heatmap` creates a directory named ``heatmap_<PID>``.


pstats display options
Expand Down
9 changes: 9 additions & 0 deletions Include/internal/pycore_global_objects_fini_generated.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions Include/internal/pycore_global_strings.h
Original file line number Diff line number Diff line change
Expand Up @@ -376,9 +376,11 @@ struct _Py_global_strings {
STRUCT_FOR_ID(co_varnames)
STRUCT_FOR_ID(code)
STRUCT_FOR_ID(col_offset)
STRUCT_FOR_ID(collector)
STRUCT_FOR_ID(command)
STRUCT_FOR_ID(comment_factory)
STRUCT_FOR_ID(compile_mode)
STRUCT_FOR_ID(compression)
STRUCT_FOR_ID(config)
STRUCT_FOR_ID(consts)
STRUCT_FOR_ID(context)
Expand Down Expand Up @@ -441,7 +443,9 @@ struct _Py_global_strings {
STRUCT_FOR_ID(event)
STRUCT_FOR_ID(eventmask)
STRUCT_FOR_ID(exc)
STRUCT_FOR_ID(exc_tb)
STRUCT_FOR_ID(exc_type)
STRUCT_FOR_ID(exc_val)
STRUCT_FOR_ID(exc_value)
STRUCT_FOR_ID(excepthook)
STRUCT_FOR_ID(exception)
Expand Down Expand Up @@ -697,6 +701,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(print_file_and_line)
STRUCT_FOR_ID(priority)
STRUCT_FOR_ID(progress)
STRUCT_FOR_ID(progress_callback)
STRUCT_FOR_ID(progress_routine)
STRUCT_FOR_ID(proto)
STRUCT_FOR_ID(protocol)
Expand Down Expand Up @@ -737,6 +742,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(reversed)
STRUCT_FOR_ID(rounding)
STRUCT_FOR_ID(salt)
STRUCT_FOR_ID(sample_interval_us)
STRUCT_FOR_ID(sched_priority)
STRUCT_FOR_ID(scheduler)
STRUCT_FOR_ID(script)
Expand Down Expand Up @@ -776,8 +782,10 @@ struct _Py_global_strings {
STRUCT_FOR_ID(spam)
STRUCT_FOR_ID(src)
STRUCT_FOR_ID(src_dir_fd)
STRUCT_FOR_ID(stack_frames)
STRUCT_FOR_ID(stacklevel)
STRUCT_FOR_ID(start)
STRUCT_FOR_ID(start_time_us)
STRUCT_FOR_ID(statement)
STRUCT_FOR_ID(stats)
STRUCT_FOR_ID(status)
Expand Down Expand Up @@ -818,6 +826,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(times)
STRUCT_FOR_ID(timespec)
STRUCT_FOR_ID(timestamp)
STRUCT_FOR_ID(timestamp_us)
STRUCT_FOR_ID(timetuple)
STRUCT_FOR_ID(timeunit)
STRUCT_FOR_ID(top)
Expand Down
9 changes: 9 additions & 0 deletions Include/internal/pycore_runtime_init_generated.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading