Skip to content

Commit 3ba306e

Browse files
authored
Merge pull request #1283 from rylev/only-label-when-confident
Only label PRs as perf regressions if we're confident enough
2 parents b0145e1 + db8f2f0 commit 3ba306e

File tree

2 files changed

+125
-122
lines changed

2 files changed

+125
-122
lines changed

site/src/comparison.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,14 @@ impl ComparisonSummary {
337337
pub fn is_relevant(&self) -> bool {
338338
!self.is_empty()
339339
}
340+
341+
pub fn num_changes(&self) -> usize {
342+
self.relevant_comparisons.len()
343+
}
344+
345+
pub fn largest_change(&self) -> Option<&TestResultComparison> {
346+
self.relevant_comparisons.first()
347+
}
340348
}
341349

342350
async fn write_triage_summary(
@@ -984,7 +992,7 @@ impl TestResultComparison {
984992
///
985993
/// This is the average of the absolute magnitude of the change
986994
/// and the amount above the significance threshold.
987-
fn magnitude(&self) -> Magnitude {
995+
pub fn magnitude(&self) -> Magnitude {
988996
let change = self.relative_change().abs();
989997
let threshold = self.significance_threshold();
990998
let over_threshold = if change < threshold * 1.5 {
@@ -1058,7 +1066,7 @@ impl std::hash::Hash for TestResultComparison {
10581066
}
10591067

10601068
// The direction of a performance change
1061-
#[derive(PartialEq, Eq, Hash, Debug)]
1069+
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
10621070
pub enum Direction {
10631071
Improvement,
10641072
Regression,

site/src/github.rs

Lines changed: 115 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::api::github::Issue;
2-
use crate::comparison::{write_summary_table, ComparisonSummary, Direction};
2+
use crate::comparison::{write_summary_table, ComparisonSummary, Direction, Magnitude};
33
use crate::load::{Config, SiteCtxt, TryCommit};
44

55
use anyhow::Context as _;
@@ -558,154 +558,154 @@ pub async fn post_finished(ctxt: &SiteCtxt) {
558558
///
559559
/// `is_master_commit` is used to differentiate messages for try runs and post-merge runs.
560560
async fn post_comparison_comment(ctxt: &SiteCtxt, commit: QueuedCommit, is_master_commit: bool) {
561+
let pr = commit.pr;
562+
let body = summarize_run(ctxt, commit, is_master_commit).await;
563+
564+
post_comment(&ctxt.config, pr, body).await;
565+
}
566+
567+
async fn summarize_run(ctxt: &SiteCtxt, commit: QueuedCommit, is_master_commit: bool) -> String {
561568
let comparison_url = format!(
562569
"https://perf.rust-lang.org/compare.html?start={}&end={}",
563570
commit.parent_sha, commit.sha
564571
);
565-
let (summary, direction) =
566-
categorize_benchmark(ctxt, commit.sha.clone(), commit.parent_sha).await;
572+
let comparison = match crate::comparison::compare(
573+
collector::Bound::Commit(commit.parent_sha),
574+
collector::Bound::Commit(commit.sha.clone()),
575+
"instructions:u".to_owned(),
576+
ctxt,
577+
)
578+
.await
579+
{
580+
Ok(Some(c)) => c,
581+
_ => return String::from("ERROR categorizing benchmark run!"),
582+
};
583+
584+
let errors = if !comparison.newly_failed_benchmarks.is_empty() {
585+
let benchmarks = comparison
586+
.newly_failed_benchmarks
587+
.iter()
588+
.map(|(benchmark, _)| format!("- {benchmark}"))
589+
.collect::<Vec<_>>()
590+
.join("\n");
591+
format!("\n**Warning ⚠**: The following benchmark(s) failed to build:\n{benchmarks}\n")
592+
} else {
593+
String::new()
594+
};
595+
596+
let benchmark_map = ctxt.get_benchmark_category_map().await;
597+
let (primary, secondary) = comparison.summarize_by_category(benchmark_map);
598+
599+
const DISAGREEMENT: &str = "If you disagree with this performance assessment, \
600+
please file an issue in [rust-lang/rustc-perf](https://github.com/rust-lang/rustc-perf/issues/new).";
601+
let footer = format!("{DISAGREEMENT}{errors}");
602+
603+
if !primary.is_relevant() && !secondary.is_relevant() {
604+
return format!("This benchmark run did not return any relevant results.\n\n{footer}");
605+
}
606+
607+
let primary_short_summary = generate_short_summary(&primary);
608+
let secondary_short_summary = generate_short_summary(&secondary);
609+
610+
let mut summary = format!(
611+
r#"
612+
- Primary benchmarks: {primary_short_summary}
613+
- Secondary benchmarks: {secondary_short_summary}
614+
"#
615+
);
616+
write!(summary, "\n\n").unwrap();
617+
618+
write_summary_table(&primary, &secondary, true, &mut summary);
567619

568-
let body = format!(
569-
"Finished benchmarking commit ({sha}): [comparison url]({url}).
620+
write!(summary, "\n{footer}").unwrap();
621+
622+
let direction = primary.direction().or(secondary.direction());
623+
let next_steps = next_steps(primary, secondary, direction, is_master_commit);
624+
625+
format!(
626+
"Finished benchmarking commit ({sha}): [comparison url]({comparison_url}).
570627
571628
**Summary**: {summary}
572-
{rest}",
629+
{next_steps}",
573630
sha = commit.sha,
574-
url = comparison_url,
575-
summary = summary,
576-
rest = if is_master_commit {
577-
master_run_body(direction)
578-
} else {
579-
try_run_body(direction)
631+
)
632+
}
633+
634+
fn next_steps(
635+
primary: ComparisonSummary,
636+
secondary: ComparisonSummary,
637+
direction: Option<Direction>,
638+
is_master_commit: bool,
639+
) -> String {
640+
// whether we are confident enough this is a real change and it deserves to be looked at
641+
let deserves_attention = match (primary.largest_change(), secondary.largest_change()) {
642+
(Some(c), _) if c.magnitude() >= Magnitude::Medium => true,
643+
(_, Some(c)) if c.magnitude() >= Magnitude::Medium => true,
644+
_ => {
645+
let primary_n = primary.num_changes();
646+
let secondary_n = secondary.num_changes();
647+
(primary_n * 2 + secondary_n) >= 6
580648
}
581-
);
649+
};
650+
let label = match (deserves_attention, direction) {
651+
(true, Some(Direction::Regression | Direction::Mixed)) => "+perf-regression",
652+
_ => "-perf-regression",
653+
};
582654

583-
post_comment(&ctxt.config, commit.pr, body).await;
655+
if is_master_commit {
656+
master_run_body(label)
657+
} else {
658+
try_run_body(label)
659+
}
584660
}
585661

586-
fn master_run_body(direction: Option<Direction>) -> String {
587-
let label = match direction {
588-
Some(Direction::Regression | Direction::Mixed) => "+perf-regression",
589-
Some(Direction::Improvement) | None => "-perf-regression",
590-
};
591-
let next_steps = match direction {
592-
Some(Direction::Regression | Direction::Mixed) => {
593-
"\n\n**Next Steps**: If you can justify the \
662+
fn master_run_body(label: &str) -> String {
663+
let next_steps = if label.starts_with("+") {
664+
"\n\n**Next Steps**: If you can justify the \
594665
regressions found in this perf run, please indicate this with \
595666
`@rustbot label: +perf-regression-triaged` along with \
596667
sufficient written justification. If you cannot justify the regressions \
597668
please open an issue or create a new PR that fixes the regressions, \
598669
add a comment linking to the newly created issue or PR, \
599670
and then add the `perf-regression-triaged` label to this PR."
600-
}
601-
Some(Direction::Improvement) | None => "",
671+
} else {
672+
""
602673
};
603674

604675
format!(
605676
"
606677
{next_steps}
607678
608679
@rustbot label: {label}",
609-
next_steps = next_steps,
610-
label = label
611680
)
612681
}
613682

614-
fn try_run_body(direction: Option<Direction>) -> String {
615-
let label = match direction {
616-
Some(Direction::Regression | Direction::Mixed) => "+perf-regression",
617-
Some(Direction::Improvement) | None => "-perf-regression",
618-
};
619-
let next_steps = match direction {
620-
Some(Direction::Regression | Direction::Mixed) => {
621-
"\n\n**Next Steps**: If you can justify the regressions found in \
683+
fn try_run_body(label: &str) -> String {
684+
let next_steps = if label.starts_with("+") {
685+
"\n\n**Next Steps**: If you can justify the regressions found in \
622686
this try perf run, please indicate this with \
623687
`@rustbot label: +perf-regression-triaged` along with \
624688
sufficient written justification. If you cannot justify the regressions \
625689
please fix the regressions and do another perf run. If the next run \
626690
shows neutral or positive results, the label will be automatically removed."
627-
}
628-
Some(Direction::Improvement) | None => "",
691+
} else {
692+
""
629693
};
630694

631695
format!(
632696
"
633697
Benchmarking this pull request likely means that it is \
634698
perf-sensitive, so we're automatically marking it as not fit \
635699
for rolling up. While you can manually mark this PR as fit \
636-
for rollup, we strongly recommend not doing so since this PR led to changes in \
700+
for rollup, we strongly recommend not doing so since this PR may lead to changes in \
637701
compiler perf.{next_steps}
638702
639703
@bors rollup=never
640704
@rustbot label: +S-waiting-on-review -S-waiting-on-perf {label}",
641-
next_steps = next_steps,
642-
label = label
643705
)
644706
}
645707

646-
async fn categorize_benchmark(
647-
ctxt: &SiteCtxt,
648-
commit_sha: String,
649-
parent_sha: String,
650-
) -> (String, Option<Direction>) {
651-
let comparison = match crate::comparison::compare(
652-
collector::Bound::Commit(parent_sha),
653-
collector::Bound::Commit(commit_sha),
654-
"instructions:u".to_owned(),
655-
ctxt,
656-
)
657-
.await
658-
{
659-
Ok(Some(c)) => c,
660-
_ => return (String::from("ERROR categorizing benchmark run!"), None),
661-
};
662-
663-
let errors = if !comparison.newly_failed_benchmarks.is_empty() {
664-
let benchmarks = comparison
665-
.newly_failed_benchmarks
666-
.iter()
667-
.map(|(benchmark, _)| format!("- {benchmark}"))
668-
.collect::<Vec<_>>()
669-
.join("\n");
670-
format!("\n**Warning ⚠**: The following benchmark(s) failed to build:\n{benchmarks}\n")
671-
} else {
672-
String::new()
673-
};
674-
675-
let benchmark_map = ctxt.get_benchmark_category_map().await;
676-
let (primary, secondary) = comparison.summarize_by_category(benchmark_map);
677-
678-
const DISAGREEMENT: &str = "If you disagree with this performance assessment, \
679-
please file an issue in [rust-lang/rustc-perf](https://github.com/rust-lang/rustc-perf/issues/new).";
680-
let footer = format!("{DISAGREEMENT}{errors}");
681-
682-
if !primary.is_relevant() && !secondary.is_relevant() {
683-
return (
684-
format!("This benchmark run did not return any relevant results.\n\n{footer}"),
685-
None,
686-
);
687-
}
688-
689-
let (primary_short_summary, primary_direction) = generate_short_summary(&primary);
690-
let (secondary_short_summary, secondary_direction) = generate_short_summary(&secondary);
691-
692-
let mut result = format!(
693-
r#"
694-
- Primary benchmarks: {primary_short_summary}
695-
- Secondary benchmarks: {secondary_short_summary}
696-
"#
697-
);
698-
write!(result, "\n\n").unwrap();
699-
700-
write_summary_table(&primary, &secondary, true, &mut result);
701-
702-
write!(result, "\n{footer}").unwrap();
703-
704-
let direction = primary_direction.or(secondary_direction);
705-
(result, direction)
706-
}
707-
708-
fn generate_short_summary(summary: &ComparisonSummary) -> (String, Option<Direction>) {
708+
fn generate_short_summary(summary: &ComparisonSummary) -> String {
709709
// Add an "s" to a word unless there's only one.
710710
fn ending(word: &'static str, count: usize) -> std::borrow::Cow<'static, str> {
711711
if count == 1 {
@@ -714,25 +714,20 @@ fn generate_short_summary(summary: &ComparisonSummary) -> (String, Option<Direct
714714
format!("{}s", word).into()
715715
}
716716

717-
if summary.is_relevant() {
718-
let direction = summary.direction().unwrap();
719-
let num_improvements = summary.number_of_improvements();
720-
let num_regressions = summary.number_of_regressions();
717+
let num_improvements = summary.number_of_improvements();
718+
let num_regressions = summary.number_of_regressions();
721719

722-
let text = match direction {
723-
Direction::Improvement => format!(
724-
"🎉 relevant {} found",
725-
ending("improvement", num_improvements)
726-
),
727-
Direction::Regression => format!(
728-
"😿 relevant {} found",
729-
ending("regression", num_regressions)
730-
),
731-
Direction::Mixed => "mixed results".to_string(),
732-
};
733-
(text, Some(direction))
734-
} else {
735-
("no relevant changes found".to_string(), None)
720+
match summary.direction() {
721+
Some(Direction::Improvement) => format!(
722+
"🎉 relevant {} found",
723+
ending("improvement", num_improvements)
724+
),
725+
Some(Direction::Regression) => format!(
726+
"😿 relevant {} found",
727+
ending("regression", num_regressions)
728+
),
729+
Some(Direction::Mixed) => "mixed results".to_string(),
730+
None => "no relevant changes found".to_string(),
736731
}
737732
}
738733

0 commit comments

Comments
 (0)