perf: round 15 — grouped-listing O(N²) rebucket, exif/reseed allocs, tantivy zero-hit snippet skip
Benchmark-gated, same rule as rounds 2–14: every change ships with a BEFORE/AFTER benchmark and an equivalence/safety gate; an AFTER that doesn't beat its BEFORE is rolled back. The rule is encoded per harness (GATE FAIL non-zero exit in the Rust examples, threshold expect() in vitest). F1 — Grouped listings (trash / recent / favorites / shared-with-me) re-bucketed the WHOLE accumulated list on every infinite-scroll page. ResourceSectionsBuilder (new, off the reactive graph) re-buckets only the fresh page and hands VirtualList the same rows array reference for untouched buckets. 50×50 (2 500-item) drain: 63 750 → 2 500 bucketOf calls (25.5×), 12.5 → 1.3 ms wall (9.9×); O(N²/page) → O(N). Deep-equal to the full-rebuild reference at every page for both a contiguous (date) and a non-contiguous (trash-by-drive) group-by; reference-stability + fallback gated. B1 — exif Make/Model: the display String was thrown away to allocate the trimmed copy; display_value_trimmed trims in place (drain + truncate), 2 → 1 alloc per field (8 → 4 allocs/op, 1.26×). B2 — content-index worker: text_extractor::supports (lowercases MIME + extension) was called twice per file per drain batch; classify once into a Vec<bool> and thread it through both uses. 256-file batch: 704 → 353 allocs, 34.5 → 16.7 µs (2.07×). B3 — tantivy: skip SnippetGenerator::create on a zero-hit content search (return Ok(vec![]) once top_docs.is_empty()); the per-hit loop was empty. 400-doc index: 1 575.6 → 1 237.2 ns (1.27×), widens with index size. Harnesses: examples/bench_round15_micro.rs, examples/bench_round15_tantivy.rs, frontend resourceSections.bench.test.ts; writeup in benches/ROUND15.md. Also normalizes two round14 bench examples that were committed unformatted (cargo fmt --all). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012o47jSrtL7xuNGTHXmtiYL
This commit is contained in:
+18
@@ -354,6 +354,24 @@ name = "bench_micro_allocs"
|
||||
path = "examples/bench_micro_allocs.rs"
|
||||
required-features = ["bench"]
|
||||
|
||||
# Round-15 battery ────────────────────────────────────────────────────────────
|
||||
|
||||
# Round-15 CPU/alloc micro-pack — exif Make/Model in-place trim (drop the
|
||||
# throwaway display String), content-index worker single supports() classify
|
||||
# per file (was called twice per drain batch). No Postgres.
|
||||
[[example]]
|
||||
name = "bench_round15_micro"
|
||||
path = "examples/bench_round15_micro.rs"
|
||||
required-features = ["bench"]
|
||||
|
||||
# Round-15 tantivy zero-hit snippet skip — the SnippetGenerator::create the
|
||||
# search path builds even when the query matched no documents (pure waste on a
|
||||
# no-hit content search). Builds a RAM index; no Postgres.
|
||||
[[example]]
|
||||
name = "bench_round15_tantivy"
|
||||
path = "examples/bench_round15_tantivy.rs"
|
||||
required-features = ["bench"]
|
||||
|
||||
# Round-14 battery ────────────────────────────────────────────────────────────
|
||||
|
||||
# Round-14 query-shape pack — lightbox face-box narrow projection (drop the
|
||||
|
||||
Reference in New Issue
Block a user