Skip to content

perf(runtime): drop the saturated buffer address filter (-2.46% command CPU) - #10108

Closed
proggeramlug wants to merge 1 commit into
PerryTS:mainfrom
proggeramlug:perf/drop-dead-buffer-addr-filter
Closed

perf(runtime): drop the saturated buffer address filter (-2.46% command CPU)#10108
proggeramlug wants to merge 1 commit into
PerryTS:mainfrom
proggeramlug:perf/drop-dead-buffer-addr-filter

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Summary

BUFFER_LIKE_ADDR_FILTER is saturated on any realistic claude-code workload — it ends every measured run with all 1,024 bits set and rejects nothing, while costing three hash rounds and up to three dependent loads on every one of ~26.6 M admitted probes per run. Removing it is measurably faster. The min/max window in front of it stays and keeps doing all of the rejecting.

Minimum command CPU 1.22 → 1.19 s (−2.46 %), paired median −3.60 %, faster in five of six interleaved pairs and tied in the sixth, peak RSS no worse.

Why the filter's own adoption note no longer holds

The note asked the capacity question and answered it from a 400-character reply: 213 cumulative registrations, live_max 201, true_positives=53,109 (0.207 % of admits) → a predicted 10.0 % false-positive rate, "the filter rejects about nine of every ten addresses the window admits".

Both premises fail on an ordinary command (startup, two real Read tool calls, streamed reply). PERRY_BUFFER_DIAG — the instrument that already ships beside the filter — two rows:

probes=31,457,281 admits=26,577,900 (84.49 %) rejected=4,879,381 (15.51 %)
true_positives=23,620,613 (88.873135 % of admits)
registrations=3232 unregistrations=1907 live_max=1618
  • The population is 15× larger than assumed. 3,232 cumulative admissions and 1,618 live against 1,024 bits, so the filter saturates. Every rejection above comes from BUFFER_LIKE_ADDR_WINDOW, at 15.51 % — not the 25.94 % the note quotes.
  • The question's answer is usually yes. 88.87 % of admitted probes find a real registered buffer, against 0.207 % on the --help-shaped workload the note measured. A filter cannot remove work the registry genuinely has to do; even a correctly sized one could only have taken the ~2.96 M false positives per row off the slow path.

So the structure is pure overhead on this workload, and sizing it up would not have helped much either.

Measurement

Six interleaved pairs plus two node rows on the quiet Linux box, campaign lock held, one binary and one environment variable — the filter's own env-var arm against the default — so the arms are the same bytes and the same compiler.

Pair filter on filter off change
1 1.33 s 1.33 s 0.00 %
2 1.29 s 1.27 s −1.55 %
3 1.27 s 1.19 s −6.30 %
4 1.31 s 1.20 s −8.40 %
5 1.22 s 1.20 s −1.64 %
6 1.26 s 1.19 s −5.56 %

Minima 1.22 → 1.19 s (−2.46 %), medians 1.28 → 1.20 s, paired median −3.60 %. Peak RSS maxima 664.5 → 635.2 MiB. Node anchor in the same session: command CPU 0.41 / 0.42 s, peak RSS 335.5 MiB. CPU accounting has hundredth-second granularity, so six pairs support a positive result of this size rather than a precise universal figure, and this is one workload on one host.

Risk

Deleting a negative accelerator can only cost the lookup that was already there; it cannot produce a wrong answer, and the release build's authoritative path is untouched. The debug-build machine-check that re-derives every rejection from the authoritative tables is unchanged, so a registration route added without admitting to the window still panics in the first test that exercises it.

perry-runtime buffer tests pass unchanged. The change is confined to crates/perry-runtime/src/buffer/header.rs: the static, the env-var accessor, two admit calls and one term in the probe, with the measured rationale left in place of the old note.

Context for the structure itself: #10109 (two of the four instances of this filter type had stopped discriminating, and nothing in a shipping build can tell). The sibling owner where the remedy is the opposite one — size it up rather than delete it — is #10110.

