Files
hakorune/src/backend/vm_stats.rs
Moe Charm e54561e69f Phase 10.7 - JIT統計とイベント機能の完成
主要な実装:
- PHI(b1)統計追跡: phi_total_slots/phi_b1_slotsをJSON出力
- 関数単位統計API: JitStatsBox.perFunction()で詳細統計取得
- JITイベントシステム: compile/execute/fallback/trapをJSONL形式で記録
- Store/Load命令対応: ローカル変数を含む関数のJIT実行が可能に

新しいBox:
- JitStatsBox: JIT統計の取得
- JitConfigBox: JIT設定の管理(将来用)
- JitEventsBox: イベントのJSONL出力(将来用)
- JitPolicyBox: 実行ポリシー管理(将来用)

CLI拡張:
- --jit-exec, --jit-stats, --jit-dump等のフラグ追加
- --jit-directモードでの独立JIT実行
- NYASH_JIT_*環境変数によるきめ細かい制御

ドキュメント:
- Phase 10.7実装計画の詳細化
- Phase 10.9 (ビルトインBox JIT) の計画追加
- JIT統計JSONスキーマ v1の仕様化

ChatGPT5との共同開発により、JIT基盤が大幅に強化されました。
次はPhase 10.9でビルトインBoxのJIT対応を進め、
Python統合(Phase 10.1)への道を開きます。

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-28 09:26:58 +09:00

111 lines
5.2 KiB
Rust

/*!
* 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);
}
}
}
/// Print a concise unified JIT summary alongside VM stats when enabled
pub(super) fn maybe_print_jit_unified_stats(&self) {
// Show when either JIT stats requested or VM stats are on
let jit_enabled = std::env::var("NYASH_JIT_STATS").ok().as_deref() == Some("1");
let vm_enabled = std::env::var("NYASH_VM_STATS").ok().map(|v| v != "0").unwrap_or(false);
let jit_json = std::env::var("NYASH_JIT_STATS_JSON").ok().as_deref() == Some("1");
if !jit_enabled && !vm_enabled { return; }
if let Some(jm) = &self.jit_manager {
// Gather basic counters
let sites = jm.sites();
let compiled = jm.compiled_count();
let total_hits: u64 = jm.total_hits();
let ok = jm.exec_ok_count();
let tr = jm.exec_trap_count();
let total_exec = ok + tr;
let fb_rate = if total_exec > 0 { (tr as f64) / (total_exec as f64) } else { 0.0 };
let handles = crate::jit::rt::handles::len();
let cfg = crate::jit::config::current();
let caps = crate::jit::config::probe_capabilities();
let abi_mode = if cfg.native_bool_abi && caps.supports_b1_sig { "b1_bool" } else { "i64_bool" };
let b1_norm = crate::jit::rt::b1_norm_get();
let ret_b1_hints = crate::jit::rt::ret_bool_hint_get();
if jit_json {
let payload = serde_json::json!({
"version": 1,
"sites": sites,
"compiled": compiled,
"hits": total_hits,
"exec_ok": ok,
"trap": tr,
"fallback_rate": fb_rate,
"handles": handles,
"abi_mode": abi_mode,
"abi_b1_enabled": cfg.native_bool_abi,
"abi_b1_supported": caps.supports_b1_sig,
"b1_norm_count": b1_norm,
"ret_bool_hint_count": ret_b1_hints,
"phi_total_slots": crate::jit::rt::phi_total_get(),
"phi_b1_slots": crate::jit::rt::phi_b1_get(),
"top5": jm.top_hits(5).into_iter().map(|(name, hits, compiled, handle)| {
serde_json::json!({
"name": name,
"hits": hits,
"compiled": compiled,
"handle": handle
})
}).collect::<Vec<_>>()
});
println!("{}", serde_json::to_string_pretty(&payload).unwrap_or_else(|_| String::from("{}")));
} else {
eprintln!("[JIT] summary: sites={} compiled={} hits={} exec_ok={} trap={} fallback_rate={:.2} handles={}",
sites, compiled, total_hits, ok, tr, fb_rate, handles);
eprintln!(" abi_mode={} b1_norm_count={} ret_bool_hint_count={}", abi_mode, b1_norm, ret_b1_hints);
}
}
}
}