Skip to content

command scratch: keep a 64 KiB resident prefix; report sink: synchronize once at the trailer - #549

Closed
luisleo526 wants to merge 5 commits into
mainfrom
perf/cr397-e1-ss1
Closed

luisleo526 wants to merge 5 commits into
mainfrom
perf/cr397-e1-ss1

Conversation

@luisleo526

Copy link
Copy Markdown
Collaborator

Summary

Two independent reductions of disk traffic in the report and command-scratch paths. The report bytes are unchanged.

  • Resident command-scratch prefix. A command-scratch store keeps its first 64 KiB resident in the page buffer it already owns (the read-cache slots stay empty while resident, so no stale hit after a spill). The first page past the limit migrates the whole prefix to the file once; RAM stays authoritative until that copy succeeds, then writes go through as before. Fixed memory: 3 stores x (64 KiB + 2 KiB) = 202,752 B per run, recorded in docs/design/arena-bound.md.
  • Report sink synchronized once. The sink is synchronized once, in the trailer or abandon path, instead of after every window. On Linux the sink requires O_DIRECT, so only size metadata was left unsynchronized between windows. A sync error now appears at the end of the run, with the same text, before any report byte. Borrowed descriptors (FIFO/socket) are never synchronized.

Evidence

  • One spot box (c5.4xlarge), fixed-id script on a 105,159-bar feed, 8 cells: all byte-equal, including the named sink files. Engine call 1.587 s -> 1.206 s; pwrite64 200,314 -> 11,436; fdatasync 250 -> 159 (the remaining calls are other files); pread64 unchanged; peak RSS 75.8 MB, flat. Whole-process wall about 6.99 s -> 6.60 s. n=1. This is a different measurement from the separate bulk-verify change in run_json.py.
  • Lab, final head (107 matching tests): 105 pass. The 2 failures are the same two that fail on clean main on the overlay filesystem host (test_report_sink_writer_memory, test_o1bk_production_backing).
  • Red replay of the new sink-sync test against main's per-window writer: 8 of 10 cases fail for the right reason (the writer synchronized before its trailer / before a failed write); the byte and memory cases pass on both writers, as the test header states.
  • The new command-scratch spill test has no red replay: it needs a construction overload that main lacks, so it does not compile there.
  • Tests derive their expectations from the version-1 wire format and SHA-256 vectors, not from the code under test.

Notes

  • On macOS the sink uses F_NOCACHE, a hint, so the "dirty cache cannot accumulate" argument is weaker there; macOS is outside the engine gate.
  • Three existing tests changed: one selects the all-file backing explicitly, one is strengthened (zero physical page I/O under the 64 KiB premise; logical counters equal store counters).

🤖 Generated with Claude Code

luisleo526 and others added 5 commits October 27, 2026 15:39
…nc the report sink once at close

Command scratch: the first 64 KiB of each store's extent now lives in the store's
existing page buffer instead of reaching the scratch file on every write. The
first page past that size copies the whole prefix to the file once and the store
then behaves as before (write-through file with the read cache). The fixed
bound is 3 x (64 KiB + 2 KiB) per run and is added to the arena-bound ledger.
Logical reads, writes, charges, typed failures and the byte budget are unchanged;
tests that inspect the scratch descriptor directly now select the all-file
construction explicitly.

Report sink: the per-window pwrite and ftruncate stay; the per-window data
synchronisation moves to one synchronisation when the trailer is written (and on
abandon), before the digest is copied into the trailer, so a failed synchronise is
still reported by the same call with the same error before any report is
returned.

On the 105,159-bar fixed-id benchmark the engine call drops from about 1.59 s to
1.21 s; pwrite64 calls fall from 200,314 to 11,436 and fdatasync from 250 to 159.
Report and sink bytes are identical.
…ing short-circuit; note the ledger is prose

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
@luisleo526

Copy link
Copy Markdown
Collaborator Author

Superseded by command-scratch-resident, Head ref must be a branch (createPullRequest) (the same change as one commit on current main).

@luisleo526

Copy link
Copy Markdown
Collaborator Author

Superseded by 557 (the same change as one commit on current main).

luisleo526 added a commit that referenced this pull request Oct 27, 2026
…nc the report sink once at close (#557)

Command scratch: the first 64 KiB of each store's extent now lives in the store's
existing page buffer instead of reaching the scratch file on every write. The
first page past that size copies the whole prefix to the file once and the store
then behaves as before (write-through file with the read cache). The fixed
bound is 3 x (64 KiB + 2 KiB) per run and is added to the arena-bound ledger.
Logical reads, writes, charges, typed failures and the byte budget are unchanged;
tests that inspect the scratch descriptor directly now select the all-file
construction explicitly.

Report sink: the per-window pwrite and ftruncate stay; the per-window data
synchronisation moves to one synchronisation when the trailer is written (and on
abandon), before the digest is copied into the trailer, so a failed synchronise is
still reported by the same call with the same error before any report is
returned.

On the 105,159-bar fixed-id benchmark the engine call drops from about 1.59 s to
1.21 s; pwrite64 calls fall from 200,314 to 11,436 and fdatasync from 250 to 159.
Report and sink bytes are identical.

The source allocation-bound gate indexes the sites the resident prefix added or
moved in the command scratch files: its reviewed site inventory follows (13
identities replaced by 14, nothing else), two new unreviewed entries cover the
reserve and the resident flag, and the unreviewed ceiling rises by those two
(1264 to 1266); the real-tree test pins the new open count.

Two citations that prose words introduced after a comma now carry their symbol
in backticks before the line anchor.

The design page and the memory-management page replace the old read-cache
wording with the resident-prefix ledger. Sentences replaced, named for the
revert check: "has no kMaxResident input or native journal-page term",
"changes neither its per-user storage terms nor its command-store shares",
"The bound codec uses the existing command-store share", "supplies no new
private RSS/AS certification" (introduced by 91353de) and "up to 64 KiB of page
bytes per store on the heap", "Counted in bytes; independent of extent and
bars" (introduced by 6d2bf95).

The sink-sync test's counting allocator routes the nothrow allocation forms too,
because AddressSanitizer intercepts them.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>


Test note: test_report_sink_writer_memory and test_run_json_bounded_transport read page residency with mincore; on the Cloud Run overlay filesystem they fail on unmodified main too and pass on a disk-backed VM on main and on this branch.

Supersedes #549 (same change, one commit on current main).



## Stated limits

1. "Typed failures unchanged" holds for the failure type and its setup only. A command store of at most 64 KiB now lives in memory and can no longer see scratch I/O errors; a failure that used to appear at the first write now appears at the spill, when the store grows past 64 KiB.
2. Report sink durability: the data synchronisation moved from every 64 KiB window to one synchronisation when the trailer is written (and on abandon). A crash between windows can lose the last unsynchronised windows of an unfinished report; a finished report is synchronised before its digest is returned. This is a deliberate trade for fewer system calls.
3. The macOS branch (`fsync` instead of `fdatasync`, `F_NOCACHE`) is not exercised by the new tests, which are Linux-only.
4. Performance: a single run on the 105,159-bar fixed-id benchmark showed the engine call going from about 1.59 s to about 1.21 s with 200,314 -> 11,436 pwrite64 calls. This is one run, not a replicated measurement; it is stated as an observation, not a claim.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
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.

1 participant