From 50d54e1f46dbfe69219458021187d1a40e87c974 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Wed, 3 Sep 2025 15:47:06 +0200 Subject: [PATCH 1/3] perf: parallelize remappings provider --- Cargo.lock | 1 + Cargo.toml | 2 + crates/config/Cargo.toml | 1 + crates/config/src/providers/remappings.rs | 109 ++++++++++++---------- 4 files changed, 66 insertions(+), 47 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1718eb345b535..b4eab3abc22b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4609,6 +4609,7 @@ dependencies = [ "mesc", "number_prefix", "path-slash", + "rayon", "regex", "reqwest", "revm", diff --git a/Cargo.toml b/Cargo.toml index 90285042d8f0e..fe933f5f0dbb8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -153,9 +153,11 @@ scrypt.opt-level = 3 # Misc. rayon.opt-level = 3 +rayon-core.opt-level = 3 regex.opt-level = 3 regex-syntax.opt-level = 3 regex-automata.opt-level = 3 +walkdir.opt-level = 3 # Override packages which aren't perf-sensitive for faster compilation speed and smaller binary size. [profile.release.package] diff --git a/crates/config/Cargo.toml b/crates/config/Cargo.toml index 14501769887c0..38d2e5ea4a410 100644 --- a/crates/config/Cargo.toml +++ b/crates/config/Cargo.toml @@ -34,6 +34,7 @@ heck.workspace = true itertools.workspace = true mesc.workspace = true number_prefix = "0.4" +rayon.workspace = true regex.workspace = true reqwest.workspace = true semver = { workspace = true, features = ["serde"] } diff --git a/crates/config/src/providers/remappings.rs b/crates/config/src/providers/remappings.rs index 8bd2d5cacb2a3..8890de642487c 100644 --- a/crates/config/src/providers/remappings.rs +++ b/crates/config/src/providers/remappings.rs @@ -4,6 +4,7 @@ use figment::{ value::{Dict, Map}, }; use foundry_compilers::artifacts::remappings::{RelativeRemapping, Remapping}; +use rayon::prelude::*; use std::{ borrow::Cow, collections::{BTreeMap, HashSet, btree_map::Entry}, @@ -207,19 +208,16 @@ impl RemappingsProvider<'_> { // TODO: if a lib specifies contexts for remappings manually, we need to figure out how to // resolve that if self.auto_detect_remappings { + let (nested_foundry_remappings, auto_detected_remappings) = rayon::join( + || self.find_nested_foundry_remappings(), + || self.auto_detect_remappings(), + ); + let mut lib_remappings = BTreeMap::new(); - // find all remappings of from libs that use a foundry.toml - for r in self.lib_foundry_toml_remappings() { + for r in nested_foundry_remappings { insert_closest(&mut lib_remappings, r.context, r.name, r.path.into()); } - // use auto detection for all libs - for r in self - .lib_paths - .iter() - .map(|lib| self.root.join(lib)) - .inspect(|lib| trace!(?lib, "find all remappings")) - .flat_map(|lib| Remapping::find_many(&lib)) - { + for r in auto_detected_remappings { // this is an additional safety check for weird auto-detected remappings if ["lib/", "src/", "contracts/"].contains(&r.name.as_str()) { trace!(target: "forge", "- skipping the remapping"); @@ -246,50 +244,67 @@ impl RemappingsProvider<'_> { } /// Returns all remappings declared in foundry.toml files of libraries - fn lib_foundry_toml_remappings(&self) -> impl Iterator + '_ { + fn find_nested_foundry_remappings(&self) -> impl Iterator + '_ { self.lib_paths - .iter() + .par_iter() .map(|p| if p.is_absolute() { self.root.join("lib") } else { self.root.join(p) }) .flat_map(foundry_toml_dirs) - .inspect(|lib| { - trace!("find all remappings of nested foundry.toml lib: {:?}", lib); + .flat_map_iter(|lib| { + trace!(?lib, "find all remappings of nested foundry.toml"); + self.nested_foundry_remappings(&lib) }) - .flat_map(|lib: PathBuf| { - // load config, of the nested lib if it exists - let Ok(config) = Config::load_with_root(&lib) else { return vec![] }; - let config = config.sanitized(); - - // if the configured _src_ directory is set to something that - // [Remapping::find_many()] doesn't classify as a src directory (src, contracts, - // lib), then we need to manually add a remapping here - let mut src_remapping = None; - if ![Path::new("src"), Path::new("contracts"), Path::new("lib")] - .contains(&config.src.as_path()) - && let Some(name) = lib.file_name().and_then(|s| s.to_str()) - { - let mut r = Remapping { - context: None, - name: format!("{name}/"), - path: format!("{}", lib.join(&config.src).display()), - }; - if !r.path.ends_with('/') { - r.path.push('/') - } - src_remapping = Some(r); - } + .collect::>() + .into_iter() + } - // Eventually, we could set context for remappings at this location, - // taking into account the OS platform. We'll need to be able to handle nested - // contexts depending on dependencies for this to work. - // For now, we just leave the default context (none). - let mut remappings = - config.remappings.into_iter().map(Remapping::from).collect::>(); + fn nested_foundry_remappings(&self, lib: &Path) -> Vec { + // load config, of the nested lib if it exists + let Ok(config) = Config::load_with_root(lib) else { return vec![] }; + let config = config.sanitized(); + + // if the configured _src_ directory is set to something that + // `Remapping::find_many` doesn't classify as a src directory (src, contracts, + // lib), then we need to manually add a remapping here + let mut src_remapping = None; + if ![Path::new("src"), Path::new("contracts"), Path::new("lib")] + .contains(&config.src.as_path()) + && let Some(name) = lib.file_name().and_then(|s| s.to_str()) + { + let mut r = Remapping { + context: None, + name: format!("{name}/"), + path: format!("{}", lib.join(&config.src).display()), + }; + if !r.path.ends_with('/') { + r.path.push('/') + } + src_remapping = Some(r); + } - if let Some(r) = src_remapping { - remappings.push(r); - } - remappings + // Eventually, we could set context for remappings at this location, + // taking into account the OS platform. We'll need to be able to handle nested + // contexts depending on dependencies for this to work. + // For now, we just leave the default context (none). + let mut remappings = + config.remappings.into_iter().map(Remapping::from).collect::>(); + + if let Some(r) = src_remapping { + remappings.push(r); + } + remappings + } + + /// Auto detect remappings from the lib paths + fn auto_detect_remappings(&self) -> impl Iterator + '_ { + self.lib_paths + .par_iter() + .flat_map_iter(|lib| { + let lib = self.root.join(lib); + trace!(?lib, "find all remappings"); + Remapping::find_many(&lib) }) + .collect::>() + .into_iter() } } From a3521ec7c805a1e53e0fa4380e79fdfd645ec5c6 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Wed, 3 Sep 2025 16:56:07 +0200 Subject: [PATCH 2/3] patch --- Cargo.lock | 16 +++++----------- Cargo.toml | 2 +- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b4eab3abc22b3..d14b34fd02ba8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4487,8 +4487,7 @@ dependencies = [ [[package]] name = "foundry-compilers" version = "0.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bb5aabd4c628c89db350909672e723834009cf5ed3af5bffd50504f311e408" +source = "git+https://github.com/foundry-rs/compilers.git?branch=dani%2Fpar-remapping-find_many#3a184b25bdc4d085931e99518717d03374879fa1" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -4521,8 +4520,7 @@ dependencies = [ [[package]] name = "foundry-compilers-artifacts" version = "0.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e87be595faa8f44496f970d45bb7b6676a85002d6c955e9b6e06495002408168" +source = "git+https://github.com/foundry-rs/compilers.git?branch=dani%2Fpar-remapping-find_many#3a184b25bdc4d085931e99518717d03374879fa1" dependencies = [ "foundry-compilers-artifacts-solc", "foundry-compilers-artifacts-vyper", @@ -4531,8 +4529,7 @@ dependencies = [ [[package]] name = "foundry-compilers-artifacts-solc" version = "0.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41e854b93aa40d9144e604a3abc86ce084f3185d07d4f1c5b323036ffcf58f04" +source = "git+https://github.com/foundry-rs/compilers.git?branch=dani%2Fpar-remapping-find_many#3a184b25bdc4d085931e99518717d03374879fa1" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -4547,15 +4544,13 @@ dependencies = [ "thiserror 2.0.16", "tokio", "tracing", - "walkdir", "yansi", ] [[package]] name = "foundry-compilers-artifacts-vyper" version = "0.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe557fdf36c54f2e612043524277d0597623a6a3153c8b33aa19a6596ab06158" +source = "git+https://github.com/foundry-rs/compilers.git?branch=dani%2Fpar-remapping-find_many#3a184b25bdc4d085931e99518717d03374879fa1" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -4569,8 +4564,7 @@ dependencies = [ [[package]] name = "foundry-compilers-core" version = "0.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "972f228152765e199041a7c8fecc217b5ab4aade8e6bdd5ef62caa781a3cf239" +source = "git+https://github.com/foundry-rs/compilers.git?branch=dani%2Fpar-remapping-find_many#3a184b25bdc4d085931e99518717d03374879fa1" dependencies = [ "alloy-primitives", "cfg-if", diff --git a/Cargo.toml b/Cargo.toml index fe933f5f0dbb8..4d3217f8d9e4a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -415,7 +415,7 @@ rexpect = { git = "https://github.com/rust-cli/rexpect", rev = "2ed0b1898d7edaf6 ## foundry # foundry-block-explorers = { git = "https://github.com/foundry-rs/block-explorers.git", rev = "f5b46b2" } -# foundry-compilers = { git = "https://github.com/foundry-rs/compilers.git", rev = "e4a9b04" } +foundry-compilers = { git = "https://github.com/foundry-rs/compilers.git", branch = "dani/par-remapping-find_many" } # foundry-fork-db = { git = "https://github.com/foundry-rs/foundry-fork-db", rev = "eee6563" } ## solar From 973294cf484d88b36d857a6a5604f555f8632cac Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Wed, 3 Sep 2025 17:12:36 +0200 Subject: [PATCH 3/3] Revert "patch" This reverts commit a3521ec7c805a1e53e0fa4380e79fdfd645ec5c6. --- Cargo.lock | 16 +++++++++++----- Cargo.toml | 2 +- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d14b34fd02ba8..b4eab3abc22b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4487,7 +4487,8 @@ dependencies = [ [[package]] name = "foundry-compilers" version = "0.19.1" -source = "git+https://github.com/foundry-rs/compilers.git?branch=dani%2Fpar-remapping-find_many#3a184b25bdc4d085931e99518717d03374879fa1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bb5aabd4c628c89db350909672e723834009cf5ed3af5bffd50504f311e408" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -4520,7 +4521,8 @@ dependencies = [ [[package]] name = "foundry-compilers-artifacts" version = "0.19.1" -source = "git+https://github.com/foundry-rs/compilers.git?branch=dani%2Fpar-remapping-find_many#3a184b25bdc4d085931e99518717d03374879fa1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e87be595faa8f44496f970d45bb7b6676a85002d6c955e9b6e06495002408168" dependencies = [ "foundry-compilers-artifacts-solc", "foundry-compilers-artifacts-vyper", @@ -4529,7 +4531,8 @@ dependencies = [ [[package]] name = "foundry-compilers-artifacts-solc" version = "0.19.1" -source = "git+https://github.com/foundry-rs/compilers.git?branch=dani%2Fpar-remapping-find_many#3a184b25bdc4d085931e99518717d03374879fa1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41e854b93aa40d9144e604a3abc86ce084f3185d07d4f1c5b323036ffcf58f04" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -4544,13 +4547,15 @@ dependencies = [ "thiserror 2.0.16", "tokio", "tracing", + "walkdir", "yansi", ] [[package]] name = "foundry-compilers-artifacts-vyper" version = "0.19.1" -source = "git+https://github.com/foundry-rs/compilers.git?branch=dani%2Fpar-remapping-find_many#3a184b25bdc4d085931e99518717d03374879fa1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe557fdf36c54f2e612043524277d0597623a6a3153c8b33aa19a6596ab06158" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -4564,7 +4569,8 @@ dependencies = [ [[package]] name = "foundry-compilers-core" version = "0.19.1" -source = "git+https://github.com/foundry-rs/compilers.git?branch=dani%2Fpar-remapping-find_many#3a184b25bdc4d085931e99518717d03374879fa1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "972f228152765e199041a7c8fecc217b5ab4aade8e6bdd5ef62caa781a3cf239" dependencies = [ "alloy-primitives", "cfg-if", diff --git a/Cargo.toml b/Cargo.toml index 4d3217f8d9e4a..fe933f5f0dbb8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -415,7 +415,7 @@ rexpect = { git = "https://github.com/rust-cli/rexpect", rev = "2ed0b1898d7edaf6 ## foundry # foundry-block-explorers = { git = "https://github.com/foundry-rs/block-explorers.git", rev = "f5b46b2" } -foundry-compilers = { git = "https://github.com/foundry-rs/compilers.git", branch = "dani/par-remapping-find_many" } +# foundry-compilers = { git = "https://github.com/foundry-rs/compilers.git", rev = "e4a9b04" } # foundry-fork-db = { git = "https://github.com/foundry-rs/foundry-fork-db", rev = "eee6563" } ## solar