Skip to content

⚡ Bolt: [performance improvement] Reduce eventqueue GC pressure#24

Merged
matdev83 merged 2 commits into
mainfrom
bolt-eventqueue-optimization-8043453630250216761
Jun 22, 2026
Merged

⚡ Bolt: [performance improvement] Reduce eventqueue GC pressure#24
matdev83 merged 2 commits into
mainfrom
bolt-eventqueue-optimization-8043453630250216761

Conversation

@matdev83

Copy link
Copy Markdown
Owner

The PendingEventQueue in internal/core/stream translates large wire chunks into many canonical events. Its compaction logic was reallocating an entire new slice with every shift if the queue capacity was over 32. Since these queues process rapidly arriving stream events, shifting head-to-tail down the existing array via copy is much cheaper than make+copy except when the array has bloated excessively (>1024 cap and <25% active).

This PR:
💡 What: Replaced the eager make reallocation in PendingEventQueue.compactIfNeeded with in-place copy slice shifting, only reallocating when the buffer is severely bloated.
🎯 Why: To reduce GC pressure and allocation overhead on the hot stream queue path.
📊 Impact: pushPop benchmark throughput improved ~35% (175k ns -> 126k ns) and allocations dropped from 13 to 9 per run.
🔬 Measurement: Run cd internal/core/stream && go test -bench=BenchmarkPendingEventQueue_pushPop -benchmem


PR created automatically by Jules for task 8043453630250216761 started by @matdev83

The `PendingEventQueue` in `internal/core/stream` translates large wire chunks into many canonical events. Its compaction logic was reallocating an entire new slice with every shift if the queue capacity was over 32. Since these queues process rapidly arriving stream events, shifting head-to-tail down the existing array via `copy` is much cheaper than `make`+`copy` except when the array has bloated excessively (>1024 cap and <25% active).

This PR:
💡 What: Replaced the eager `make` reallocation in `PendingEventQueue.compactIfNeeded` with in-place `copy` slice shifting, only reallocating when the buffer is severely bloated.
🎯 Why: To reduce GC pressure and allocation overhead on the hot stream queue path.
📊 Impact: pushPop benchmark throughput improved ~35% (175k ns -> 126k ns) and allocations dropped from 13 to 9 per run.
🔬 Measurement: Run `cd internal/core/stream && go test -bench=BenchmarkPendingEventQueue_pushPop -benchmem`

Co-authored-by: matdev83 <211248003+matdev83@users.noreply.github.com>
@google-labs-jules

Copy link
Copy Markdown
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@matdev83, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 16 minutes and 5 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 73997caf-f8cc-4d48-8b70-a96bce06936f

📥 Commits

Reviewing files that changed from the base of the PR and between 6b89437 and ded6f70.

📒 Files selected for processing (2)
  • internal/core/stream/eventqueue.go
  • internal/core/stream/eventqueue_internal_test.go
📝 Walkthrough

Walkthrough

PendingEventQueue.compactIfNeeded is updated to prefer copying live elements in-place to the front of the existing buffer, restricting reallocation to buffers where capacity exceeds 1024 and fewer than one quarter of slots are alive. The .jules/bolt.md file records the change with benchmark figures.

Changes

PendingEventQueue Compaction Optimization

Layer / File(s) Summary
compactIfNeeded: in-place slide default, shrink-only reallocation
internal/core/stream/eventqueue.go, .jules/bolt.md
Replaces the old reallocation condition (alive <= cap/2 && cap > 32) with a narrow condition (cap > 1024 && alive < cap/4), reallocating at alive*2 only in that case and using copy-based in-place sliding otherwise. Documents the new strategy and benchmark results in .jules/bolt.md.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~5 minutes

