Skip to content

Conversation

@elbywan
Copy link
Contributor

@elbywan elbywan commented Apr 30, 2025

Goal

In a nutshell: this PR aims to fix a huge memory consumption issue when using the pnp feature in a large codebase.

As of today the Plug'n'Play manifest is read/deserialized from the.pnp.cjs file into a struct which is then cached by the path of the file containing the import/require statement. Is seems inefficient since the path can change a lot for large codebases even though the manifest contents are ultimately the same.

This PR changes the code to use the path of the manifest itself as the key to avoid storing the same manifest multiple times.

Context

In my current company we are in the process of migrating from esbuild to rspack to build our frontend assets in a huge monorepo (>10 millions LOC). We are also experimenting with Module Federation.

Our rspack build pipeline works well except when enabling the Module Federation plugin, memory consumption goes through the roof quickly reaching 128+Gb on my machine.

I noticed that one of the main difference between these runs is that we are using our own custom resolver plugin based on enhanced-resolve whereas Module Federation heavily uses rspack-resolver like here.

In order to pinpoint the issue I used the instruments osx app to profile the build and monitor the allocations, and here are some results that prompted me to make these changes:


Screenshot 2025-04-30 at 14 32 43
Heavy memory consumption

Screenshot 2025-04-30 at 14 33 58
The load_pnp_manifest() method is called in a redundant way

Screenshot 2025-04-30 at 14 42 33
With this fix: no more memory leak

@CLAassistant
Copy link

CLAassistant commented Apr 30, 2025

CLA assistant check
All committers have signed the CLA.

src/lib.rs Outdated
Comment on lines 811 to 815
self.pnp_manifest_path_cache.entry(cached_path.to_path_buf()).or_insert_with(|| {
let manifest_path =
pnp::find_closest_pnp_manifest_path(cached_path.to_path_buf()).unwrap();
self.cache.value(&manifest_path)
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did you try caching by cached_path.to_path_bug().parent()? All files from a same folder should have the same PnP manifest path (and find_closest_pnp_manifest_path accepts folders).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll check this out 👍

Copy link
Contributor Author

@elbywan elbywan Apr 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like using the parent makes these tests fail for some reason: 😬

---- tests::pnp::pnp1 stdout ----
thread 'tests::pnp::pnp1' panicked at src/tests/pnp.rs:19:5:
assertion `left == right` failed
  left: Err(NotFound("is-even"))
 right: Ok("/Users/julien.elbaz/dev/experiments/rspack-resolver/fixtures/pnp/.yarn/cache/is-even-npm-1.0.0-9f726520dc-2728cc2f39.zip/node_modules/is-even/index.js")

---- tests::pnp::resolve_in_pnp_linked_folder stdout ----
thread 'tests::pnp::resolve_in_pnp_linked_folder' panicked at src/tests/pnp.rs:106:5:
assertion `left == right` failed
  left: Err(NotFound("lib/lib.js"))
 right: Ok("/Users/julien.elbaz/dev/experiments/rspack-resolver/fixtures/pnp/shared/lib.js")

I'll leave this optimization out for the moment.

@elbywan elbywan marked this pull request as draft April 30, 2025 13:12
@elbywan elbywan marked this pull request as ready for review April 30, 2025 13:51
@codspeed-hq
Copy link

codspeed-hq bot commented May 1, 2025

CodSpeed Performance Report

Merging #69 will improve performances by ×5.2

Comparing elbywan:fix-pnp-manifest-caching (75ba6fb) with main (5974ee3)

Summary

⚡ 1 improvements
✅ 2 untouched benchmarks

Benchmarks breakdown

Benchmark BASE HEAD Change
resolver[pnp resolve] 11.3 ms 2.2 ms ×5.2

@stormslowly
Copy link
Contributor

hi @elbywan thank you for your great work!
coudl you plz add codspeed benchmark to prevent the performance downgrading.

Later, will move the pnp functions to CachedPath for more consistent coding style.

@stormslowly
Copy link
Contributor

CodSpeed Performance Report

Merging #69 will improve performances by ×5.2

Comparing elbywan:fix-pnp-manifest-caching (75ba6fb) with main (5974ee3)

Summary

⚡ 1 improvements ✅ 2 untouched benchmarks

Benchmarks breakdown

Benchmark BASE HEAD Change
resolver[pnp resolve] 11.3 ms 2.2 ms ×5.2

nice job!

@stormslowly stormslowly merged commit 9be837a into web-infra-dev:main May 6, 2025
18 checks passed
@elbywan elbywan deleted the fix-pnp-manifest-caching branch May 7, 2025 07:27
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.

4 participants