perf: cut cold-index RSS 4.3GB→1GB and wall-time ~6.5×#519
Merged
Conversation
Two independent fixes to the initial scan/index path, measured on a ~16k-file repo (cold `codedb index`): 4.3GB/~24s -> 1.0GB/3.7s. 1. Memory (src/watcher.zig, initialScanWorker): each parse worker held one long-lived page_allocator arena for its whole chunk, so it retained the high-water-mark of every file's transient parse state (AST/token buffers from parseContentForIndexing) chunk-wide and never reclaimed it (~3.5GB). Now each file is parsed in a per-file scratch arena that is reset between files; only keep-data (content dupe + Explorer.cloneOutline, now pub) is copied into the persistent results arena. Threading model unchanged (parse parallel, commit serial on the main thread), so the copy is race-free. -> 4.3GB to 1.0GB. 2. Speed (src/explore.zig, rebuildSymbolIndexFor): commit called removeSymbolIndexFor per file, which scans the entire global symbol index. On a cold scan every file is new (nothing to evict), making the whole pass O(files * total_symbols). Skip the scan when the path has no prior entry (had_prior=false). Commit phase 23.7s -> 1.5s. Both verified: 670/670 tests pass; search + symbol lookup (`find`) confirmed correct on the rebuilt index. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Benchmark Regression ReportThresholds: 10.00% and 50,000 ns absolute delta
|
This was referenced Jun 2, 2026
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.
Summary
Two independent fixes to the initial scan/index path. Measured on a ~16k-file repo with a cold
codedb index:−77% memory, ~6.5× faster — no functional change.
1. Memory — per-file scratch arena (
src/watcher.zig)Each parse worker held one long-lived
page_allocatorarena for its entire chunk.parseContentForIndexingthrows off large transient parse state (AST/token buffers) that isn't part of the returned content/outline; an arena never reclaims freed memory, so each worker's arena ballooned to the high-water-mark of every file's transients across its whole chunk (~3.5 GB total).Now each file is parsed in a per-file scratch arena that resets between files; only keep-data (content dupe +
Explorer.cloneOutline, madepub) is copied into the persistent results arena. The threading model is unchanged — parse parallel, commit serial on the main thread — so the per-worker copy is race-free.2. Speed — symbol-index O(n²) (
src/explore.zig)commitcalledremoveSymbolIndexForper file, which scans the entire global symbol index to evict the path's old entries. On a cold scan every file is brand-new (nothing to evict), so the whole pass was O(files × total_symbols) — billions of comparisons. Skip the scan when the path has no prior entry (had_prior=false).Commit phase: 23,713 ms → 1,517 ms (14×).
Phase breakdown (after)
The parse was already fast (0.5s), so the win came from the commit, not from adding parallel workers.
Verification
zig build test→ 670/670 passsearch(50 hits) and symbol lookup (find) return correct results.Also bumps
build.zig.zonto0.2.5824.