Skip to content

Lock the parse-bound Snappy corpus and record both denominators - #346

Merged
iderex merged 1 commit into
mainfrom
issue/119-worstlit
Aug 10, 2026
Merged

Lock the parse-bound Snappy corpus and record both denominators#346
iderex merged 1 commit into
mainfrom
issue/119-worstlit

Conversation

@iderex

@iderex iderex commented Aug 10, 2026

Copy link
Copy Markdown
Owner

What & why

Closes #119.

The M3 worst-case rung was locked on one constructed corpus, the copy chain at
maximum element density: back-to-back minimum-cost copies at offset 1, four
decoded bytes per element. Throughput here is reported per decoded byte, so a
corpus locked at four decoded bytes an element says nothing about the regime
that costs four times the parse work for the same reported byte. That regime
had no owner in the harness, and a density lock on the copy chain would not
have noticed its absence.

This adds the literal chain beside it. Same 64 KiB block of one repeated byte,
same 3200-chunk scale, same one element per two compressed bytes, spelled out
as one length-1 literal element per output byte instead of copied. The two
corpora decode to identical bytes and differ only in what an element costs to
produce, which is what makes the pair a comparison rather than two numbers.

The means is C++ in bench/bench_snappy.cpp beside the corpus it contrasts
with, because the two share the report, the timing loop, the oracle gate and
the replicator, and differ only in how one block is built. The replicator is
now shared rather than copied, so the 64 KiB chunk unit has one authority.

The recorded denominators land with the corpus rather than after it: the claim
this corpus exists to support is the comparison between the two regimes, and
one row alone does not carry it. No kernel moves in this change, so the rule
that numbers and kernel changes never travel together is not engaged.

Type of change

  • Decode kernel / device code
  • Format support (LZ4 / Snappy / GDeflate / Zstd)
  • API surface
  • Performance
  • Bug fix
  • Refactor / code quality
  • Build / CI / supply chain
  • Docs

Engineering checklist

  • Fail-closed preserved. The construction refuses a block below 256 output
    bytes, --worstlit refuses to be combined with corpus files or a shape
    flag, and --worst --worstlit together is refused because two regimes
    cannot share one methodology block. All three exercised below.

  • Oracle coverage: the pinned snappy 1.2.2 decoder passes verdict on every
    constructed stream and the round trip is compared byte for byte, before
    anything is timed. That gate is necessary and demonstrably not
    sufficient, which is what the two locks are for.

  • Determinism preserved. The corpus is constructed from fixed constants
    with no PRNG and no input files; the reported digest a475ef89da01c0e4
    is reproducible from the flags alone.

  • Every CUDA API call's error is checked; no exceptions cross the C ABI.
    Not applicable: no CUDA in this change. bench_snappy links neither the
    CUDA runtime nor a kernel header.

  • An adversarial review (/security-review) was run.

    **No adversarial-lens review was run for this change and there was no
    second reader.** `bench/CMakeLists.txt` is on the sensitive surface, so
    this is a gap and not an exemption. What stands in its place is the
    executed evidence below: both locks were broken and observed to red for
    the reason each names, each broken corpus was also run with the locks
    disabled to show what the oracle gate lets through, and the full suite
    ran on a device. That is evidence, not a reviewer, and it does not
    cover what a reviewer would have looked for.
    
  • Review record. None: see above.

GPU sanitizer gate

  • Not applicable: this change touches no device code. bench_snappy is
    CPU-only by construction, and the two ctest entries it registers carry
    no gpu label.

The device-side sanitizer net has not run successfully on this project at all,
per #258, and nothing here changes that.

Performance checklist

  • The claim is measured, not reasoned. Both denominators are recorded in
    docs/BENCHMARKS.md with the full methodology block the harness emits,
    including host CPU, corpus digest, run protocol and element density.
    Recorded inside the digest-pinned
    nvidia/cuda:12.6.2-devel-ubuntu24.04 container.
  • No regression against the recorded baseline: this adds rows for a corpus
    that had none and changes no existing number.

The measurement contradicts what the element count predicts, and the section
says so rather than around it. The literal chain carries four times the
elements per decoded byte (209,715,200 against 52,432,000 over the same 209.72
MB) and finishes 20% sooner. Per element the ordering reverses five to one:
215.8 M elements/s against 42.9 M. The reference's offset-1 copy is the cost
on that corpus, not its parse. The section records that this ordering belongs
to the reference decoder and must not be carried over to a device row, because
a warp-cooperative decoder attacks the two regimes with different machinery
and which one floors it is a measurement nobody has taken.

Quality checklist

  • Minimal. The replicator, the report, the timing loop and the oracle gate
    are shared with the sibling corpus rather than duplicated; the new code
    is one block builder, one lock function and one flag.
  • Self-documenting: the comments say why the literal chain's locks are not
    the copy chain's, which is the non-obvious part.
  • The new structural property is locked as a new ctest entry,
    bench_snappy_worstlit_selfcheck, with the timeout assertion updated so
    the configure step still refuses an entry without one.

