Benchmarking

Benchmarking is measuring performance in a controlled, repeatable way — to compare two implementations, track performance over time, or validate that an optimization actually helped. It sounds simple ("time how long it takes"), but benchmarking correctly is surprisingly hard: naive benchmarks are riddled with pitfalls that produce confidently wrong numbers. A benchmark that measures the wrong thing is worse than no benchmark, because it gives false certainty.

Benchmarking complements profiling: profiling tells you where the time goes within a program; benchmarking tells you how fast a specific piece is and whether a change improved it. The discipline is rigor — warming up, running enough iterations, controlling for noise, and reporting honest statistics — so the numbers actually mean something.

TL;DR

Quick Example

Use a real benchmarking library, not a hand-rolled timer — it handles warmup and iterations:

Micro vs Macro Benchmarks

💡 Micro-benchmark results don't always translate to real-world gains — a function 2× faster in isolation may be irrelevant if it's 1% of total runtime. Always connect micro results back to a profile of the whole system.

The Many Pitfalls

Naive benchmarking produces wrong numbers in predictable ways:

This is why you should use a real benchmarking framework (pytest-benchmark, JMH, Criterion, Benchmark.js) — they handle warmup, iteration, and statistics correctly.

Honest Measurement

Best Practices

Common Mistakes

Hand-rolling a naive timer

Optimizing a micro-benchmark that doesn't matter

FAQ

What's the difference between profiling and benchmarking?

Profiling measures where a program spends its time and memory across its whole execution — it points you at the hot spots. Benchmarking measures how fast a specific piece of code is, in a controlled, repeatable way, typically to compare implementations or detect regressions. You usually profile first to find what matters, then benchmark that specific code to compare alternatives or confirm an optimization helped. Profiling answers "what should I optimize?"; benchmarking answers "is version A faster than version B, and by how much?" They're complementary tools.

Why are naive benchmarks so often wrong?

Because performance measurement has many traps that quietly invalidate results. Without warmup, you measure JIT compilation and cold caches instead of steady-state speed. Compilers can eliminate "dead code" whose result you don't use, so you measure nothing. A single run is dominated by system noise (other processes, CPU scaling, GC pauses). Tiny inputs hide cache and scaling effects. And timing the setup along with the operation skews everything. Each pitfall produces a confidently-wrong number. Real benchmarking frameworks exist precisely to handle warmup, iteration counts, and statistics correctly so you avoid these traps.

Should I report the average time?

Not alone — averages hide too much. A single mean can be dragged by outliers, conceals the variance that tells you how noisy your measurement is, and obscures the tail latency that often matters most to users. Report a distribution: median (typical case), p95/p99 (the tail), min (best case under ideal conditions), and some measure of spread. This shows both the typical performance and how reliable and consistent it is. Good benchmarking tools report these automatically; trusting a lone average is one of the most common measurement mistakes.

Do micro-benchmark results translate to real-world performance?

Often not directly, which is a critical caveat. A function shown to be 2× faster in an isolated micro-benchmark might be irrelevant if it's a tiny fraction of total runtime, and isolated code can behave differently inside a real program due to caching, inlining, JIT decisions, and memory effects the micro-benchmark doesn't capture. Always connect micro-benchmark results back to a profile of the whole system: optimize the things that actually dominate real workloads, and validate improvements with macro/end-to-end measurement. A faster micro-benchmark is a hypothesis, not a guarantee of real-world gain.

Related Topics

References