Files
hakorune/src/backend/vm_stats.rs

55 lines
2.2 KiB
Rust
Raw Normal View History

/*!
* VM Stats & Diagnostics - prints per-instruction counters and timing
*
* Responsibility:
* - Aggregate instruction counts (by MIR opcode)
* - Print text or JSON summary based on env vars
* - Stay side-effect free w.r.t. VM execution semantics
*/
use super::vm::VM;
impl VM {
/// Print simple VM execution statistics when enabled via env var
pub(super) fn maybe_print_stats(&mut self) {
let enabled = std::env::var("NYASH_VM_STATS").ok().map(|v| v != "0").unwrap_or(false);
if !enabled { return; }
let elapsed_ms = self.exec_start.map(|t| t.elapsed().as_secs_f64() * 1000.0).unwrap_or(0.0);
let mut items: Vec<(&str, usize)> = self.instr_counter.iter().map(|(k,v)| (*k, *v)).collect();
items.sort_by(|a,b| b.1.cmp(&a.1).then_with(|| a.0.cmp(&b.0)));
let total: usize = items.iter().map(|(_,v)| *v).sum();
let json_enabled = std::env::var("NYASH_VM_STATS_JSON").ok().map(|v| v != "0").unwrap_or(false)
|| std::env::var("NYASH_VM_STATS_FORMAT").map(|v| v == "json").unwrap_or(false);
if json_enabled {
let counts_obj: std::collections::BTreeMap<&str, usize> = self.instr_counter.iter().map(|(k,v)| (*k, *v)).collect();
let top20: Vec<_> = items.iter().take(20).map(|(op,cnt)| {
serde_json::json!({ "op": op, "count": cnt })
}).collect();
let now_ms = {
use std::time::{SystemTime, UNIX_EPOCH};
SystemTime::now().duration_since(UNIX_EPOCH).map(|d| d.as_millis() as u64).unwrap_or(0)
};
let payload = serde_json::json!({
"total": total,
"elapsed_ms": elapsed_ms,
"counts": counts_obj,
"top20": top20,
"timestamp_ms": now_ms
});
match serde_json::to_string_pretty(&payload) {
Ok(s) => println!("{}", s),
Err(_) => println!("{{\"total\":{},\"elapsed_ms\":{:.3}}}", total, elapsed_ms),
}
} else {
println!("\n🧮 VM Stats: {} instructions in {:.3} ms", total, elapsed_ms);
for (k, v) in items.into_iter().take(20) {
println!(" {:>10}: {:>8}", k, v);
}
}
}
}