use log::{debug, error, info}; use obnam_benchmark::junk::junk; use obnam_benchmark::result::Result; use obnam_benchmark::specification::Specification; use obnam_benchmark::suite::Suite; use std::fs::File; use std::path::PathBuf; use std::process::exit; use structopt::StructOpt; fn main() { pretty_env_logger::init_custom_env("OBNAM_BENCHMARK_LOG"); info!("obnam-benchmark starts"); if let Err(err) = real_main() { eprintln!("ERROR: {}", err); error!("{}", err); exit(1); } info!("obnam-benchmark ends successfully"); } fn real_main() -> anyhow::Result<()> { debug!("parsing command line"); let opt = Opt::from_args(); debug!("parsed: {:#?}", opt); match opt.cmd { Command::GenerateJunk(x) => x.run()?, Command::Run(x) => x.run()?, Command::Spec(x) => x.run()?, Command::Steps(x) => x.run()?, } Ok(()) } #[derive(Debug, StructOpt)] struct Opt { #[structopt(subcommand)] cmd: Command, } #[derive(Debug, StructOpt)] enum Command { /// Run benchmarks Run(Run), /// Dump the specification as JSON Spec(Spec), /// Generate some junk data in a file. GenerateJunk(GenerateJunk), /// Show the steps for running a benchmark. Steps(Steps), } #[derive(Debug, StructOpt)] struct Run { /// Name of the specification file #[structopt(parse(from_os_str))] spec: PathBuf, /// Name of file where the results will be written. #[structopt(long, parse(from_os_str))] output: PathBuf, } impl Run { fn run(&self) -> anyhow::Result<()> { info!("running benchmarks from {}", self.spec.display()); let spec = Specification::from_file(&self.spec)?; let mut suite = Suite::new()?; let mut result = Result::default(); for step in spec.steps().iter() { result.push(suite.execute(step)?); } debug!("writing results to {}", self.output.display()); let output = File::create(&self.output)?; serde_json::to_writer_pretty(&output, &result)?; Ok(()) } } #[derive(Debug, StructOpt)] struct Spec { /// Name of the specification file #[structopt(parse(from_os_str))] spec: PathBuf, /// Name of JSON file to write #[structopt(long, parse(from_os_str))] output: PathBuf, } impl Spec { fn run(&self) -> anyhow::Result<()> { info!("dumping specification file as JSON"); debug!("reading specification from {}", self.spec.display()); let input = File::open(&self.spec)?; let spec: Specification = serde_yaml::from_reader(&input)?; debug!("writing specification as JSON to {}", self.output.display()); let output = File::create(&self.output)?; serde_json::to_writer(&output, &spec)?; Ok(()) } } #[derive(Debug, StructOpt)] struct GenerateJunk { /// Number of bytes of junk to create #[structopt()] bytes: u64, /// Name of the output file #[structopt(parse(from_os_str))] filename: PathBuf, } impl GenerateJunk { fn run(&self) -> anyhow::Result<()> { info!( "generating {} bytes of junk into {}", self.bytes, self.filename.display() ); let mut output = File::create(&self.filename)?; junk(&mut output, self.bytes)?; Ok(()) } } #[derive(Debug, StructOpt)] struct Steps { /// Name of the specification file #[structopt(parse(from_os_str))] spec: PathBuf, } impl Steps { fn run(&self) -> anyhow::Result<()> { info!( "showing steps to run benchmarks from {}", self.spec.display() ); let spec = Specification::from_file(&self.spec)?; for step in spec.steps().iter() { println!("{:?}", step); } Ok(()) } }