bench(#190): declare the history corpus reading as a phase, and measure the corpus axis - #204
Open
yifanxuaaa wants to merge 4 commits into
Open
yifanxuaaa wants to merge 4 commits into
yifanxuaaa wants to merge 4 commits into
Conversation
…us axis The `history.*` rows declared their phases in a way that could not reconcile: the harness reads its corpus between the measured children, so 18.1 s (stride10) and 23.0 s (stride3) of the complete command sat outside every declared phase and `runner.py` failed the reconciliation closed to INCOMPLETE. `phases::add_preparation` lets a driver attribute a measured span of harness input assembly to the preparation phase, and `ops::history` declares its corpus reading there. The declaration can only make the budgeted command larger. Reconciliation now PASSES: the unexplained remainder is the child's own non-phase work, 25.8 ms and 46.4 ms inside a ~1 s tolerance. The corpus axis of the cache stance is measured instead of assumed: `workload::history::ReadProbe` takes `mincore` over a fresh mapping of each corpus file before this invocation first reads it, once per distinct path, and the driver publishes that plus the chain's `rusage` disk_read_bytes delta. stride10: 45,338 files, 489,820,959 B, 62,319 pages, **0 resident**, 603,807,744 B from the device. stride3: 78,439 files, 850,636,296 B, 107,780 pages, **4,298 resident (3.988 %)**, 977,244,160 B from the device. Diagnostics only: nothing fails on them, nothing is de-warmed, and this is not a cold claim. Measured: stride10 wall 37.613 s, preparation 17.766 s, operation 19,738,993,418 ns; stride3 wall 75.121 s, preparation 26.033 s, operation 48,976,026,830 ns. Both classify NOT_RUN under the ordinary 15 s and the declared 25 s exception, so the corpus reading being declared corrects L44's projection: the declared commands are 37.521 s / 75.038 s, not 36.3 / 73.0, and stride10 does not fit 25 s. Checks: 117 harness tests PASS on this source, release build PASS (sha256 190424195506d4d54b24d253b483986d9aadf542fe125ae61225d833c2102ab1). Harness Clippy's 21 warnings and 1 denied-lint error are inherited, none in the added lines. The three touched files are rustfmt-clean; 121 pre-existing format diffs elsewhere were reverted rather than swept in. Resource commands ran under both global flocks after the quiet preflight; one collector attempt was refused for pre-creating its output directory, consumed no sample and is retained. Production LOC: 85725 -> 85725 (delta 0); reference 65417, core 20308. Harness +180/-5 lines in core/benchmark/fs-bench-pro-storage-content/src (excluded from production LOC). Ledger L45. Refs #190.
7 tasks
history-stride1 is the one history.* row no #190 campaign had sampled. Cap declared before the sample by the retained convention (~4.5 s of complete command per state): 720 s, never approached. The driver refuses per-state phase nodes above 53 states, so stride1 ran the ordinary recording. Measured: wall 199.025 s, preparation 52.664 s (corpus 51.142 s), operation 146.178 s over 157 states, reconciliation PASS, both budget limits NOT_RUN. Per state: mean 931.1 ms, median 698.5 ms, max 8,952.0 ms. Corpus probe: 180,128 files, 2,933 pages resident at first read (1.19%), 2,369,449,984 B from the device. The substantive finding is a depth term. Per-state elapsed tracks changed bytes (+0.90 to +0.99), but ns per changed byte rises 1.7-2.8x down the chain, and at matched changed volume the second half of the chain costs 1.22-2.31x the first with ns per byte roughly doubling. Localised by sub-phase, both product paths carry it: stride3 filesystem 47.5 -> 843.4 ms/state (17.8x) and storage.accept_loop 78.0 -> 658.3 (8.4x). Bounds stated: within-run, one sample, 2-21 states per band, matched on changed bytes only, no mechanism attributed. Store bytes, the one axis where v0.1.6 is directly comparable: stride10 +905,216 above its target, stride3 -946,176 below, stride1 +593,920 above; on content the core is below the historical apparent figure on two of three rows. Allocation is not precise: stride3 reads 62,152,704 then and 63,078,400 now for Stores that hash identically. Also closed by measurement: the retained source without the instrumentation patch reproduces the measured candidate's Stores byte for byte (4af37932aa3391b1..., f5c7ff5a6b4f0821...). The retained source's own timing remains the open gap. Production LOC: 85725 -> 85725 (delta 0); reference 65417, core 20308. Ledger L46. Refs #190.
Two axes, measured, and the mechanism behind the second. More chunks for the same history: 17 states 377.4 changed MB -> 19.739 s; 53 states 713.7 MB -> 48.976 s; 157 states 1,719.8 MB -> 146.178 s. Operation grows 7.41x against 9.24x states, and ns per changed MB rises 63% from the coarsest to the finest split, because finer chunking writes more total content and every state pays the depth term. The depth term is per-unit cost, not per-byte work. At matched changed volume, late-half states cost 1.2-2.3x the early half; provider waves per changed MB fall (0.45-0.80x), chain edges per record call stay flat (0.33->0.36), pack fetches per wave rise 4.0-4.8x, KiB per fetch rise 1.3-2.2x, the decoded-group hit rate falls 0.967->0.898, and pack bytes copied per changed MB rise up to 7.1x (12.1 M -> 86.2 M). Elasticity of filesystem ns/MB against ln(state): +8,755,936 (stride10), +13,108,101 (stride3). The read path makes fewer, larger calls as the chain grows - a bounded cache against a growing working set, stated as the reading the counters point at rather than a measured cache curve. Consequence: L42's Priority B pack/decoded-cache scope treatment (per-leaf reuse with a Store-write invalidation contract) is the best-motivated next experiment, and its value should grow with history length; chunk-selection policy is the largest multiplier in the table and is a product decision. No automatic cache growth proposed. Production LOC: 85725 -> 85725 (delta 0). Ledger L47. Refs #190.
Hands the depth term to the next round: the three-row starting point, the scaling measurements, the counter evidence that the term is per-unit cost rather than per-byte work, the two candidate explanations and the experiment that separates them (L42's Priority B pack/decoded-cache scope with a Store-write invalidation contract), the Store-byte comparison and the allocation movement measured on identical content, the v0.1.6 scope correction, and the full protocol and do-not list. Documentation-only. Production LOC: 85725 -> 85725 (delta 0); reference 65417, core 20308. Ledger L48. Refs #190.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #203 (the qualification disposition); this PR's base is that branch so the diff is only this round.
57d761b36.Executes the first two steps of the plan I put to the owner: declare the corpus reading as a phase, and measure the corpus axis. One sample per selection, retained source (no instrumentation patch), both global flocks held after the quiet preflight, established 120/240 s diagnostic caps. No pin written, no budget class changed, #190 stays open.
The change
Harness only, +180/−5 lines in
core/benchmark/fs-bench-pro-storage-content/src; no product line:phases::add_preparation(ns)— attributes a measured span of harness input assembly to the preparation phase, so the four declared phases account for an invocation whose assembly happens between the measured children. The declaration can only make the budgeted command larger.workload::history::ReadProbe—mincoreover a fresh mapping of each corpus file before this invocation first reads it, once per distinct path. Diagnostic only.ops::history— declares the corpus span, begins the probe after preparation closes, publishes the probe and the chain'srusagedisk_read_bytesdelta.Workload untouched: same corpus, same states, same measured children, one construction worker, nothing invalidated, no timeout enlarged, no selection shrunk.
Reconciliation: was INCOMPLETE, now PASS
phases.compose(the runner's own function, imported not reimplemented): PASS for both.Measured
Operation is within 0.8% / 1.1% of the retained 19,888,424,711 / 49,501,013,748 ns. Two independent instruments agree on the corpus axis, and the second run shows the first run's leavings: real, measurable, small. Positive control: the Store this run wrote reads back as 3,007/3,011 resident pages through the same
mincoremethod. Not a cold claim — nothing was invalidated and one run per selection establishes no distribution.Correction to the disposition, by measurement
DISPOSITION §2.3/§2.4 projected the declared commands at 36.3 s / 73.0 s and concluded stride10 would fit a declared 25 s exception. Measured they are 37.521 s / 75.038 s and both exceed 25 s. The projection's arithmetic was right and its input was wrong (the retained runs' corpus readings were 16.2 / 23.0 s; these are 17.6 / 25.5 s). So D4 has three shapes: a new frozen large-history class; a prepared, identity-checked corpus input — the setup-reuse route
AGENTS.md§2 requires, projected ~20 s / ~50 s and labelled NOT_MEASURED, motivated by the measured 27.9 MB/s across 45,338 files (388 µs per file: a per-file cost, not a bandwidth cost); or diagnostic only.Checks and limits
cargo +1.85.1 test117 tests PASS on this source; release build PASS (sha256 190424195506d4d54b24d253b483986d9aadf542fe125ae61225d833c2102ab1). Harness Clippy's 21 warnings and 1 denied-lint error (never_loop,src/ops/history.rs:1855at HEAD) are inherited, none in the added lines. The three touched files are rustfmt-clean; 121 pre-existing format diffs elsewhere were reverted rather than swept in. One collector attempt was refused by the child for pre-creating its output directory; it consumed no sample and is retained atruns/refused-history-stride10-exit2/.Standing rulings respected: no pin written, no value hand-edited, no cold claim, no cache pooled, no selection shrunk, no timeout enlarged, no case re-run, no diagnostic cap promoted, no history row added to
registry::cases()/FROZEN_CARDINALITY/ the 217-row self-check.Production LOC: 85,725 → 85,725 (delta 0); reference 65,417, core 20,308. Ledger L45.
docs/roadmap/0.1/0.1.7/evidence/stage-6-history-190-corpus-phase-20260920T054215Z/README.md · analysis · collector
Refs #190.