Skip to content

Commit 38e3ebc

Browse files
committed
miri-script: support saving bench results in a baseline JSON file
1 parent 58ad698 commit 38e3ebc

File tree

4 files changed

+60
-10
lines changed

4 files changed

+60
-10
lines changed

Diff for: src/tools/miri/miri-script/Cargo.lock

+2
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,8 @@ dependencies = [
250250
"itertools",
251251
"path_macro",
252252
"rustc_version",
253+
"serde",
254+
"serde_derive",
253255
"serde_json",
254256
"shell-words",
255257
"tempfile",

Diff for: src/tools/miri/miri-script/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ xshell = "0.2.6"
2323
rustc_version = "0.4"
2424
dunce = "1.0.4"
2525
directories = "5"
26+
serde = "1"
2627
serde_json = "1"
28+
serde_derive = "1"
2729
tempfile = "3.13.0"
2830
clap = { version = "4.5.21", features = ["derive"] }

Diff for: src/tools/miri/miri-script/src/commands.rs

+51-9
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
1+
use std::collections::HashMap;
12
use std::ffi::{OsStr, OsString};
2-
use std::io::Write;
3+
use std::fs::File;
4+
use std::io::{BufReader, BufWriter, Write};
35
use std::ops::{Not, Range};
46
use std::path::PathBuf;
57
use std::time::Duration;
68
use std::{env, net, process};
79

810
use anyhow::{Context, Result, anyhow, bail};
911
use path_macro::path;
12+
use serde_derive::{Deserialize, Serialize};
13+
use tempfile::TempDir;
1014
use walkdir::WalkDir;
1115
use xshell::{Shell, cmd};
1216

@@ -179,8 +183,8 @@ impl Command {
179183
Command::Doc { flags } => Self::doc(flags),
180184
Command::Fmt { flags } => Self::fmt(flags),
181185
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),
184188
Command::Toolchain { flags } => Self::toolchain(flags),
185189
Command::RustcPull { commit } => Self::rustc_pull(commit.clone()),
186190
Command::RustcPush { github_user, branch } => Self::rustc_push(github_user, branch),
@@ -379,7 +383,12 @@ impl Command {
379383
Ok(())
380384
}
381385

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<()> {
383392
// The hyperfine to use
384393
let hyperfine = env::var("HYPERFINE");
385394
let hyperfine = hyperfine.as_deref().unwrap_or("hyperfine -w 1 -m 5 --shell=none");
@@ -391,15 +400,17 @@ impl Command {
391400
// Make sure we have an up-to-date Miri installed and selected the right toolchain.
392401
Self::install(vec![])?;
393402
}
403+
let baseline_temp_dir = if save_baseline.is_some() { Some(TempDir::new()?) } else { None };
394404

405+
let miri_dir = miri_dir()?;
395406
let sh = Shell::new()?;
396-
sh.change_dir(miri_dir()?);
407+
sh.change_dir(&miri_dir);
397408
let benches_dir = "bench-cargo-miri";
398-
let benches: Vec<OsString> = if benches.is_empty() {
409+
let benches: Vec<String> = if benches.is_empty() {
399410
sh.read_dir(benches_dir)?
400411
.into_iter()
401412
.filter(|path| path.is_dir())
402-
.map(Into::into)
413+
.map(|path| path.into_os_string().into_string().unwrap())
403414
.collect()
404415
} else {
405416
benches.into_iter().map(Into::into).collect()
@@ -414,16 +425,47 @@ impl Command {
414425
let target_flag = &target_flag;
415426
let toolchain = active_toolchain()?;
416427
// Run the requested benchmarks
417-
for bench in benches {
428+
for bench in &benches {
418429
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+
}
419437
// We don't attempt to escape `current_bench`, but we wrap it in quotes.
420438
// That seems to make Windows CI happy.
421439
cmd!(
422440
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}'\"'"
424442
)
425443
.run()?;
426444
}
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+
427469
Ok(())
428470
}
429471

Diff for: src/tools/miri/miri-script/src/main.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#![allow(clippy::needless_question_mark)]
1+
#![allow(clippy::needless_question_mark, rustc::internal)]
22

33
mod commands;
44
mod coverage;
@@ -117,6 +117,10 @@ pub enum Command {
117117
/// When `true`, skip the `./miri install` step.
118118
#[arg(long)]
119119
no_install: bool,
120+
/// Store the benchmark result in the given file, so it can be used
121+
/// as the baseline for a future run.
122+
#[arg(long)]
123+
save_baseline: Option<String>,
120124
/// List of benchmarks to run (default: run all benchmarks).
121125
benches: Vec<String>,
122126
},

0 commit comments

Comments
 (0)