Sampling profiler for Python programs written in Rust with extremely low overhead
—
Comprehensive configuration system supporting multiple profiling modes, output formats, and platform-specific options. Enables fine-tuned control over profiling behavior for different use cases from development to production.
Main configuration object controlling all aspects of py-spy behavior. Provides sensible defaults while allowing customization for specific profiling scenarios.
pub struct Config {
/// Process locking strategy during sampling
pub blocking: LockingStrategy,
/// Whether to profile native C/C++/Cython extensions
pub native: bool,
/// Sampling rate in Hz (samples per second)
pub sampling_rate: u64,
/// Output file format for record command
pub format: Option<FileFormat>,
/// Whether to include line numbers in output
pub show_line_numbers: bool,
/// Recording duration for record command
pub duration: RecordDuration,
/// Include idle/sleeping threads in results
pub include_idle: bool,
/// Include thread IDs in flamegraph output
pub include_thread_ids: bool,
/// Profile child processes and subprocesses
pub subprocesses: bool,
/// Only show threads holding the GIL
pub gil_only: bool,
/// Hide progress bar output
pub hide_progress: bool,
/// Capture stdout/stderr from spawned processes
pub capture_output: bool,
/// Output format for dump command (JSON vs text)
pub dump_json: bool,
/// Number of local variables to collect (0 = none)
pub dump_locals: u64,
/// Show full file paths vs shortened versions
pub full_filenames: bool,
/// Line number reporting mode
pub lineno: LineNo,
/// Console refresh rate for top command
pub refresh_seconds: f64,
// Additional private fields for CLI usage...
}
impl Config {
/// Creates Config from command line arguments
pub fn from_commandline() -> Config;
/// Creates Config from specific argument list
pub fn from_args(args: &[String]) -> clap::Result<Config>;
}
impl Default for Config {
fn default() -> Config;
}Default Configuration:
Config {
blocking: LockingStrategy::Lock,
native: false,
sampling_rate: 100,
format: None,
show_line_numbers: false,
duration: RecordDuration::Unlimited,
include_idle: false,
include_thread_ids: false,
subprocesses: false,
gil_only: false,
hide_progress: false,
capture_output: true,
dump_json: false,
dump_locals: 0,
full_filenames: false,
lineno: LineNo::LastInstruction,
refresh_seconds: 1.0,
// CLI-specific fields omitted...
}Controls how py-spy interacts with the target process during sampling, affecting both accuracy and performance impact.
pub enum LockingStrategy {
/// Standard mode: pause process during sampling for accurate results
Lock,
/// Non-blocking mode: sample without pausing (lower impact, potential inaccuracy)
NonBlocking,
/// Process is already locked by another tool
AlreadyLocked,
}Usage Examples:
// Standard mode - most accurate, slight performance impact
let mut config = Config::default();
config.blocking = LockingStrategy::Lock;
// Production mode - minimal impact, potential sampling errors
let mut config = Config::default();
config.blocking = LockingStrategy::NonBlocking;Multiple output formats for different analysis tools and workflows.
pub enum FileFormat {
/// SVG flamegraph for visual analysis
flamegraph,
/// Raw flamegraph data (text format)
raw,
/// Speedscope JSON format for speedscope.app
speedscope,
/// Chrome trace format for chrome://tracing
chrometrace,
}
impl std::str::FromStr for FileFormat {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err>;
}Format Descriptions:
Controls how long profiling sessions run, useful for automated profiling and resource management.
pub enum RecordDuration {
/// Continue recording until manually stopped (Ctrl-C)
Unlimited,
/// Record for specified number of seconds
Seconds(u64),
}Usage Examples:
// Short burst profiling
let mut config = Config::default();
config.duration = RecordDuration::Seconds(30);
// Continuous profiling until stopped
let mut config = Config::default();
config.duration = RecordDuration::Unlimited;Controls how line numbers are reported in stack traces.
pub enum LineNo {
/// Don't include line numbers
NoLine,
/// Use first line of function definition
First,
/// Use line of last executed instruction (default)
LastInstruction,
}Optimized for detailed analysis during development with comprehensive information collection.
use py_spy::{Config, LockingStrategy, RecordDuration, LineNo};
fn development_config() -> Config {
let mut config = Config::default();
config.blocking = LockingStrategy::Lock; // Accurate sampling
config.show_line_numbers = true; // Include line numbers
config.include_idle = false; // Skip idle threads
config.sampling_rate = 100; // Standard rate
config.lineno = LineNo::LastInstruction; // Precise line info
config.full_filenames = true; // Full paths for debugging
config
}Minimizes performance impact while collecting useful profiling data.
use py_spy::{Config, LockingStrategy, RecordDuration};
fn production_config() -> Config {
let mut config = Config::default();
config.blocking = LockingStrategy::NonBlocking; // Minimal impact
config.sampling_rate = 50; // Lower sampling rate
config.duration = RecordDuration::Seconds(60); // Limited duration
config.hide_progress = true; // No UI interference
config.gil_only = true; // Focus on active threads
config
}Configured for profiling applications using C/C++/Cython extensions.
use py_spy::{Config, LockingStrategy};
fn native_extension_config() -> Config {
let mut config = Config::default();
config.native = true; // Enable native profiling
config.blocking = LockingStrategy::Lock; // Required for native traces
config.show_line_numbers = true; // Helpful for mixed code
config.sampling_rate = 200; // Higher rate for detail
config
}Configured for profiling applications that spawn child processes.
use py_spy::{Config, RecordDuration};
fn subprocess_config() -> Config {
let mut config = Config::default();
config.subprocesses = true; // Follow child processes
config.include_thread_ids = true; // Distinguish processes
config.duration = RecordDuration::Seconds(120); // Longer duration
config.sampling_rate = 50; // Manage overhead
config
}SVG format providing interactive visualization of call stack hierarchies.
use py_spy::{Config, FileFormat};
let mut config = Config::default();
config.format = Some(FileFormat::flamegraph);
config.show_line_numbers = true; // Include line info in frames
config.include_thread_ids = false; // Clean visualizationFeatures:
JSON format optimized for detailed analysis in speedscope.app.
use py_spy::{Config, FileFormat};
let mut config = Config::default();
config.format = Some(FileFormat::speedscope);
config.include_thread_ids = true; // Thread separation
config.show_line_numbers = true; // Detailed frame infoFeatures:
JSON format compatible with Chrome DevTools and Perfetto.
use py_spy::{Config, FileFormat};
let mut config = Config::default();
config.format = Some(FileFormat::chrometrace);
config.include_thread_ids = true; // Thread-based visualization
config.sampling_rate = 1000; // High resolutionFeatures:
Text format compatible with flamegraph.pl and custom processing tools.
use py_spy::{Config, FileFormat};
let mut config = Config::default();
config.format = Some(FileFormat::raw);
config.full_filenames = true; // Complete paths
config.show_line_numbers = true; // Line informationFeatures:
// Core dump analysis (Linux only)
let mut config = Config::default();
config.core_filename = Some("/path/to/core.dump".to_string());
// Docker-aware profiling
config.blocking = LockingStrategy::NonBlocking; // May be required in containers// macOS requires more conservative settings
let mut config = Config::default();
config.sampling_rate = 50; // Lower rate for stability
// Note: Requires root privileges (sudo)// Windows-specific optimizations
let mut config = Config::default();
config.sampling_rate = 100; // Standard rate works well
config.hide_progress = true; // Better console compatibilityConfiguration errors are typically reported through clap's error system when using from_args(), or through Result types in the library API.
use py_spy::Config;
// Handle CLI parsing errors
let config = match Config::from_args(&args) {
Ok(config) => config,
Err(e) => {
eprintln!("Configuration error: {}", e);
std::process::exit(1);
}
};
// Validate configuration compatibility
if config.native && config.blocking == LockingStrategy::NonBlocking {
eprintln!("Error: Native profiling requires blocking mode");
std::process::exit(1);
}Install with Tessl CLI
npx tessl i tessl/pypi-py-spy