From 814ac9a75d343435ac7c8c2ff6dad8ab89eb8a4c Mon Sep 17 00:00:00 2001 From: David Sherret Date: Wed, 29 May 2024 14:59:35 -0400 Subject: [PATCH] perf: avoid building module graph if dynamic specifier already in graph (#24035) --- cli/module_loader.rs | 32 +++++++++++++++++-- .../dynamic_already_prepared/__test__.jsonc | 8 +++++ .../run/dynamic_already_prepared/dynamic.ts | 1 + .../run/dynamic_already_prepared/dynamic2.ts | 1 + .../run/dynamic_already_prepared/dynamic3.ts | 1 + .../run/dynamic_already_prepared/main.out | 1 + .../run/dynamic_already_prepared/main.ts | 2 ++ 7 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 tests/specs/run/dynamic_already_prepared/__test__.jsonc create mode 100644 tests/specs/run/dynamic_already_prepared/dynamic.ts create mode 100644 tests/specs/run/dynamic_already_prepared/dynamic2.ts create mode 100644 tests/specs/run/dynamic_already_prepared/dynamic3.ts create mode 100644 tests/specs/run/dynamic_already_prepared/main.out create mode 100644 tests/specs/run/dynamic_already_prepared/main.ts diff --git a/cli/module_loader.rs b/cli/module_loader.rs index 91227802ac..e5f45ea3c3 100644 --- a/cli/module_loader.rs +++ b/cli/module_loader.rs @@ -171,7 +171,7 @@ impl ModuleLoadPreparer { ) .await?; - self.module_graph_builder.graph_roots_valid(graph, roots)?; + self.graph_roots_valid(graph, roots)?; // write the lockfile if there is one if let Some(lockfile) = &self.lockfile { @@ -205,6 +205,14 @@ impl ModuleLoadPreparer { Ok(()) } + + pub fn graph_roots_valid( + &self, + graph: &ModuleGraph, + roots: &[ModuleSpecifier], + ) -> Result<(), AnyError> { + self.module_graph_builder.graph_roots_valid(graph, roots) + } } struct SharedCliModuleLoaderState { @@ -806,8 +814,26 @@ impl ModuleLoader let inner = self.0.clone(); async move { - let graph_container = inner.graph_container.clone(); - let module_load_preparer = inner.shared.module_load_preparer.clone(); + let graph_container = &inner.graph_container; + let module_load_preparer = &inner.shared.module_load_preparer; + + if is_dynamic { + // When the specifier is already in the graph then it means it + // was previously loaded, so we can skip that and only check if + // this part of the graph is valid. + // + // This doesn't acquire a graph update permit because that will + // clone the graph which is a bit slow. + let graph = graph_container.graph(); + if !graph.roots.is_empty() && graph.get(&specifier).is_some() { + log::debug!("Skipping prepare module load."); + // roots are already validated so we can skip those + if !graph.roots.contains(&specifier) { + module_load_preparer.graph_roots_valid(&graph, &[specifier])?; + } + return Ok(()); + } + } let root_permissions = if is_dynamic { inner.dynamic_permissions.clone() diff --git a/tests/specs/run/dynamic_already_prepared/__test__.jsonc b/tests/specs/run/dynamic_already_prepared/__test__.jsonc new file mode 100644 index 0000000000..1a68b88c11 --- /dev/null +++ b/tests/specs/run/dynamic_already_prepared/__test__.jsonc @@ -0,0 +1,8 @@ +{ + "tests": { + "skips_prepare_module_load": { + "args": "run -A --log-level=debug main.ts", + "output": "main.out" + } + } +} diff --git a/tests/specs/run/dynamic_already_prepared/dynamic.ts b/tests/specs/run/dynamic_already_prepared/dynamic.ts new file mode 100644 index 0000000000..296d5492b0 --- /dev/null +++ b/tests/specs/run/dynamic_already_prepared/dynamic.ts @@ -0,0 +1 @@ +console.log(1); diff --git a/tests/specs/run/dynamic_already_prepared/dynamic2.ts b/tests/specs/run/dynamic_already_prepared/dynamic2.ts new file mode 100644 index 0000000000..00c424d740 --- /dev/null +++ b/tests/specs/run/dynamic_already_prepared/dynamic2.ts @@ -0,0 +1 @@ +await import("./dynamic3.ts"); diff --git a/tests/specs/run/dynamic_already_prepared/dynamic3.ts b/tests/specs/run/dynamic_already_prepared/dynamic3.ts new file mode 100644 index 0000000000..ae6da29f8f --- /dev/null +++ b/tests/specs/run/dynamic_already_prepared/dynamic3.ts @@ -0,0 +1 @@ +await import("./dynamic.ts"); diff --git a/tests/specs/run/dynamic_already_prepared/main.out b/tests/specs/run/dynamic_already_prepared/main.out new file mode 100644 index 0000000000..f1f5b25951 --- /dev/null +++ b/tests/specs/run/dynamic_already_prepared/main.out @@ -0,0 +1 @@ +[WILDCARD]Prepared module load.[WILDCARD]Skipping prepare module load.[WILDCARD]Skipping prepare module load.[WILDCARD]Skipping prepare module load.[WILDCARD] diff --git a/tests/specs/run/dynamic_already_prepared/main.ts b/tests/specs/run/dynamic_already_prepared/main.ts new file mode 100644 index 0000000000..c7f3948eb7 --- /dev/null +++ b/tests/specs/run/dynamic_already_prepared/main.ts @@ -0,0 +1,2 @@ +await import("./dynamic.ts"); +await import("./dynamic2.ts");