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 = 4_000;
const UPDATES: usize = 2_000;
const WINDOW_SIZE: usize = 200;

#[derive(Debug)]
struct WindowRow {
    start: usize,
    end: usize,
    p50_ms: f64,
    p95_ms: f64,
    p99_ms: f64,
}

#[derive(Debug)]
struct OverallRow {
    p50_ms: f64,
    p95_ms: f64,
    p99_ms: f64,
    max_ms: f64,
}

fn main() {
    println!("Rust .me sustained mutation benchmark");
    println!("nodes={NODE_COUNT}, updates={UPDATES}, window={WINDOW_SIZE}\n");

    let result = run_sustained_mutation();

    println!("Summary:");
    println!("p50_ms\tp95_ms\tp99_ms\tmax_ms");
    println!(
        "{:.6}\t{:.6}\t{:.6}\t{:.6}",
        result.overall.p50_ms, result.overall.p95_ms, result.overall.p99_ms, result.overall.max_ms
    );

    println!("\nWindowed p95 drift check:");
    println!("window\tp50_ms\tp95_ms\tp99_ms");
    for window in &result.windows {
        println!(
            "{}-{}\t{:.6}\t{:.6}\t{:.6}",
            window.start, window.end, window.p50_ms, window.p95_ms, window.p99_ms
        );
    }

    let first = result
        .windows
        .first()
        .map(|window| window.p95_ms)
        .unwrap_or_default();
    let last = result
        .windows
        .last()
        .map(|window| window.p95_ms)
        .unwrap_or_default();
    let drift = if first > 0.0 {
        (last - first) / first
    } else {
        0.0
    };
    println!("\np95 drift: {:.2}%", drift * 100.0);
}

struct SustainedResult {
    overall: OverallRow,
    windows: Vec<WindowRow>,
}

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

    for index in 1..=NODE_COUNT {
        kernel
            .postulate(format!("items[{index}].value"), 10 + (index % 7) as u64)
            .expect("item value write should succeed");
    }
    kernel
        .postulate("factor", 1_u64)
        .expect("factor write should succeed");
    kernel
        .derive("items[1]", "score", "value * 2")
        .expect("warm item derivation should succeed");
    kernel
        .derive(format!("items[{NODE_COUNT}]"), "score", "value * factor")
        .expect("measured item derivation should succeed");

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

    let mut samples = Vec::with_capacity(UPDATES);

    for update in 1..=UPDATES {
        let factor = (update % 17) + 1;
        let started = Instant::now();
        kernel
            .postulate("factor", factor as u64)
            .expect("factor mutation should succeed");
        let score = kernel
            .read(format!("items[{NODE_COUNT}].score"))
            .cloned()
            .expect("measured score should be readable");
        samples.push(started.elapsed());
        assert_eq!(score, Value::from((base_value() * factor as u64) as f64));
    }

    let mut sorted = samples.clone();
    sorted.sort_unstable();

    let windows = samples
        .chunks(WINDOW_SIZE)
        .enumerate()
        .map(|(index, window)| {
            let mut sorted_window = window.to_vec();
            sorted_window.sort_unstable();
            WindowRow {
                start: index * WINDOW_SIZE + 1,
                end: index * WINDOW_SIZE + window.len(),
                p50_ms: millis(percentile(&sorted_window, 50)),
                p95_ms: millis(percentile(&sorted_window, 95)),
                p99_ms: millis(percentile(&sorted_window, 99)),
            }
        })
        .collect::<Vec<_>>();

    SustainedResult {
        overall: OverallRow {
            p50_ms: millis(percentile(&sorted, 50)),
            p95_ms: millis(percentile(&sorted, 95)),
            p99_ms: millis(percentile(&sorted, 99)),
            max_ms: millis(*sorted.last().expect("samples should not be empty")),
        },
        windows,
    }
}

fn base_value() -> u64 {
    10 + (NODE_COUNT % 7) 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
}