subms 0.2.1

Zero-dependency perf-test harness for Rust: timed stages, percentiles, and a stable JSON shape consumed by the submillisecond.com cookbook. Includes a `Recipe` trait for cookbook benchmarks.
Documentation
//! Recipe trait: a reusable low-latency component plus its standard
//! benchmark stages. The harness ([`crate::PerfHarness`]) carries timing
//! samples and emits stable JSON for the submillisecond.com cookbook.

use crate::PerfHarness;

/// Parameters shared by every recipe benchmark. Recipes may interpret
/// these per-domain (e.g., `entries` = bloom filter inserts, or LSM keys).
#[derive(Debug, Clone)]
pub struct BenchParams {
    /// Number of work items per stage.
    pub entries: usize,
    /// Number of warm-up items before timed stages begin.
    pub warmup: usize,
    /// Seed for any deterministic RNG used by the recipe.
    pub seed: u64,
}

impl Default for BenchParams {
    fn default() -> Self {
        Self {
            entries: 50_000,
            warmup: 5_000,
            seed: 0,
        }
    }
}

/// A cookbook recipe: a benchmark workload that can be timed through a
/// [`PerfHarness`].
pub trait Recipe {
    /// Workload name as it appears in the harness JSON output.
    fn name(&self) -> &str;

    /// Run the recipe's stages, populating `h` with timed samples.
    fn run(&self, h: &mut PerfHarness, params: &BenchParams);
}

/// Run a recipe and return the populated harness, ready to serialise.
pub fn benchmark<R: Recipe + ?Sized>(recipe: &R, params: &BenchParams) -> PerfHarness {
    let mut h = PerfHarness::new(recipe.name(), "rust");
    h.input("entries", &params.entries.to_string());
    h.input("warmup", &params.warmup.to_string());
    h.input("seed", &params.seed.to_string());
    recipe.run(&mut h, params);
    h
}