0
# py-spy
1
2
A sampling profiler for Python programs written in Rust that allows developers to visualize what their Python programs are spending time on without restarting the program or modifying code. py-spy operates outside the profiled Python process with extremely low overhead, making it safe for production use.
3
4
## Package Information
5
6
- **Package Name**: py-spy
7
- **Package Type**: pypi
8
- **Language**: Rust (command-line tool)
9
- **Installation**: `pip install py-spy`
10
- **Platforms**: Linux, macOS, Windows, FreeBSD
11
- **Python Support**: 2.3-2.7, 3.3-3.13
12
13
## Core Imports
14
15
py-spy is primarily used as a command-line tool installed via pip. For advanced users who want to embed py-spy functionality in Rust applications:
16
17
```rust
18
use py_spy::{Config, PythonSpy, StackTrace, Frame, Pid};
19
use py_spy::sampler::Sampler;
20
use anyhow::Error;
21
```
22
23
## Basic Usage
24
25
### Command Line Interface
26
27
```bash
28
# Profile existing process (record to flamegraph)
29
py-spy record -o profile.svg --pid 12345
30
31
# Profile new Python program
32
py-spy record -o profile.svg -- python myprogram.py
33
34
# Live console view (like top)
35
py-spy top --pid 12345
36
37
# Single stack trace snapshot
38
py-spy dump --pid 12345
39
```
40
41
### Rust Library API
42
43
```rust
44
use py_spy::{Config, PythonSpy, Pid};
45
use anyhow::Error;
46
47
fn profile_python_process(pid: Pid) -> Result<(), Error> {
48
// Create configuration with defaults
49
let config = Config::default();
50
51
// Create profiler instance
52
let mut spy = PythonSpy::new(pid, &config)?;
53
54
// Get current stack traces
55
let traces = spy.get_stack_traces()?;
56
57
// Process each thread's stack trace
58
for trace in traces {
59
println!("Thread {:#X} ({})", trace.thread_id, trace.status_str());
60
for frame in &trace.frames {
61
println!(" {} ({}:{})", frame.name, frame.filename, frame.line);
62
}
63
}
64
65
Ok(())
66
}
67
```
68
69
## Architecture
70
71
py-spy uses a multi-layered architecture for safe, cross-platform Python process profiling:
72
73
- **Process Memory Access**: Platform-specific memory reading (process_vm_readv on Linux, vm_read on macOS, ReadProcessMemory on Windows)
74
- **Python Interpreter Analysis**: Version-specific bindings for Python 2.3-3.13 to parse interpreter state
75
- **Stack Trace Collection**: Traverses PyFrameObject chains to reconstruct call stacks
76
- **Native Extension Support**: Optional libunwind integration for C/C++/Cython profiling
77
- **Output Generation**: Multiple format support (flamegraph, speedscope, Chrome trace, raw data)
78
79
This design enables py-spy to profile Python processes safely without code modification or significant performance impact.
80
81
## Capabilities
82
83
### Command Line Interface
84
85
Complete command-line profiling tool with three main subcommands and extensive configuration options for production and development use.
86
87
```bash { .api }
88
py-spy record [OPTIONS] [--pid PID | -- PYTHON_PROGRAM...]
89
py-spy top [OPTIONS] [--pid PID | -- PYTHON_PROGRAM...]
90
py-spy dump [OPTIONS] [--pid PID | -- PYTHON_PROGRAM...]
91
```
92
93
[Command Line Interface](./cli.md)
94
95
### Rust Library API
96
97
Programmatic profiling interface for integrating py-spy functionality into Rust applications and custom profiling tools.
98
99
```rust { .api }
100
struct PythonSpy;
101
impl PythonSpy {
102
fn new(pid: Pid, config: &Config) -> Result<PythonSpy, Error>;
103
fn get_stack_traces(&mut self) -> Result<Vec<StackTrace>, Error>;
104
}
105
106
struct Sampler;
107
impl Sampler {
108
fn new(pid: Pid, config: &Config) -> Result<Sampler, Error>;
109
}
110
impl Iterator for Sampler {
111
type Item = Sample;
112
}
113
```
114
115
[Rust Library API](./rust-api.md)
116
117
### Configuration and Output Formats
118
119
Comprehensive configuration system supporting multiple profiling modes, output formats, and platform-specific options.
120
121
```rust { .api }
122
struct Config {
123
blocking: LockingStrategy,
124
native: bool,
125
sampling_rate: u64,
126
format: Option<FileFormat>,
127
// ... additional fields
128
}
129
130
enum FileFormat {
131
flamegraph, // SVG flamegraph
132
speedscope, // JSON for speedscope.app
133
chrometrace, // Chrome trace format
134
raw, // Raw flamegraph data
135
}
136
```
137
138
[Configuration and Output](./config.md)
139
140
## Core Types
141
142
### Stack Trace Representation
143
144
```rust { .api }
145
struct StackTrace {
146
pid: Pid,
147
thread_id: u64,
148
thread_name: Option<String>,
149
os_thread_id: Option<u64>,
150
active: bool,
151
owns_gil: bool,
152
frames: Vec<Frame>,
153
process_info: Option<Arc<ProcessInfo>>,
154
}
155
156
impl StackTrace {
157
fn status_str(&self) -> &str;
158
fn format_threadid(&self) -> String;
159
}
160
```
161
162
### Frame Information
163
164
```rust { .api }
165
struct Frame {
166
name: String,
167
filename: String,
168
module: Option<String>,
169
short_filename: Option<String>,
170
line: i32,
171
locals: Option<Vec<LocalVariable>>,
172
is_entry: bool,
173
is_shim_entry: bool,
174
}
175
```
176
177
### Process Identification
178
179
```rust { .api }
180
type Pid = remoteprocess::Pid;
181
```
182
183
### Configuration Enums
184
185
```rust { .api }
186
enum LockingStrategy {
187
Lock, // Standard blocking mode
188
NonBlocking, // Minimal performance impact
189
AlreadyLocked, // Process already locked
190
}
191
192
enum RecordDuration {
193
Unlimited,
194
Seconds(u64),
195
}
196
197
enum LineNo {
198
NoLine,
199
First,
200
LastInstruction,
201
}
202
```