explaingit

benfred/py-spy

15,178Rust

TLDR

py-spy is a tool that watches a running Python program from the outside and reports which parts of its code are taking the most time.

Mindmap

A visual breakdown will appear here once this repo is fully enriched.

In plain English

py-spy is a tool that watches a running Python program from the outside and reports which parts of its code are taking the most time. The category it belongs to is called a sampling profiler. Sampling profilers periodically check what a program is doing, then aggregate those snapshots to show where time is spent. The distinguishing point of py-spy is that you do not need to restart the Python program or change a single line of its source code to use it. You just point py-spy at the running process. The README emphasises that py-spy is safe to use on production code. It is written in Rust, which the author cites for speed, and it runs in a separate process from the Python program it is watching. A buggy or slow profiler cannot interfere with the program serving real traffic because the profiler is not inside it. py-spy works on Linux, macOS, Windows, and FreeBSD, and supports CPython versions 2.3 through 2.7 and 3.3 through 3.14. Installation is usually one command, such as pip install py-spy or brew install py-spy on macOS. py-spy has three subcommands. record writes a profile to a file, by default an interactive SVG flame graph that shows which function calls dominated, with options for speedscope-format output or raw data. top shows a live updating view in the terminal of the functions currently using the most time, modelled on the Unix top command. dump prints the current call stack for every Python thread once, which the README describes as useful when you need to find where a hung program is stuck. A --locals flag also prints the local variables in each stack frame. Under the hood, py-spy reads the memory of the target Python process directly, using process_vm_readv on Linux, vm_read on macOS, and ReadProcessMemory on Windows. It walks the Python interpreter's internal data structures to reconstruct the call stack of each Python thread. Because Python's internal layout changes between versions, py-spy uses Rust's bindgen tool to generate per-version definitions of the relevant structures. When the target Python binary is stripped of symbols, py-spy scans memory for something that looks like a valid interpreter state. Other documented features include profiling native C, C++, or Cython extensions with --native, profiling all child processes with --subprocesses, and a note that reading another process's memory often requires running as root on Linux and always requires it on macOS.

Open on GitHub → Explain another repo

Generated 2026-05-21 · Model: sonnet-4-6 · Verify against the repo before relying on details.