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}