crucible.garethcooke.com
C++ performance engineering,
measured.
Each post is a focused optimisation problem — naive vs tuned implementations, real hardware measurements on a documented reference machine, and visualisations of system behaviour rather than algorithm steps.
Posts
- 01
Sorted vs unsorted: a branch-prediction deep dive
Same code. Same data. Three variants. Why does one run 7× faster — and why does the branchless version close most of the gap without sorting anything?
2026-05-17 - 02
False sharing: a 13.6× throughput gap from 56 missing bytes
Same algorithm. Same fill stream. Same machine. The only variable is struct layout — and it dominates.
2026-05-16 - 03
Black-Scholes: same model, four implementations, ~10× spread
Polynomial approximations buy 11% on their own — but they're the gate to a 9× SIMD win that libm's erfc can't reach.
2026-05-14 - 04
Same queue API. Different tail by orders of magnitude.
End-to-end enqueue→dequeue, market-data thread to strategy thread. Lock-free SPSC vs mutex + condvar. At 1 MHz offered load, the median is already ~13× apart: lock-free ~130 ns, mutex ~1.7 µs. The tail diverges to ~20× at p99.9; past saturation, orders of magnitude and bistable.
2026-06-05 - 05
Allocators: cross-thread order pipeline
Cross-thread Order lifecycle benchmarked across three allocator strategies — malloc, freelist with return queue, and arena with batch handoff. The result that survives contact with the data isn't the one the design discussion would lead you to expect.
2026-06-05 - 06
AoS vs SoA: bandwidth amplification, not a crossover
Scanning a 128 B option-quote struct across the Zen 2 cache hierarchy. The AoS-vs-SoA gap is 7× when one field per element is hot and vanishes when every field is — and the SIMD win lands largest where memory bandwidth is smallest.
2026-06-05 - 07
No crossover: absl::flat_hash_map wins at every N and workload mix
Five map implementations swept from N=8 to N≈4M on a Zen 2 CCX. The 'small map → flat structure' folklore expected a crossover; the data found none. absl::flat_hash_map is fastest at every N, in both pure-lookup and modify-mixed workloads, and the sorted-vector primitives collapse under any modify load at non-trivial N.
2026-06-05 - 08
The comparison lower bound is a wall. Integer keys let you walk around it.
std::sort is the default everyone reaches for, and on fixed-width integer keys it's rarely the fastest. A look at why a radix sort sidesteps the Ω(n log n) wall, why input shape decides the comparison-sort race, and why a data-independent sort is the one you want when a worst-case input on a hot path is what you have to bound.
2026-06-05 - 09
NEON on ARM: vector width is not a given
The demo 3 Black-Scholes kernel on a Cortex-A76. NEON delivers ~4.3× over scalar at 16k, rising to ~4.8× at 1M — and stops there. Where Zen 2 had AVX2 to reach for, the Pi 5 doesn't. Vector width is a property of the silicon.
2026-06-02 - 10
Core-to-core latency: the seam inside a Zen 2 die
Two cores on the same chip, millimetres apart, talk in 72 ns or 160 ns depending on which side of an invisible line they sit on. Measuring the CCX boundary — and the placement effect that nearly turned into a phantom finding.
2026-07-28