From 9eb3651cb0513882c8b79a9b8e30c6e8a05bf4f1 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Wed, 20 Nov 2024 15:50:31 +0100 Subject: [PATCH 1/3] feat: add global -j, --threads --- Cargo.lock | 1 + crates/cast/bin/cmd/create2.rs | 25 +++++++++++------- crates/cast/tests/cli/main.rs | 5 ++++ crates/cli/Cargo.toml | 3 ++- crates/cli/src/opts/global.rs | 45 ++++++++++++++++++++++---------- crates/forge/bin/cmd/test/mod.rs | 18 +------------ crates/forge/tests/cli/cmd.rs | 5 ++++ crates/script/src/lib.rs | 2 +- 8 files changed, 61 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 189f2b222b52..b72136e3d6c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3681,6 +3681,7 @@ dependencies = [ "foundry-wallets", "futures", "indicatif", + "rayon", "regex", "serde", "serde_json", diff --git a/crates/cast/bin/cmd/create2.rs b/crates/cast/bin/cmd/create2.rs index 17523e094577..957a8f190a15 100644 --- a/crates/cast/bin/cmd/create2.rs +++ b/crates/cast/bin/cmd/create2.rs @@ -4,7 +4,6 @@ use eyre::{Result, WrapErr}; use rand::{rngs::StdRng, RngCore, SeedableRng}; use regex::RegexSetBuilder; use std::{ - num::NonZeroUsize, sync::{ atomic::{AtomicBool, Ordering}, Arc, @@ -73,9 +72,9 @@ pub struct Create2Args { #[arg(alias = "ch", long, value_name = "HASH", required_unless_present = "init_code")] init_code_hash: Option, - /// Number of threads to use. Defaults to and caps at the number of logical cores. - #[arg(short, long)] - jobs: Option, + /// Number of threads to use. Zero specifies the number of logical cores. + #[arg(global = true, long, short = 'j', visible_alias = "jobs")] + threads: Option, /// Address of the caller. Used for the first 20 bytes of the salt. #[arg(long, value_name = "ADDRESS")] @@ -107,7 +106,7 @@ impl Create2Args { salt, init_code, init_code_hash, - jobs, + threads, caller, seed, no_random, @@ -168,8 +167,8 @@ impl Create2Args { let regex = RegexSetBuilder::new(regexs).case_insensitive(!case_sensitive).build()?; let mut n_threads = std::thread::available_parallelism().map_or(1, |n| n.get()); - if let Some(jobs) = jobs { - n_threads = n_threads.min(jobs.get()); + if let Some(threads) = threads { + n_threads = n_threads.min(threads); } if cfg!(test) { n_threads = n_threads.min(2); @@ -433,8 +432,14 @@ mod tests { #[test] fn j0() { - let e = - Create2Args::try_parse_from(["foundry-cli", "--starts-with=00", "-j0"]).unwrap_err(); - let _ = e.print(); + let args = Create2Args::try_parse_from([ + "foundry-cli", + "--starts-with=00", + "--init-code-hash", + &B256::ZERO.to_string(), + "-j0", + ]) + .unwrap(); + assert_eq!(args.threads, Some(0)); } } diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index 2483fa479820..8e79b0e8de08 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -28,6 +28,11 @@ Options: -h, --help Print help (see a summary with '-h') + -j, --threads + Number of threads to use. Zero specifies the number of logical cores + + [aliases: jobs] + -V, --version Print version diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 9fa867db3c8f..8b741937d7c6 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -37,7 +37,9 @@ dotenvy = "0.15" eyre.workspace = true futures.workspace = true indicatif = "0.17" +rayon.workspace = true regex = { workspace = true, default-features = false } +serde_json.workspace = true serde.workspace = true strsim = "0.11" strum = { workspace = true, features = ["derive"] } @@ -45,7 +47,6 @@ tokio = { workspace = true, features = ["macros"] } tracing-subscriber = { workspace = true, features = ["registry", "env-filter"] } tracing.workspace = true yansi.workspace = true -serde_json.workspace = true tracing-tracy = { version = "0.11", optional = true } diff --git a/crates/cli/src/opts/global.rs b/crates/cli/src/opts/global.rs index 99690a530d3f..0fdf809f7e2e 100644 --- a/crates/cli/src/opts/global.rs +++ b/crates/cli/src/opts/global.rs @@ -3,7 +3,7 @@ use foundry_common::shell::{ColorChoice, OutputFormat, OutputMode, Shell, Verbos use serde::{Deserialize, Serialize}; /// Global options. -#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, Parser)] +#[derive(Clone, Debug, Default, Serialize, Deserialize, Parser)] pub struct GlobalOpts { /// Verbosity level of the log messages. /// @@ -16,39 +16,47 @@ pub struct GlobalOpts { /// - 3 (-vvv): Print execution traces for failing tests. /// - 4 (-vvvv): Print execution traces for all tests, and setup traces for failing tests. /// - 5 (-vvvvv): Print execution and setup traces for all tests. - #[clap(short, long, global = true, verbatim_doc_comment, conflicts_with = "quiet", action = ArgAction::Count, help_heading = "Display options")] - pub verbosity: Verbosity, + #[arg(help_heading = "Display options", global = true, short, long, verbatim_doc_comment, conflicts_with = "quiet", action = ArgAction::Count)] + verbosity: Verbosity, /// Do not print log messages. - #[clap(short, long, global = true, alias = "silent", help_heading = "Display options")] + #[arg(help_heading = "Display options", global = true, short, long, alias = "silent")] quiet: bool, /// Format log messages as JSON. - #[clap( - long, - global = true, - alias = "format-json", - conflicts_with_all = &["quiet", "color"], - help_heading = "Display options" - )] + #[arg(help_heading = "Display options", global = true, long, alias = "format-json", conflicts_with_all = &["quiet", "color"])] json: bool, /// The color of the log messages. - #[clap(long, global = true, value_enum, help_heading = "Display options")] + #[arg(help_heading = "Display options", global = true, long, value_enum)] color: Option, + + /// Number of threads to use. Zero specifies the number of logical cores. + #[arg(global = true, long, short = 'j', visible_alias = "jobs")] + threads: Option, } impl GlobalOpts { /// Initialize the global options. - pub fn init(self) -> eyre::Result<()> { + pub fn init(&self) -> eyre::Result<()> { // Set the global shell. self.shell().set(); + // Initialize the thread pool only if `threads` was requested to avoid unnecessary overhead. + if self.threads.is_some() { + self.force_init_thread_pool()?; + } + Ok(()) } + /// Initialize the global thread pool. + pub fn force_init_thread_pool(&self) -> eyre::Result<()> { + init_thread_pool(self.threads.unwrap_or(0)) + } + /// Create a new shell instance. - pub fn shell(self) -> Shell { + pub fn shell(&self) -> Shell { let mode = match self.quiet { true => OutputMode::Quiet, false => OutputMode::Normal, @@ -62,3 +70,12 @@ impl GlobalOpts { Shell::new_with(format, mode, color, self.verbosity) } } + +/// Initialize the global thread pool. +pub fn init_thread_pool(threads: usize) -> eyre::Result<()> { + rayon::ThreadPoolBuilder::new() + .thread_name(|i| format!("foundry-{i}")) + .num_threads(threads) + .build_global()?; + Ok(()) +} diff --git a/crates/forge/bin/cmd/test/mod.rs b/crates/forge/bin/cmd/test/mod.rs index 435c34275850..59434d5eb42b 100644 --- a/crates/forge/bin/cmd/test/mod.rs +++ b/crates/forge/bin/cmd/test/mod.rs @@ -65,7 +65,7 @@ foundry_config::merge_impl_figment_convert!(TestArgs, opts, evm_opts); #[derive(Clone, Debug, Parser)] #[command(next_help_heading = "Test options")] pub struct TestArgs { - /// Include the global options. + // Include global options for users of this struct. #[command(flatten)] pub global: GlobalOpts, @@ -149,11 +149,6 @@ pub struct TestArgs { #[arg(long)] pub fuzz_input_file: Option, - /// Max concurrent threads to use. - /// Default value is the number of available CPUs. - #[arg(long, short = 'j', visible_alias = "jobs")] - pub threads: Option, - /// Show test execution progress. #[arg(long)] pub show_progress: bool, @@ -276,13 +271,6 @@ impl TestArgs { // Merge all configs. let (mut config, mut evm_opts) = self.load_config_and_evm_opts_emit_warnings()?; - // Set number of max threads to execute tests. - // If not specified then the number of threads determined by rayon will be used. - if let Some(test_threads) = config.threads { - trace!(target: "forge::test", "execute tests with {} max threads", test_threads); - rayon::ThreadPoolBuilder::new().num_threads(test_threads).build_global()?; - } - // Explicitly enable isolation for gas reports for more correct gas accounting. if self.gas_report { evm_opts.isolate = true; @@ -898,10 +886,6 @@ impl Provider for TestArgs { dict.insert("show_progress".to_string(), true.into()); } - if let Some(threads) = self.threads { - dict.insert("threads".to_string(), threads.into()); - } - Ok(Map::from([(Config::selected_profile(), dict)])) } } diff --git a/crates/forge/tests/cli/cmd.rs b/crates/forge/tests/cli/cmd.rs index 3cd4ae5edb04..64843d25b570 100644 --- a/crates/forge/tests/cli/cmd.rs +++ b/crates/forge/tests/cli/cmd.rs @@ -33,6 +33,11 @@ Options: -h, --help Print help (see a summary with '-h') + -j, --threads + Number of threads to use. Zero specifies the number of logical cores + + [aliases: jobs] + -V, --version Print version diff --git a/crates/script/src/lib.rs b/crates/script/src/lib.rs index 0f0283b9f01a..aeea4940a0be 100644 --- a/crates/script/src/lib.rs +++ b/crates/script/src/lib.rs @@ -78,7 +78,7 @@ foundry_config::merge_impl_figment_convert!(ScriptArgs, opts, evm_opts); /// CLI arguments for `forge script`. #[derive(Clone, Debug, Default, Parser)] pub struct ScriptArgs { - /// Include the global options. + // Include global options for users of this struct. #[command(flatten)] pub global: GlobalOpts, From 46789dea5a241a40a3516e0529b7eb11cfb2f60b Mon Sep 17 00:00:00 2001 From: zerosnacks <95942363+zerosnacks@users.noreply.github.com> Date: Thu, 21 Nov 2024 09:19:46 +0100 Subject: [PATCH 2/3] Update crates/cli/src/opts/global.rs --- crates/cli/src/opts/global.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cli/src/opts/global.rs b/crates/cli/src/opts/global.rs index 0fdf809f7e2e..ad715f24180a 100644 --- a/crates/cli/src/opts/global.rs +++ b/crates/cli/src/opts/global.rs @@ -31,7 +31,7 @@ pub struct GlobalOpts { #[arg(help_heading = "Display options", global = true, long, value_enum)] color: Option, - /// Number of threads to use. Zero specifies the number of logical cores. + /// Number of threads to use. Specifying 0 defaults to the number of logical cores. #[arg(global = true, long, short = 'j', visible_alias = "jobs")] threads: Option, } From d72be2023f715a455b7947d16f61145af16a5f94 Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Thu, 21 Nov 2024 10:23:06 +0100 Subject: [PATCH 3/3] fix tests after comment update --- crates/cast/bin/cmd/create2.rs | 2 +- crates/cast/tests/cli/main.rs | 2 +- crates/config/README.md | 2 +- crates/forge/tests/cli/cmd.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/cast/bin/cmd/create2.rs b/crates/cast/bin/cmd/create2.rs index 957a8f190a15..f46066137dbb 100644 --- a/crates/cast/bin/cmd/create2.rs +++ b/crates/cast/bin/cmd/create2.rs @@ -72,7 +72,7 @@ pub struct Create2Args { #[arg(alias = "ch", long, value_name = "HASH", required_unless_present = "init_code")] init_code_hash: Option, - /// Number of threads to use. Zero specifies the number of logical cores. + /// Number of threads to use. Specifying 0 defaults to the number of logical cores. #[arg(global = true, long, short = 'j', visible_alias = "jobs")] threads: Option, diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index 8e79b0e8de08..bdc4a6044d0c 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -29,7 +29,7 @@ Options: Print help (see a summary with '-h') -j, --threads - Number of threads to use. Zero specifies the number of logical cores + Number of threads to use. Specifying 0 defaults to the number of logical cores [aliases: jobs] diff --git a/crates/config/README.md b/crates/config/README.md index 139c2a9f5601..9fcd30ac99dc 100644 --- a/crates/config/README.md +++ b/crates/config/README.md @@ -115,7 +115,7 @@ no_match_contract = "Bar" match_path = "*/Foo*" no_match_path = "*/Bar*" no_match_coverage = "Baz" -# Number of threads to use. Not set or zero specifies the number of logical cores. +# Number of threads to use. Specifying 0 defaults to the number of logical cores. threads = 0 # whether to show test execution progress show_progress = true diff --git a/crates/forge/tests/cli/cmd.rs b/crates/forge/tests/cli/cmd.rs index 64843d25b570..e0000e01bee0 100644 --- a/crates/forge/tests/cli/cmd.rs +++ b/crates/forge/tests/cli/cmd.rs @@ -34,7 +34,7 @@ Options: Print help (see a summary with '-h') -j, --threads - Number of threads to use. Zero specifies the number of logical cores + Number of threads to use. Specifying 0 defaults to the number of logical cores [aliases: jobs]