Skip to main content

mobench_sdk/
runner.rs

1//! Benchmark execution runtime
2//!
3//! This module provides the execution engine that runs registered benchmarks
4//! and collects timing data.
5
6use crate::registry::{find_benchmark, list_benchmark_names};
7use crate::timing::BenchSpec;
8use crate::types::{BenchError, RunnerReport};
9
10/// Runs a benchmark by name
11///
12/// Looks up the benchmark function in the registry and executes it with the
13/// given specification. The benchmark's runner handles all timing, including
14/// any setup/teardown logic.
15///
16/// # Arguments
17///
18/// * `spec` - Benchmark specification including function name, iterations, and warmup
19///
20/// # Returns
21///
22/// * `Ok(BenchReport)` - Report containing timing samples
23/// * `Err(BenchError)` - If the function is not found or execution fails
24///
25/// # Example
26///
27/// ```ignore
28/// use mobench_sdk::{BenchSpec, run_benchmark};
29///
30/// let spec = BenchSpec {
31///     name: "my_benchmark".to_string(),
32///     iterations: 100,
33///     warmup: 10,
34/// };
35///
36/// let report = run_benchmark(spec)?;
37/// println!("Mean: {} ns", report.mean());
38/// ```
39pub fn run_benchmark(spec: BenchSpec) -> Result<RunnerReport, BenchError> {
40    // Find the benchmark function in the registry
41    let bench_fn = find_benchmark(&spec.name).ok_or_else(|| {
42        let available = list_benchmark_names()
43            .into_iter()
44            .map(String::from)
45            .collect();
46        BenchError::UnknownFunction(spec.name.clone(), available)
47    })?;
48
49    // Call the runner directly - it handles setup/teardown and timing internally
50    let report = (bench_fn.runner)(spec)?;
51
52    Ok(report)
53}
54
55/// Builder for constructing and running benchmarks
56///
57/// Provides a fluent interface for configuring benchmark parameters.
58///
59/// # Example
60///
61/// ```ignore
62/// use mobench_sdk::BenchmarkBuilder;
63///
64/// let report = BenchmarkBuilder::new("my_benchmark")
65///     .iterations(100)
66///     .warmup(10)
67///     .run()?;
68/// ```
69#[derive(Debug, Clone)]
70pub struct BenchmarkBuilder {
71    function: String,
72    iterations: u32,
73    warmup: u32,
74}
75
76impl BenchmarkBuilder {
77    /// Creates a new benchmark builder
78    ///
79    /// # Arguments
80    ///
81    /// * `function` - Name of the benchmark function to run
82    pub fn new(function: impl Into<String>) -> Self {
83        Self {
84            function: function.into(),
85            iterations: 100, // Default
86            warmup: 10,      // Default
87        }
88    }
89
90    /// Sets the number of iterations
91    ///
92    /// # Arguments
93    ///
94    /// * `n` - Number of times to run the benchmark (after warmup)
95    pub fn iterations(mut self, n: u32) -> Self {
96        self.iterations = n;
97        self
98    }
99
100    /// Sets the number of warmup iterations
101    ///
102    /// # Arguments
103    ///
104    /// * `n` - Number of warmup runs (not measured)
105    pub fn warmup(mut self, n: u32) -> Self {
106        self.warmup = n;
107        self
108    }
109
110    /// Runs the benchmark and returns the report
111    ///
112    /// # Returns
113    ///
114    /// * `Ok(BenchReport)` - Report containing timing samples
115    /// * `Err(BenchError)` - If the function is not found or execution fails
116    pub fn run(self) -> Result<RunnerReport, BenchError> {
117        let spec = BenchSpec {
118            name: self.function,
119            iterations: self.iterations,
120            warmup: self.warmup,
121        };
122
123        run_benchmark(spec)
124    }
125}
126
127#[cfg(test)]
128mod tests {
129    use super::*;
130
131    #[test]
132    fn test_builder_defaults() {
133        let builder = BenchmarkBuilder::new("test_fn");
134        assert_eq!(builder.iterations, 100);
135        assert_eq!(builder.warmup, 10);
136    }
137
138    #[test]
139    fn test_builder_customization() {
140        let builder = BenchmarkBuilder::new("test_fn").iterations(50).warmup(5);
141        assert_eq!(builder.iterations, 50);
142        assert_eq!(builder.warmup, 5);
143    }
144}