use std::time::Instant;
use afterburner::{Afterburner, AfterburnerError, FuelGauge, ScriptId};
use serde_json::{Value, json};
const SIZES: &[(&str, usize)] = &[
("1 KiB", 1024),
("1 MiB", 1024 * 1024),
("22 MB", 22 * 1000 * 1000),
];
fn gauge(fuel: Option<u64>) -> FuelGauge {
FuelGauge {
fuel,
..FuelGauge::unlimited()
}
}
fn measure_fuel(call: &dyn Fn(&FuelGauge) -> Result<Value, AfterburnerError>) -> u64 {
let mut hi: u64 = 1 << 20;
loop {
match call(&gauge(Some(hi))) {
Ok(_) => break,
Err(AfterburnerError::FuelExhausted) => {
hi = hi.checked_mul(2).expect("fuel bracket overflow");
}
Err(e) => panic!("unexpected error while bracketing fuel: {e:?}"),
}
}
let mut lo = hi / 2;
while hi - lo > hi / 512 {
let mid = lo + (hi - lo) / 2;
match call(&gauge(Some(mid))) {
Ok(_) => hi = mid,
Err(AfterburnerError::FuelExhausted) => lo = mid,
Err(e) => panic!("unexpected error while bisecting fuel: {e:?}"),
}
}
hi
}
fn time_one(call: &dyn Fn(&FuelGauge) -> Result<Value, AfterburnerError>) -> f64 {
let mut samples: Vec<f64> = (0..3)
.map(|_| {
let t = Instant::now();
call(&gauge(None)).expect("timed run failed");
t.elapsed().as_secs_f64() * 1e3
})
.collect();
samples.sort_by(|a, b| a.partial_cmp(b).expect("non-NaN"));
samples[1]
}
fn report(
label: &str,
size_label: &str,
call: &dyn Fn(&FuelGauge) -> Result<Value, AfterburnerError>,
) {
let ms = time_one(call);
let fuel = measure_fuel(call);
println!("{label:<14} {size_label:>6} fuel={fuel:>14} wall={ms:>9.2} ms");
}
fn main() {
let ab = Afterburner::new().expect("engine build");
let json_id: ScriptId = ab
.register("module.exports = (d) => d.payload.length")
.expect("register json script");
for (size_label, n) in SIZES {
let payload = "a".repeat(*n);
let input = json!({ "payload": payload });
report("json-input", size_label, &|g: &FuelGauge| {
ab.run_with(&json_id, &input, g)
});
}
let get_again_id = ab
.register("module.exports = (d) => __AB_GET_INPUT__().length")
.expect("register get-again script");
for (size_label, n) in SIZES {
let payload = "a".repeat(*n);
let input = json!({ "payload": payload });
report("json+get-again", size_label, &|g: &FuelGauge| {
ab.run_with(&get_again_id, &input, g)
});
}
let raw_id = ab
.register("module.exports = (bytes) => bytes.length")
.expect("register raw script");
for (size_label, n) in SIZES {
let payload = vec![b'a'; *n];
report("raw-input", size_label, &|g: &FuelGauge| {
ab.run_raw_with(&raw_id, &payload, g)
});
}
}