Repository navigation
v1.16.0
Warning
Superseded by v1.17.0 — upgrade.
This release shipped --readahead-subblock-dispatch on by default, and that default is
rolled back in v1.17.0. It costs wall clock on an index-then-stream reader — a handle that
reads scattered and then streams a large contiguous range, which is the common
metadata-then-payload shape. Measured after this release: median 0.798 throughput against
the flag off, below both brackets in 8 of 8 reps, with uncovered demand misses 62 → 81 and
bytes identical.
The flag itself is unchanged and still available. If you know your workload reads slices and
stops, --readahead-subblock-dispatch still gives the byte savings described below; the
correction is only that it is the wrong thing to turn on for everyone. See
#407 for the measurement.
Changed
-
--readahead-subblock-dispatchis on by default (#407).
Pass=falseto disable. This was pre-registered: wall clock neutral on both moving rows with
faults flat meant the default moves on.GRIB HEMCO byte amplification 3.02× → 1.39× 1.79× → 1.48× wall, median B/D 1.005 (11 kept reps) 0.974 (5 kept reps) uncovered demand misses 69 in every arm 331–333 in every arm GETs 71–74 339–341 Each flagged run was bracketed by two default runs, with a rep discarded when the brackets
disagreed by more than 10% — necessary because GRIB's ~3 s wall drifts 15–24% between brackets,
which is larger than the effect. The tester disclosed that the flagged arm looked faster in
the first six reps and that the impression did not survive the rule: the high-drift reps were
exactly the ones it discards.FITS, three control shapes, a whole-object
ddand a scatter-then-stream handle are all
unchanged, and the arm cannot fire where the evidence gate is off, so cross-region and
region-unknown mounts are unaffected. The default reaches exactly the in-region regime the
measurement covers.
Added
-
The sub-block arm's test now reports uncovered demand misses, which is the mechanism by
which it could cost wall clock (#407). Bytes
a reader never wanted are pure waste; bytes it did want and now has to fault for are a stall,
and a byte count cannot tell those apart — which is the whole reason the default decision is
open after a clean byte result.On the walk fixture the arm halves bytes and triples uncovered misses (4 → 12) while
prefetch hits fall 6 → 1. Treated as a bytes-for-faults trade, break-even is around
100 MB/s of effective bandwidth at a 30 ms first byte, and ~30 MB/s at 100 ms — so if that
fault increase transferred to a real workload, the arm would be a wall loss at any bandwidth
those instances actually reach. An external run measured the GET count flat (72 → 71) on the
real shape, which argues it does not transfer. The two signals disagree, and only a
wall-clock cell on the real workload settles it.Logged, not asserted. Any bound on this ratio would be a tuned constant on a
fixture-specific quantity, which is how both #340's and #349's withdrawn defaults were placed.
The figures are in the test output so a future change to this arm shows its effect on faults
and not only on bytes.
Fixed
-
--readahead-subblock-dispatch's help and docs row carried fixture figures and a stale
"measured inert" note (#407). Both now carry
the external v1.15.0 measurement, two arms and two reps with the default arm reproducing the
previous release exactly as the control:shape default with the flag GETs prefetch-rangeGRIB .idxsweep3.02× 1.39× 72 → 71 0 → 5.05 MB HEMCO time-slice 1.79× 1.48× 340 → 339 0.26 → 4.98 MB FITS cutout 2.20× 2.20× 12 → 12 0 All of GRIB's
wholefills becomeprefetch-rangeand its used:issued goes 2:24 → 2:5, so the
change is attributable rather than inferred. The GET count does not rise, which settles the
#124 concern that a byte win would arrive as a
GET explosion: the span replaces whole-block fetches rather than fanning out.Two shapes qualify, not one, and the docs now say so. I predicted only GRIB would move, on
the premise that HEMCO handles never enterRandom; a trace I had already quoted showed one of
them at 129 consecutiverandom→randomtransitions. The trigger is a property of the access
pattern, not of a file format — any handle that reads scattered and then reads a short
contiguous stretch meets it. Recorded so the next reader does not inherit the wrong premise.And the pre-registration it broke was badly written. Its failure condition — "if FITS or
HEMCO move at all, the mechanism is not as described" — conflated whether the trigger behaves
as specified with which shapes meet it. Only the first is a claim about the code. A falsifier
that depends on a guess about someone else's workload tests the guess.Still off by default, and the row now says what is missing: wall clock on the two rows that
move. The arm bounds prefetch, so its risk is latency rather than bytes — fetching 0.46× the
bytes could be faster, neutral or slower, and a byte count cannot separate those. #309's 11×
regression came from a prefetch-depth change that looked clean on totals. -
My bytes-for-faults model was a fixture artifact, and it is now pinned as one. A fixture at
8 MiB field spacing showed the arm halving bytes while tripling uncovered demand misses,
from which I published a break-even implying the arm would be a wall loss at any realistic
bandwidth. The external cell then measured faults flat on both real shapes.The cause is the spacing: the default dispatches
window + 1blocks, which at that spacing
overshoots into the next field, so the default's over-fetch was accidentally prefetching it
and the arm's shorter span was not. At wider spacings the fault counts are identical and the
byte saving is larger — and a scattered walk jumps farther than the window by definition. A
test now measures both sides of that boundary, so the artifact cannot return disguised as a
regression.It asserts the delta between arms across two spacings, not an absolute count:
UncoveredMiss
fires when a demand read finds its chunk neither cached nor in flight, so it races the prefetch
goroutine and picks up extra misses under load. The first version asserted equality, passed
alone, and failed twice in three package runs — the same mistake as the #313 gate test that
asserted the gate halves peak pressure.