use std::time::{Duration, Instant};
fn percentile(mut samples: Vec<Duration>, p: f64) -> Duration {
samples.sort();
let idx = ((p / 100.0) * (samples.len() - 1) as f64).round() as usize;
samples[idx]
}
fn main() {
let _ = std::hint::black_box(exocortex_pack_dev_v1::pack_def().name.clone());
let _ = std::hint::black_box(exocortex_pack_mortgage_v1::pack_def().name.clone());
let functions = exocortex_kernel::verbs::registered_pack_functions();
assert!(
!functions.is_empty(),
"the pack-function registry must not be empty: the mortgage pack declares one"
);
let m = std::env::var("SLO_MULTIPLIER")
.ok()
.and_then(|v| v.parse::<f64>().ok())
.unwrap_or(1.0)
.clamp(1.0, 3.0);
if m != 1.0 {
println!("SLO budgets relaxed x{m} (SLO_MULTIPLIER)");
}
let mut all_ok = true;
for reg in functions {
let input = sample_input_from_schema(&(reg.input_schema)());
let run = || exocortex_ops::eval_pack_function_cached(reg.body, &input);
for _ in 0..50 {
run().expect("pack function executes");
}
let mut samples: Vec<Duration> = Vec::with_capacity(1000);
for _ in 0..1000 {
let t0 = Instant::now();
run().expect("pack function executes");
samples.push(t0.elapsed());
}
let p50 = percentile(samples.clone(), 50.0);
let p99 = percentile(samples.clone(), 99.0);
let p50_budget = Duration::from_micros(reg.p50_budget_us as u64).mul_f64(m);
let p99_budget = Duration::from_micros(reg.p99_budget_us as u64).mul_f64(m);
let ok = p50 < p50_budget && p99 < p99_budget;
println!(
"{}::{}: p50={p50:?} (budget {p50_budget:?}) p99={p99:?} (budget {p99_budget:?}) โ {}",
reg.pack_name,
reg.verb_name,
if ok { "PASS" } else { "FAIL" }
);
all_ok &= ok;
}
println!(
"pack-function SLO gate: {}",
if all_ok { "PASS" } else { "FAIL" }
);
if !all_ok {
std::process::exit(1);
}
}
fn sample_input_from_schema(schema: &schemars::schema::RootSchema) -> serde_json::Value {
use schemars::schema::{InstanceType, Schema};
use serde_json::json;
let mut out = serde_json::Map::new();
let Some(object) = &schema.schema.object else {
return json!({});
};
for (name, schema) in object.properties.iter() {
let value = match schema {
Schema::Object(o) if o.instance_type == Some(InstanceType::Boolean.into()) => {
json!(true)
}
_ => json!("categorical"),
};
out.insert(name.clone(), value);
}
serde_json::Value::Object(out)
}