Profiling Commands

The profile command provides comprehensive performance analysis tools for CPU profiling, memory tracking, and benchmarking.

Overview

Profiling commands are provided by the structum-cli-tools plugin:

pip install structum-cli-tools

This adds three profiling subcommands for performance optimization.

Commands

profile run

CPU profiling with py-spy sampling profiler. Generates interactive flamegraphs.

Arguments:

script

Python script to profile (required)

Options:

--output / -o

Output file for flamegraph (default: profile.svg)

--format / -f

Output format: flamegraph, speedscope, raw (default: flamegraph)

--duration / -d

Profile duration in seconds (default: until script ends)

--rate / -r

Sampling rate in Hz (default: 100)

Examples:

# Basic CPU profiling
structum profile run app.py

# High-resolution 60-second profile
structum profile run app.py --rate=500 --duration=60

# Speedscope format for web viewing
structum profile run app.py -f speedscope -o profile.json

Flamegraph Reading:

  • Width: Time spent in function (wider = more time)

  • Height: Call stack depth

  • Click: Zoom into specific function

Tools: py-spy

profile memory

Memory profiling for leak detection and optimization.

Arguments:

script

Python script to profile (required)

Options:

--output / -o

Output file for results (default: stdout)

--interval / -i

Sampling interval in seconds (default: 0.1)

Examples:

# Track memory usage
structum profile memory app.py

# Save detailed report
structum profile memory app.py -o memory.log

# High-frequency sampling
structum profile memory app.py --interval=0.01

Output:

Shows line-by-line memory usage and increments:

Line    Mem usage    Increment   Occurrences   Line Contents
=============================================================
 10     50.2 MiB     50.2 MiB           1   @profile
 11                                         def load_data():
 12    150.5 MiB    100.3 MiB           1       data = read_file()

Tools: memory_profiler

profile benchmark

Run performance benchmarks using pytest-benchmark.

Arguments:

path

Path to benchmark tests (default: tests/)

Options:

--compare / -c

Compare with previous benchmark (git ref)

--save / -s

Save benchmark results to file

Examples:

# Run all benchmarks
structum profile benchmark

# Specific benchmark directory
structum profile benchmark tests/benchmarks/

# Compare with previous version
structum profile benchmark --compare=v0.1.0

# Save results
structum profile benchmark --save=baseline.json

Writing Benchmarks:

import pytest

@pytest.mark.benchmark
def test_performance(benchmark):
    result = benchmark(expensive_function, arg1, arg2)
    assert result is not None

Tools: pytest-benchmark

Configuration

Performance Tuning

Sampling Rate (profile run): - Lower (50-100 Hz): Less overhead, less detail - Higher (500-1000 Hz): More overhead, more detail - Default 100 Hz is good for most cases

Memory Interval (profile memory): - 0.1s: Standard detail - 0.01s: High-resolution (more overhead) - 1.0s: Coarse-grained overview

Benchmark Configuration

Create pytest.ini or configure in pyproject.toml:

[tool.pytest.ini_options]
markers = [
    "benchmark: Performance benchmarks",
]

CI/CD Integration

GitHub Actions Profiling

name: Performance

on: [push, pull_request]

jobs:
  benchmark:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Install tools
        run: pip install structum-cli-tools

      - name: Run benchmarks
        run: structum profile benchmark --save=current.json

      - name: Compare with baseline
        run: structum profile benchmark --compare=main

Continuous Profiling

For production profiling, consider:

  • py-spy in record mode (minimal overhead)

  • Periodic memory snapshots

  • Automated flamegraph uploads

Best Practices

CPU Profiling

  1. Profile realistic workloads - Use production-like data

  2. Multiple runs - Average results across runs

  3. Focus on hot paths - Optimize widest functions first

  4. Measure impact - Benchmark before/after changes

Memory Profiling

  1. Incremental analysis - Look for unexpected jumps

  2. Generator patterns - Use generators for large datasets

  3. Cache management - Clear caches between measurements

  4. Leak detection - Run extended tests

Benchmarking

  1. Isolate code - Benchmark specific functions

  2. Warm-up iterations - Run warm-up before measurement

  3. Statistical significance - Multiple iterations

  4. Version comparison - Track performance over time

Troubleshooting

Permission Errors

py-spy may need elevated permissions:

# Linux: use sudo
sudo -E structum profile run app.py

# macOS: grant permissions in System Preferences

High Overhead

Reduce sampling rate:

structum profile run app.py --rate=50

Memory Profiler Slow

Increase interval:

structum profile memory app.py --interval=1.0

See Also