summaryrefslogtreecommitdiff
path: root/src/suite.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/suite.rs')
-rw-r--r--src/suite.rs153
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))
+ }
+}