21.8 · Writing benchmarks you can believe: the optimiser, build settings and growth tests
A number from a benchmark is only evidence if the code under test actually ran, in the build users get, at a size where the trend is visible. Most disappointing numbers are an artefact of the test, not the code.
Mental model. Distrust a result until you know the optimiser did not delete the work, the build matches Release, and the cost grows as you think.
Harness traps
Dead-code elimination and the cost of an unoptimised build.
- Your micro-benchmark reports an absurdly fast time. What did the optimiser probably do, and how do you write a benchmark that cannot be fooled?
In an optimised build the compiler deletes work whose result is never used. A loop that computes a value and throws it away has no side effects, so it can be… - How much slower is a Debug (-Onone) build than Release (-O), why, and what does that mean for profiling and for what you ship?
Debug builds optimise for compile speed and debuggability: no inlining, no specialisation of generics, no removal of retain/release pairs, extra checks, and…
Complexity by experiment
Finding the real growth rate by measuring n and 4n.
- How do you find out how an operation really scales, and which Swift operations that look cheap are quadratic?
Do not guess the complexity of a call; measure at n and 4n. If the time grows about four-fold the loop is linear, if it grows about sixteen-fold it is…
More in Performance & energy
- 21.1 · Measure first: the method, the metrics and the noise
- 21.2 · Instruments templates, signposts and XCTMetric
- 21.3 · MetricKit, Organizer and a performance culture
- 21.4 · SwiftUI invalidation and long lists
- 21.5 · The costs that show up in profiles: collections, strings, formatters, JSON, images and disk
- 21.6 · Energy: CPU wake-ups, timers, radios, location and thermal state
- 21.7 · App size: thinning, on-demand resources and the binary
- 21.9 · Memory you can count: allocations, dirty versus clean pages and decoded images
- 21.10 · The main thread in code: hang watchdogs, actor hops and quality of service
- 21.11 · Launch: lazy initialisation and measuring from process start
- 21.12 · Counting wake-ups: why polling costs energy even when the work is tiny