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.
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.
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.
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.
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.
git clone https://github.com/LaelaZorana/python-perf-optimizer
cd python-perf-optimizer
pip install -e .
pip install numpy pytestfrom 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# 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_concatBoth 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.
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
pytest tests/ -vMIT, Laela Zorana
Links: GitHub · HuggingFace · Kaggle