Skip to content

profiling.sampling: Statistical Profiler in the Standard Library

profiling.sampling is the statistical sampling profiler that ships with Python 3.15, developed under the codename Tachyon. It samples the call stacks of a Python process on a timer rather than instrumenting every call, and it can attach to a process that is already running by PID. The CLI is invoked as python -m profiling.sampling, with run and attach as the two profiling entry points and replay for converting saved binary profiles to other output formats.

The new module sits inside the broader PEP 799 reorganization of the standard-library profilers. cProfile moves to profiling.tracing (with cProfile kept as a backward-compatible alias), the legacy pure-Python profile module is deprecated in 3.15 and scheduled for removal in 3.17, and the new sampling profiler lives at profiling.sampling.

Availability

Python 3.15 is in alpha as of May 2026; the final release is scheduled for October 2026. The CLI surface documented here matches 3.15.0a8, and flags may still change before the stable release.

uv installs alpha and beta Pythons with the same command it uses for stable releases:

uv python install 3.15        # pulls the latest published 3.15 (currently an alpha)
uv python install 3.15.0a8    # pins a specific pre-release

uv python install 3.15 resolves to the latest version matching that minor, so it picks up newer alphas, betas, and the final release as they ship. To pin a project virtualenv to a specific pre-release, use uv venv --python 3.15.0a8. The Version Compatibility section explains why the exact pin matters when attaching the profiler to a running process.

When to use profiling.sampling

Reach for profiling.sampling when a Python process is running in production or in a long-running development session and a stack profile is needed without restarting it. The profiler attaches to a PID, runs out of process, and produces flame graphs, pstats output, or live terminal stats. It supersedes much of what required a third-party install before 3.15 (see py-spy and pyinstrument), although the third-party tools still cover Python versions before 3.15 and have more mature flame-graph ecosystems.

For exact call counts or per-line attribution, use the deterministic side of the package: profiling.tracing (the relocated cProfile) for call counts and line_profiler for line-level attribution. The trade-offs between the two designs are covered in Sampling vs deterministic profilers.

Subcommands

The CLI is invoked as python -m profiling.sampling <subcommand>:

Subcommand Purpose
run Launch a Python script or module and profile it from startup
attach Attach to a running process by PID and profile until duration elapses
replay Convert a previously recorded binary profile to another output format

Sampling Options

The default sampling rate is 1 kHz. The documented maximum is 1 MHz.

  • -r, --sampling-rate accepts a number or a unit suffix (10000, 10khz, 10k)
  • -d, --duration runs for a fixed number of seconds; default is until the target completes
  • -a, --all-threads samples every thread instead of only the main thread
  • --realtime-stats prints sampling statistics during the run
  • --blocking pauses the target during each sample for a guaranteed-consistent stack at the cost of perturbing the program

Profiling Modes

--mode selects what each sample counts:

Mode What it measures
wall (default) Wall-clock time; every sample counts regardless of thread state
cpu On-CPU time only; samples taken while a thread is running on a core
gil GIL-holding time; samples taken only while the thread holds the GIL
exception Exception-handling time; samples taken only while an exception is in flight

Wall-clock mode includes time spent blocked on I/O or await. CPU mode excludes it. GIL mode is useful when diagnosing contention in multithreaded programs.

Async, Native, and Opcode Profiling

  • --async-aware reconstructs asyncio task stacks across await boundaries; --async-mode running shows only the running task and --async-mode all includes waiting tasks
  • --native includes <native> frames for C extensions and the interpreter itself
  • --no-gc excludes <GC> frames so garbage collection time does not dominate the report
  • --opcodes records bytecode opcode information for instruction-level profiling
  • --subprocesses follows multiprocessing and subprocess children automatically

Output Formats

Output formats are mutually exclusive flags:

Flag Output Viewer
--pstats (default) Text table to stdout, or a binary .pstats file pstats module, IDE viewers
--collapsed Semicolon-separated stacks External flame-graph tools (e.g. Brendan Gregg’s scripts)
--flamegraph Self-contained interactive HTML Any browser
--diff-flamegraph BASELINE.bin Differential HTML flame graph Any browser; color-codes regressions vs. a baseline binary
--gecko Gecko-format JSON Firefox Profiler
--heatmap HTML directory with line-level overlays Any browser
--binary Compact binary; supports zstd compression Use with replay to convert later

-o/--output selects the output path, --browser auto-opens HTML output, and --compression {auto,zstd,none} controls the binary format.

The --live flag (available on both run and attach) opens a top-style terminal interface with sortable columns, a substring filter (/), per-thread navigation, and adjustable refresh rate.

Permissions

Sampling another process requires OS-level memory inspection, which has the same constraints as py-spy:

  • Linux: ptrace capability, or root, or relax kernel.yama.ptrace_scope
  • macOS: root, or a binary signed with the com.apple.security.cs.debugger entitlement
  • Windows: administrator, or SeDebugPrivilege

A target that the profiler launched itself (python -m profiling.sampling run script.py) does not require elevated privileges on Linux or Windows; attaching to an already-running PID does. macOS requires elevated privileges in both cases.

Version Compatibility

The profiler must run on the same Python minor version as the target process. Pre-release builds must match exactly: 3.15.0a8 profiling 3.15.0a7 will fail. This is stricter than third-party profilers like py-spy that read process memory through OS APIs and support a range of CPython versions from a single profiler binary.

Pros

  • Ships in the standard library; no pip install and no separate binary.
  • Async-aware sampling reconstructs task stacks across await boundaries.
  • Output formats include HTML flame graphs, Gecko JSON for the Firefox Profiler, line-level heatmaps, and differential flame graphs against a saved baseline.
  • Live terminal mode is built in; previously this required austin-tui or similar.
  • Differential flame graphs against a saved baseline are a first-class operation, useful for regression hunting in CI.

Cons

  • Available only in Python 3.15 and newer. Older Pythons keep needing third-party tools.
  • Profiler and target must share a Python minor version, and pre-release versions must match exactly.
  • On macOS, even python -m profiling.sampling run script.py requires elevated privileges; the OS does not allow process-memory inspection without them.
  • Same OS permission model as out-of-process profilers on the other platforms (ptrace on Linux, admin on Windows).
  • The output formats unique to profiling.sampling (heatmap directories, differential flame graphs) do not have third-party viewers yet, so existing flame-graph viewers like speedscope.app and the Perfetto UI do not consume them out of the box.

Learn More

Last updated on