diff --git a/Cargo.lock b/Cargo.lock index 151ed16c2..faea014a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -375,6 +375,7 @@ dependencies = [ "flate2", "futures", "humansize", + "inquire", "intern", "jobserver", "lazy_static", @@ -496,6 +497,31 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossterm" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67" +dependencies = [ + "bitflags 1.3.2", + "crossterm_winapi", + "libc", + "mio", + "parking_lot", + "signal-hook", + "signal-hook-mio", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" +dependencies = [ + "winapi", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -634,6 +660,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "dyn-clone" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" + [[package]] name = "either" version = "1.8.1" @@ -863,6 +895,24 @@ dependencies = [ "slab", ] +[[package]] +name = "fuzzy-matcher" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54614a3312934d066701a80f20f15fa3b56d67ac7722b39eea5b4c9dd1d66c94" +dependencies = [ + "thread_local", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + [[package]] name = "generic-array" version = "0.14.6" @@ -980,9 +1030,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.3.1" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hex" @@ -1163,6 +1213,23 @@ dependencies = [ "str_stack", ] +[[package]] +name = "inquire" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fddf93031af70e75410a2511ec04d49e758ed2f26dad3404a934e0fb45cc12a" +dependencies = [ + "bitflags 2.6.0", + "crossterm", + "dyn-clone", + "fuzzy-matcher", + "fxhash", + "newline-converter", + "once_cell", + "unicode-segmentation", + "unicode-width", +] + [[package]] name = "instant" version = "0.1.12" @@ -1464,6 +1531,15 @@ dependencies = [ "tempfile", ] +[[package]] +name = "newline-converter" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b6b097ecb1cbfed438542d16e84fd7ad9b0c76c8a65b7f9039212a3d14dc7f" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "nom" version = "7.1.3" @@ -2257,6 +2333,27 @@ dependencies = [ "dirs", ] +[[package]] +name = "signal-hook" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-mio" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" +dependencies = [ + "libc", + "mio", + "signal-hook", +] + [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -2812,11 +2909,17 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-segmentation" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" + [[package]] name = "unicode-width" -version = "0.1.10" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "untrusted" diff --git a/collector/Cargo.toml b/collector/Cargo.toml index 9146a651c..58fb6b4c2 100644 --- a/collector/Cargo.toml +++ b/collector/Cargo.toml @@ -42,6 +42,7 @@ tabled = { version = "0.14.0", features = ["ansi-str"] } humansize = "2.1.3" regex = "1.7.1" analyzeme = "12.0.0" +inquire = "0.7.5" benchlib = { path = "benchlib" } diff --git a/collector/src/bin/collector.rs b/collector/src/bin/collector.rs index cd7290323..3d8ee7078 100644 --- a/collector/src/bin/collector.rs +++ b/collector/src/bin/collector.rs @@ -635,11 +635,15 @@ enum Commands { #[command(flatten)] db: DbOption, + /// Metric used to compare artifacts. + #[arg(long)] + metric: Option, + /// The name of the base artifact to be compared. - base: String, + base: Option, /// The name of the modified artifact to be compared. - modified: String, + modified: Option, }, } @@ -1200,11 +1204,16 @@ Make sure to modify `{dir}/perf-config.json` if the category/artifact don't matc println!("Data of artifact {name} were removed"); Ok(0) } - Commands::BenchCmp { db, base, modified } => { + Commands::BenchCmp { + db, + base, + modified, + metric, + } => { let pool = Pool::open(&db.db); let rt = build_async_runtime(); let conn = rt.block_on(pool.connection()); - rt.block_on(compare_artifacts(conn, base, modified))?; + rt.block_on(compare_artifacts(conn, metric, base, modified))?; Ok(0) } } diff --git a/collector/src/compare.rs b/collector/src/compare.rs index 1f0a54542..c96e6e7e7 100644 --- a/collector/src/compare.rs +++ b/collector/src/compare.rs @@ -1,4 +1,4 @@ -use std::sync::Arc; +use std::{str::FromStr, sync::Arc}; use database::{ metric::Metric, @@ -7,16 +7,95 @@ use database::{ }; use tabled::{Table, Tabled}; +static ALL_METRICS: &[Metric] = &[ + Metric::InstructionsUser, + Metric::Cycles, + Metric::WallTime, + Metric::MaxRSS, + Metric::LinkedArtifactSize, + Metric::AssemblyFileSize, + Metric::BranchMisses, + Metric::CacheMisses, + Metric::CodegenUnitLlvmIrCount, + Metric::CodegenUnitSize, + Metric::ContextSwitches, + Metric::CpuClock, + Metric::CpuClockUser, + Metric::CrateMetadataSize, + Metric::CyclesUser, + Metric::DepGraphSize, + Metric::DocByteSize, + Metric::DwoFileSize, + Metric::Faults, + Metric::FaultsUser, + Metric::LlvmBitcodeSize, + Metric::LlvmIrSize, + Metric::ObjectFileSize, + Metric::QueryCacheSize, + Metric::TaskClock, + Metric::TaskClockUser, + Metric::WorkProductIndexSize, +]; + /// Compare 2 artifacts and print the result. pub async fn compare_artifacts( mut conn: Box, - base: String, - modified: String, + metric: Option, + base: Option, + modified: Option, ) -> anyhow::Result<()> { let index = database::Index::load(&mut *conn).await; - let query = CompileBenchmarkQuery::default() - .metric(database::selector::Selector::One(Metric::InstructionsUser)); + let metric = match metric { + Some(v) => v, + None => { + let metric_str = inquire::Select::new( + "Choose metric:", + ALL_METRICS.iter().map(|m| m.as_str()).collect::>(), + ) + .prompt()?; + Metric::from_str(metric_str).map_err(|e| anyhow::anyhow!(e))? + } + }; + + let mut aids = index.artifacts().map(str::to_string).collect::>(); + if aids.len() < 2 { + return Err(anyhow::anyhow!( + "There are not enough artifacts to compare, at least two are needed" + )); + } + + let select_artifact_id = |name: &str, aids: &Vec| { + anyhow::Ok( + inquire::Select::new( + &format!("Choose {} artifact to compare:", name), + aids.clone(), + ) + .prompt()?, + ) + }; + + let base = match base { + Some(v) => v, + None => select_artifact_id("base", &aids)?.to_string(), + }; + aids.retain(|id| id != &base); + let modified = if aids.len() == 1 { + let new_modified = aids[0].clone(); + println!( + "Only 1 artifact remains, automatically selecting: {}", + new_modified + ); + + new_modified + } else { + match modified { + Some(v) => v, + None => select_artifact_id("modified", &aids)?.to_string(), + } + }; + + let query = CompileBenchmarkQuery::default().metric(database::selector::Selector::One(metric)); let resp = query .execute( &mut *conn,