Skip to content

Reduce rule-result allocation churn with a preallocated caller-owned slice - #1021

Merged
matthyx merged 1 commit into
mainfrom
fix/rule-slice-prealloc-20261007
Oct 8, 2026
Merged

matthyx merged 1 commit into
mainfrom
fix/rule-slice-prealloc-20261007

Conversation

@matthyx

@matthyx matthyx commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

CreateAllRules grows a nil slice on every call, repeatedly allocating and copying rule structs. A five-minute node-agent pprof capture attributed 47.29 MB on one node directly to that append loop.

Allocate the caller-owned result slice once at its final length. Preserve nil results for empty creators, rule order, shallow copies, lazy prefilter initialization, locking, and visibility of synchronized rule additions, updates, and deletions. Callers can continue filtering results in place without changing the creator. Cache TTL and invalidation behavior are unchanged.

Validation:

  • Regression tests passed against the original implementation before the change; normal and race tests pass after it, including concurrent synchronization and first-call prefilter initialization.
  • Rule creator and binding-cache tests, vet, formatting, and independent review passed.
  • Production integration benchmark, backported onto v0.3.251 with the OTel upgrade and otherwise identical dependencies, Go toolchain, and five samples per case: at 512 rules, nil/cached-filter calls fall from 261,840 to 122,880 B/op and 10 to 1 allocations; at 1,024 rules, from 794,320 to 245,760 B/op and 12 to 1 allocations. Median time improves in all nine tested count/state cases. Non-filter parsing remains unchanged.

A separate matched benchmark on this PR’s main base also shows one allocation per nil/cached-filter call. The allocation counts and byte reductions match the production integration results; timing improves for all cases except the 128-rule non-filter case (+0.5%).

Direct three-node DigitalOcean validation completed with the same stabilized microservices workload, batch size 512, three-minute warmup, and five-minute capture. The runtime dependency versions match except for the rule-preallocation commit. Total allocation bytes/sec fell 14.1%; direct CreateAllRules flat allocation bytes/sec fell 81.1%. RSS fell 2.4% and working set fell 4.5%. Frontend requests were 640 versus 686 with zero failures; no collector or detected export/drop errors occurred. Agent and workload restarts stayed zero.

Final sampled forced-GC live heap was 8.2% higher. Almost all of that difference already existed at capture start (11.51 MB initially versus 12.06 MB finally, across three agents); live-heap differences are distributed across unchanged initialization/cache/BTF allocation sites. No final live sample was attributed directly to CreateAllRules. This short sequential run supports an allocation-churn improvement, not a retained-heap improvement or long-term CPU guarantee.

Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
@coderabbitai

coderabbitai Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Review in 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: 0a84915e-a528-4633-803d-d8c842311672
📥 Commits

Reviewing files that changed from the base of the PR and between e33c1ff and 892d007.

📒 Files selected for processing (2)
  • pkg/rulemanager/rulecreator/factory.go
  • pkg/rulemanager/rulecreator/factory_allocation_test.go

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

CreateAllRules now returns nil when no rules exist and preallocates the result slice before filling it. New tests cover slice ownership, synchronization, concurrent calls, prefilter initialization, and allocation benchmarks.

Changes

CreateAllRules result behavior

Layer / File(s) Summary
Allocate and validate rule results
pkg/rulemanager/rulecreator/factory.go, pkg/rulemanager/rulecreator/factory_allocation_test.go
CreateAllRules returns nil for an empty rule set and fills a preallocated result slice. Tests cover caller mutations, synchronization, concurrent calls, prefilter initialization, and allocation benchmarks.

Priority: ⬇️ Low

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

Change: Refactor

Merge Risk: ⚪ Minimal · up to 892d0

The change is ready to merge after normal checks.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 6 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: preallocating a caller-owned rule-result slice to reduce allocation churn.
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
🛠️ Fix failing CI checks 💡
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@github-actions

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown

Performance Benchmark Results

Node-Agent Resource Usage
Metric BEFORE AFTER Delta
Avg CPU (cores) 0.135 0.135 -0.0%
Peak CPU (cores) 0.144 0.144 -0.5%
Peak CPU p95 (cores) 0.142 0.143 +0.1%
Avg Memory (MiB) 386.979 307.742 -20.5%
Peak Memory (MiB) 389.844 311.082 -20.2%
Dedup Effectiveness

No data available.

Copilot AI 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.

🟢 Approval recommended

The focused optimization preserves existing semantics and is covered by relevant regression and concurrency tests.

0 open findings

What changed in this PR

Optimizes rule creation by replacing repeated slice growth with one exact-size allocation while preserving synchronization and behavior.

Changes:

  • Preallocates CreateAllRules results.
  • Adds regression, concurrency, prefilter, and benchmark coverage.
File Description
pkg/​rulemanager/​rulecreator/​factory.go Uses an exact-size caller-owned result slice.
pkg/​rulemanager/​rulecreator/​factory_allocation_test.go Verifies behavior and allocation performance.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@matthyx
matthyx merged commit e458013 into main Oct 8, 2026
40 of 41 checks passed
@matthyx
matthyx deleted the fix/rule-slice-prealloc-20261007 branch October 8, 2026 05:22
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.

2 participants