use std::{
env, fs,
fs::File,
io::{self, BufRead, BufReader, Write},
path::{Path, PathBuf},
process::{Command, Stdio},
thread,
time::{SystemTime, UNIX_EPOCH},
};
fn main() {
if let Err(error) = run() {
eprintln!("msrt bench log error: {error}");
std::process::exit(1);
}
}
fn run() -> io::Result<()> {
let args: Vec<String> = env::args().skip(1).collect();
let log_path = log_path()?;
for bench in ["poll", "protocol"] {
run_bench(bench, &args, &log_path)?;
}
println!("cargo bench log written to {}", log_path.display());
Ok(())
}
fn run_bench(bench: &str, args: &[String], log_path: &Path) -> io::Result<()> {
let mut command = Command::new("cargo");
command.arg("bench").arg("--bench").arg(bench);
command.args(args);
command.stdout(Stdio::piped()).stderr(Stdio::piped());
let mut child = command.spawn()?;
let stdout = child
.stdout
.take()
.ok_or_else(|| io::Error::other("missing cargo bench stdout"))?;
let stderr = child
.stderr
.take()
.ok_or_else(|| io::Error::other("missing cargo bench stderr"))?;
let stdout_log = log_path.to_path_buf();
let stdout_thread = thread::spawn(move || tee_reader(stdout, stdout_log, false));
let stderr_log = log_path.to_path_buf();
let stderr_thread = thread::spawn(move || tee_reader(stderr, stderr_log, true));
let status = child.wait()?;
join_thread(stdout_thread)?;
join_thread(stderr_thread)?;
if status.success() {
Ok(())
} else {
Err(io::Error::other(format!(
"cargo bench exited with {status}"
)))
}
}
fn log_path() -> io::Result<PathBuf> {
let dir = Path::new("log");
fs::create_dir_all(dir)?;
let timestamp = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map_err(io::Error::other)?
.as_secs();
Ok(dir.join(format!("cargo-bench-{timestamp}.log")))
}
fn tee_reader<R>(reader: R, log_path: PathBuf, stderr: bool) -> io::Result<()>
where
R: io::Read,
{
let mut log = File::options().create(true).append(true).open(log_path)?;
for line in BufReader::new(reader).lines() {
let line = line?;
if stderr {
eprintln!("{line}");
} else {
println!("{line}");
}
writeln!(log, "{line}")?;
}
Ok(())
}
fn join_thread(thread: thread::JoinHandle<io::Result<()>>) -> io::Result<()> {
thread
.join()
.map_err(|_| io::Error::other("bench log thread panicked"))?
}