Skip to content

Commit 9f9a5b0

Browse files
committed
Post a summary table to PRs after perf. runs
1 parent cf072f3 commit 9f9a5b0

File tree

2 files changed

+160
-23
lines changed

2 files changed

+160
-23
lines changed

‎site/src/comparison.rs

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,61 @@ impl ComparisonSummary {
421421
.unwrap();
422422
}
423423
}
424+
425+
/// Writes a Markdown table containing summary of relevant results.
426+
pub fn write_summary_table(&self, result: &mut String) {
427+
use std::fmt::Write;
428+
429+
fn render_stat<F: FnOnce() -> Option<f64>>(count: usize, calculate: F) -> String {
430+
let value = if count > 0 {
431+
calculate()
432+
} else {
433+
None
434+
};
435+
value.map(|value| format!("{value:.1}%")).unwrap_or_else(|| "N/A".to_string())
436+
}
437+
438+
writeln!(
439+
result,
440+
r#"| | Regressions 😿 | Improvements 🎉 | All relevant changes |
441+
|:---:|:---:|:---:|:---:|"#
442+
)
443+
.unwrap();
444+
writeln!(
445+
result,
446+
"| count[^1] | {} | {} | {} |",
447+
self.num_regressions,
448+
self.num_improvements,
449+
self.num_regressions + self.num_improvements
450+
)
451+
.unwrap();
452+
writeln!(
453+
result,
454+
"| mean[^2] | {} | {} | {:.1}% |",
455+
render_stat(self.num_regressions, || Some(self.arithmetic_mean_of_regressions())),
456+
render_stat(self.num_improvements, || Some(self.arithmetic_mean_of_improvements())),
457+
self.arithmetic_mean_of_changes()
458+
)
459+
.unwrap();
460+
461+
let largest_change = self.most_relevant_changes().iter().fold(0.0, |accum: f64, item| {
462+
let change = item.map(|v| v.relative_change() * 100.0).unwrap_or(0.0);
463+
accum.max(change)
464+
});
465+
466+
writeln!(
467+
result,
468+
"| max | {} | {} | {:.1}% |",
469+
render_stat(self.num_regressions, || self.largest_regression().map(|r| r.relative_change() * 100.0)),
470+
render_stat(self.num_improvements, || self.largest_improvement().map(|r| r.relative_change() * 100.0)),
471+
largest_change
472+
)
473+
.unwrap();
474+
475+
writeln!(result, r#"
476+
[^1]: *number of relevant changes*
477+
[^2]: *the arithmetic mean of the percent change*"#).unwrap();
478+
}
424479
}
425480

