#![allow(clippy::unwrap_used)]
use std::env;
use std::fs;
use std::path::PathBuf;
use std::process::exit;
use std::time::Instant;
use dellingr::{ArgCount, RetCount, State};
const WARM_ITERATIONS: u32 = 20;
const DEFAULT_TARGET: &str = "numerics/arithmetic";
fn main() {
let _guard = hotpath::HotpathGuardBuilder::new("dellingr::hotpath")
.percentiles(&[50.0, 95.0, 99.0])
.functions_limit(0)
.build();
let target = env::args()
.nth(1)
.unwrap_or_else(|| DEFAULT_TARGET.to_string());
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let script_path = manifest_dir.join("examples").join(format!("{target}.lua"));
let source = match fs::read_to_string(&script_path) {
Ok(s) => s,
Err(e) => {
eprintln!("Failed to read {}: {e}", script_path.display());
exit(1);
}
};
let chunk_name = format!("@examples/{target}.lua");
let mut state = State::new();
let parse_start = Instant::now();
if let Err(e) = state.load_string_named(&source, Some(chunk_name)) {
eprintln!("Parse error in {}: {e}", script_path.display());
exit(1);
}
let parse_us = parse_start.elapsed().as_micros();
if let Err(e) = state.call(ArgCount::Fixed(0), RetCount::Fixed(0)) {
eprintln!("Chunk run error in {}: {e}", script_path.display());
exit(1);
}
let setup_cost = state.cost_used();
let setup_heap_bytes = state.heap_size();
let setup_object_count = state.object_count();
state.get_global("_bench");
let cold_start = Instant::now();
if let Err(e) = state.call(ArgCount::Fixed(0), RetCount::Fixed(0)) {
eprintln!("Cold _bench call error in {}: {e}", script_path.display());
exit(1);
}
let cold_call_us = cold_start.elapsed().as_micros();
let cold_cost = state.cost_used() - setup_cost;
let warm_start = Instant::now();
for _ in 0..WARM_ITERATIONS {
state.get_global("_bench");
if let Err(e) = state.call(ArgCount::Fixed(0), RetCount::Fixed(0)) {
eprintln!("Warm _bench call error in {}: {e}", script_path.display());
exit(1);
}
}
let warm_total_us = warm_start.elapsed().as_micros();
let warm_avg_us = warm_total_us / u128::from(WARM_ITERATIONS);
let warm_total_cost = state.cost_used() - setup_cost - cold_cost;
let warm_avg_cost = warm_total_cost / u64::from(WARM_ITERATIONS);
let cost_per_us = if warm_avg_us > 0 {
warm_avg_cost as f64 / warm_avg_us as f64
} else {
0.0
};
let final_heap_bytes = state.heap_size();
let final_object_count = state.object_count();
eprintln!("target={target}");
eprintln!("parse_us={parse_us}");
eprintln!("cold_call_us={cold_call_us}");
eprintln!("cold_cost={cold_cost}");
eprintln!("warm_iterations={WARM_ITERATIONS}");
eprintln!("warm_avg_us={warm_avg_us}");
eprintln!("warm_avg_cost={warm_avg_cost}");
eprintln!("cost_per_us={cost_per_us:.2}");
eprintln!("setup_heap_bytes={setup_heap_bytes}");
eprintln!("setup_object_count={setup_object_count}");
eprintln!("final_heap_bytes={final_heap_bytes}");
eprintln!("final_object_count={final_object_count}");
}