-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
perf(es/plugin): Use shared tokio runtime to avoid creation overhead #11267
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Fixes #10926 Previously, each plugin invocation created a new tokio runtime when no existing runtime was available, causing severe performance degradation (~6x slower). This was particularly problematic for builds with multiple plugins and files. This change introduces a shared `Lazy<Runtime>` that is initialized once and reused across all plugin calls, eliminating the expensive overhead of: - Thread pool initialization - I/O driver setup - Timer infrastructure creation The shared runtime is only used when: - The `plugin` feature is enabled - The `manual-tokio-runtime` feature is NOT enabled - No existing tokio runtime context is available 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
🦋 Changeset detectedLatest commit: 81557a6 The changes in this PR will be included in the next version bump. Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Claude finished @kdy1's task —— View job PR Review Complete ✅This is a well-implemented performance optimization that addresses a significant regression. Here's my detailed review: Todo List:
🟢 Strengths1. Excellent Performance Design
2. Proper Feature Gating
3. Code Quality
🟡 Areas for Improvement1. Error Handling Enhancement // Current (line 34-36):
tokio::runtime::Runtime::new()
.expect("Failed to create shared tokio runtime for plugin execution")
// Consider:
tokio::runtime::Builder::new_multi_thread()
.worker_threads(2) // or configurable
.thread_name("swc-plugin-worker")
.enable_all()
.build()
.expect("Failed to create shared tokio runtime for plugin execution")The current approach uses default settings, but explicit configuration would be more predictable and allow for optimization. 2. Missing Documentation
3. Potential Resource Consideration 🟢 Security AssessmentNo security concerns identified:
🟡 Test Coverage GapsMissing test scenarios:
Suggested tests: #[cfg(all(test, feature = "plugin", not(feature = "manual-tokio-runtime")))]
mod tests {
use super::*;
#[test]
fn test_shared_runtime_initialization() {
// Verify runtime is created and reused
}
#[test]
fn test_fallback_to_existing_runtime() {
// Test behavior when Handle::try_current() succeeds
}
}🟢 Performance AnalysisExcellent approach:
The implementation should deliver the claimed 6x performance improvement for multi-plugin builds. 🔧 Minor Suggestions
✅ Overall AssessmentThis is a high-quality performance fix that:
Recommendation: Approve with minor documentation improvements The code is ready to merge as-is, but would benefit from the suggested documentation and test additions in follow-up work. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR addresses a significant performance regression introduced in v1.4.6 by implementing a shared tokio runtime for plugin execution. Instead of creating a new runtime for each plugin call (which involves expensive thread pool and I/O driver initialization), the code now uses a lazily-initialized static runtime that is reused across all plugin transformations, reducing overhead by approximately 6x.
Key Changes:
- Added
SHARED_RUNTIMEstatic usingLazy<tokio::runtime::Runtime>for reuse across plugin calls - Modified
RustPlugins::apply()to use the shared runtime instead of creating new instances - Applied conditional compilation to only use this optimization when the
pluginfeature is enabled andmanual-tokio-runtimeis not
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| /// call. | ||
| #[cfg(all(feature = "plugin", not(feature = "manual-tokio-runtime")))] | ||
| static SHARED_RUNTIME: Lazy<tokio::runtime::Runtime> = Lazy::new(|| { | ||
| tokio::runtime::Runtime::new() |
Copilot
AI
Nov 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The Runtime::new() constructor creates a multi-threaded runtime by default when the "rt-multi-thread" feature is enabled. However, for clarity and explicitness, consider using Runtime::new() with explicit builder configuration. For example:
tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.expect("Failed to create shared tokio runtime for plugin execution")This makes it explicit that a multi-threaded runtime is being created and ensures the I/O and time drivers are enabled, which aligns with the documented performance improvements in the PR description.
| tokio::runtime::Runtime::new() | |
| tokio::runtime::Builder::new_multi_thread() | |
| .enable_all() | |
| .build() |
Binary Sizes
Commit: ee5cc74 |
CodSpeed Performance ReportMerging #11267 will not alter performanceComparing Summary
|
**Description:** #11267 introduced this mistake. - `SHARED_RUNTIME.block_on(fut)` is enabled with`#[cfg(feature = "plugin")]` - `SHARED_RUNTIME` is enabled with `#[cfg(all(feature = "plugin", not(feature = "manual-tokio-runtime")))]` - If both features are enabled, the compiler goes failed. The problem is that cfg! doesn't remove the code actually. `#[cfg]` is needed here
Summary
Lazy<Runtime>to avoid creating a new tokio runtime for each plugin callBackground
Starting in v1.4.6, the plugin system experienced severe performance degradation due to creating a fresh
tokio::runtime::Runtimefor every plugin transformation when no existing runtime was available. This involved expensive initialization of:For builds with multiple plugins and many files, this overhead compounded exponentially.
Changes
SHARED_RUNTIME: Lazy<tokio::runtime::Runtime>that initializes once and is reused across all plugin callsRustPlugins::apply()to use the shared runtime instead of creating a new onepluginfeature is enabled andmanual-tokio-runtimeis NOT enabledtokio::runtime::Handle::try_current()Performance Impact
This change eliminates the 6x performance regression introduced in v1.4.6:
Test Plan
cargo check -p swc --features pluginmanual-tokio-runtimefeature🤖 Generated with Claude Code