426481
/// The amount of confidence we have that a comparison actually represents a real
@@ -1233,3 +1288,102 @@ fn compare_link(start: &ArtifactId, end: &ArtifactId) -> String {
12331288
start, end
12341289
)
12351290
}
1291+
1292+
#[cfg(test)]
1293+
mod tests {
1294+
use std::collections::HashSet;
1295+
1296+
use database::{ArtifactId, Profile, Scenario};
1297+
1298+
use crate::comparison::{
1299+
ArtifactDescription, Comparison, ComparisonSummary, TestResultComparison,
1300+
};
1301+
1302+
#[test]
1303+
fn summary_table_only_improvements() {
1304+
let summary = create_summary(vec![(10.0, 5.0), (8.0, 2.0)]);
1305+
check_table(
1306+
summary, r#"
1307+
| | Regressions 😿 | Improvements 🎉 | All relevant changes |
1308+
|:---:|:---:|:---:|:---:|
1309+
| count[^1] | 0 | 2 | 2 |
1310+
| mean[^2] | N/A | -62.5% | -62.5% |
1311+
| max | N/A | -75.0% | 0.0% |
1312+
1313+
[^1]: *number of relevant changes*
1314+
[^2]: *the arithmetic mean of the percent change*
1315+
"#.trim_start(),
1316+
);
1317+
}
1318+
1319+
#[test]
1320+
fn summary_table_only_regressions() {
1321+
let summary = create_summary(vec![(5.0, 10.0), (1.0, 3.0)]);
1322+
check_table(
1323+
summary, r#"
1324+
| | Regressions 😿 | Improvements 🎉 | All relevant changes |
1325+
|:---:|:---:|:---:|:---:|
1326+
| count[^1] | 2 | 0 | 2 |
1327+
| mean[^2] | 150.0% | N/A | 150.0% |
1328+
| max | 200.0% | N/A | 200.0% |
1329+
1330+
[^1]: *number of relevant changes*
1331+
[^2]: *the arithmetic mean of the percent change*
1332+
"#.trim_start(),
1333+
);
1334+
}
1335+
1336+
#[test]
1337+
fn summary_table_mixed() {
1338+
let summary = create_summary(vec![(10.0, 5.0), (5.0, 10.0), (1.0, 3.0), (4.0, 1.0)]);
1339+
check_table(
1340+
summary, r#"
1341+
| | Regressions 😿 | Improvements 🎉 | All relevant changes |
1342+
|:---:|:---:|:---:|:---:|
1343+
| count[^1] | 2 | 2 | 4 |
1344+
| mean[^2] | 150.0% | -62.5% | 43.8% |
1345+
| max | 200.0% | -75.0% | 200.0% |
1346+
1347+
[^1]: *number of relevant changes*
1348+
[^2]: *the arithmetic mean of the percent change*
1349+
"#.trim_start(),
1350+
);
1351+
}
1352+
1353+
fn check_table(summary: ComparisonSummary, expected: &str) {
1354+
let mut result = String::new();
1355+
summary.write_summary_table(&mut result);
1356+
assert_eq!(result, expected);
1357+
}
1358+
1359+
fn create_summary(values: Vec<(f64, f64)>) -> ComparisonSummary {
1360+
let mut statistics = HashSet::new();
1361+
for (index, diff) in values.into_iter().enumerate() {
1362+
statistics.insert(TestResultComparison {
1363+
benchmark: index.to_string().as_str().into(),
1364+
profile: Profile::Check,
1365+
scenario: Scenario::Empty,
1366+
variance: None,
1367+
results: diff,
1368+
});
1369+
}
1370+
1371+
let comparison = Comparison {
1372+
a: ArtifactDescription {
1373+
artifact: ArtifactId::Tag("a".to_string()),
1374+
pr: None,
1375+
bootstrap: Default::default(),
1376+
bootstrap_total: 0,
1377+
},
1378+
b: ArtifactDescription {
1379+
artifact: ArtifactId::Tag("b".to_string()),
1380+
pr: None,
1381+
bootstrap: Default::default(),
1382+
bootstrap_total: 0,
1383+
},
1384+
statistics,
1385+
new_errors: Default::default(),
1386+
};
1387+
ComparisonSummary::summarize_comparison(&comparison).unwrap()
1388+
}
1389+
}

‎site/src/github.rs

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -709,31 +709,14 @@ async fn categorize_benchmark(
709709
let num_improvements = summary.number_of_improvements();
710710
let num_regressions = summary.number_of_regressions();
711711

712-
let description = match direction {
713-
Direction::Improvement => format!(
714-
"{} relevant {} 🎉",
715-
num_improvements,
716-
ending("improvement", num_improvements)
717-
),
718-
Direction::Regression => format!(
719-
"{} relevant {} 😿",
720-
num_regressions,
721-
ending("regression", num_regressions)
722-
),
723-
Direction::Mixed => format!(
724-
"{} relevant {} 🎉 but {} relevant {} 😿",
725-
num_improvements,
726-
ending("improvement", num_improvements),
727-
num_regressions,
728-
ending("regression", num_regressions)
729-
),
712+
let short_summary = match direction {
713+
Direction::Improvement => format!("🎉 relevant {} found", ending("improvement", num_improvements)),
714+
Direction::Regression => format!("😿 relevant {} found", ending("regression", num_regressions)),
715+
Direction::Mixed => "mixed results".to_string(),
730716
};
731-
let mut result = format!(
732-
"This benchmark run shows {} to instruction counts.\n",
733-
description
734-
);
735717

736-
summary.write_summary_lines(&mut result, None);
718+
let mut result = format!("Summary: {short_summary}\n");
719+
summary.write_summary_table(&mut result);
737720
write!(result, "\n{}", DISAGREEMENT).unwrap();
738721
(result, Some(direction))
739722
}

0 commit comments

Comments
 (0)