@@ -8,6 +8,7 @@ use crate::compile::execute::{CargoProcess, Processor};
88use crate :: toolchain:: Toolchain ;
99use crate :: utils:: wait_for_future;
1010use anyhow:: { bail, Context } ;
11+ use database:: selector:: CompileTestCase ;
1112use log:: debug;
1213use std:: collections:: { HashMap , HashSet } ;
1314use std:: fmt:: { Display , Formatter } ;
@@ -243,6 +244,7 @@ impl Benchmark {
243244 toolchain : & Toolchain ,
244245 iterations : Option < usize > ,
245246 targets : & [ Target ] ,
247+ already_computed : & hashbrown:: HashSet < CompileTestCase > ,
246248 ) -> anyhow:: Result < ( ) > {
247249 if self . config . disabled {
248250 eprintln ! ( "Skipping {}: disabled" , self . name) ;
@@ -273,19 +275,62 @@ impl Benchmark {
273275 return Ok ( ( ) ) ;
274276 }
275277
276- eprintln ! ( "Preparing {}" , self . name) ;
277- let mut target_dirs: Vec < ( ( CodegenBackend , Profile , Target ) , TempDir ) > = vec ! [ ] ;
278+ struct BenchmarkDir {
279+ dir : TempDir ,
280+ scenarios : HashSet < Scenario > ,
281+ profile : Profile ,
282+ backend : CodegenBackend ,
283+ target : Target ,
284+ }
285+
286+ // Materialize the test cases that we want to benchmark
287+ // We need to handle scenarios a bit specially, because they share the target directory
288+ let mut benchmark_dirs: Vec < BenchmarkDir > = vec ! [ ] ;
289+
278290 for backend in backends {
279291 for profile in & profiles {
280292 for target in targets {
281- target_dirs. push ( (
282- ( * backend, * profile, * target) ,
283- self . make_temp_dir ( & self . path ) ?,
284- ) ) ;
293+ // Do we have any scenarios left to compute?
294+ let remaining_scenarios = scenarios
295+ . iter ( )
296+ . flat_map ( |scenario| {
297+ self . create_test_cases ( scenario, profile, backend, target)
298+ . into_iter ( )
299+ . map ( |test_case| ( * scenario, test_case) )
300+ } )
301+ . filter ( |( _, test_case) | !already_computed. contains ( test_case) )
302+ . map ( |( scenario, _) | scenario)
303+ . collect :: < HashSet < Scenario > > ( ) ;
304+ if remaining_scenarios. is_empty ( ) {
305+ continue ;
306+ }
307+
308+ let temp_dir = self . make_temp_dir ( & self . path ) ?;
309+ benchmark_dirs. push ( BenchmarkDir {
310+ dir : temp_dir,
311+ scenarios : remaining_scenarios,
312+ profile : * profile,
313+ backend : * backend,
314+ target : * target,
315+ } ) ;
285316 }
286317 }
287318 }
288319
320+ if benchmark_dirs. is_empty ( ) {
321+ eprintln ! (
322+ "Skipping {}: all test cases were previously computed" ,
323+ self . name
324+ ) ;
325+ return Ok ( ( ) ) ;
326+ }
327+
328+ eprintln ! (
329+ "Preparing {} (test cases: {})" ,
330+ self . name,
331+ benchmark_dirs. len( )
332+ ) ;
333+
289334 // In parallel (but with a limit to the number of CPUs), prepare all
290335 // profiles. This is done in parallel vs. sequentially because:
291336 // * We don't record any measurements during this phase, so the
@@ -319,18 +364,18 @@ impl Benchmark {
319364 . get ( ) ,
320365 )
321366 . context ( "jobserver::new" ) ?;
322- let mut threads = Vec :: with_capacity ( target_dirs . len ( ) ) ;
323- for ( ( backend , profile , target ) , prep_dir ) in & target_dirs {
367+ let mut threads = Vec :: with_capacity ( benchmark_dirs . len ( ) ) ;
368+ for benchmark_dir in & benchmark_dirs {
324369 let server = server. clone ( ) ;
325370 let thread = s. spawn :: < _ , anyhow:: Result < ( ) > > ( move || {
326371 wait_for_future ( async move {
327372 let server = server. clone ( ) ;
328373 self . mk_cargo_process (
329374 toolchain,
330- prep_dir . path ( ) ,
331- * profile,
332- * backend,
333- * target,
375+ benchmark_dir . dir . path ( ) ,
376+ benchmark_dir . profile ,
377+ benchmark_dir . backend ,
378+ benchmark_dir . target ,
334379 )
335380 . jobserver ( server)
336381 . run_rustc ( false )
@@ -365,10 +410,11 @@ impl Benchmark {
365410 let mut timing_dirs: Vec < ManuallyDrop < TempDir > > = vec ! [ ] ;
366411
367412 let benchmark_start = std:: time:: Instant :: now ( ) ;
368- for ( ( backend, profile, target) , prep_dir) in & target_dirs {
369- let backend = * backend;
370- let profile = * profile;
371- let target = * target;
413+ for benchmark_dir in & benchmark_dirs {
414+ let backend = benchmark_dir. backend ;
415+ let profile = benchmark_dir. profile ;
416+ let target = benchmark_dir. target ;
417+ let scenarios = & benchmark_dir. scenarios ;
372418 eprintln ! (
373419 "Running {}: {:?} + {:?} + {:?} + {:?}" ,
374420 self . name, profile, scenarios, backend, target,
@@ -388,7 +434,7 @@ impl Benchmark {
388434 }
389435 log:: debug!( "Benchmark iteration {}/{}" , i + 1 , iterations) ;
390436 // Don't delete the directory on error.
391- let timing_dir = ManuallyDrop :: new ( self . make_temp_dir ( prep_dir . path ( ) ) ?) ;
437+ let timing_dir = ManuallyDrop :: new ( self . make_temp_dir ( benchmark_dir . dir . path ( ) ) ?) ;
392438 let cwd = timing_dir. path ( ) ;
393439
394440 // A full non-incremental build.
@@ -458,6 +504,42 @@ impl Benchmark {
458504
459505 Ok ( ( ) )
460506 }
507+
508+ fn create_test_cases (
509+ & self ,
510+ scenario : & Scenario ,
511+ profile : & Profile ,
512+ backend : & CodegenBackend ,
513+ target : & Target ,
514+ ) -> Vec < CompileTestCase > {
515+ self . patches
516+ . iter ( )
517+ . map ( |patch| CompileTestCase {
518+ benchmark : database:: Benchmark :: from ( self . name . 0 . as_str ( ) ) ,
519+ profile : match profile {
520+ Profile :: Check => database:: Profile :: Check ,
521+ Profile :: Debug => database:: Profile :: Debug ,
522+ Profile :: Doc => database:: Profile :: Doc ,
523+ Profile :: DocJson => database:: Profile :: DocJson ,
524+ Profile :: Opt => database:: Profile :: Opt ,
525+ Profile :: Clippy => database:: Profile :: Clippy ,
526+ } ,
527+ scenario : match scenario {
528+ Scenario :: Full => database:: Scenario :: Empty ,
529+ Scenario :: IncrFull => database:: Scenario :: IncrementalEmpty ,
530+ Scenario :: IncrUnchanged => database:: Scenario :: IncrementalFresh ,
531+ Scenario :: IncrPatched => database:: Scenario :: IncrementalPatch ( patch. name ) ,
532+ } ,
533+ backend : match backend {
534+ CodegenBackend :: Llvm => database:: CodegenBackend :: Llvm ,
535+ CodegenBackend :: Cranelift => database:: CodegenBackend :: Cranelift ,
536+ } ,
537+ target : match target {
538+ Target :: X86_64UnknownLinuxGnu => database:: Target :: X86_64UnknownLinuxGnu ,
539+ } ,
540+ } )
541+ . collect ( )
542+ }
461543}
462544
463545/// Directory containing compile-time benchmarks.
0 commit comments