Skip to content

Benchmarking and Load Testing

Why Does Benchmarking Exist?

"It feels slow" or "I think this change made it faster" aren't claims you can actually validate — they're impressions, not measurements. Benchmarking exists to replace impressions with a precise, repeatable number: run a specific operation, measure exactly how long it takes, and do it enough times to get a statistically stable result you can genuinely compare before and after a change.

"I optimized this function"

↓

Prove it: run the OLD version 1,000 times, record the timing
           run the NEW version 1,000 times, record the timing
           compare the two DISTRIBUTIONS, not just a single run

A single run of anything is noisy — affected by what else is running on the machine at that moment, caching effects, JIT warmup in some languages, and plain randomness. Benchmarking properly means running enough iterations to separate a genuine improvement from noise, not trusting one measurement in isolation.


Micro-Benchmarking

Measuring one specific, isolated function, algorithm, or operation's performance precisely — in complete isolation from the rest of the system.

import timeit

def old_implementation(data):
    return sorted(data, key=lambda x: x.value)

def new_implementation(data):
    return sorted(data, key=attrgetter("value"))

old_time = timeit.timeit(lambda: old_implementation(sample_data), number=1000)
new_time = timeit.timeit(lambda: new_implementation(sample_data), number=1000)

Running an operation many times, in isolation, and comparing the resulting distributions is exactly how you validate a specific optimization actually did what you intended — precisely, with a real number, rather than a hopeful assumption.

The Real Limitation: Isolation Isn't Reality

This is the crucial caveat, and it's the direct segue into load testing: a function benchmarked in complete isolation can behave completely differently under real, concurrent, mixed production conditions.

A database query, benchmarked ALONE:  fast, no contention, no
                                        competing queries at all

The SAME query, running under REAL production load:  potentially
    much slower — competing for the same rows with other concurrent
    transactions (lock contention, from the Locks chapter), competing
    for the same limited connection pool (from the Connection
    Pooling chapter), competing for the database's own actual
    concurrent processing capacity (from the Throughput chapter)

A micro-benchmark answers "how fast is this operation, alone, with nothing else happening?" — a genuinely useful, necessary question, but a fundamentally different one from "how does this operation actually behave under realistic, concurrent production conditions?" This gap is exactly why load testing exists as a separate, complementary practice.


Load Testing — A Different Scale of Measurement

Instead of measuring one isolated operation, load testing simulates realistic, concurrent, production-like traffic against the whole system, to answer a different question entirely: how much load can this system actually sustain, and how does it behave — or fail — as that load increases?

Micro-benchmark:  "how fast is THIS function, in isolation?"

Load test:         "how does the WHOLE SYSTEM behave under
                    realistic, CONCURRENT traffic, and where does
                    it actually break down?"

Types of Load Testing

Load Testing (standard):  simulate EXPECTED, normal peak traffic —
                           does the system handle its actual,
                           anticipated real-world load comfortably?

Stress Testing:            deliberately push traffic PAST expected
                            capacity, specifically to find the ACTUAL
                            breaking point and observe HOW the system
                            fails (gracefully — rejecting excess
                            requests cleanly — or catastrophically —
                            crashing entirely, taking down requests
                            that would otherwise have succeeded)

Soak / Endurance Testing:   sustained, realistic load over a LONG
                            duration (hours, not minutes) — specifically
                            to catch problems that ONLY appear over
                            time: a slow memory leak (from the
                            Profiling chapter), gradually accumulating
                            resource exhaustion, disk filling up from
                            logs — issues a short burst test would
                            never reveal at all

Spike Testing:              a SUDDEN, extreme burst of traffic —
                             testing specifically how the system
                             reacts to a rapid, unexpected surge,
                             including how quickly auto-scaling
                             (from the Horizontal Scaling chapter)
                             actually reacts and adds capacity

Each of these answers a genuinely different question about the system's real-world resilience — a system that passes standard load testing comfortably might still have a slow memory leak that only a multi-hour soak test would ever surface, or might fail catastrophically rather than gracefully under a stress test that pushes past its actual capacity.


Real-World Examples

k6, JMeter, Locust, Gatling

