diff options
Diffstat (limited to 'src/suite.rs')
-rw-r--r-- | src/suite.rs | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/src/suite.rs b/src/suite.rs new file mode 100644 index 0000000..4e35723 --- /dev/null +++ b/src/suite.rs @@ -0,0 +1,153 @@ +use crate::result::{Measurement, OpMeasurements, Operation}; +use crate::specification::{Create, FileCount}; +use crate::step::Step; +use log::{debug, info}; +use std::fs::File; +use std::path::PathBuf; +use std::time::Instant; +use tempfile::{tempdir, TempDir}; + +/// A running benchmark suite. +/// +/// This manages temporary data created for the benchmarks, and +/// executes individual steps in the suite. +pub struct Suite { + benchmark: Option<Benchmark>, +} + +/// Possible errors from running a benchmark suite. +#[derive(Debug, thiserror::Error)] +pub enum SuiteError { + /// Error creating a temporary directory. + #[error(transparent)] + TempDir(#[from] std::io::Error), + + /// File creation failed. + #[error("Failed to create file {0}: {1}")] + CreateFile(PathBuf, std::io::Error), +} + +impl Suite { + pub fn new() -> Result<Self, SuiteError> { + Ok(Self { benchmark: None }) + } + + /// Execute one step in the benchmark suite. + /// + /// Return a measurement of the step. + pub fn execute(&mut self, step: &Step) -> Result<OpMeasurements, SuiteError> { + debug!("executing step {:?}", step); + let time = Instant::now(); + let mut om = match step { + Step::Start(name) => { + assert!(self.benchmark.is_none()); + let mut benchmark = Benchmark::new(name)?; + let om = benchmark.start()?; + self.benchmark = Some(benchmark); + om + } + Step::Stop(name) => { + assert!(self.benchmark.is_some()); + assert_eq!(name, self.benchmark.as_ref().unwrap().name()); + let om = self.benchmark.as_mut().unwrap().stop()?; + self.benchmark = None; + om + } + Step::Create(x) => { + assert!(self.benchmark.is_some()); + self.benchmark.as_mut().unwrap().create(x)? + } + Step::Rename(x) => { + assert!(self.benchmark.is_some()); + self.benchmark.as_mut().unwrap().rename(x)? + } + Step::Delete(x) => { + assert!(self.benchmark.is_some()); + self.benchmark.as_mut().unwrap().delete(x)? + } + Step::Backup(x) => { + assert!(self.benchmark.is_some()); + self.benchmark.as_mut().unwrap().backup(*x)? + } + Step::Restore(x) => { + assert!(self.benchmark.is_some()); + self.benchmark.as_mut().unwrap().restore(*x)? + } + }; + + let t = std::time::Duration::from_millis(10); + std::thread::sleep(t); + + let ms = time.elapsed().as_millis(); + debug!("step duration was {} ms", ms); + om.push(Measurement::DurationMs(ms)); + Ok(om) + } +} + +struct Benchmark { + name: String, + tempdir: Option<TempDir>, +} + +impl Benchmark { + fn new(name: &str) -> Result<Self, SuiteError> { + Ok(Self { + name: name.to_string(), + tempdir: Some(tempdir()?), + }) + } + + fn name(&self) -> &str { + &self.name + } + + fn tempdir(&self) -> &TempDir { + self.tempdir.as_ref().unwrap() + } + + fn start(&mut self) -> Result<OpMeasurements, SuiteError> { + info!("starting benchmark {}", self.name()); + Ok(OpMeasurements::new(self.name(), Operation::Start)) + } + + fn stop(&mut self) -> Result<OpMeasurements, SuiteError> { + info!("ending benchmark {}", self.name); + self.tempdir.take().unwrap().close()?; + Ok(OpMeasurements::new(self.name(), Operation::Stop)) + } + + fn create(&mut self, create: &Create) -> Result<OpMeasurements, SuiteError> { + info!("creating {} test data files", create.files); + let tempdir = self.tempdir().path(); + debug!("creating {} files in {}", create.files, tempdir.display()); + + for i in 0..create.files { + let filename = tempdir.join(format!("{}", i)); + debug!("creating {}", filename.display()); + File::create(&filename).map_err(|err| SuiteError::CreateFile(filename, err))?; + } + + Ok(OpMeasurements::new(self.name(), Operation::Create)) + } + + fn rename(&mut self, count: &FileCount) -> Result<OpMeasurements, SuiteError> { + info!("renaming {} test data files", count.files); + Ok(OpMeasurements::new(self.name(), Operation::Rename)) + } + + fn delete(&mut self, count: &FileCount) -> Result<OpMeasurements, SuiteError> { + info!("deleting {} test data files", count.files); + Ok(OpMeasurements::new(self.name(), Operation::Delete)) + } + + fn backup(&mut self, n: usize) -> Result<OpMeasurements, SuiteError> { + info!("making backup {} in benchmark {}", n, self.name()); + Ok(OpMeasurements::new(self.name(), Operation::Backup)) + } + + fn restore(&mut self, n: usize) -> Result<OpMeasurements, SuiteError> { + info!("restoring backup {} in benchmark {}", n, self.name()); + Ok(OpMeasurements::new(self.name(), Operation::Restore)) + } +} |