🚥 Pre-merge checks | ✅ 8
✅ Passed checks (8 passed)
Check name Status Explanation
Title check ✅ Passed The title directly describes the main technical change (reducing GC pressure in eventqueue) with an appropriate performance-focused prefix, matching the changeset's optimization objective.
Description check ✅ Passed The description provides comprehensive context about the change, explaining the problem, solution, and measured impact, all directly related to the changeset modifications.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
No Secrets ✅ Passed PR modifies only .jules/bolt.md (documentation) and internal/core/stream/eventqueue.go (performance optimization). Comprehensive scanning for credentials, API keys, tokens, private keys, passwo...
Context Propagation ✅ Passed The custom check for context propagation is not applicable. The changes modify only PendingEventQueue.compactIfNeeded, a private memory optimization method unrelated to context, cancellation, or...
No Accidental Public Api Break ✅ Passed No public API breaks detected. The PR only modifies compactIfNeeded (private method) in internal/core/stream/eventqueue.go. All exported methods (Len, Push, PopFront, NewPendingEventQueue) remain u...

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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 and usage tips.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/core/stream/eventqueue.go`:
- Around line 96-97: The copy and reslice operation in the eventqueue compaction
logic leaves old entries in the truncated portion of the backing array, which
prevents garbage collection of popped events. After the reslice statement `q.buf
= q.buf[:alive]`, explicitly zero out the tail of the buffer from index alive to
the original length to clear the old event references and allow them to be
garbage collected.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: dfadfb1b-77b6-447e-a979-8d5925cd98f4

📥 Commits

Reviewing files that changed from the base of the PR and between ce359a8 and 6b89437.

📒 Files selected for processing (2)
  • .jules/bolt.md
  • internal/core/stream/eventqueue.go
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: qa
🧰 Additional context used
📓 Path-based instructions (3)
internal/core/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

internal/core/**/*.go: Core packages must not import official provider SDKs
Core packages must not import concrete plugins
Return errors, do not panic in request paths
Keep core files small and cohesive
Do not mix frontend codec logic, routing policy, and backend invocation in one package
Prefer explicit construction and registration over DI containers, reflection, or global registries
No package-level mutable global state in core code
Capability mismatches must fail explicitly; never silently drop required semantics
Advanced request/response mutation belongs behind hook interfaces, not inside core business logic
Narrow interfaces, small files, simple control flow (keep the core boring)

Files:

  • internal/core/stream/eventqueue.go
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*.go: Use small interfaces defined where they are consumed
Every I/O boundary takes context.Context
Do not use Java-style interface prefixes; use idiomatic Go names such as Store, Router, Clock
Avoid any unless unavoidable at a protocol boundary
Wrap errors with %w and preserve classification metadata
Avoid circular imports by design
Prefer the standard library unless a dependency clearly reduces complexity
Use small interfaces defined where they are consumed
Slices in JSON and returned values should use explicit empty initialization (s := []T{} or make) to prevent null in JSON
Establish explicit ownership for goroutines, channels, buffers, and cancellation
Do not use Go's native plugin package in v1
Add package docs where the boundary is non-obvious
Line length ~120+ characters; break at semantic boundaries. Single long lines preferred for embedded JSON/SSE to preserve stream integrity

For server, CLI, worker, or network code, check that context.Context is propagated correctly, cancellation is respected, and new goroutines cannot leak indefinitely

Files:

  • internal/core/stream/eventqueue.go

⚙️ CodeRabbit configuration file

**/*.go: Review as production Go code. Prioritize correctness, race conditions, goroutine leaks, context cancellation, timeout handling, error wrapping, nil-pointer risks, resource cleanup, defer placement, API compatibility, interface design, dependency boundaries, and testability. Avoid generic style comments when gofmt/golangci-lint already covers the issue.

Files:

  • internal/core/stream/eventqueue.go
internal/**

⚙️ CodeRabbit configuration file

internal/**: Focus on package boundaries, hidden coupling, unexported API design, concurrency safety, deterministic behavior, and whether logic belongs in this internal package.

Files:

  • internal/core/stream/eventqueue.go
🪛 markdownlint-cli2 (0.22.1)
.jules/bolt.md

[warning] 1-1: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 1-1: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)

🔇 Additional comments (1)
.jules/bolt.md (1)

1-3: LGTM!

Comment thread internal/core/stream/eventqueue.go
@matdev83 matdev83 merged commit f9e245a into main Jun 22, 2026
2 checks passed
@matdev83 matdev83 deleted the bolt-eventqueue-optimization-8043453630250216761 branch June 22, 2026 09:49
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