Summary by CodeRabbit

  • Refactor
    • Buffer address registration and probing now rely solely on the configured address window.
    • The separate buffer address filter and its environment-variable toggle have been removed.
  • Diagnostics
    • Updated diagnostic guidance includes measurements related to the simplified buffer address handling.

BUFFER_LIKE_ADDR_FILTER ends every measured claude-code run with all 1,024 bits
set and rejects nothing, while costing three hash rounds and up to three
dependent loads on every one of ~26.6 M admitted probes per run.

Its adoption note asked the capacity question and answered it from a
400-character reply: 213 cumulative registrations, live_max 201, true positives
0.207% of admits, predicting a 10.0% false-positive rate. An ordinary command
(startup, two real Read calls, streamed reply) falsifies both premises. The
population is 15x larger - 3,232 cumulative admissions and 1,618 live against
1,024 bits - so the filter saturates, and every rejection comes from the window
in front of it at 15.51%, not the 25.94% the note quotes. And 88.87% of admitted
probes find a real registered buffer, against 0.207% before, so a filter cannot
remove work the registry genuinely has to do.

Six interleaved pairs, one binary and one environment variable: minimum command
CPU 1.22 -> 1.19 s (-2.46%), medians 1.28 -> 1.20 s, paired median -3.60%,
faster in five pairs and tied in the sixth, peak RSS maxima 664.5 -> 635.2 MiB.
Node anchor in the same session 0.41/0.42 s.

The min/max window stays and keeps doing all of the rejecting, including the
debug-build machine-check that re-derives every rejection from the authoritative
tables. Deleting a negative accelerator cannot produce a wrong answer.
@coderabbitai

coderabbitai Bot commented Sep 12, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 13cf5fa8-a81c-4642-b424-4ac2d02b9518

📥 Commits

Reviewing files that changed from the base of the PR and between dc0d876 and b13d382.

📒 Files selected for processing (1)
  • crates/perry-runtime/src/buffer/header.rs

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

The buffer registry removes BUFFER_LIKE_ADDR_FILTER and its environment-variable control. Buffer registration and probing now rely only on BUFFER_LIKE_ADDR_WINDOW. Comments document measurements supporting the removal.

Changes

Buffer admission simplification

Layer / File(s) Summary
Use the address window for registration and probing
crates/perry-runtime/src/buffer/header.rs
Registration widens only BUFFER_LIKE_ADDR_WINDOW. is_registered_buffer checks only the address window. Comments document the removed filter and its measurements.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Refactor

Merge Risk: ⚪ Minimal · up to b13d3

The admission simplification preserves exact buffer identification and introduces no unresolved merge-blocking risk.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise, specific, and accurately identifies the main runtime performance change and measured CPU improvement.
Description check ✅ Passed The description is detailed and covers the change, rationale, measurements, risks, affected file, and test status. It omits the exact Changes, Related issue, Test plan, and Checklist headings, but the…
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 3 functions across 1 files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

proggeramlug pushed a commit that referenced this pull request Sep 12, 2026
The PR changed crates/ without one, which the changeset gate requires. Body
summarised from the commit message's own measurements.
proggeramlug pushed a commit that referenced this pull request Sep 12, 2026
Train164 (#10096, #10108, #10111, #10112) lands on main at 0.5.1537; none of the
PRs bumped the version, which is the maintainer's job at merge time. Cargo.lock
regenerated so every workspace member's inherited version moves with it.
@proggeramlug

Copy link
Copy Markdown
Contributor Author

Landed on main via merge train #10121 (rebase-merged, per-commit authorship preserved).

Your commits are on main starting at b1f056c9e0; the train tree was verified identical to main after the merge (git diff origin/main HEAD --stat empty).

One maintainer follow-up: the PR changed crates/ without a changelog.d/ fragment, which check_changeset_fragment.sh requires, so I wrote changelog.d/10108-buffer-addr-filter-removal.md from your commit message's own measurements (5fe917a5f4). The gc_runtime_root_holders gate is green after the static's removal, so it left no stale entry behind.

Closing this PR as landed — GitHub cannot auto-close it because the train merges as its own branch.

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