Widely used, purpose-built load testing tools — allowing engineers to script realistic, concurrent traffic patterns against a system and measure how it behaves as that load scales up, well beyond what a manual or ad-hoc test could simulate.


timeit / pytest-benchmark for Micro-Benchmarks

Standard, common tooling specifically for the isolated, precise, repeated-measurement style of benchmarking described at the start of this chapter — distinctly different tools from load testing frameworks, reflecting how genuinely different the two practices are in scope and purpose.


Soak Testing Uncovering a Slow Memory Leak

A directly practical, common real-world case for why soak testing exists as its own distinct category — a leak that grows by a small, seemingly negligible amount per request can be completely invisible in a short load test, yet become a genuine production incident after days of sustained real traffic, exactly the kind of issue only a long-duration test would ever catch.


Common Interview Questions

What's the difference between benchmarking and load testing?

Benchmarking (specifically micro-benchmarking) measures one specific, isolated operation's performance precisely, in complete isolation from the rest of the system. Load testing simulates realistic, concurrent, production-like traffic against the whole system, to understand its actual capacity limits and how it behaves as load increases or fails once it's exceeded — a fundamentally different scale and purpose of measurement.


Why might a query or function that benchmarks well in isolation perform poorly in production?

Because a micro-benchmark measures performance with nothing else competing for the same resources — the real system involves lock contention with other concurrent transactions, competition for a limited connection pool, and the backing database's own real concurrent processing capacity, none of which an isolated benchmark accounts for at all.


What's the difference between load testing, stress testing, and soak testing, and what does each specifically catch?

Load testing verifies the system handles its expected, normal peak traffic comfortably. Stress testing deliberately pushes past that expected capacity to find the actual breaking point and observe whether the system fails gracefully or catastrophically. Soak (endurance) testing sustains realistic load over a long duration specifically to catch issues that only emerge over time — memory leaks, gradual resource exhaustion — which a short test would never reveal.


How would you determine your system's actual maximum capacity?

Through stress testing — deliberately increasing simulated concurrent load beyond expected levels until the system's actual breaking point is found, while specifically observing how it fails (cleanly rejecting excess load, versus crashing outright and taking down requests that would otherwise have succeeded) — this is a fundamentally different exercise from a standard load test, which only verifies behavior at expected traffic levels.


Why would you run a spike test in addition to standard load testing?

To specifically evaluate how the system reacts to a sudden, unexpected surge in traffic rather than a gradual ramp-up — including how quickly auto-scaling actually detects and responds to the spike, which a standard, steadily-ramping load test wouldn't meaningfully exercise.


Common Mistakes

❌ Only micro-benchmarking in isolation and assuming that directly translates to real production behavior under concurrent load.

Misses lock contention, connection pool competition, and the backing system's own real concurrent capacity limits — all real factors a benchmark run in isolation never encounters.


❌ Never stress-testing to find the system's actual breaking point.

Means discovering the real capacity ceiling for the first time during an actual, live traffic spike, rather than in a controlled, deliberate test where the failure mode can be observed and addressed calmly beforehand.


❌ Skipping soak/endurance testing.

Misses slow memory leaks or gradual resource exhaustion that only manifest after sustained load over hours or days — exactly the class of problem a short load test structurally cannot reveal, regardless of how much concurrent traffic it simulates.


Key Takeaways

  • Benchmarking replaces vague impressions ("this feels faster") with a precise, repeatable measurement — running an operation many times and comparing distributions, not trusting a single run.
  • Micro-benchmarking measures one isolated operation's performance precisely, but doesn't capture how it behaves under real, concurrent production conditions — lock contention, connection pool competition, and shared capacity limits are all invisible to an isolated benchmark.
  • Load testing simulates realistic, concurrent traffic against the whole system to answer a genuinely different question: how much load can it actually sustain, and how does it behave as that load increases.
  • Stress testing, soak testing, and spike testing each catch a different category of real-world failure mode — the actual breaking point, slow degradation over long duration, and reaction speed to sudden traffic surges, respectively.
  • Discovering a system's real capacity limits and long-term degradation issues through deliberate, controlled testing is far preferable to discovering them for the first time during an actual, live production incident.