Skip to content

perf: reduce PathBuf allocations in resolution pipeline#1027

Closed
Brooooooklyn wants to merge 1 commit intomainfrom
perf/reduce-path-allocations
Closed

perf: reduce PathBuf allocations in resolution pipeline#1027
Brooooooklyn wants to merge 1 commit intomainfrom
perf/reduce-path-allocations

Conversation

@Brooooooklyn
Copy link
Copy Markdown
Member

@Brooooooklyn Brooooooklyn commented Feb 24, 2026

  • Use Box::from(path) instead of path.to_path_buf().into_boxed_path()
    in Cache::value() to avoid intermediate PathBuf allocation
  • Change Resolution to store CachedPath instead of PathBuf, deferring
    the PathBuf allocation to callers who actually need owned paths
  • Change canonicalize() and load_realpath() to return CachedPath
    instead of PathBuf, avoiding unnecessary cloning
  • Store Box<Path> instead of PathBuf in canonicalized cache fallback

In a 10K module rolldown benchmark, this eliminates ~87K to_path_buf
allocations (10.7 MB) from the resolution pipeline, reducing them to
effectively zero.

Co-Authored-By: Claude Opus 4.6 [email protected]


Note

Medium Risk
Mostly a perf-driven type/ownership refactor across the resolver’s core path plumbing; low behavioral intent but subtle changes around canonicalization and path equality/formatting could surface platform-specific regressions (notably Windows/symlinks).

Overview
Reduces allocation churn in the resolution pipeline by switching from owned PathBuf returns to cached CachedPath values, including updating Resolution to store a CachedPath and only materializing a PathBuf on demand.

Updates cache internals to avoid intermediate PathBuf creation (Box::from(path) in Cache::value) and to store canonicalization fallbacks as Box<Path>; adjusts Windows canonicalization prefix-stripping to re-enter the cache. Tests and tracing were updated to use the new Resolution/realpath APIs.

Written by Cursor Bugbot for commit 924d4d7. This will update automatically on new commits. Configure here.

Copy link
Copy Markdown
Member Author

Brooooooklyn commented Feb 24, 2026


How to use the Graphite Merge Queue

Add the label merge to this PR to add it to the merge queue.

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

- Use `Box::from(path)` instead of `path.to_path_buf().into_boxed_path()`
  in `Cache::value()` to avoid intermediate PathBuf allocation
- Change `Resolution` to store `CachedPath` instead of `PathBuf`, deferring
  the PathBuf allocation to callers who actually need owned paths
- Change `canonicalize()` and `load_realpath()` to return `CachedPath`
  instead of `PathBuf`, avoiding unnecessary cloning
- Store `Box<Path>` instead of `PathBuf` in canonicalized cache fallback

In a 10K module rolldown benchmark, this eliminates ~87K `to_path_buf`
allocations (10.7 MB) from the resolution pipeline, reducing them to
effectively zero.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@Brooooooklyn Brooooooklyn force-pushed the perf/reduce-path-allocations branch from c9e8136 to 924d4d7 Compare February 24, 2026 02:06
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq bot commented Feb 24, 2026

Merging this PR will degrade performance by 8.49%

⚡ 1 improved benchmark
❌ 3 regressed benchmarks
✅ 9 untouched benchmarks
⏩ 5 skipped benchmarks1

⚠️ Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Benchmark BASE HEAD Efficiency
complex_real 21.4 µs 23.4 µs -8.49%
resolver_memory[multi-thread] 447 µs 424.8 µs +5.23%
large 26 µs 26.9 µs -3.34%
small 11.3 µs 11.7 µs -3.26%

Comparing perf/reduce-path-allocations (924d4d7) with main (d0b7b7a)

Open in CodSpeed

Footnotes

  1. 5 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@Brooooooklyn
Copy link
Copy Markdown
Member Author

The CodSpeed regression appears to be noise

@codecov
Copy link
Copy Markdown

codecov bot commented Feb 24, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.14%. Comparing base (1dd6e37) to head (924d4d7).
⚠️ Report is 3 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1027      +/-   ##
==========================================
+ Coverage   94.09%   94.14%   +0.05%     
==========================================
  Files          19       19              
  Lines        3436     3433       -3     
==========================================
- Hits         3233     3232       -1     
+ Misses        203      201       -2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@Boshen
Copy link
Copy Markdown
Member

Boshen commented Feb 24, 2026

Code was working as intended.

@Boshen Boshen closed this Feb 24, 2026
@Boshen Boshen deleted the perf/reduce-path-allocations branch February 24, 2026 04:15
graphite-app bot pushed a commit to rolldown/rolldown that referenced this pull request Feb 24, 2026
- Skip `cwd.join(importer)` when importer is already an absolute path,
  passing `&Path` directly to `resolve_file()` instead of allocating a
  new PathBuf (~50K avoided allocations per 10K module build)
- Apply the same optimization in rolldown_plugin_vite_resolve (2 sites)
- Point oxc_resolver to local path for coordinated optimization

Combined with the oxc-resolver changes oxc-project/oxc-resolver#1027, this eliminates ~174K
`to_path_buf` allocations (21.3 MB) down to effectively zero,
yielding ~9% faster JS API median on a 10K module benchmark.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Small, localized change to how importer paths are passed into the resolver; primary risk is subtle behavior differences if callers pass unusual absolute/relative importer strings.
>
> **Overview**
> Reduces resolve-time allocations by detecting when an `importer` is already an absolute path and calling `resolve_file(importer, ...)` directly instead of `cwd.join(importer)`/`root.join(importer)`.
>
> Applies this optimization in `rolldown_resolver::Resolver::resolve` and in two resolution paths in `rolldown_plugin_vite_resolve::Resolver::resolve_raw` (including the `try_prefix` fallback).
>
> <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 51016de. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
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