this-me 0.3.0

Rust ground for the modern .me semantic kernel.
Documentation
use std::time::{Duration, Instant};

use this_me::kernel::{Kernel, Value};

const NODE_COUNT: usize = 3_000;
const ITERATIONS: usize = 120;

#[derive(Debug)]
struct BenchRow {
    mode: &'static str,
    p50_ms: f64,
    p95_ms: f64,
    p99_ms: f64,
    k: usize,
}

fn main() {
    println!("Rust .me explain overhead benchmark");
    println!("nodes={NODE_COUNT}, iterations={ITERATIONS}\n");
    println!("mode\tp50_ms\tp95_ms\tp99_ms\tk");

    let baseline = run_loop(setup(), false);
    let with_explain = run_loop(setup(), true);
    let explain_only = run_explain_only(setup());
    let overhead_pct = if baseline.p95_ms > 0.0 {
        ((with_explain.p95_ms - baseline.p95_ms) / baseline.p95_ms) * 100.0
    } else {
        0.0
    };

    print_row(&baseline);
    print_row(&with_explain);
    print_row(&explain_only);
    println!("\np95 overhead: {overhead_pct:.2}%");
}

fn setup() -> Kernel {
    let mut kernel = Kernel::new();

    kernel
        .postulate("factor", 2_u64)
        .expect("factor write should succeed");
    for index in 1..=NODE_COUNT {
        kernel
            .postulate(format!("nodes[{index}].value"), 100 + (index % 13) as u64)
            .expect("node value write should succeed");
        kernel
            .derive(format!("nodes[{index}]"), "out", "value * factor")
            .expect("node derivation should succeed");
    }

    assert_eq!(
        kernel.read(format!("nodes[{NODE_COUNT}].out")),
        Some(&Value::from((base_value() * 2) as f64))
    );
    kernel
}

fn run_loop(mut kernel: Kernel, with_explain: bool) -> BenchRow {
    let mut samples = Vec::with_capacity(ITERATIONS);
    let mut k = 0;

    for iteration in 0..ITERATIONS {
        let factor = (iteration % 9) + 1;
        let started = Instant::now();
        kernel
            .postulate("factor", factor as u64)
            .expect("factor mutation should succeed");
        let result = kernel
            .read(format!("nodes[{NODE_COUNT}].out"))
            .cloned()
            .expect("derived value should be readable");
        assert_eq!(result, Value::from((base_value() * factor as u64) as f64));

        if with_explain {
            let explanation = kernel
                .explain(format!("nodes[{NODE_COUNT}].out"))
                .expect("explain should succeed");
            k = explanation.meta.k;
            assert_eq!(k, NODE_COUNT);
            samples.push(started.elapsed());
        } else {
            samples.push(started.elapsed());
            k = kernel
                .explain(format!("nodes[{NODE_COUNT}].out"))
                .expect("baseline explain after timing should succeed")
                .meta
                .k;
            assert_eq!(k, NODE_COUNT);
        }
    }

    samples.sort_unstable();
    BenchRow {
        mode: if with_explain {
            "with_explain"
        } else {
            "baseline"
        },
        p50_ms: millis(percentile(&samples, 50)),
        p95_ms: millis(percentile(&samples, 95)),
        p99_ms: millis(percentile(&samples, 99)),
        k,
    }
}

fn run_explain_only(mut kernel: Kernel) -> BenchRow {
    kernel
        .postulate("factor", 3_u64)
        .expect("factor mutation should succeed");
    assert_eq!(
        kernel.read(format!("nodes[{NODE_COUNT}].out")),
        Some(&Value::from((base_value() * 3) as f64))
    );

    let mut samples = Vec::with_capacity(ITERATIONS);
    let mut k = 0;

    for _ in 0..ITERATIONS {
        let started = Instant::now();
        let explanation = kernel
            .explain(format!("nodes[{NODE_COUNT}].out"))
            .expect("explain should succeed");
        samples.push(started.elapsed());
        k = explanation.meta.k;
        assert_eq!(k, NODE_COUNT);
    }

    samples.sort_unstable();
    BenchRow {
        mode: "explain_only",
        p50_ms: millis(percentile(&samples, 50)),
        p95_ms: millis(percentile(&samples, 95)),
        p99_ms: millis(percentile(&samples, 99)),
        k,
    }
}

fn print_row(row: &BenchRow) {
    println!(
        "{}\t{:.6}\t{:.6}\t{:.6}\t{}",
        row.mode, row.p50_ms, row.p95_ms, row.p99_ms, row.k
    );
}

fn base_value() -> u64 {
    100 + (NODE_COUNT % 13) as u64
}

fn percentile(samples: &[Duration], percentile: usize) -> Duration {
    assert!(!samples.is_empty());
    let index = ((samples.len() - 1) * percentile).div_ceil(100);
    samples[index.min(samples.len() - 1)]
}

fn millis(duration: Duration) -> f64 {
    duration.as_secs_f64() * 1_000.0
}