aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAria <me@aria.rip>2023-10-31 16:04:51 +0000
committerAria <me@aria.rip>2023-10-31 16:04:51 +0000
commit81917b800b206621e39a4d83b347e7b31d717645 (patch)
tree229540a2f4a6111aff6bbf1ff575e0307c94f1c9
parent8a2b8dbc30e32c4112088b67c1d39f55175439a4 (diff)
feat(benchmarker): cleaner interface for running benchmarks
-rw-r--r--primrose/crates/candelabra-benchmarker/examples/run_vec.rs8
-rw-r--r--primrose/crates/candelabra-benchmarker/src/container.rs21
-rw-r--r--primrose/crates/candelabra-benchmarker/src/indexable.rs19
-rw-r--r--primrose/crates/candelabra-benchmarker/src/lib.rs94
-rw-r--r--primrose/crates/candelabra-benchmarker/src/results.rs66
-rw-r--r--primrose/crates/candelabra-benchmarker/src/stack.rs20
6 files changed, 127 insertions, 101 deletions
diff --git a/primrose/crates/candelabra-benchmarker/examples/run_vec.rs b/primrose/crates/candelabra-benchmarker/examples/run_vec.rs
index 677a538..5dd60da 100644
--- a/primrose/crates/candelabra-benchmarker/examples/run_vec.rs
+++ b/primrose/crates/candelabra-benchmarker/examples/run_vec.rs
@@ -1,9 +1,13 @@
-use candelabra_benchmarker::{ContainerExt, IndexableExt};
+use candelabra_benchmarker::Benchmarker;
const NS: [usize; 3] = [1, 10, 100];
fn main() {
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("debug")).init();
- dbg!(Vec::<usize>::benchmark_container(&NS).merge(Vec::<usize>::benchmark_indexable(&NS)));
+ dbg!(Benchmarker::<Vec<usize>, usize>::with_ns(&NS)
+ .container()
+ .indexable()
+ .stack()
+ .finish());
}
diff --git a/primrose/crates/candelabra-benchmarker/src/container.rs b/primrose/crates/candelabra-benchmarker/src/container.rs
index 1f5eb45..f32594f 100644
--- a/primrose/crates/candelabra-benchmarker/src/container.rs
+++ b/primrose/crates/candelabra-benchmarker/src/container.rs
@@ -4,12 +4,10 @@ use log::debug;
use primrose_library::traits::Container;
use rand::{distributions::Standard, prelude::Distribution, random, thread_rng, Rng};
-use crate::{bench::benchmark_op, Results, RunResults, SingleNResults};
+use crate::{bench::benchmark_op, RunResults, SingleNResults};
+/// Benchmark [`primrose_library::traits::Container`] operations
pub trait ContainerExt<E> {
- /// Benchmark at the given `ns`.
- fn benchmark_container(ns: &[usize]) -> Results;
-
/// Benchmark at a single `n`.
fn benchmark_container_at(n: usize) -> SingleNResults;
@@ -35,21 +33,6 @@ where
E: Clone,
Standard: Distribution<E>,
{
- fn benchmark_container(ns: &[usize]) -> Results {
- debug!(
- "Benchmarking {} at {} different n values",
- type_name::<T>(),
- ns.len()
- );
-
- let mut by_n = HashMap::new();
- for n in ns {
- by_n.insert(*n, Self::benchmark_container_at(*n));
- }
-
- Results { by_n }
- }
-
fn benchmark_container_at(n: usize) -> SingleNResults {
let mut by_op = HashMap::new();
diff --git a/primrose/crates/candelabra-benchmarker/src/indexable.rs b/primrose/crates/candelabra-benchmarker/src/indexable.rs
index 122ec58..915d093 100644
--- a/primrose/crates/candelabra-benchmarker/src/indexable.rs
+++ b/primrose/crates/candelabra-benchmarker/src/indexable.rs
@@ -6,10 +6,8 @@ use rand::{distributions::Standard, prelude::Distribution, random};
use crate::{benchmark_op, Results, RunResults, SingleNResults};
+/// Benchmark [`primrose_library::traits::Indexable`] operations
pub trait IndexableExt<E> {
- /// Benchmark at the given `ns`.
- fn benchmark_indexable(ns: &[usize]) -> Results;
-
/// Benchmark at a single `n`.
fn benchmark_indexable_at(n: usize) -> SingleNResults;
@@ -28,21 +26,6 @@ where
T: Container<E> + Indexable<E> + Default,
Standard: Distribution<E>,
{
- fn benchmark_indexable(ns: &[usize]) -> Results {
- debug!(
- "Benchmarking {} at {} different n values",
- type_name::<T>(),
- ns.len()
- );
-
- let mut by_n = HashMap::new();
- for n in ns {
- by_n.insert(*n, Self::benchmark_indexable_at(*n));
- }
-
- Results { by_n }
- }
-
fn benchmark_indexable_at(n: usize) -> SingleNResults {
let mut by_op = HashMap::new();
diff --git a/primrose/crates/candelabra-benchmarker/src/lib.rs b/primrose/crates/candelabra-benchmarker/src/lib.rs
index 1e46af4..3361048 100644
--- a/primrose/crates/candelabra-benchmarker/src/lib.rs
+++ b/primrose/crates/candelabra-benchmarker/src/lib.rs
@@ -1,6 +1,6 @@
-use std::{collections::HashMap, time::Duration};
-
mod bench;
+use std::{collections::HashMap, marker::PhantomData};
+
pub use bench::benchmark_op;
mod container;
@@ -12,60 +12,66 @@ pub use indexable::IndexableExt;
mod stack;
pub use stack::StackExt;
-/// Results for a whole suite of benchmarks
-#[derive(Debug, Clone)]
-pub struct Results {
- /// Results for each collection size tested with
- pub by_n: HashMap<usize, SingleNResults>,
-}
+mod results;
+pub use results::*;
-/// Name of an operation
-pub type OpName = &'static str;
+/// Runs benchmarks at varying `n`s with a builder-style interface.
+///
+/// This mostly just makes our code generation easier.
+pub struct Benchmarker<T, E>(&'static [usize], Results, PhantomData<(T, E)>);
+impl<T, E> Benchmarker<T, E> {
+ /// Create a benchmarker that will repeat all benchmarks with each of the given n values.
+ pub fn with_ns(ns: &'static [usize]) -> Self {
+ Self(
+ ns,
+ Results {
+ by_n: HashMap::new(),
+ },
+ PhantomData::default(),
+ )
+ }
-/// Results for operations all ran at the same container size
-#[derive(Debug, Clone)]
-pub struct SingleNResults {
- /// Results for each operation
- pub by_op: HashMap<OpName, RunResults>,
+ /// Finish benchmarking and get the results
+ pub fn finish(self) -> Results {
+ self.1
+ }
}
-/// Results for a single benchmark
-#[derive(Debug, Clone)]
-pub struct RunResults {
- /// Number of times the benchmark was run
- pub times: usize,
-
- /// The minimum time taken
- pub min: Duration,
-
- /// The maximum time taken
- pub max: Duration,
+impl<T, E> Benchmarker<T, E>
+where
+ T: ContainerExt<E>,
+{
+ /// Run benchmarks for [`primrose_library::traits::Container`] operations.
+ pub fn container(mut self) -> Self {
+ for n in self.0 {
+ self.1.add(*n, T::benchmark_container_at(*n));
+ }
- /// The average (mean) time taken
- pub avg: Duration,
+ self
+ }
}
-
-impl Results {
- pub fn merge(&mut self, b: Self) -> &mut Self {
- for (n, res_b) in b.by_n {
- self.by_n
- .entry(n)
- .and_modify(|res_a| {
- res_a.merge(res_b.clone());
- })
- .or_insert(res_b);
+impl<T, E> Benchmarker<T, E>
+where
+ T: IndexableExt<E>,
+{
+ /// Run benchmarks for [`primrose_library::traits::Indexable`] operations.
+ pub fn indexable(mut self) -> Self {
+ for n in self.0 {
+ self.1.add(*n, T::benchmark_indexable_at(*n));
}
self
}
}
-impl SingleNResults {
- /// Merge results from `b` into these results.
- /// If `b` contains benchmarks for operations we have a result for, results from `b` are preferred.
- pub fn merge(&mut self, b: Self) -> &mut Self {
- for (name, res_b) in b.by_op {
- self.by_op.insert(name, res_b);
+impl<T, E> Benchmarker<T, E>
+where
+ T: StackExt<E>,
+{
+ /// Run benchmarks for [`primrose_library::traits::Stack`] operations.
+ pub fn stack(mut self) -> Self {
+ for n in self.0 {
+ self.1.add(*n, T::benchmark_stack_at(*n));
}
self
diff --git a/primrose/crates/candelabra-benchmarker/src/results.rs b/primrose/crates/candelabra-benchmarker/src/results.rs
new file mode 100644
index 0000000..835a6e7
--- /dev/null
+++ b/primrose/crates/candelabra-benchmarker/src/results.rs
@@ -0,0 +1,66 @@
+use std::{collections::HashMap, time::Duration};
+
+/// Results for a whole suite of benchmarks
+#[derive(Debug, Clone)]
+pub struct Results {
+ /// Results for each collection size tested with
+ pub by_n: HashMap<usize, SingleNResults>,
+}
+
+/// Name of an operation
+pub type OpName = &'static str;
+
+/// Results for operations all ran at the same container size
+#[derive(Debug, Clone)]
+pub struct SingleNResults {
+ /// Results for each operation
+ pub by_op: HashMap<OpName, RunResults>,
+}
+
+/// Results for a single benchmark
+#[derive(Debug, Clone)]
+pub struct RunResults {
+ /// Number of times the benchmark was run
+ pub times: usize,
+
+ /// The minimum time taken
+ pub min: Duration,
+
+ /// The maximum time taken
+ pub max: Duration,
+
+ /// The average (mean) time taken
+ pub avg: Duration,
+}
+
+impl Results {
+ pub fn add(&mut self, n: usize, b: SingleNResults) -> &mut Self {
+ self.by_n
+ .entry(n)
+ .and_modify(|res_a| {
+ res_a.merge(b.clone());
+ })
+ .or_insert(b);
+
+ self
+ }
+ pub fn merge(&mut self, b: Self) -> &mut Self {
+ for (n, res_b) in b.by_n {
+ self.add(n, res_b);
+ }
+
+ self
+ }
+}
+
+impl SingleNResults {
+ /// Merge results from `b` into these results.
+ /// If `b` contains benchmarks for operations we have a result for, results from `b` are preferred.
+ pub fn merge(&mut self, b: Self) -> &mut Self {
+ for (name, res_b) in b.by_op {
+ self.by_op.insert(name, res_b);
+ }
+
+ self
+ }
+}
diff --git a/primrose/crates/candelabra-benchmarker/src/stack.rs b/primrose/crates/candelabra-benchmarker/src/stack.rs
index 4010cae..f6b32f0 100644
--- a/primrose/crates/candelabra-benchmarker/src/stack.rs
+++ b/primrose/crates/candelabra-benchmarker/src/stack.rs
@@ -6,10 +6,8 @@ use rand::{distributions::Standard, prelude::Distribution, random};
use crate::{benchmark_op, Results, RunResults, SingleNResults};
+/// Benchmark [`primrose_library::traits::Stack`] operations
pub trait StackExt<E> {
- /// Benchmark at the given `ns`.
- fn benchmark_stack(ns: &[usize]) -> Results;
-
/// Benchmark at a single `n`.
fn benchmark_stack_at(n: usize) -> SingleNResults;
@@ -19,26 +17,12 @@ pub trait StackExt<E> {
/// Benchmark `pop` at a single `n`.
fn benchmark_stack_pop(n: usize) -> RunResults;
}
+
impl<T, E> StackExt<E> for T
where
T: Stack<E> + Default,
Standard: Distribution<E>,
{
- fn benchmark_stack(ns: &[usize]) -> Results {
- debug!(
- "Benchmarking {} at {} different n values",
- type_name::<T>(),
- ns.len()
- );
-
- let mut by_n = HashMap::new();
- for n in ns {
- by_n.insert(*n, Self::benchmark_stack_at(*n));
- }
-
- Results { by_n }
- }
-
fn benchmark_stack_at(n: usize) -> SingleNResults {
let mut by_op = HashMap::new();