LinuxCommandLibrary

py-spy

Profile running Python programs

TLDR

Show a live view of the functions that take the most execution time of a running process

$ py-spy top [[-p|--pid]] [pid]
copy

Start a program and show a live view of the functions that take the most execution time
$ py-spy top -- python [path/to/file.py]
copy

Produce an SVG flame graph of the function call execution time
$ py-spy record [[-o|--output]] [path/to/profile.svg] [[-p|--pid]] [pid]
copy

Dump the call stack of a running process
$ py-spy dump [[-p|--pid]] [pid]
copy

SYNOPSIS

py-spy command [options] (--pid PID | -- CMD [ARGS...])

Common Commands:
  py-spy record [record_options] (--pid PID | -- CMD [ARGS...])
  py-spy dump [dump_options] (--pid PID | -- CMD [ARGS...])
  py-spy top [top_options] (--pid PID | -- CMD [ARGS...])

PARAMETERS

command
    The py-spy subcommand to execute: record (for flame graphs), dump (for snapshot), or top (for live view).

--pid PID
    Attach to a running Python process specified by its Process ID.

-- CMD [ARGS...]
    Run a command and profile the Python process it spawns. Arguments after `--` are passed directly to the command.

--threads
    Profile all Python threads within the target process, not just the main thread.

--subprocesses
    Profile all Python subprocesses spawned by the target process.

--output FILE (-o)
    (Used with record) Output the profiling data to the specified file, commonly an SVG for flame graphs.

--format FORMAT
    (Used with record) Specify the output format: svg (default), raw (folded stacks), or speedscope.

--rate RATE (-r)
    (Used with record, top) Set the sampling rate in samples per second (default is 100 Hz).

--duration SECONDS
    (Used with record) Record for a fixed duration in seconds then exit.

--idle
    (Used with record) Include frames where the interpreter is idle (e.g., waiting on I/O) in the profiling data.

--full-stack
    (Used with dump) Show full Python stack traces, including internal interpreter frames.

--locals
    (Used with dump) Include local variables in the stack dump (use with caution as it can reveal sensitive data).

DESCRIPTION

py-spy is a sampling profiler for Python programs. It allows you to profile any running Python program without restarting the process or modifying the code. Built in Rust for speed and safety, py-spy attaches to the target Python process and samples its call stack at a regular interval. This approach results in very low overhead, making it ideal for use in production environments. It can generate flame graphs, display live `top`-like views of CPU usage, or dump a snapshot of the current call stack. py-spy is particularly useful for identifying performance bottlenecks, CPU utilization issues, and understanding where your Python code spends its time, even when C extensions or native code are involved.

CAVEATS

On Linux, py-spy requires either root privileges or the CAP_SYS_PTRACE capability to attach to other processes. It works by directly reading from the target process's memory, which means it may not correctly interpret data if the Python interpreter's internal structures change significantly across Python versions. While low, there is still some overhead introduced by sampling. Ensure the Python interpreter is not stripped of symbols for optimal results.

HOW IT WORKS

On Linux, py-spy uses the `ptrace` system call to attach to a running Python process. It then directly reads memory from the target process to identify the Python interpreter's state and reconstruct the call stack. This direct memory access allows it to work without requiring any changes to the Python application's code or interpreter, making it truly non-invasive.

PROFILING OUTPUT

The primary output format for the record command is an interactive SVG flame graph. Flame graphs provide a visual representation of the call stack, showing where time is being spent and highlighting hot paths. py-spy also supports raw call stack data output (useful for other analysis tools) and the speedscope format for analysis in the speedscope.app UI, which offers various visualization modes.

HISTORY

Developed by Ben Frederickson, py-spy was created to address the need for a low-overhead, non-invasive Python profiler that could be used in production environments without requiring code modifications or application restarts. It is notable for being written entirely in Rust, which contributes to its performance and safety characteristics. Its development started around 2018 and quickly gained traction in the Python community due to its unique capabilities and ease of use compared to traditional Python profilers.

SEE ALSO

perf(1), strace(1), gdb(1), Built-in Python profilers (e.g., cProfile, profile), Linux `top` command (for similar live process view)

Copied to clipboard