@@ -17,6 +17,7 @@ use anyhow::{bail, Context};
17
17
use chrono:: { Date , Duration , NaiveDate , Utc } ;
18
18
use clap:: { ArgAction , Parser , ValueEnum } ;
19
19
use colored:: Colorize ;
20
+ use github:: get_pr_comments;
20
21
use log:: debug;
21
22
use reqwest:: blocking:: Client ;
22
23
@@ -26,6 +27,7 @@ mod least_satisfying;
26
27
mod repo_access;
27
28
mod toolchains;
28
29
30
+ use crate :: github:: get_commit;
29
31
use crate :: least_satisfying:: { least_satisfying, Satisfies } ;
30
32
use crate :: repo_access:: { AccessViaGithub , AccessViaLocalGit , RustRepositoryAccessor } ;
31
33
use crate :: toolchains:: {
@@ -558,11 +560,30 @@ impl Config {
558
560
Ok ( ( ) )
559
561
}
560
562
563
+ fn do_perf_search ( & self , result : & BisectionResult ) {
564
+ let toolchain = & result. searched [ result. found ] ;
565
+ match self . search_perf_builds ( toolchain) {
566
+ Ok ( result) => {
567
+ let url = format ! (
568
+ "https://github.com/rust-lang-ci/rust/commit/{}" ,
569
+ result. searched[ result. found]
570
+ )
571
+ . red ( )
572
+ . bold ( ) ;
573
+ eprintln ! ( "Regression in {url}" ) ;
574
+ }
575
+ Err ( e) => {
576
+ eprintln ! ( "ERROR: {e}" ) ;
577
+ }
578
+ }
579
+ }
580
+
561
581
// bisection entry point
562
582
fn bisect ( & self ) -> anyhow:: Result < ( ) > {
563
583
if self . is_commit {
564
584
let bisection_result = self . bisect_ci ( ) ?;
565
585
self . print_results ( & bisection_result) ;
586
+ self . do_perf_search ( & bisection_result) ;
566
587
} else {
567
588
let nightly_bisection_result = self . bisect_nightlies ( ) ?;
568
589
self . print_results ( & nightly_bisection_result) ;
@@ -583,6 +604,7 @@ impl Config {
583
604
let ci_bisection_result = self . bisect_ci_via ( & working_commit, & bad_commit) ?;
584
605
585
606
self . print_results ( & ci_bisection_result) ;
607
+ self . do_perf_search ( & ci_bisection_result) ;
586
608
print_final_report ( self , & nightly_bisection_result, & ci_bisection_result) ;
587
609
}
588
610
}
@@ -1154,6 +1176,75 @@ impl Config {
1154
1176
dl_spec,
1155
1177
} )
1156
1178
}
1179
+
1180
+ fn search_perf_builds ( & self , toolchain : & Toolchain ) -> anyhow:: Result < BisectionResult > {
1181
+ eprintln ! ( "Attempting to search unrolled perf builds" ) ;
1182
+ let Toolchain { spec : ToolchainSpec :: Ci { commit, .. } , ..} = toolchain else {
1183
+ bail ! ( "not a ci commit" ) ;
1184
+ } ;
1185
+ let summary = get_commit ( commit) ?. summary ;
1186
+ if !summary. starts_with ( "Auto merge of #" ) && !summary. contains ( "Rollup of" ) {
1187
+ bail ! ( "not a rollup pr" ) ;
1188
+ }
1189
+ let pr = summary. split ( ' ' ) . nth ( 3 ) . unwrap ( ) ;
1190
+ // remove '#'
1191
+ let pr = pr. chars ( ) . skip ( 1 ) . collect :: < String > ( ) ;
1192
+ let comments = get_pr_comments ( & pr) ?;
1193
+ let perf_comment = comments
1194
+ . iter ( )
1195
+ . filter ( |c| c. user . login == "rust-timer" )
1196
+ . find ( |c| c. body . contains ( "Perf builds for each rolled up PR" ) )
1197
+ . context ( "couldn't find perf build comment" ) ?;
1198
+ let builds = perf_comment
1199
+ . body
1200
+ . lines ( )
1201
+ // lines of table with PR builds
1202
+ . filter ( |l| l. starts_with ( "|#" ) )
1203
+ // get the commit link
1204
+ . filter_map ( |l| l. split ( '|' ) . nth ( 2 ) )
1205
+ // get the commit sha
1206
+ . map ( |l| l. split_once ( '[' ) . unwrap ( ) . 1 . rsplit_once ( ']' ) . unwrap ( ) . 0 )
1207
+ . collect :: < Vec < _ > > ( ) ;
1208
+ let short_sha = builds
1209
+ . iter ( )
1210
+ . map ( |sha| sha. chars ( ) . take ( 8 ) . collect ( ) )
1211
+ . collect :: < Vec < String > > ( ) ;
1212
+ eprintln ! ( "Found commits {short_sha:?}" ) ;
1213
+ self . linear_in_commits ( & builds)
1214
+ }
1215
+
1216
+ fn linear_in_commits ( & self , commits : & [ & str ] ) -> anyhow:: Result < BisectionResult > {
1217
+ let dl_spec = DownloadParams :: for_ci ( self ) ;
1218
+
1219
+ let toolchains = commits
1220
+ . into_iter ( )
1221
+ . map ( |commit| {
1222
+ let mut t = Toolchain {
1223
+ spec : ToolchainSpec :: Ci {
1224
+ commit : commit. to_string ( ) ,
1225
+ alt : self . args . alt ,
1226
+ } ,
1227
+ host : self . args . host . clone ( ) ,
1228
+ std_targets : vec ! [ self . args. host. clone( ) , self . target. clone( ) ] ,
1229
+ } ;
1230
+ t. std_targets . sort ( ) ;
1231
+ t. std_targets . dedup ( ) ;
1232
+ t
1233
+ } )
1234
+ . collect :: < Vec < _ > > ( ) ;
1235
+
1236
+ let Some ( found) = toolchains. iter ( ) . position ( |t| {
1237
+ self . install_and_test ( t, & dl_spec) . unwrap_or ( Satisfies :: Unknown ) == Satisfies :: Yes
1238
+ } ) else {
1239
+ bail ! ( "none of the toolchains satisfied the predicate" ) ;
1240
+ } ;
1241
+
1242
+ Ok ( BisectionResult {
1243
+ searched : toolchains,
1244
+ found,
1245
+ dl_spec,
1246
+ } )
1247
+ }
1157
1248
}
1158
1249
1159
1250
#[ derive( Clone ) ]
0 commit comments