use std::hint::black_box;
use std::time::{Duration, Instant};
use airsl::{Engine, Policy, ResourceLimits, Script};
const FULL_ITERATIONS: usize = 1000;
const SMOKE_ITERATIONS: usize = 10;
const TRIVIAL: &str = "return 1";
const fn unbounded() -> Policy {
Policy::confined().with_limits(ResourceLimits::none())
}
const CALLBACK_HEAVY: &str = "for i = 1, 1000 do airsstack.json.encode({ a = i }) end return 1";
fn main() -> Result<(), airsl::Error> {
let iterations = if std::env::args().any(|arg| arg == "--bench") {
FULL_ITERATIONS
} else {
SMOKE_ITERATIONS
};
println!("iterations: {iterations}");
for (label, policy) in [
("ceilings armed", Policy::confined()),
("no ceilings", unbounded()),
] {
report(
&format!("engine construction, {label}"),
iterations,
construction(&policy, iterations)?,
);
report(
&format!("eval, reused engine, trivial, {label}"),
iterations,
reused(&policy, TRIVIAL, iterations)?,
);
report(
&format!("eval, reused engine, callback-heavy, {label}"),
iterations,
reused(&policy, CALLBACK_HEAVY, iterations)?,
);
report(
&format!("eval, fresh engine, trivial, {label}"),
iterations,
fresh(&policy, iterations)?,
);
}
Ok(())
}
fn report(label: &str, iterations: usize, elapsed: Duration) {
let divisor = u128::try_from(iterations).unwrap_or(1).max(1);
let per = elapsed.as_nanos() / divisor;
println!("{label:<52} {per:>10} ns/iter");
}
fn construction(policy: &Policy, iterations: usize) -> Result<Duration, airsl::Error> {
let start = Instant::now();
for _ in 0..iterations {
let engine = Engine::builder().policy(policy.clone()).build()?;
black_box(&engine);
}
Ok(start.elapsed())
}
fn reused(policy: &Policy, source: &str, iterations: usize) -> Result<Duration, airsl::Error> {
let engine = Engine::builder().policy(policy.clone()).build()?;
let script = Script::from_source(source, "bench")?;
let start = Instant::now();
for _ in 0..iterations {
black_box(engine.eval_to::<i64>(&script)?);
}
Ok(start.elapsed())
}
fn fresh(policy: &Policy, iterations: usize) -> Result<Duration, airsl::Error> {
let script = Script::from_source(TRIVIAL, "bench")?;
let start = Instant::now();
for _ in 0..iterations {
let engine = Engine::builder().policy(policy.clone()).build()?;
black_box(engine.eval_to::<i64>(&script)?);
}
Ok(start.elapsed())
}