Task guide

August 22, 2026 · View on GitHub

How to produce a number worth believing. The rules are in AGENTS.md; this is the method.

The denominator

vLLM is the bar, quant-matched, in its production configuration. Never benchmark against --enforce-eager and call it parity. llama.cpp may appear only as an explicitly labelled secondary comparison.

Both sides run the pinned oracle on identical model artifacts, prompts, token counts, batching, concurrency, and sampling. If the two sides differ in any of those, the ratio means nothing.

Prove the oracle actually runs the model before trusting it as a denominator — constructing a config proves nothing.

Getting a clean measurement

One GPU job at a time. Take the box lock before any measurement, stop competing services, and never run two large models at once — unified-memory boxes reboot rather than swap.

Calibrate the noise band from repeated identical legs before interpreting a delta. Discard cold legs for a named cause, never because they are inconvenient. Use paired, order-alternated A/B legs and a majority rule; a single pair is an anecdote.

Prefer an instrument that is immune to page-cache effects (GPU-active time per step) over wall clock when the host is doing heavy I/O.

The clock is part of the measurement

The SM clock differs between boots and does not announce it. On dgx.casa one boot ran the timed window at a median 2470 MHz and the next at a flat 2190 — a 12.79% delta, with clocks_throttle_reasons.active = 0x0 and persistence Enabled throughout, so nothing looked wrong. It repriced a byte-identical marlin::Marlin with no source change by +9.65%, which is larger than either deficit that comparison was being used to rank (#543). Two probes eight minutes apart inside one boot disagreed by ~6% uniformly.

So a number is quotable only with the clock it was taken at. tools/bench/gpu_clock_state.py is the one helper that samples, folds and asserts it: the SM clock across the measured window (min/median/max, the retained sample count and the idle count), clocks.max.sm, clocks.applications.graphics, the active throttle reasons, persistence mode, and the boot id.

Two harnesses call it today. scripts/dgx-online-serving.sh records a clock window per leg, and tools/bench/online_gate_summary.py asserts it. The DFlash2 speed gate takes ONE WINDOW PER ARM and tools/bench/dflash2_speed_harness.py delegates the whole judgement to this helper, including the cross-arm pairing — a single window spanning both arms cannot see the offset, and the offset is the term that transfers into the ratio. The ARM opens that window, not the shell that drives it (tools/bench/dflash2_oracle_capture.ClockWindow, which runs this helper's own sample CLI). scripts/dflash2-speed-gate.sh used to start the sampler itself and hand the arm the summary path, and this helper writes that summary only when the sampler STOPS — so the arm refused with [Errno 2] No such file or directory before the model loaded, and closing the window first produced every one of 98 clock samples was idle. The summary had to describe the arm and to exist before it, and both cannot hold (#1657). The clock is a precondition of the MEASUREMENT and not of the arm's execution: the arm runs, its sampler stops, the summary is written, and only then is it read and judged — and a run whose window turns out unusable writes its evidence and still yields no number. That last clause is load-bearing on the branch where the sampler writes NOTHING, which is the one the leased run met: this helper builds the record before it writes it, and it refuses an entirely idle window, so the sampler exits 2 with no summary at all. A window object that raises there discards the arm that already ran — every leg, record and token id — so it records the failure instead and lets the driver refuse once the evidence is on disk. A new harness that takes a window around work it drives itself should take the same shape. The trace and per-kernel harnesses — finalize_*_trace.py, summarize_torch_kernels.py, gdn_packed_component.py — are not wired, so a us/call or per-kernel figure from those paths carries no clock attribution and cannot be quoted as one. That is not a footnote: it is the path both retracted #543 findings came from. Wiring them is owed work tracked in specs/bench-assert-clock-state.md; until it lands, import the helper and record a window yourself before ranking anything from a trace, or say plainly that the figure is unattributed. Any new harness imports this helper rather than rolling its own.

Two arms on different boots are not comparable. The summary refuses that pair outright; --allow-cross-boot waives the boot id and nothing else, and stamps a recorded caveat rather than passing silently — the GPU, driver, maximum SM clock, applications clock and persistence mode are compared across the arms unconditionally, because a waived boot is not a waived machine. Within a run the SM-clock spread must stay at or below 5%, and the two arms' medians within 1% of each other — and their means within 1% too, which is a separate rule and not a restatement: on the three 2026-08-19 Qwen3.8-27B c1 pairings the median offset reads exactly 0.00% on all three while the arms' mean clocks are 0.10 to 0.25 points apart, because the excursion population sits below the median and is the part that does not cancel between the arms (#1546). Throughput is an integral over the window, so the mean is what transfers. A record captured before that term carries no mean and is refused rather than skipped, so an archived evidence tree has to be re-recorded rather than re-summarized. A window must also have been observed: at least 30 retained busy samples and a majority of the window busy, because the spread over one sample is definitionally 0.00% — the best score the gate can award — so without a floor the window nobody watched outscores the one that was. The argument for all four numbers, including why the spread ceiling is deliberately not held to the criterion the offset was chosen by, is in specs/bench-assert-clock-state.md.

Pin the clocks before measuring, under the lock. Passwordless sudo is available on dgx, and -lgc is supported:

sudo nvidia-smi -lgc 2100        # pin, before the first leg
sudo nvidia-smi -rgc             # release, after the last one

This works on the host path only. Inside an rc lease nvidia-smi -lgc returns LGC_RC=4, "The current user does not have permission to change clocks", even as root, measured 2026-08-19 on dgx:gpu0 in three jobs. Fleet devices are reachable by lease only, so for them the SM clock can be SAMPLED and not pinned, and a pairing may be refused on within-run spread with no lever to fix it. The missing capability is named and the ask is a one-line manifest change: the worker's CapBnd is the default OCI set and holds no CAP_SYS_ADMIN, measured inside leases on two fleet devices (specs/lease-gpu-capability.md, #1354). Read environment.md before you plan a paired series.

Pinning is a shared-host mutation. Never run -lgc or -rgc while another session holds $HOME/gpu.lock — it silently reprices their in-flight measurement, which is the very defect this section exists for. Take the lock, pin, measure, reset, release. It is a pre-measurement step, not a standing configuration: leaving the box pinned makes every later run inherit a state nobody recorded, which is where this started.

Figures recorded before 2026-08-12 predate clock assertion. They are not withdrawn and are not restated — they simply carry no clock attribution, so a delta smaller than ~10% between two of them is not established by them alone.

Budget the disk before the run. A production RelWithDebInfo CUDA build tree is about 169 GiB — the build contract claimed ~3 GiB until 2026-08-10, a 56x underestimate on the one number that decides whether a grid fits. A full disk does not fail loudly: it voids the binding through memory-return tolerance while still emitting plausible ratios. Leave real headroom, and delete the tree once the evidence directory is captured (evidence is tens of MiB).

Two ratio sets that disagree may be two different HARNESSES rather than a regression. Compare their absolute numbers before believing either; ratios are scale-invariant and hide an order-of-magnitude mismatch completely. If the change between the readings is provably inert (a byte-identical refactor), suspect the measurement, not the code.

Two arms have to BE two arms

A pair that measured one artifact twice already produced a "no speedup" result in this tree and was nearly reported as a refutation (#672, specs/minimax-music3.md §16.6a). The tell was not the times, which were 0.26 % apart and read as noise. It was the identical call count: equal times are noise, equal counts are identity.

A different sha256 does not establish it (#1516). Measured on a minimal project of the shape this repository's examples have — one SHARED library carrying the change, one thin client linking it — two byte-identical source trees built into two build directories give two clients of equal size with different hashes, and making the library change for real leaves the client byte-for-byte the hash it already had. CMake writes the build-tree RPATH into a client and no CMAKE_SKIP_BUILD_RPATH is set here. Hashing the library instead only moves the problem: it is stable across two build directories and differs across two SOURCE directories, because VT_CHECK embeds __FILE__ and nothing sets -ffile-prefix-map. In the two-clone shape a two-tree A/B is required to use, no artifact hash in this tree is falsifiable.

Prefer a same-binary A/B. Where a runtime switch turns the change off inside one binary there is no second artifact and no hash to be vacuous: VT_OP_PROVIDER_DISABLE=<provider> is that lever for anything behind the op provider seam (src/vt/cuda/cuda_attention_cross.cu:636), and GetOpProviderStats says which kernel actually ran.

Otherwise render the verdict with the control, not the hash.

scripts/ab-arms-differ.py --artifact-a A --artifact-b B \
    --root-a /tmp/b-old --root-b /tmp/b-new \
    --control ar.depth_forward 1414 808

Equal hashes stay FATAL. A hash-only verdict is refused by name, and an artifact that embeds its own build or source root is reported with the offset, so the hash leg's worth is stated instead of assumed. At least one control must have moved. Two kinds catch different failures and neither subsumes the other: a behavioural control is a value the arms computed and is the only leg that catches a stale binary; a source control is the hash of the file the change lives in and catches two arms that are one source. scripts/music3-vocoder-conv-ab.sh is the worked example.

Reading a profile

A whole-run kernel ranking is a trap. It sums prefill and decode, so the top-percentage kernel is frequently one-time prefill work that no decode step touches. Use a decode-only window or diff two sequence lengths. A Max far above the Median means you are looking at a mixture, not a hot loop.

Profile the entire step, not only the kernels. Several of the largest wins here were host-side waste, not slow math.

Before accepting a gap as "GPU-bound", trace both implementations with the same tool on the same workload and compare what actually ran.

Recording it

Record the exact build and run recipe, revisions, model hashes, environment, clock and contention state, raw output, and the same-binary A/B. Reproduce on an idle box before acceptance. "Clock state" is the concrete list in §The clock is part of the measurement, boot id included, not a prose adjective.

Record every required axis — throughput, latency, memory — as both values and ratios. An axis below floor is an open gap, not a rounding error.

Never record a ceiling. An apparent same-architecture limit is an unresolved implementation difference; name the next traceable hypothesis instead.

Accepted and pending results go in benchmark-record.md and docs/BENCHMARKS.md. Method specific to one lever stays in parity-lever-protocol.md.