Skip to content

perf(api): box the cold entry-point futures so consumers stop re-codegening the graphs - #843

Merged
jlucaso1 merged 1 commit into
mainfrom
perf/boxed-cold-entry-points
Jun 11, 2026
Merged

perf(api): box the cold entry-point futures so consumers stop re-codegening the graphs#843
jlucaso1 merged 1 commit into
mainfrom
perf/boxed-cold-entry-points

Conversation

@jlucaso1

@jlucaso1 jlucaso1 commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

Problem

Coroutines (async fn state machines) are LocalCopy items across crates: any consumer crate that awaits a lib future codegens the entire state machine graph behind it into its own binary, with per-crate symbols that fat LTO cannot merge. Measured on the demo bin, the consumer crate re-instantiated ~1.8 MiB of the lib this way. Inline attributes do not change coroutine instantiation mode; I measured a #[inline(never)] sweep at exactly zero effect before landing on this design.

Change

Bot::build, Bot::run and Client::connect keep their public async fn signatures but now delegate through a #[inline(never)] plain function that returns the real graph as Pin<Box<dyn Future>>. The consumer's copy of the entry point shrinks to a tiny shim coroutine that polls through a vtable, so the construction, run-loop and connect graphs are compiled exactly once, in the lib. Cost: one heap allocation per process for each entry point (they are all once-per-session).

Measured

On top of #842: .text 11.85 MiB -> 11.74 MiB (-113 KiB); consumer-crate reinstantiation 1815 KiB -> 1484 KiB.

What deliberately stays

The remaining consumer-side duplication is the send graph reached from user handler closures (send_message_impl and the cache coroutines it awaits). Erasing that would cost a Box::pin per outgoing message, the same per-message boxing #673 removed for allocation churn, so it stays static. The only stable-Rust alternative is -Zshare-generics, which is nightly.

Tests

No signature or behavior changes; full wacore + lib suites pass (1838 tests).

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown

Warning

Review limit reached

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

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

Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab.

⌛ 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.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ca0fd3f7-d259-4b27-9823-8ab08aa7d3c3

📥 Commits

Reviewing files that changed from the base of the PR and between 5d40649 and bb8ac4e.

📒 Files selected for processing (3)
  • src/bot.rs
  • src/client/lifecycle.rs
  • wacore/src/runtime.rs
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: boxing cold entry-point futures to prevent consumer crates from re-codegenerating the state machine graphs.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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 The pull request description clearly articulates the problem being solved, the specific changes made, measured performance improvements, and deliberate exclusions.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch perf/boxed-cold-entry-points

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.

Base automatically changed from perf/proto-codec-pinning to main June 11, 2026 07:05

@cubic-dev-ai cubic-dev-ai 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.

No issues found across 2 files

Re-trigger cubic

@jlucaso1
jlucaso1 force-pushed the perf/boxed-cold-entry-points branch from 5d40649 to 2705ebe Compare June 11, 2026 07:07
@codspeed-hq

codspeed-hq Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 141 untouched benchmarks


Comparing perf/boxed-cold-entry-points (bb8ac4e) with main (d472d04)

Open in CodSpeed

…gening the graphs

Coroutines are LocalCopy across crates: any consumer crate that awaits a lib future codegens the whole state machine graph behind it into its own binary, and inline attributes cannot change that (measured: zero effect). The demo bin re-instantiated ~1.8 MiB of the lib this way.

Bot::build, Bot::run and Client::connect now delegate to a #[inline(never)] plain function that returns the graph as Pin<Box<dyn Future>>, so callers poll through a vtable and the construction/run/connect graphs are compiled once, in the lib. Public signatures are unchanged and the cost is one allocation per process for each entry point.

Measured on the release bin: .text 11.85 MiB to 11.74 MiB (-113 KiB on top of the codec pinning); consumer-crate reinstantiation 1815 KiB to 1484 KiB. The remainder is the send graph reached from user handler closures; erasing it would cost a Box::pin per outgoing message (the same per-message boxing #673 removed), so it stays.
@jlucaso1
jlucaso1 force-pushed the perf/boxed-cold-entry-points branch from 2705ebe to bb8ac4e Compare June 11, 2026 07:18
@jlucaso1
jlucaso1 merged commit 0aa6cb9 into main Jun 11, 2026
11 checks passed
@jlucaso1
jlucaso1 deleted the perf/boxed-cold-entry-points branch June 11, 2026 07:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant