mirror of
https://github.com/samuelncui/yatm.git
synced 2026-11-08 12:26:33 +00:00
Organize documentation by audience: packaged user guides in docs/operations (including Devices, Tape scripts, Auto read order, Jobs, offline migration and tar recovery), contributor procedures in docs/development, maintainer release procedures in docs/release, current behavior in docs/architecture (now with separate Tape and read-planning documents) and evidence in docs/research. Each rule keeps one owner and other pages link to it; the document checker, the packaged guide allowlist and their tests follow the new layout. The documents land together because the new guides and index link to each other. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
243 lines
18 KiB
Markdown
243 lines
18 KiB
Markdown
# Performance Acceptance
|
|
|
|
Use fixed, representative benchmarks to record current interface performance and detect
|
|
regressions. Compare a repair with its preserved pre-repair source, a pull request with its exact
|
|
base, and a release with its recorded accepted source baseline. Do not silently replace that
|
|
baseline or require comparison with the first Alpha release.
|
|
|
|
Run each standard Go benchmark **once per source**, with `-count=1 -benchmem`. Go calibrates the
|
|
iterations within that run; there is no minimum number of separate samples or confidence-interval
|
|
gate. Use the same reviewed harness, fixture sizes, Go patch version, SQLite mode, CPU setting
|
|
and filesystem for both sources. Measure baseline and candidate serially, with other builds,
|
|
tests and agents stopped during timing. Record source identities, commands and raw results;
|
|
a skipped case, missing metric or incomplete run is not evidence.
|
|
|
|
The [suite manifest](../../dev/performance/suites.json) selects the appropriate scope:
|
|
|
|
| Tier | Coverage | Use |
|
|
| --- | --- | --- |
|
|
| `fast` | 10,000-entry List, Ignore, Search and Scan; 1,000/10,000-entry Archive result pages | Related pull requests and local changes |
|
|
| `critical` | List/Search/Scan and Archive result pages with 100,000 entries | Traversal, SQL, projection and buffering changes |
|
|
| `release` | Critical List/Search/Scan, Archive pages at 1,000/10,000/100,000/1,000,000 entries, and candidate-only million-entry correctness checks | Release acceptance |
|
|
| `migration` | 10,000 Files and 20,000 physical copies on disk SQLite | Legacy archived-content reconciliation changes |
|
|
| `read-fast` | Representative tar/LTFS planning benchmarks and all five development seeds | Restore planning development and affected pull requests |
|
|
| `read` | The same planning benchmarks, all five development and five acceptance seeds, and fixed references | Complete Restore route-quality acceptance |
|
|
| `read-resources` | Streamed 100,000/1,000,000-item budget and cancellation cases, plus production tar evaluator cases | Restore planning resource and cleanup acceptance |
|
|
|
|
For List/Scan choose one of `fast`, `critical` or `release`; do not repeat the smaller tiers inside
|
|
a release run. Use `migration` separately when its reconciliation changes. Large-data correctness
|
|
checks remain separate from timing and run once. Frontend changes also use the relevant list
|
|
interaction and virtualization tests in the frontend suite, and the
|
|
[frontend benchmark](../../frontend/README.md#frontend-benchmarks) uses Vitest's native comparison
|
|
with one invocation per source. Browser tests cover actual rendering and interaction. Shared loading or virtual-list changes
|
|
include a cold route, deliberately delayed code/data responses, an error and explicit Retry,
|
|
and forward/reverse/distant scrolling with long rows. Verify request counts, selected menus
|
|
and real scroll geometry: a mocked virtualizer cannot establish those layout properties.
|
|
|
|
List/Search fixtures associate half the entries with catalog Files and request attributes,
|
|
status, operations and navigation. They cover random/reverse names, 16 directory levels,
|
|
102 Ignore rules with exclusion and negation, and the first and next 100-row Search pages.
|
|
List records first-batch and complete-response latency with a receiver retaining all rows;
|
|
Search records each page's response latency. Both report allocations. Setup is outside the timer
|
|
and Go's benchmark loop reuses the fixture during calibration. The million-entry List check
|
|
verifies completeness, ordering and bounded batches with a receiver retaining only counters and
|
|
the previous name. Go `B/op` excludes native SQLite memory; these checks do not claim a peak RSS bound.
|
|
|
|
Scan covers one selection across one, three and nine Locations, a small physical selection in a
|
|
large recorded Location, and renamed originals across three Locations. Each case reports Create,
|
|
completion, first-result-page and total latency, plus allocations. Scan intentionally uses
|
|
`-benchtime=1x -count=1`: it modifies catalog state, so a second operation on that same catalog
|
|
would measure a different workload. Catalog setup and Job deletion remain outside the timer.
|
|
The million-entry Scan check verifies completion and all result pages once on the candidate.
|
|
|
|
Result browsing uses `go test ./internal/executor/scan -run '^$' -bench '^BenchmarkScanListEntries$'
|
|
-benchmem -count=1`: a retained 100,000-entry manifest, first-page counts, forward/reverse
|
|
cursors and far offsets, with warm or reopened runners and Preview presence checks. Fixture
|
|
creation is outside timing. This isolates the public handler from Scan execution, RPC transport
|
|
and browser rendering. Keep its small fixture correctness check in the regular Go suite.
|
|
|
|
Archive result paging uses `go test ./internal/executor/archive -run '^$'
|
|
-bench '^BenchmarkArchiveManifestPages$' -benchmem -count=1`. It queries retained on-disk
|
|
manifests of 1,000, 10,000, 100,000 and 1,000,000 synthetic files in 200-row pages, including an initial
|
|
total, forward/reverse cursors and a far offset. Fixture construction and correctness
|
|
checks are outside timing. This measures manifest queries and result projection, not
|
|
Archive preparation, RPC transport, browser rendering or physical Tape I/O.
|
|
|
|
Legacy migration changes use the same collector with `--tier migration`; it runs
|
|
`BenchmarkPrepareArchivedVersions` once on each source with `-benchtime=1x`, records identities
|
|
and feeds the same comparison command. Each operation consumes fresh on-disk staging tables,
|
|
including duplicate copies across pages; setup and result-count checks remain outside the timer.
|
|
This focused check measures archived-content reconciliation, while complete migration acceptance
|
|
uses the packaged installer and a copied legacy backup through the
|
|
[package controller](../release/package-acceptance.md#remote-packaged-binary-acceptance).
|
|
|
|
Restore planning separates deterministic route quality from representative execution timing.
|
|
The common harness runs against both the frozen old source and the candidate with identical
|
|
inputs and models. `read-fast` uses the development seed set; `read` also includes the separate
|
|
acceptance seed set. Each report retains the complete case inventory, generator version,
|
|
seed, selection and population sizes, input/model hashes, full inputs, LOGICAL and retained
|
|
routes, best working cost, adoption result and termination reason. Small exact references
|
|
enumerate every complete file permutation under the actual initial-state and completion semantics.
|
|
Nominal admission makes their eligible and unconstrained minima coincide; sensitivity results remain
|
|
separate from search. Fixed references supply signed cost gaps for both implementations;
|
|
falling short of a reference does not stop measurement or discard a complete route.
|
|
The fixed mixed308 case retains its measured LTFS layout and the fixed 1.5 TB population retains
|
|
its original mixed sizes and 20% selection. Synthetic boundary cases may span more logical data
|
|
than a physical LTO-5 cartridge: their purpose is to force distinct continuous runs and exercise
|
|
31/32/33-run search boundaries, not to predict that cartridge's capacity or elapsed time.
|
|
The quality and representative timing harnesses use the same 300-second budget on both sources,
|
|
matching the Device default; the fixed 1.5 TB workload must not receive a shortened acceptance
|
|
budget. Explicit resource deadline/cancellation tests retain their separate budgets. Reports retain
|
|
bounded per-pass search diagnostics so exhausted budgets can be explained without rerunning or
|
|
resampling the workload.
|
|
Both read tiers check that the scenario budget reaches the instrumented production evaluator;
|
|
quality and timing consumers cannot independently override it.
|
|
The two fixed 1.5 TB cases retain their LOGICAL, generated and selected costs, including a tied
|
|
LOGICAL fallback. Complete the selected experiments before comparing route quality, planning
|
|
cost and resource use; no minimum improvement or per-case no-regression rule selects the winner.
|
|
|
|
The [route comparison](../../dev/performance/read-quality.mjs) reports wins, ties, losses and
|
|
exclusions overall and by backend/family, with median, P90 and worst absolute/relative cost
|
|
changes and exact-reference gaps. These percentiles describe the fixed input population,
|
|
not timing confidence. Every case retains its input and routes, including the identified worst
|
|
case. LOGICAL-to-old, LOGICAL-to-new, old-to-new, best-working-to-retained and model-plus-planning
|
|
costs remain separate. A complete route retained at budget expiry remains comparable and carries
|
|
an explicit termination label; missing models, skipped cases and failed runs retain their status
|
|
and cannot provide an invented cost. Every nominal increase, fixed-reference gap and parameter
|
|
tradeoff stays visible. Policy labels are descriptive metadata, not a validator allowlist or an
|
|
acceptance rule. The comparison completes even when a route is slower than LOGICAL, an old
|
|
implementation or a reference. Member coverage, replay consistency and evidence integrity remain
|
|
correctness checks. Synthetic one-factor rescoring of locate, longitudinal and read coefficients
|
|
at 0.5/1/2 is sensitivity evidence, not physical-device evidence.
|
|
|
|
Representative planning benchmarks use one fresh operation (`-benchtime=1x`) per source and
|
|
report total time/allocations, indexing, search/scoring, standalone full retained-route scoring,
|
|
nominal provider evaluator calls (`evaluations/op`), optional all-model planner diagnostic counts
|
|
(`total-evaluations/op`), temporary disk bytes, modeled route cost and model-plus-planning cost.
|
|
Selections of at most 200 members also report `lower-bound-model-s/op`: a Held-Karp bound on
|
|
the same modeled costs, below every complete route, so its distance to the retained cost bounds the
|
|
remaining search gap. It is a reported quantity, not a pass threshold; larger selections omit it.
|
|
The all-model count includes nominal and variant scoring calls; an older source without that
|
|
diagnostic reports it as unavailable, and the pair comparison does not compare it. Process
|
|
high-water RSS includes native SQLite allocations and is cumulative across the test binary;
|
|
it is not an isolated per-case peak. The explicit `read-resources` tier streams large inputs,
|
|
checks complete consumption or authoritative-manifest fallback, exercises cancellation during
|
|
ingestion and after optimization state allocation, and verifies temporary-directory cleanup.
|
|
On cancellation, `plan-ns/op` includes cleanup performed before `PlanReadSequence` returns;
|
|
`consume-cleanup-ns/op` then measures post-return settling and checks. For successful plans,
|
|
the latter also includes execution-index traversal and `Close`.
|
|
Its disk sampling includes SQLite journals and may miss peaks between samples. Resource and
|
|
CPU/allocation increases above 10% remain investigation warnings rather than automatic failures;
|
|
route costs and parameter sensitivity are likewise reported for review without automatic rejection.
|
|
|
|
Use repeatable `--package ./internal/apis`, `--package ./internal/executor/scan` or
|
|
`--package ./internal/executor/archive` to compare only that package's suites within the
|
|
selected tier. Package names must match the manifest;
|
|
structural checks and common harness files follow the selected packages. `pair.json` records
|
|
requested, selected, executed and skipped packages and structural scope. A completed subset is
|
|
not a full release comparison. Baseline and candidate use independent mutable temporary fixtures.
|
|
The manifest and shared harness are captured once and applied identically to both sources.
|
|
|
|
Fixture-only changes can measure preparation separately with
|
|
`go test ./internal/apis -run '^$' -bench '^BenchmarkFilesFixtureSetup$' -benchtime=1x -benchmem -count=1`.
|
|
It measures fresh file creation and catalog seeding at 10,000 and 100,000 entries; deferred cleanup
|
|
is outside the timer. It is not a List/Search runtime comparison. Reuse their existing measurements
|
|
when their implementation and equivalent input distribution remain unchanged.
|
|
|
|
The collector snapshots the supplied sources and installs the same reviewed harness in both.
|
|
It records commits and actual source hashes, including dirty changes, then compiles both suites
|
|
before measuring. Each suite executes its standard Go test binary once per source. This is the
|
|
same benchmark mechanism as `go test -run '^$' -bench PATTERN -benchmem -benchtime=1s -count=1`;
|
|
precompilation keeps compilation out of the measurement window. It adds no custom sampling loop.
|
|
|
|
```shell
|
|
node --test dev/check-performance.test.mjs dev/performance/*.test.mjs
|
|
|
|
PERF_OUTPUT="$(mktemp -d)/pair"
|
|
node dev/performance/collect.mjs \
|
|
--baseline "$PERF_BASELINE" --candidate "$PERF_CANDIDATE" \
|
|
--harness "$PERF_HARNESS" --out "$PERF_OUTPUT" \
|
|
--tier fast --environment "$PERF_ENVIRONMENT" --idle
|
|
node dev/check-performance.mjs "$PERF_OUTPUT"
|
|
```
|
|
|
|
Set the checkout paths and environment label explicitly. Output must be a new directory outside
|
|
all source checkouts. Defaults are `--cpu 2`, `--benchtime 1s` and `--cgo 1`; use `--cgo 0` for
|
|
pure-Go SQLite. The harness's `go.mod` selects the exact Go patch toolchain. Only ordinary source
|
|
files are supported; symlinks/submodules and incompatible harnesses fail instead of silently
|
|
changing the inputs. Sources are measured on the same host, not compared with unrelated old
|
|
machine timings. Ambient Go configuration and workspace/module edits are disabled.
|
|
|
|
The [comparison](../../dev/check-performance.mjs) reports each measured time/allocation value and
|
|
percentage change. An increase above 10% flags the case for review; it does not prove a code
|
|
regression or fail a completed comparison. CI highlights these flags as warnings. Missing, invalid
|
|
or failed measurements still fail the command. Review the flagged implementation and measurement
|
|
conditions before accepting the change; if necessary, rerun only that case on both sources. Keep
|
|
the initial result and explain the finding. Finish the comparison before selecting an implementation;
|
|
weigh observed route quality, planning cost, resource use and applicability together, including
|
|
losses and tradeoffs. Do not repeat the whole suite until it passes or automatically replace the
|
|
baseline. The comparison reports measurements, not release approval.
|
|
|
|
Keep `pair.json`, raw `.bench` files, structural logs and `comparison.json` as verification
|
|
artifacts outside maintained documentation. Read tiers additionally seal paired full-case JSON
|
|
reports and logs. Failed quality runs retain full inputs and any partial routes for diagnosis;
|
|
failed or unexecuted cases cannot complete acceptance. An interrupted collection remains incomplete.
|
|
|
|
The [Performance workflow](../../.github/workflows/performance.yml) measures a PR's exact head
|
|
and event base with the base revision's reviewed harness. It also runs the frontend's native
|
|
directory and 1,000/10,000/100,000/1,000,000-row Job cache comparison serially after the Go
|
|
measurements. Both collectors retain source/harness identities and raw results; missing,
|
|
failed or unmatched cases cannot complete a comparison. Manual critical/release runs use the
|
|
requested full candidate commit and `PERFORMANCE_ACCEPTED_BASELINE`, an explicitly accepted full
|
|
commit SHA. Both sources run once on that runner. The workflow is read-only, retains evidence on
|
|
failure, and never updates the baseline or publishes a release. Missing tools/harness require a
|
|
reviewed change; a missing or invalid baseline fails the hosted comparison.
|
|
Affected pull requests also run `read-fast` when Media/Restore planning sources, the common
|
|
performance harness, its workflow or the canonical Restore fixture change. Explicit `read` and
|
|
`read-resources` dispatches select full quality and large-resource evidence separately.
|
|
|
|
Release preparation requires one completed, reviewed `release` comparison of the final source
|
|
against the recorded accepted source baseline, collected locally or through the hosted workflow.
|
|
Both sides must use the same host, tools and reviewed harness under the conditions above. Evidence
|
|
must identify the exact baseline, candidate and harness commits and content hashes, including any
|
|
dirty changes, with the commands, raw results and flag resolutions. Complete the structural checks
|
|
and relevant frontend checks as well. Review the completed results and record the implementation
|
|
choice and tradeoffs before candidate or source-push approval. An incomplete comparison remains
|
|
open work. A completed local comparison
|
|
satisfies this requirement without uploading its baseline or repeating it on a hosted runner.
|
|
Candidate assembly runs its source and package gates without automatically invoking Performance.
|
|
|
|
After measurement, review the diff against each measured operation. Retain its evidence when
|
|
the relevant runtime source, dependencies, harness, fixtures and measurement settings are
|
|
unchanged, recording the measured and final commits. Documentation or unrelated runtime/tooling
|
|
changes do not require repeating that operation. Rerun only affected benchmarks and resolve their
|
|
flags; do not repeat the whole release tier for a change to one component. The final source
|
|
preflight and acceptance of the exact release archives remain required.
|
|
|
|
## Large Identical Results
|
|
|
|
Use the native benchmark for before/after Find and retained-page costs with the same 10,000-
|
|
and 100,000-File fixtures. Fixture creation is outside the measured operations:
|
|
|
|
```shell
|
|
go test ./internal/library -run '^$' -bench '^BenchmarkIdenticalRetainedResult$' -benchmem -count=1
|
|
```
|
|
|
|
The opt-in performance fixture builds isolated 10,000- and 100,000-File catalogs with many pairs,
|
|
a large group, a long transitive chain, saved versions, hidden names and unknown sizes. It measures
|
|
one complete Find and retained 200-row reads, then checks every sort direction, random offsets and
|
|
File ID position lookups against an independent result. Page checks verify that catalog collection
|
|
and component construction do not run again.
|
|
|
|
```shell
|
|
YATM_IDENTICAL_PERF=1 go test -count=1 ./internal/library \
|
|
-run '^TestIdenticalLargeCatalogPerformance$' -v -timeout 30m
|
|
CGO_ENABLED=0 YATM_IDENTICAL_PERF=1 go test -count=1 ./internal/library \
|
|
-run '^TestIdenticalLargeCatalogPerformance$' -v -timeout 30m
|
|
```
|
|
|
|
These measurements cover query staging and retained SQL reads, not API member observation or
|
|
browser rendering. Go allocation measurements exclude fixture construction and native SQLite
|
|
memory; use an external process measurement when peak memory matters. The ordinary unit suite
|
|
skips this fixture, and the default Demo remains small enough for interactive review.
|