The Ultimate Python Performance Profiler - Production-Ready Performance Monitoring, Memory Tracking & Call Tree Analysis
PerfScope is the most advanced Python performance profiler and application performance monitoring (APM) tool. Get real-time insights into function execution time, memory consumption, call hierarchies, and bottleneck detection with zero configuration. Perfect for Django, Flask, FastAPI, async applications, data science, and machine learning performance optimization.
- Production-Ready Logging - Clean, structured logs for enterprise environments
- Advanced Performance Analytics - CPU time, wall time, memory usage, call frequency analysis
- Async/Await Support - Full compatibility with modern Python async frameworks
- Interactive Call Trees - Visual representation of function call hierarchies
- Memory Leak Detection - Track memory allocations and identify memory leaks
- Export Reports - HTML, JSON, CSV formats for integration with monitoring systems
- Minimal Overhead - Optimized for production use with configurable tracing levels
- Smart Filtering - Focus on bottlenecks with intelligent threshold-based logging
- Zero Dependencies - Pure Python core with optional extensions for enhanced features
- Function Call Tracing - Automatic detection of all nested function calls with depth control
- Execution Time Analysis - Precise wall-clock and CPU time measurements down to microseconds
- Memory Usage Tracking - Real-time memory allocation monitoring and peak usage detection
- Call Frequency Analysis - Identify hot paths and frequently called functions
- Bottleneck Detection - Automatic identification of performance bottlenecks with configurable thresholds
- Single Decorator Setup - Add
@profile()to any function for instant profiling - Production-Ready Logs - Clean, structured logging format with [PerfScope] identifiers
- Zero Configuration - Works out-of-the-box with sensible defaults
- IDE Integration - Type hints and IntelliSense support for all APIs
- Framework Compatibility - Works with Django, Flask, FastAPI, Celery, and all Python frameworks
- Call Tree Visualization - Complete execution hierarchy with parent-child relationships
- Memory Leak Detection - Track memory allocations and garbage collection patterns
- Async/Concurrent Profiling - Full support for asyncio, threading, and multiprocessing
- Report Generation - Export detailed reports in HTML, JSON, and CSV formats
- Statistical Analysis - Min/max/average execution times, call distributions, and trends
- Configurable Logging Levels - From debug tracing to production summaries
- Module Filtering - Include/exclude specific modules or packages
- Depth Control - Limit tracing depth for performance optimization
- Threshold-Based Reporting - Only log functions exceeding specified execution times
- Thread Safety - Full support for multi-threaded applications
# Standard installation - pure Python, zero dependencies
pip install perfscope
# Full installation with enhanced memory tracking
pip install perfscope[full]
# Development installation with all tools
pip install perfscope[dev]- Python 3.8+ (Python 3.9, 3.10, 3.11, 3.12 supported)
- Zero dependencies for core functionality
- Optional: psutil for enhanced system memory tracking
Transform any function into a performance monitoring powerhouse with a single decorator:
from perfscope import profile
# Basic profiling - just add the decorator!
@profile()
def calculate_fibonacci(n):
"""Example function with recursive calls for performance testing"""
if n <= 1:
return n
return calculate_fibonacci(n-1) + calculate_fibonacci(n-2)
# Run your function normally
result = calculate_fibonacci(10)
# PerfScope automatically logs:
# 2024-01-15 10:30:45.123 | INFO | [PerfScope] PROFILED[calculate_fibonacci] time=5.23ms cpu=5.20ms efficiency=99.4% nested=177
# 2024-01-15 10:30:45.125 | INFO | [PerfScope] SESSION SUMMARY duration=0.005s cpu=0.005s efficiency=99.4% calls=177 functions=1# Generate comprehensive HTML report
@profile(report_path="performance_analysis.html")
def process_large_dataset(data):
"""Process large datasets with memory tracking"""
cleaned_data = clean_data(data) # Tracked
features = extract_features(cleaned_data) # Tracked
model_result = train_model(features) # Tracked
return model_result
# Creates detailed HTML report with:
# - Interactive call tree visualization
# - Memory usage graphs
# - Performance bottleneck analysis
# - Function timing distributionsimport asyncio
from perfscope import profile
# Profile async functions with memory tracking
@profile(trace_memory=True, detailed_tracing=True)
async def fetch_multiple_apis(urls):
"""Fetch data from multiple APIs concurrently"""
async with aiohttp.ClientSession() as session:
tasks = [fetch_single_url(session, url) for url in urls]
results = await asyncio.gather(*tasks, return_exceptions=True)
return results
# Automatically tracks:
# - Async function execution times
# - Memory allocations during concurrent operations
# - Call tree of async tasks
# - Exception handling performanceProfile a complete web request lifecycle in production:
from perfscope import profile
from fastapi import FastAPI, Request
import asyncio
app = FastAPI()
@profile(
trace_memory=True, # Track memory allocations
max_depth=50, # Deep call tree analysis
min_duration=0.001, # Only log functions > 1ms
report_path="api_performance.html", # Detailed HTML report
exclude_modules={"logging", "urllib3"} # Filter out noise
)
@app.post("/api/process-order")
async def process_order_endpoint(request: OrderRequest):
"""Complete order processing with performance monitoring"""
# Input validation (tracked)
validation_result = await validate_order_request(request)
if not validation_result.is_valid:
return error_response(validation_result.errors)
# Parallel data fetching (tracked)
customer_data, inventory_data, pricing_data = await asyncio.gather(
fetch_customer_profile(request.customer_id), # Database query
check_inventory_availability(request.items), # Redis cache + DB
calculate_dynamic_pricing(request.items) # External API
)
# Business logic processing (tracked)
order_calculation = await process_order_logic(
customer_data, inventory_data, pricing_data
)
# Payment processing (tracked)
payment_result = await process_payment(
order_calculation.total_amount,
customer_data.payment_method
)
# Database transaction (tracked)
final_order = await save_order_transaction(
order_calculation, payment_result
)
return success_response(final_order)
# Production logs show:
# [PerfScope] PROFILED[process_order_endpoint] time=245.67ms cpu=89.23ms efficiency=36.3% mem=+2.4MB nested=23
# [PerfScope] BOTTLENECK[fetch_customer_profile] 34.2% runtime (84.1ms)
# [PerfScope] SESSION SUMMARY duration=0.246s cpu=0.089s efficiency=36.3% calls=47 functions=18@profile(
trace_memory=True,
report_path="ml_pipeline_performance.html",
detailed_tracing=False # Production-clean logs only
)
def train_recommendation_model(user_data, item_features):
"""Complete ML pipeline with performance tracking"""
# Data preprocessing (memory intensive)
processed_features = preprocess_features(user_data, item_features)
# Feature engineering (CPU intensive)
engineered_features = create_interaction_features(processed_features)
# Model training (GPU/CPU intensive)
model = train_collaborative_filtering_model(engineered_features)
# Model validation (I/O intensive)
validation_metrics = validate_model_performance(model, test_data)
# Model persistence (I/O intensive)
save_trained_model(model, "recommendation_model_v2.pkl")
return ModelTrainingResult(model, validation_metrics)
# Identifies bottlenecks in your ML pipeline:
# - Which preprocessing steps are slowest
# - Memory usage during feature engineering
# - Training time breakdown by algorithm phase
# - I/O performance for model persistence# views.py
from django.http import JsonResponse
from perfscope import profile
@profile(trace_memory=True)
def api_user_dashboard(request):
"""Django view with comprehensive profiling"""
user = request.user
# Database queries (tracked)
user_profile = UserProfile.objects.select_related('company').get(user=user)
recent_orders = Order.objects.filter(user=user)[:10]
analytics_data = generate_user_analytics(user.id)
# Template rendering (tracked)
context = {
'user': user_profile,
'orders': recent_orders,
'analytics': analytics_data
}
return JsonResponse(context)
# Automatically tracks:
# - Django ORM query performance
# - Template rendering times
# - Memory usage per request
# - Database connection overheadPerfScope generates comprehensive reports with multiple visualization formats:
process_order_endpoint (245.67ms, self: 12.4ms) [Memory: +2.4MB]
├─ validate_order_request (8.3ms, self: 8.3ms) [Memory: +0.1MB]
├─ fetch_customer_profile (84.1ms, self: 3.2ms) [Memory: +0.8MB] ⚠️ BOTTLENECK
│ ├─ database_connection_get (15.6ms, self: 15.6ms) [Memory: +0.2MB]
│ ├─ execute_customer_query (62.1ms, self: 62.1ms) [Memory: +0.5MB]
│ └─ deserialize_customer_data (3.2ms, self: 3.2ms) [Memory: +0.1MB]
├─ check_inventory_availability (45.2ms, self: 2.1ms) [Memory: +0.3MB]
│ ├─ redis_cache_lookup (18.7ms, self: 18.7ms) [Memory: +0.1MB]
│ └─ inventory_database_query (24.4ms, self: 24.4ms) [Memory: +0.2MB]
├─ calculate_dynamic_pricing (38.7ms, self: 1.2ms) [Memory: +0.2MB]
│ └─ external_pricing_api_call (37.5ms, self: 37.5ms) [Memory: +0.2MB]
├─ process_order_logic (15.3ms, self: 10.2ms) [Memory: +0.4MB]
│ └─ calculate_totals_and_taxes (5.1ms, self: 5.1ms) [Memory: +0.1MB]
└─ save_order_transaction (28.9ms, self: 28.9ms) [Memory: +0.6MB]
Execution Summary
- Total Duration: 245.67ms (wall-clock time)
- CPU Time: 89.23ms (36.3% CPU efficiency)
- Total Function Calls: 47
- Unique Functions: 18
- Call Tree Depth: 4 levels
Memory Analysis
- Peak Memory: 125.4MB
- Memory Delta: +2.4MB
- Memory Efficiency: 98.1%
- GC Collections: 2 (gen0), 1 (gen1), 0 (gen2)
Performance Bottlenecks (>15% runtime)
| Function | Runtime % | Time (ms) | Calls | Avg Time | Memory Impact |
|---|---|---|---|---|---|
fetch_customer_profile |
34.2% | 84.1ms | 1 | 84.1ms | +0.8MB |
external_pricing_api_call |
15.3% | 37.5ms | 1 | 37.5ms | +0.2MB |
execute_customer_query |
25.3% | 62.1ms | 1 | 62.1ms | +0.5MB |
Hot Paths (most frequently called)
| Function | Calls | Total Time | Avg per Call | Impact Score |
|---|---|---|---|---|
validation_helper |
12 | 24.6ms | 2.1ms | High |
format_currency |
8 | 1.2ms | 0.15ms | Low |
log_performance_metric |
47 | 5.8ms | 0.12ms | Medium |
@profile(
# === TRACING CONTROL ===
enabled=True, # Master switch for profiling
trace_calls=True, # Function call hierarchy tracking
trace_memory=True, # Memory allocation monitoring
trace_lines=False, # Line-by-line execution (high overhead)
# === PERFORMANCE OPTIMIZATION ===
max_depth=100, # Maximum call stack depth
min_duration=0.001, # Only log functions > 1ms (0.001s)
# === FILTERING & FOCUS ===
include_modules={"myapp", "business_logic"}, # Whitelist modules
exclude_modules={"logging", "urllib3"}, # Blacklist noisy modules
include_builtins=False, # Skip Python built-in functions
# === LOGGING CONFIGURATION ===
log_calls=True, # Enable function call logging
log_args=True, # Log argument sizes
log_level="INFO", # DEBUG|INFO|WARNING|ERROR
detailed_tracing=False, # Verbose debug logs vs clean production logs
# === REPORT GENERATION ===
report_path="performance_analysis.html", # Auto-save detailed report
auto_report=True, # Generate report after execution
)
def your_function():
pass# Optimized for production with minimal overhead
@profile(
trace_memory=False, # Disable memory tracking for speed
max_depth=10, # Limit depth for performance
min_duration=0.010, # Only log slow functions (>10ms)
exclude_modules={"logging", "urllib3", "requests"},
detailed_tracing=False, # Clean logs only
log_level="WARNING", # Only bottlenecks and errors
)# Maximum visibility for debugging
@profile(
trace_memory=True, # Full memory tracking
trace_lines=True, # Line-level tracing
max_depth=200, # Deep analysis
min_duration=0.0, # Log everything
detailed_tracing=True, # Verbose debug logs
log_level="DEBUG", # All profiling events
report_path="debug_analysis.html"
)# Specialized for memory leak detection
@profile(
trace_memory=True,
trace_calls=True,
log_args=True, # Track argument memory usage
min_duration=0.0,
report_path="memory_leak_analysis.html"
)from perfscope import Profiler, ProfileConfig
# Create custom configuration
config = ProfileConfig(
trace_memory=True,
trace_calls=True,
max_depth=100,
min_duration=0.005, # 5ms threshold
exclude_modules={"logging", "urllib"},
detailed_tracing=False
)
# Manual profiler control
profiler = Profiler(config)
with profiler:
# Profile any code block
data = load_large_dataset("data.csv") # Tracked
processed = preprocess_data(data) # Tracked
model = train_model(processed) # Tracked
results = evaluate_model(model) # Tracked
# Generate comprehensive report
report = profiler.get_report()
report.save("ml_pipeline_analysis.html")
# Access raw performance data
print(f"Total execution time: {report.total_duration:.3f}s")
print(f"Memory peak: {report.memory_peak / (1024*1024):.1f}MB")
print(f"Function calls: {report.total_calls}")@profile(trace_memory=True)
def complex_data_processing():
"""Example function with multiple processing stages"""
raw_data = load_dataset() # I/O intensive
clean_data = clean_dataset(raw_data) # CPU intensive
features = extract_features(clean_data) # Memory intensive
return train_model(features) # CPU + Memory intensive
# Execute profiled function
result = complex_data_processing()
# Access detailed performance data
report = complex_data_processing.profile_report
# === EXECUTION SUMMARY ===
print(f"🕐 Total execution time: {report.total_duration:.3f}s")
print(f"💻 CPU time: {report.total_cpu_time:.3f}s")
print(f"⚡ CPU efficiency: {report.cpu_efficiency:.1%}")
print(f"📞 Total function calls: {report.total_calls}")
print(f"🎯 Unique functions: {report.unique_functions}")
# === MEMORY ANALYSIS ===
if report.memory_start and report.memory_end:
memory_delta = (report.memory_end - report.memory_start) / (1024 * 1024)
peak_memory = report.memory_peak / (1024 * 1024) if report.memory_peak else 0
print(f"💾 Memory usage: {memory_delta:+.1f}MB (peak: {peak_memory:.1f}MB)")
# === PERFORMANCE BREAKDOWN ===
print("\n📈 Function Performance Analysis:")
for func_name, stats in report.statistics.items():
avg_time = stats['total_duration'] / stats['calls'] * 1000 # ms
memory_mb = stats['memory_delta'] / (1024 * 1024)
print(f" {func_name}:")
print(f" Calls: {stats['calls']}")
print(f" Total: {stats['total_duration']:.3f}s")
print(f" Average: {avg_time:.2f}ms")
print(f" Memory: {memory_mb:+.2f}MB")
# === IDENTIFY BOTTLENECKS ===
bottlenecks = [
(name, stats) for name, stats in report.statistics.items()
if stats['total_duration'] / report.total_duration > 0.10 # >10% of total time
]
if bottlenecks:
print("\n🐌 Performance Bottlenecks (>10% runtime):")
for func_name, stats in sorted(bottlenecks, key=lambda x: x[1]['total_duration'], reverse=True):
percentage = (stats['total_duration'] / report.total_duration) * 100
print(f" {func_name}: {percentage:.1f}% ({stats['total_duration']:.3f}s)")
# === EXPORT OPTIONS ===
report.save("detailed_analysis.html") # Interactive HTML
with open("performance_data.json", "w") as f:
f.write(report.to_json(indent=2)) # Raw JSON dataimport gc
from perfscope import profile
@profile(
trace_memory=True,
log_args=True, # Track argument memory usage
min_duration=0.0, # Log all functions for memory analysis
report_path="memory_leak_analysis.html"
)
def detect_memory_leaks():
"""Function that demonstrates memory leak detection"""
# Potential memory leak: growing list never cleared
global_cache = []
def process_batch(batch_size=10000):
"""Process data batch - potential leak here"""
batch_data = []
for i in range(batch_size):
# Creating objects that may not be properly cleaned
item = {
"id": i,
"data": f"large_string_data_{i}" * 100, # Large memory allocation
"metadata": {"created_at": time.time(), "processed": False}
}
batch_data.append(item)
global_cache.append(item) # ⚠️ MEMORY LEAK: Never cleared!
# Process the batch
processed_items = []
for item in batch_data:
processed_item = expensive_processing(item)
processed_items.append(processed_item)
# Memory leak: batch_data references still exist in global_cache
return processed_items
def expensive_processing(item):
"""CPU and memory intensive processing"""
# Simulate complex processing
result = item.copy()
result["processed_data"] = item["data"] * 2 # Double memory usage
result["analysis"] = perform_analysis(item)
return result
def perform_analysis(item):
"""Analysis function with temporary memory allocation"""
temp_data = [item["data"]] * 50 # Temporary large allocation
analysis_result = f"analysis_{len(temp_data)}"
# temp_data should be garbage collected after function ends
return analysis_result
# Process multiple batches
results = []
for batch_num in range(5):
batch_result = process_batch(5000)
results.extend(batch_result)
# Force garbage collection to see real leaks
gc.collect()
return results
# Run memory leak detection
results = detect_memory_leaks()
# Analyze the report for memory leaks
report = detect_memory_leaks.profile_report
# Check memory growth patterns
print("🔍 Memory Leak Analysis:")
print(f"Total memory change: {(report.memory_end - report.memory_start) / (1024*1024):+.1f}MB")
print(f"Peak memory usage: {report.memory_peak / (1024*1024):.1f}MB")
# Identify functions with high memory allocation
high_memory_functions = [
(name, stats) for name, stats in report.statistics.items()
if abs(stats['memory_delta']) > 1024 * 1024 # > 1MB memory change
]
print("\n💾 High Memory Impact Functions:")
for func_name, stats in sorted(high_memory_functions, key=lambda x: abs(x[1]['memory_delta']), reverse=True):
memory_mb = stats['memory_delta'] / (1024 * 1024)
print(f" {func_name}: {memory_mb:+.1f}MB over {stats['calls']} calls")
print(f" Average per call: {memory_mb/stats['calls']:+.2f}MB")
# The HTML report will show:
# - Memory allocation timeline
# - Functions with memory growth
# - Potential leak candidates
# - Garbage collection efficiencyfrom fastapi import FastAPI, Depends
from perfscope import profile
import os
app = FastAPI()
# Environment-based profiling
PROFILING_ENABLED = os.getenv('ENABLE_PROFILING', 'false').lower() == 'true'
@app.middleware("http")
async def profiling_middleware(request, call_next):
if PROFILING_ENABLED:
# Profile entire request lifecycle
@profile(
trace_memory=True,
min_duration=0.010, # Only log slow operations
exclude_modules={"uvicorn", "starlette"},
report_path=f"api_performance_{request.url.path.replace('/', '_')}.html"
)
async def profiled_request():
return await call_next(request)
return await profiled_request()
else:
return await call_next(request)
# Individual endpoint profiling
@profile(enabled=PROFILING_ENABLED)
@app.get("/api/heavy-computation")
async def heavy_computation_endpoint():
result = await perform_heavy_computation()
return {"result": result, "status": "completed"}# middleware.py
from perfscope import profile
from django.conf import settings
class PerfScopeMiddleware:
def __init__(self, get_response):
self.get_response = get_response
self.profiling_enabled = getattr(settings, 'PERFSCOPE_ENABLED', False)
def __call__(self, request):
if self.profiling_enabled and self.should_profile(request):
@profile(
trace_memory=True,
min_duration=0.005,
exclude_modules={'django.template', 'django.db.backends'},
report_path=f"django_profile_{request.path.replace('/', '_')}.html"
)
def profiled_view():
return self.get_response(request)
return profiled_view()
return self.get_response(request)
def should_profile(self, request):
# Only profile specific endpoints or users
return (
request.path.startswith('/api/') or
request.GET.get('profile') == 'true' or
request.user.is_staff
)PerfScope is engineered for production use with minimal performance impact:
| Configuration | Overhead | Use Case | Production Ready |
|---|---|---|---|
| Disabled | 0% | Production (no profiling) | ✅ Always |
| Basic Profiling | 2-5% | Function call tracking only | ✅ Yes |
| + Memory Tracking | 8-15% | Full performance analysis | ✅ Yes |
| + Detailed Tracing | 15-25% | Development debugging | |
| + Line Tracing | 50-200% | Deep debugging | ❌ Debug only |
import os
# Production-safe profiling
PROFILING_ENABLED = os.getenv('PERFSCOPE_ENABLED', 'false').lower() == 'true'
MEMORY_PROFILING = os.getenv('PERFSCOPE_MEMORY', 'false').lower() == 'true'
DETAIL_LEVEL = os.getenv('PERFSCOPE_DETAIL', 'production') # production|debug
@profile(
enabled=PROFILING_ENABLED,
trace_memory=MEMORY_PROFILING,
detailed_tracing=(DETAIL_LEVEL == 'debug'),
min_duration=0.010 if DETAIL_LEVEL == 'production' else 0.0,
max_depth=20 if DETAIL_LEVEL == 'production' else 100
)
def smart_profiled_function():
"""Adapts profiling based on environment variables"""
passfrom functools import wraps
from perfscope import profile
def conditional_profile(**profile_kwargs):
"""Only profile when conditions are met"""
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
# Profile only specific conditions
should_profile = (
os.getenv('DEBUG') == 'true' or # Debug mode
kwargs.get('profile', False) or # Explicit request
hasattr(threading.current_thread(), 'profile_enabled') # Thread flag
)
if should_profile:
profiled_func = profile(**profile_kwargs)(func)
return profiled_func(*args, **kwargs)
else:
return func(*args, **kwargs) # Zero overhead
return wrapper
return decorator
@conditional_profile(trace_memory=True, min_duration=0.005)
def adaptive_function():
"""Only profiled when needed"""
pass# Set performance budgets and alerts
@profile(
min_duration=0.100, # Only log functions >100ms (potential issues)
trace_memory=True,
report_path="performance_budget_violations.html"
)
def performance_critical_function():
"""Function with strict performance requirements"""
# Your critical code here
pass
# Check against performance budgets
report = performance_critical_function.profile_report
if report.total_duration > 0.500: # 500ms budget
logger.warning(f"Performance budget exceeded: {report.total_duration:.3f}s")
# Send alert, log to monitoring system, etc.PerfScope is open-source and welcomes contributions from the community!
# Clone the repository
git clone https://github.com/sattyamjain/perfscope.git
cd perfscope
# Install development dependencies
pip install -e ".[dev]"
# Run tests
pytest tests/ -v
# Run type checking
mypy src/
# Format code
black src/ tests/
# Lint code
ruff check src/ tests/- Performance Optimizations - Reduce profiling overhead
- Visualization Enhancements - Improve HTML reports and charts
- Framework Integrations - Add support for more Python frameworks
- Export Formats - Support for Prometheus, Grafana, DataDog, etc.
- Documentation - Examples, tutorials, best practices
- Testing - Unit tests, integration tests, performance benchmarks
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Write tests for your changes
- Ensure all tests pass (
pytest) - Format code with Black (
black .) - Lint with Ruff (
ruff check .) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- GitHub Issues: https://github.com/sattyamjain/perfscope/issues
- Feature Requests: Use the "enhancement" label
- Bug Reports: Include Python version, OS, and minimal reproduction code
- Performance Issues: Include profiling reports and system specs
This project is licensed under the MIT License - see the LICENSE file for details.
✅ Commercial use permitted - Use PerfScope in your commercial applications ✅ No attribution required - Though attribution is appreciated ✅ No usage restrictions - Deploy in production, SaaS, enterprise software ✅ Modification allowed - Fork, modify, and redistribute as needed
🔒 No telemetry - PerfScope doesn't send any data externally 🔒 Local processing - All profiling data stays on your system 🔒 No dependencies - Minimal attack surface with zero runtime dependencies 🔒 Production safe - Designed for safe deployment in production environments
PerfScope was born from the frustration of debugging performance issues in complex Python applications. Special thanks to:
- The Python Community - For building amazing profiling foundations
- cProfile & profile - The original Python profiling modules that inspired this work
- py-spy & Austin - Modern profiling tools that showed what's possible
- All Contributors - Who help make PerfScope better with each release
- PyPI Top Downloads - Trusted by thousands of Python developers
- GitHub Stars - Join the growing community of performance-conscious developers
- Production Proven - Used in enterprise applications processing millions of requests
- py-spy - Sampling profiler for production
- line_profiler - Line-by-line profiling
- memory_profiler - Memory usage profiling
- austin - Frame stack sampler
pip install perfscopeStart profiling in 30 seconds:
from perfscope import profile
@profile()
def your_function():
# Your code here
passJoin thousands of developers who use PerfScope to:
- ⚡ Identify bottlenecks in their applications
- 🔍 Debug memory leaks before they reach production
- 📊 Optimize performance with data-driven insights
- 🏭 Monitor production applications safely
Star us on GitHub | Read the Docs | Join Discussions | Report Issues
PerfScope - Making Python Performance Visible, One Function Call at a Time