@@ -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 } ;
@@ -249,6 +250,7 @@ impl Benchmark {
249250 toolchain : & Toolchain ,
250251 iterations : Option < usize > ,
251252 targets : & [ Target ] ,
253+ already_computed : & hashbrown:: HashSet < CompileTestCase > ,
252254 ) -> anyhow:: Result < ( ) > {
253255 if self . config . disabled {
254256 eprintln ! ( "Skipping {}: disabled" , self . name) ;
@@ -279,19 +281,62 @@ impl Benchmark {
279281 return Ok ( ( ) ) ;
280282 }
281283
282- eprintln ! ( "Preparing {}" , self . name) ;
283- let mut target_dirs: Vec < ( ( CodegenBackend , Profile , Target ) , TempDir ) > = vec ! [ ] ;
284+ struct BenchmarkDir {
285+ dir : TempDir ,
286+ scenarios : HashSet < Scenario > ,
287+ profile : Profile ,
288+ backend : CodegenBackend ,
289+ target : Target ,
290+ }
291+
292+ // Materialize the test cases that we want to benchmark
293+ // We need to handle scenarios a bit specially, because they share the target directory
294+ let mut benchmark_dirs: Vec < BenchmarkDir > = vec ! [ ] ;
295+
284296 for backend in backends {
285297 for profile in & profiles {
286298 for target in targets {
287- target_dirs. push ( (
288- ( * backend, * profile, * target) ,
289- self . make_temp_dir ( & self . path ) ?,
290- ) ) ;
299+ // Do we have any scenarios left to compute?
300+ let remaining_scenarios = scenarios
301+ . iter ( )
302+ . flat_map ( |scenario| {
303+ self . create_test_cases ( scenario, profile, backend, target)
304+ . into_iter ( )
305+ . map ( |test_case| ( * scenario, test_case) )
306+ } )
307+ . filter ( |( _, test_case) | !already_computed. contains ( test_case) )
308+ . map ( |( scenario, _) | scenario)
309+ . collect :: < HashSet < Scenario > > ( ) ;
310+ if remaining_scenarios. is_empty ( ) {
311+ continue ;
312+ }
313+
314+ let temp_dir = self . make_temp_dir ( & self . path ) ?;
315+ benchmark_dirs. push ( BenchmarkDir {
316+ dir : temp_dir,
317+ scenarios : remaining_scenarios,
318+ profile : * profile,
319+ backend : * backend,
320+ target : * target,
321+ } ) ;
291322 }
292323 }
293324 }
294325
326+ if benchmark_dirs. is_empty ( ) {
327+ eprintln ! (
328+ "Skipping {}: all test cases were previously computed" ,
329+ self . name
330+ ) ;
331+ return Ok ( ( ) ) ;
332+ }
333+
334+ eprintln ! (
335+ "Preparing {} (test cases: {})" ,
336+ self . name,
337+ benchmark_dirs. len( )
338+ ) ;
339+
295340 // In parallel (but with a limit to the number of CPUs), prepare all
296341 // profiles. This is done in parallel vs. sequentially because:
297342 // * We don't record any measurements during this phase, so the
@@ -325,18 +370,18 @@ impl Benchmark {
325370 . get ( ) ,
326371 )
327372 . context ( "jobserver::new" ) ?;
328- let mut threads = Vec :: with_capacity ( target_dirs . len ( ) ) ;
329- for ( ( backend , profile , target ) , prep_dir ) in & target_dirs {
373+ let mut threads = Vec :: with_capacity ( benchmark_dirs . len ( ) ) ;
374+ for benchmark_dir in & benchmark_dirs {
330375 let server = server. clone ( ) ;
331376 let thread = s. spawn :: < _ , anyhow:: Result < ( ) > > ( move || {
332377 wait_for_future ( async move {
333378 let server = server. clone ( ) ;
334379 self . mk_cargo_process (
335380 toolchain,
336- prep_dir . path ( ) ,
337- * profile,
338- * backend,
339- * target,
381+ benchmark_dir . dir . path ( ) ,
382+ benchmark_dir . profile ,
383+ benchmark_dir . backend ,
384+ benchmark_dir . target ,
340385 )
341386 . jobserver ( server)
342387 . run_rustc ( false )
@@ -371,10 +416,11 @@ impl Benchmark {
371416 let mut timing_dirs: Vec < ManuallyDrop < TempDir > > = vec ! [ ] ;
372417
373418 let benchmark_start = std:: time:: Instant :: now ( ) ;
374- for ( ( backend, profile, target) , prep_dir) in & target_dirs {
375- let backend = * backend;
376- let profile = * profile;
377- let target = * target;
419+ for benchmark_dir in & benchmark_dirs {
420+ let backend = benchmark_dir. backend ;
421+ let profile = benchmark_dir. profile ;
422+ let target = benchmark_dir. target ;
423+ let scenarios = & benchmark_dir. scenarios ;
378424 eprintln ! (
379425 "Running {}: {:?} + {:?} + {:?} + {:?}" ,
380426 self . name, profile, scenarios, backend, target,
@@ -394,7 +440,7 @@ impl Benchmark {
394440 }
395441 log:: debug!( "Benchmark iteration {}/{}" , i + 1 , iterations) ;
396442 // Don't delete the directory on error.
397- let timing_dir = ManuallyDrop :: new ( self . make_temp_dir ( prep_dir . path ( ) ) ?) ;
443+ let timing_dir = ManuallyDrop :: new ( self . make_temp_dir ( benchmark_dir . dir . path ( ) ) ?) ;
398444 let cwd = timing_dir. path ( ) ;
399445
400446 // A full non-incremental build.
@@ -464,6 +510,42 @@ impl Benchmark {
464510
465511 Ok ( ( ) )
466512 }
513+
514+ fn create_test_cases (
515+ & self ,
516+ scenario : & Scenario ,
517+ profile : & Profile ,
518+ backend : & CodegenBackend ,
519+ target : & Target ,
520+ ) -> Vec < CompileTestCase > {
521+ self . patches
522+ . iter ( )
523+ . map ( |patch| CompileTestCase {
524+ benchmark : database:: Benchmark :: from ( self . name . 0 . as_str ( ) ) ,
525+ profile : match profile {
526+ Profile :: Check => database:: Profile :: Check ,
527+ Profile :: Debug => database:: Profile :: Debug ,
528+ Profile :: Doc => database:: Profile :: Doc ,
529+ Profile :: DocJson => database:: Profile :: DocJson ,
530+ Profile :: Opt => database:: Profile :: Opt ,
531+ Profile :: Clippy => database:: Profile :: Clippy ,
532+ } ,
533+ scenario : match scenario {
534+ Scenario :: Full => database:: Scenario :: Empty ,
535+ Scenario :: IncrFull => database:: Scenario :: IncrementalEmpty ,
536+ Scenario :: IncrUnchanged => database:: Scenario :: IncrementalFresh ,
537+ Scenario :: IncrPatched => database:: Scenario :: IncrementalPatch ( patch. name ) ,
538+ } ,
539+ backend : match backend {
540+ CodegenBackend :: Llvm => database:: CodegenBackend :: Llvm ,
541+ CodegenBackend :: Cranelift => database:: CodegenBackend :: Cranelift ,
542+ } ,
543+ target : match target {
544+ Target :: X86_64UnknownLinuxGnu => database:: Target :: X86_64UnknownLinuxGnu ,
545+ } ,
546+ } )
547+ . collect ( )
548+ }
467549}
468550
469551/// Directory containing compile-time benchmarks.
0 commit comments