1
+ use std:: collections:: HashMap ;
1
2
use std:: ffi:: { OsStr , OsString } ;
2
- use std:: io:: Write ;
3
+ use std:: fs:: File ;
4
+ use std:: io:: { BufReader , BufWriter , Write } ;
3
5
use std:: ops:: { Not , Range } ;
4
6
use std:: path:: PathBuf ;
5
7
use std:: time:: Duration ;
6
8
use std:: { env, net, process} ;
7
9
8
10
use anyhow:: { Context , Result , anyhow, bail} ;
9
11
use path_macro:: path;
12
+ use serde_derive:: { Deserialize , Serialize } ;
13
+ use tempfile:: TempDir ;
10
14
use walkdir:: WalkDir ;
11
15
use xshell:: { Shell , cmd} ;
12
16
@@ -179,8 +183,8 @@ impl Command {
179
183
Command :: Doc { flags } => Self :: doc ( flags) ,
180
184
Command :: Fmt { flags } => Self :: fmt ( flags) ,
181
185
Command :: Clippy { flags } => Self :: clippy ( flags) ,
182
- Command :: Bench { target, no_install, benches } =>
183
- Self :: bench ( target, no_install, benches) ,
186
+ Command :: Bench { target, no_install, save_baseline , benches } =>
187
+ Self :: bench ( target, no_install, save_baseline , benches) ,
184
188
Command :: Toolchain { flags } => Self :: toolchain ( flags) ,
185
189
Command :: RustcPull { commit } => Self :: rustc_pull ( commit. clone ( ) ) ,
186
190
Command :: RustcPush { github_user, branch } => Self :: rustc_push ( github_user, branch) ,
@@ -379,7 +383,12 @@ impl Command {
379
383
Ok ( ( ) )
380
384
}
381
385
382
- fn bench ( target : Option < String > , no_install : bool , benches : Vec < String > ) -> Result < ( ) > {
386
+ fn bench (
387
+ target : Option < String > ,
388
+ no_install : bool ,
389
+ save_baseline : Option < String > ,
390
+ benches : Vec < String > ,
391
+ ) -> Result < ( ) > {
383
392
// The hyperfine to use
384
393
let hyperfine = env:: var ( "HYPERFINE" ) ;
385
394
let hyperfine = hyperfine. as_deref ( ) . unwrap_or ( "hyperfine -w 1 -m 5 --shell=none" ) ;
@@ -391,15 +400,17 @@ impl Command {
391
400
// Make sure we have an up-to-date Miri installed and selected the right toolchain.
392
401
Self :: install ( vec ! [ ] ) ?;
393
402
}
403
+ let baseline_temp_dir = if save_baseline. is_some ( ) { Some ( TempDir :: new ( ) ?) } else { None } ;
394
404
405
+ let miri_dir = miri_dir ( ) ?;
395
406
let sh = Shell :: new ( ) ?;
396
- sh. change_dir ( miri_dir ( ) ? ) ;
407
+ sh. change_dir ( & miri_dir) ;
397
408
let benches_dir = "bench-cargo-miri" ;
398
- let benches: Vec < OsString > = if benches. is_empty ( ) {
409
+ let benches: Vec < String > = if benches. is_empty ( ) {
399
410
sh. read_dir ( benches_dir) ?
400
411
. into_iter ( )
401
412
. filter ( |path| path. is_dir ( ) )
402
- . map ( Into :: into )
413
+ . map ( |path| path . into_os_string ( ) . into_string ( ) . unwrap ( ) )
403
414
. collect ( )
404
415
} else {
405
416
benches. into_iter ( ) . map ( Into :: into) . collect ( )
@@ -414,16 +425,47 @@ impl Command {
414
425
let target_flag = & target_flag;
415
426
let toolchain = active_toolchain ( ) ?;
416
427
// Run the requested benchmarks
417
- for bench in benches {
428
+ for bench in & benches {
418
429
let current_bench = path ! ( benches_dir / bench / "Cargo.toml" ) ;
430
+ let mut export_json = None ;
431
+ if let Some ( baseline_temp_dir) = & baseline_temp_dir {
432
+ export_json = Some ( format ! (
433
+ "--export-json={}" ,
434
+ path!( baseline_temp_dir / format!( "{bench}.bench.json" ) ) . display( )
435
+ ) ) ;
436
+ }
419
437
// We don't attempt to escape `current_bench`, but we wrap it in quotes.
420
438
// That seems to make Windows CI happy.
421
439
cmd ! (
422
440
sh,
423
- "{program_name} {args...} 'cargo +'{toolchain}' miri run '{target_flag}' --manifest-path \" '{current_bench}'\" '"
441
+ "{program_name} {args...} {export_json...} 'cargo +'{toolchain}' miri run '{target_flag}' --manifest-path \" '{current_bench}'\" '"
424
442
)
425
443
. run ( ) ?;
426
444
}
445
+
446
+ // Gather/load results for baseline saving.
447
+
448
+ #[ derive( Serialize , Deserialize ) ]
449
+ struct BenchResult {
450
+ mean : f64 ,
451
+ stddev : f64 ,
452
+ }
453
+
454
+ if let Some ( baseline_file) = save_baseline {
455
+ let baseline_temp_dir = baseline_temp_dir. unwrap ( ) ;
456
+ let mut results: HashMap < & str , BenchResult > = HashMap :: new ( ) ;
457
+ for bench in & benches {
458
+ let result = File :: open ( path ! ( baseline_temp_dir / format!( "{bench}.bench.json" ) ) ) ?;
459
+ let mut result: serde_json:: Value =
460
+ serde_json:: from_reader ( BufReader :: new ( result) ) ?;
461
+ let result: BenchResult = serde_json:: from_value ( result[ "results" ] [ 0 ] . take ( ) ) ?;
462
+ results. insert ( bench, result) ;
463
+ }
464
+
465
+ let baseline = File :: create ( baseline_file) ?;
466
+ serde_json:: to_writer_pretty ( BufWriter :: new ( baseline) , & results) ?;
467
+ }
468
+
427
469
Ok ( ( ) )
428
470
}
429
471
0 commit comments