From 9189a3a6010743aa4c41c682190098a781eb77f3 Mon Sep 17 00:00:00 2001 From: shina <53410646+s7tya@users.noreply.github.com> Date: Tue, 6 Aug 2024 17:16:47 +0900 Subject: [PATCH] create bench_cmp command --- collector/src/bin/collector.rs | 21 +++++- collector/src/compare.rs | 126 +++++++++++++++++++++++++++++++++ collector/src/lib.rs | 1 + 3 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 collector/src/compare.rs diff --git a/collector/src/bin/collector.rs b/collector/src/bin/collector.rs index b99ffe95d..c294c1ac5 100644 --- a/collector/src/bin/collector.rs +++ b/collector/src/bin/collector.rs @@ -18,6 +18,7 @@ use std::{str, time::Instant}; use anyhow::Context; use clap::builder::TypedValueParser; use clap::{Arg, Parser}; +use collector::compare::compare_artifacts; use humansize::{format_size, BINARY}; use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator}; use tabled::builder::Builder; @@ -628,6 +629,18 @@ enum Commands { #[command(flatten)] db: DbOption, }, + + /// Displays diff between two local bench results. + BenchCmp { + #[command(flatten)] + db: DbOption, + + /// The name of the base artifact to be compared. + base: String, + + /// The name of the modified artifact to be compared. + modified: String, + }, } #[derive(Debug, clap::Parser)] @@ -1187,6 +1200,13 @@ 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 } => { + 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))?; + Ok(0) + } } } @@ -1736,7 +1756,6 @@ fn bench_compile( category, )); print_intro(); - let mut processor = BenchProcessor::new( tx.conn(), benchmark_name, diff --git a/collector/src/compare.rs b/collector/src/compare.rs new file mode 100644 index 000000000..1f0a54542 --- /dev/null +++ b/collector/src/compare.rs @@ -0,0 +1,126 @@ +use std::sync::Arc; + +use database::{ + metric::Metric, + selector::{BenchmarkQuery, CompileBenchmarkQuery}, + ArtifactId, Connection, +}; +use tabled::{Table, Tabled}; + +/// Compare 2 artifacts and print the result. +pub async fn compare_artifacts( + mut conn: Box, + base: String, + modified: String, +) -> anyhow::Result<()> { + let index = database::Index::load(&mut *conn).await; + + let query = CompileBenchmarkQuery::default() + .metric(database::selector::Selector::One(Metric::InstructionsUser)); + let resp = query + .execute( + &mut *conn, + &index, + Arc::new(vec![ArtifactId::Tag(base), ArtifactId::Tag(modified)]), + ) + .await + .unwrap(); + + let tuple_pstats = resp + .into_iter() + .map(|resp| { + let points = resp.series.points.collect::>(); + (points[0], points[1]) + }) + .collect::>(); + + #[derive(Tabled)] + struct Regression { + count: usize, + #[tabled(display_with = "display_range")] + range: (Option, Option), + #[tabled(display_with = "display_mean")] + mean: Option, + } + + fn format_value(value: Option) -> String { + match value { + Some(value) => format!("{:+.2}%", value), + None => "-".to_string(), + } + } + + fn display_range(&(min, max): &(Option, Option)) -> String { + format!("[{}, {}]", &format_value(min), &format_value(max)) + } + + fn display_mean(value: &Option) -> String { + match value { + Some(value) => format!("{:+.2}%", value), + None => "-".to_string(), + } + } + + impl From<&Vec> for Regression { + fn from(value: &Vec) -> Self { + let min = value.iter().copied().min_by(|a, b| a.total_cmp(b)); + let max = value.iter().copied().max_by(|a, b| a.total_cmp(b)); + let count = value.len(); + + Regression { + range: (min, max), + count, + mean: if count == 0 { + None + } else { + Some(value.iter().sum::() / count as f64) + }, + } + } + } + + let change = tuple_pstats + .iter() + .filter_map(|&(a, b)| match (a, b) { + (Some(a), Some(b)) => { + if a == 0.0 { + None + } else { + Some((b - a) / a) + } + } + (_, _) => None, + }) + .collect::>(); + let negative_change = change + .iter() + .copied() + .filter(|&c| c < 0.0) + .collect::>(); + let positive_change = change + .iter() + .copied() + .filter(|&c| c > 0.0) + .collect::>(); + + #[derive(Tabled)] + struct NamedRegression { + name: String, + #[tabled(inline)] + regression: Regression, + } + + let regressions = [negative_change, positive_change, change] + .into_iter() + .map(|c| Regression::from(&c)) + .zip(["❌", "✅", "✅, ❌"]) + .map(|(c, label)| NamedRegression { + name: label.to_string(), + regression: c, + }) + .collect::>(); + + println!("{}", Table::new(regressions)); + + Ok(()) +} diff --git a/collector/src/lib.rs b/collector/src/lib.rs index 954ee4697..f03c299f5 100644 --- a/collector/src/lib.rs +++ b/collector/src/lib.rs @@ -9,6 +9,7 @@ pub mod api; pub mod artifact_stats; pub mod cargo; pub mod codegen; +pub mod compare; pub mod compile; pub mod runtime; pub mod toolchain;