Verification

Everything below ran inside the digest-pinned container
(nvidia/cuda:12.6.2-devel-ubuntu24.04@sha256:738fba0fbdb225b7a2931c58a5c8f03a84d3cd2f6a84975826a157339ef750b8),
--gpus all, against this branch. Device: NVIDIA GeForce RTX 3080, driver
560.94. Toolchain: nvcc release 12.6, V12.6.77.

  • cmake --build build-cuda -j builds clean.
  • ctest --test-dir build-cuda --output-on-failure:
38/39 Test #38: bench_snappy_worstlit_selfcheck ...   Passed    0.01 sec
      Start 39: bench_zstd_worst_selfcheck
39/39 Test #39: bench_zstd_worst_selfcheck ........   Passed    0.16 sec

100% tests passed, 0 tests failed out of 39

Label Time Summary:
gpu    =   4.79 sec*proc (8 tests)
  • Prettier over **/*.{md,yml,yaml}: All matched files use Prettier code style!
  • Docs synced: docs/BENCHMARKS.md gains the section. No README or
    MASTERPLAN change is owed, since no behaviour, API or status row moves.

The locks, proven by breaking them

Each mutation was applied to the generator, built, run, and reverted. Each was
then run a second time with both locks disabled, to show what the oracle gate
alone accepts.

The element-rate floor. The drift it names is a generator whose literals
grew longer. Length-2 literals instead of length-1:

--- locks in force ---
the parse-bound corpus carries 0.3333 elements per compressed byte, below the 0.49 floor: its elements cost more than the two-byte length-1 literal
exit=1
--- the identical bytes, both locks disabled ---
- element density: 131072 elements, 0.3333 per compressed byte, 2.0000 decoded bytes each
exit=0

The second run is the point: the stream is a valid Snappy stream, the pinned
oracle accepts every one of them and every one round-trips, so the run goes
green and prints "max parse work per output byte" over a corpus carrying a
third of the element rate it claims.

The decoded-bytes-per-element ceiling. The drift it names is a generator
that reverted to the copy chain:

--- locks in force ---
the parse-bound corpus produces 3.9998 decoded bytes per element, above the 1.02 ceiling: its elements are no longer one output byte each, so the parse work per reported byte is not the worst case it reports
exit=1
--- the identical bytes, both locks disabled ---
- element density: 65540 elements, 0.4999 per compressed byte, 3.9998 decoded bytes each
exit=0

That run is also why one lock is not enough. 0.4999 elements per compressed
byte clears the floor comfortably, so the floor never fires on this drift, and
the corpus would have been reported as parse-bound while measuring the copy
chain.

The refusals

$ bench_snappy --worst --worstlit
--worst and --worstlit are separate corpora and separate reports; run one at a time
exit=2
$ bench_snappy --worstlit --chunked
--worstlit builds its own corpus and has one shape; it takes no files and no shape flag
exit=2
$ bench_snappy --worstlit /etc/hostname
--worstlit builds its own corpus and has one shape; it takes no files and no shape flag
exit=2

Notes

What this does not do, and where it went instead. #119 was opened as the whole
M3 bench rung and is superseded on every other part of that: the Silesia path
and CPU denominator, the copy-chain corpus, and the first recorded GPU
baselines all have their own owners, and the recorded GPU row for these
corpora belongs to #167 and waits on the Snappy kernel. The literal chain was
the one thing #119 uniquely carried, and it is what landed here.

The comparator row for the copy-chain corpus is recorded alongside rather than
in its own change. That corpus landed without a number, and a parse-bound
denominator with nothing to compare against does not carry the claim the
section is about.

The M3 worst-case rung had one constructed corpus, the copy chain, which
reaches maximum element density at four decoded bytes per element. Throughput
is reported per decoded byte, so a corpus locked at four says nothing about
the regime that costs four times the parse work for the same reported byte.
That regime had no owner anywhere in the harness.

Adds the literal chain: the same 64 KiB block of one repeated byte, spelled
out as one length-1 literal element per output byte. Same element rate per
compressed byte, a quarter of the decoded bytes each.

Two locks, because the corpus can stop being adversarial in two directions
and neither stops it decoding. Longer literals keep the round trip and drop
the element rate to a third; a revert to the copy chain keeps the element
rate and quadruples the decoded bytes per element. The compressed share the
sibling locks on is useless here, since this stream expands rather than
compresses. Each lock was proven by breaking the generator the way it names
and watching the selfcheck red, and each mutation was also run with both
locks disabled to show the oracle gate passes it.

The recorded denominators go in with the corpus rather than after it: the
claim this corpus exists to support is a comparison between the two regimes,
and one row alone does not carry it. The measurement contradicts the element
count, the copy chain being 20% slower per output byte despite a quarter of
the elements, and the section says so and says why that ordering must not be
carried over to a device row.
@iderex
iderex merged commit a31a59a into main Aug 10, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

M3 bench rung: Snappy worst-case corpora and the recorded baseline

1 participant