Skip to content

perf(search): PR A — nudge O(1), BM25 single-map, tier-1 keyed sort (#1 #3 #6) - #660

Merged
justrach merged 1 commit into
release/0.2.5828from
perf/search-latency-pr-a
Jul 9, 2026
Merged

perf(search): PR A — nudge O(1), BM25 single-map, tier-1 keyed sort (#1 #3 #6)#660
justrach merged 1 commit into
release/0.2.5828from
perf/search-latency-pr-a

Conversation

@justrach

@justrach justrach commented Jul 9, 2026

Copy link
Copy Markdown
Owner

Three behavior-preserving perf optimizations on the per-query search/rank hot path, from the perf audit and adversarially verified (produced by a 3-attempt swarm; winner independently re-verified).

Changes

#1mcp.zig appendSearchSymbolNudge: the bare-identifier nudge did a full O(U+S) symbol scan (searchSymbols scans the whole symbol_index and outlines on every call) just to test whether the query names an indexed symbol. Now uses findAllSymbols — the same helper codedb_symbol uses: ensureSymbolIndex + O(1) symbol_index.get, falling back to the outline scan only when !symbol_index_complete. Output is byte-identical (the nudge only checks results.len and prints the query string).

#3explore.zig BM25 posting loop: dropped the doc_tf hashmap. doc_best_line already accumulates .count identically per posting, so df = doc_best_line.count() and tf = entry.value_ptr.count. Two maps → one, and the redundant per-doc .get() re-lookup is eliminated. Values bit-identical.

#6explore.zig tier-1 sort: the comparator hashed 4 strings + touched 2 atomics per comparison. Now precomputes (count, len) per candidate once in O(C) (mirroring the existing tier0_order pattern) and sorts a struct-key array — identical predicate (count desc, len asc) and identical input order, so ranking output is unchanged. Bonus: stops the comparator corrupting ContentCache hit/miss stats via repeated atomic reads.

Validation

  • zig build test — full suite green, 0 failures.
  • All three are constant-factor/algorithmic wins on the per-query path; wall-time deltas should be confirmed in ReleaseFast on a large repo (Debug numbers are inadmissible; E-core variance is real), but each is justified on complexity alone.

Part of the search-latency cluster from the Fable-5 perf audit. Independent of #659.

🤖 Generated with Claude Code

#3 #6)

Three behavior-preserving optimizations on the per-query search/rank path,
identified by the perf audit and adversarially verified:

#1 (mcp.zig, appendSearchSymbolNudge): the bare-identifier nudge did a full
   O(U+S) symbol scan (searchSymbols scans the whole symbol_index AND outlines
   every call) just to test existence. Switched to findAllSymbols — the same
   helper codedb_symbol uses: ensureSymbolIndex + O(1) symbol_index.get, with
   the outline scan only when !symbol_index_complete. Output byte-identical
   (the nudge only checks results.len and prints the query string).

#3 (explore.zig, BM25 posting loop): dropped the doc_tf hashmap. doc_best_line
   already accumulates .count identically per posting, so df = doc_best_line.count()
   and tf = entry.value_ptr.count — one map instead of two, and the redundant
   per-doc .get() re-lookup is gone. Values bit-identical.

#6 (explore.zig, tier-1 sort): the comparator hashed 4 strings + touched 2
   atomics per comparison. Precompute (count, len) per candidate once in O(C)
   (mirroring tier0_order), then sort a struct-key array — identical predicate
   (count desc, len asc) and input order, so ranking is unchanged. Also stops
   the comparator corrupting ContentCache hit/miss stats.

zig build test: full suite green (0 failures).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown

Benchmark Regression Report

Thresholds: 10.00% and 50,000 ns absolute delta

NOISE means the percentage threshold was exceeded, but the absolute delta was too small to fail CI.

Tool Base (ns) Head (ns) Delta Abs Delta (ns) Status
codedb_bundle 96399 62527 -35.14% -33872 OK
codedb_changes 10737 11047 +2.89% +310 OK
codedb_context 296265 312167 +5.37% +15902 OK
codedb_deps 365 347 -4.93% -18 OK
codedb_edit 41799 41338 -1.10% -461 OK
codedb_find 2776 2747 -1.04% -29 OK
codedb_hot 24565 25622 +4.30% +1057 OK
codedb_outline 17489 16337 -6.59% -1152 OK
codedb_read 13218 13703 +3.67% +485 OK
codedb_search 90131 41553 -53.90% -48578 OK
codedb_snapshot 65321 70693 +8.22% +5372 OK
codedb_status 9450 9190 -2.75% -260 OK
codedb_symbol 59861 51748 -13.55% -8113 OK
codedb_tree 13852 13458 -2.84% -394 OK
codedb_word 12021 16911 +40.68% +4890 NOISE

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e589b3d31a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/mcp.zig
.max_results = 1,
};
const results = explorer.searchSymbols(spec, alloc) catch return;
const results = explorer.findAllSymbols(query, alloc) catch return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid materializing every duplicate symbol for the nudge

When the bare query is a common symbol such as init or main in a large repo, findAllSymbols duplicates every matching path/name/detail even though this branch only checks results.len. That puts O(matches) allocation/free work in front of each text codedb_search; the previous searchSymbols call was capped with max_results = 1, so materialization was bounded. Use an existence check or capped exact lookup for the nudge.

Useful? React with 👍 / 👎.

justrach added a commit that referenced this pull request Jul 9, 2026
@justrach
justrach merged commit e589b3d into release/0.2.5828 Jul 9, 2026
2 checks passed
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