Skip to content

Repository files navigation

python-perf-optimizer

On large Python data pipelines I kept running into the same problem: they were slow, sometimes painfully slow, and nothing in the stack could tell you why. There was no visibility into where time was actually going, no consistent way to compare before and after a change, and no guidance on what to fix first.

So I built this. It's three focused tools, a CPU profiler, a latency/throughput benchmarker, and a memory tracker, plus an optimization advisor that reads the output from all three and gives you severity-tagged recommendations. Nothing magic, just the structured analysis layer I wished existed.

This project was built in May 2026. In August 2026 I squashed the git history to a single commit during an account wide cleanup, so the commit date is newer than the work.

What It Does

1. FunctionProfiler: CPU Hotspot Analysis

Wraps cProfile and surfaces the results in a structured format: cumulative time, call counts, per-call averages. The top_hotspots(n) method returns the N most expensive functions sorted by cumulative time, and to_report() formats everything into a markdown table.

2. Benchmarker: Latency & Throughput

Measures real latency distributions (min, max, mean, p50, p95, p99, std) over many iterations with warm-up, and sustained throughput (ops/sec) over a fixed time window. The compare() method gives you speedup_x and percent improvement side-by-side.

3. MemoryTracker: Footprint & Leak Detection

Uses tracemalloc to measure peak and net allocation per call. The find_leaks() method runs a function N times and flags iterations where allocation grows beyond a threshold, which is useful for catching module-level accumulators and unbounded caches.

4. OptimizationAdvisor: Actionable Recommendations

Takes ProfileResult + MemoryResult + LeakReports and returns a list of OptimizationSuggestion objects with severity (HIGH/MEDIUM/LOW), category (CPU_HOTSPOT/MEMORY_LEAK/INEFFICIENT_LOOP/REDUNDANT_CALLS), description, and recommended_fix.

Quick Start

git clone https://github.com/LaelaZorana/python-perf-optimizer
cd python-perf-optimizer
pip install -e .
pip install numpy pytest
from perf_optimizer.benchmarker import Benchmarker
from perf_optimizer.memory_tracker import MemoryTracker
from perf_optimizer.optimizer import OptimizationAdvisor

bench = Benchmarker()
result = bench.measure_latency(my_function, arg1, iterations=500)
print(result.summary_line())
# my_function: mean=4.231ms  p50=4.198ms  p95=5.012ms  p99=6.891ms  std=0.312ms

CLI

# Profile a function by dotted path
python -m perf_optimizer profile examples.string_concat_demo.slow_concat

# Benchmark
python -m perf_optimizer benchmark examples.numpy_vectorization_demo.python_loop_sum_of_squares

# Full report (profile + memory + advisor suggestions)
python -m perf_optimizer report examples.string_concat_demo.fast_concat

Example Output

Both blocks below are pasted from real runs of the bundled demos on Python 3.13, Apple silicon. Numbers vary by machine, and on modern CPython the += case is far less bad than folklore says, because CPython optimizes in place string append when the reference count allows it. The demo shows the honest gap, and it widens with larger inputs because += still degrades toward quadratic while join stays linear.

Benchmarking string concatenation over 5000 items
=======================================================

[slow] naive += loop:
  slow_concat: mean=0.350ms  p50=0.343ms  p95=0.380ms  p99=0.435ms  std=0.023ms

[fast] str.join():
  fast_concat: mean=0.259ms  p50=0.254ms  p95=0.287ms  p99=0.322ms  std=0.016ms

Speedup: 1.35x (26.0% faster)
  Baseline  mean=0.350ms
  Optimized mean=0.259ms
  p95 speedup: 1.32x  |  p99 speedup: 1.35x

Running the NumPy vectorization demo:

Correctness check passed (sum = 333328333350000)

Benchmarking sum of squares over 100,000 elements
=======================================================

[slow] Python loop:
  Latency: python_loop_sum_of_squares: mean=2.297ms  p50=2.279ms  p95=2.451ms  p99=2.515ms  std=0.077ms
  Throughput: 440.3 ops/sec

[fast] NumPy vectorized:
  Latency: numpy_vectorized_sum_of_squares: mean=0.024ms  p50=0.022ms  p95=0.026ms  p99=0.064ms  std=0.008ms
  Throughput: 44,961.7 ops/sec

Speedup: 94.36x (98.9% faster)
  Baseline  mean=2.297ms
  Optimized mean=0.024ms
  p95 speedup: 95.49x  |  p99 speedup: 39.58x

Throughput speedup: 102.1x
  Python loop:      440.3 ops/sec
  NumPy:         44,961.7 ops/sec

--- Latency Comparison Table ---
Implementation                mean_ms     p95_ms     p99_ms
--------------------------------------------------------
Python loop                    2.2967     2.4511     2.5147
NumPy vectorized               0.0243     0.0257     0.0635

Key takeaway: NumPy is 94x faster here.
Vectorize any inner loop that operates element-wise on arrays.

Project Layout

python-perf-optimizer/
├── perf_optimizer/
│   ├── __init__.py
│   ├── __main__.py        # CLI
│   ├── profiler.py        # FunctionProfiler + ProfileResult
│   ├── benchmarker.py     # Benchmarker + LatencyResult + ThroughputResult
│   ├── memory_tracker.py  # MemoryTracker + MemoryResult + LeakReport
│   └── optimizer.py       # OptimizationAdvisor + OptimizationSuggestion
├── examples/
│   ├── string_concat_demo.py
│   ├── numpy_vectorization_demo.py
│   └── memory_leak_demo.py
├── tests/
│   ├── test_benchmarker.py
│   ├── test_memory_tracker.py
│   └── test_optimizer.py
├── requirements.txt
└── setup.py

Running Tests

pytest tests/ -v

License

MIT, Laela Zorana

Links: GitHub · HuggingFace · Kaggle

About

Python performance profiling, latency/throughput benchmarking, memory optimization, and optimization advisor with severity-tagged recommendations

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages