Lab 04: Profiling & Performance

Objective

Systematically find and fix Python performance bottlenecks using timeit, cProfile, pstats, tracemalloc, and algorithmic improvements: memoization, vectorisation with array, generator pipelines, and algorithmic complexity reduction.

Background

Premature optimisation is the root of all evil — but informed optimisation after profiling is engineering. The workflow is always: measure → identify hotspot → optimise → measure again. Python gives you first-class profiling tools in the standard library.

Time

35 minutes

Prerequisites

  • Lab 03 (Memory Management)

Tools

  • Docker: zchencow/innozverse-python:latest


Lab Instructions

Step 1: timeit — Micro-benchmarking

💡 Always benchmark with number= large enough to get stable readings. A single run of a fast function can be dominated by OS noise. Use timeit.timeit(..., number=1000) and divide — or use timeit.repeat(..., repeat=5, number=1000) and take the minimum (not mean) to exclude scheduling jitter.

📸 Verified Output:


Step 2: cProfile — Function-Level Profiling

📸 Verified Output:


Steps 3–8: Memoization, Algorithmic Complexity, Generators vs Lists, numpy, Caching, Capstone

📸 Verified Output:


Summary

Technique
Typical speedup
When to apply

lru_cache / cache

10x–∞

Repeated calls with same args

set/dict for lookup

100–10000x

O(n) search → O(1)

str.join

100–200x

String concatenation in loop

Generator pipeline

1.2–2x

Memory + moderate speed

numpy vectorisation

10–100x

Numeric array operations

Columnar storage

1.5–3x

Aggregate queries on one field

timeit

Always measure before/after

cProfile

Find hotspots first

Further Reading

Last updated