AL+

Language: RO (română) EN (English)

Email us: paul@alplustech.com

Looking back at the week of 2–8 April 2025

Measure the work before comparing Go benchmarks

Go B.Loop improves benchmark boundaries, but useful comparisons still require explicit inputs, setup rules and an observable unit of work before timing.

Citiți articolul în română

A benchmark deserves a clear description of its work before its timing deserves a comparison. Go’s B.Loop improves the mechanics of writing that measurement, but the author still chooses the inputs and decides which preparation belongs inside the measured operation. Those choices determine whether a faster result supports the decision a team actually faces.

Looking back from November 2026, the 2 April 2025 Go article explained a feature already included in Go 1.24, released on 11 February. April brought guidance, rather than the feature’s first release. Its lasting value is a better starting point for reviewing small measurements before they become evidence for a rewrite or a dependency change.

Name the operation before placing the timer

Consider an illustrative parser comparison. One possible question is how long parsing takes when bytes already exist in memory. Another is how long it takes to create those bytes and parse them. Both are legitimate questions. They require different measured regions, and the resulting numbers should have different labels.

If the benchmark prepares a byte buffer outside the loop, that preparation is outside the operation being compared. That may be exactly right for a service receiving an existing buffer. It would omit relevant work if the proposed change requires constructing a new intermediate representation for every request. Review the real calling boundary before deciding which arrangement expresses the intended comparison.

The same reasoning applies to cleanup. Releasing temporary resources after the measured region can be sensible when the question concerns the operation alone. It can also conceal a recurring cost that the application pays for every item. The framework cannot infer which of these questions the author meant. An explicit sentence describing included work makes the choice reviewable.

What B.Loop improves

The April explanation describes automatic timer boundaries around the loop and protection against unwanted compiler elimination in the recognized loop form. It also explains that Go 1.24 implements that protection by preventing inlining into the loop body. These are properties of the documented version, rather than promises about every future compiler implementation.

That protection matters because apparently plausible code can stop measuring the intended operation when its result has no observable use. A benchmark can then reward the optimizer for removing work. B.Loop reduces that particular trap; it does not prove that a function computes the right answer or that the input represents a useful case.

Keep the recognizable for b.Loop() form when relying on its documented treatment. A helper abstraction around the condition should not be assumed equivalent merely because it repeats the same number of operations in a reader’s mental model. Compiler recognition is part of this mechanism. There is little value in hiding it behind a clever local benchmark convention.

Inputs can quietly change the question

A fixed valid input is useful for isolating an operation. It does not describe the cost of malformed input, larger records or a different mix of fields. Write down the supported interpretation of the fixture. A benchmark named after an entire parser can imply more coverage than a single short record provides.

Mutable state deserves particular attention. If one iteration consumes a buffer or populates a cache, the following iteration may do different work. Decide whether the intended case is fresh state, reused state or an explicitly warmed cache. When fresh state is necessary, the cost of creating it needs a deliberate place in the measurement rather than an accidental exemption.

Correctness checks need a separate role as well. A comparison between one implementation that accepts fewer valid inputs and another that preserves the required behavior is not a performance comparison on equal terms. Establish equivalent acceptance criteria before interpreting timing. No benchmark or parser experiment was run for this article; these are proposed review questions.

Keep the old baseline interpretable

Migrating an existing benchmark changes the measurement harness. A discontinuity in its history might therefore reflect timer boundaries or compiler treatment, rather than an improvement in the implementation under test. Preserve the earlier source and toolchain information so a future maintainer can explain why the series changed.

For a proposed comparison, first keep the implementation constant while examining the harness change. Then compare implementations under the agreed harness. This separates two explanations that would otherwise compete for the same faster number. It is a suggested investigation sequence, not a reported result or a requirement to maintain two benchmark systems indefinitely.

The strongest counterargument is that a carefully maintained b.N benchmark can already have correct timer control and suitable protection against elimination. Rewriting it may bring little immediate decision value. That is a fair limit: B.Loop is a better default for new straightforward benchmarks, while migration priority depends on known ambiguity and maintenance cost.

Parallel measurements and unusual timing arrangements also deserve their own documentation rather than a mechanical search-and-replace. The recommendation here concerns ordinary sequential benchmark loops. It does not establish that every existing benchmark is wrong or that adopting the new syntax produces a speed gain in application code.

Give the result a decision it can support

For a library function, a small benchmark can help detect a local regression after its operation and inputs are stable. It cannot alone establish a customer-visible latency reduction. That broader question includes work outside the measured region, and should be evaluated separately when it matters to the release decision.

For custom software development, ask for the measurement’s contract beside its result: which operation runs, which inputs it receives and where preparation happens. Keep the compiler version with that record. B.Loop makes some mistakes harder to write; a useful benchmark still begins with an honest account of the work whose cost you want to know.