Skip to content

Create bench_cmp command #1955

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion collector/src/bin/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)]
Expand Down Expand Up @@ -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)
}
}
}

Expand Down Expand Up @@ -1736,7 +1756,6 @@ fn bench_compile(
category,
));
print_intro();

let mut processor = BenchProcessor::new(
tx.conn(),
benchmark_name,
Expand Down
126 changes: 126 additions & 0 deletions collector/src/compare.rs
Original file line number Diff line number Diff line change
@@ -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<dyn Connection>,
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::<Vec<_>>();
(points[0], points[1])
})
.collect::<Vec<_>>();

#[derive(Tabled)]
struct Regression {
count: usize,
#[tabled(display_with = "display_range")]
range: (Option<f64>, Option<f64>),
#[tabled(display_with = "display_mean")]
mean: Option<f64>,
}

fn format_value(value: Option<f64>) -> String {
match value {
Some(value) => format!("{:+.2}%", value),
None => "-".to_string(),
}
}

fn display_range(&(min, max): &(Option<f64>, Option<f64>)) -> String {
format!("[{}, {}]", &format_value(min), &format_value(max))
}

fn display_mean(value: &Option<f64>) -> String {
match value {
Some(value) => format!("{:+.2}%", value),
None => "-".to_string(),
}
}

impl From<&Vec<f64>> for Regression {
fn from(value: &Vec<f64>) -> 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::<f64>() / 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::<Vec<_>>();
let negative_change = change
.iter()
.copied()
.filter(|&c| c < 0.0)
.collect::<Vec<_>>();
let positive_change = change
.iter()
.copied()
.filter(|&c| c > 0.0)
.collect::<Vec<_>>();

#[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::<Vec<_>>();

println!("{}", Table::new(regressions));

Ok(())
}
1 change: 1 addition & 0 deletions collector/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading