[iterate-4A] diagnostics: XENIA_PROFILE wall-time profiler + probe/tooling snapshot

Handoff snapshot of the env-gated diagnostic scaffolding used across the
intro-video RE. Kept out of the milestone commits (645feb8..5573ac1) to keep
those clean; committed here so nothing is lost on handoff.

New — XENIA_PROFILE wall-time profiler (crates/xenia-gpu/src/prof.rs):
  Coarse buckets attributing playback wall time to interpreter (step_block),
  kernel HLE (call_export), block decode/cache (lookup_or_build), texture
  decode, host draw, and present; prints periodic snapshots (every 500M guest
  instr, or every 500 presents) + a clean-exit report. Hot path is gated on a
  cached is_on() (one relaxed load) so it is zero-cost when XENIA_PROFILE is
  unset. Call sites: main.rs run_superblock / parallel worker (step_block,
  lookup_or_build, call_export), texture_cache ensure_cached, render.rs present
  + dispatch_xenos_draws.

  First profile (movie playback, headless single-thread lockstep): effective
  ~35 MIPS; interpreter body ~40% @ ~95-102 MIPS; texture decode 0.3% (cache
  works); present ~0%; the rest is per-block dispatch + scheduler plumbing
  (~13 instr/block over 229M blocks). Overhead-bound, not interpreter-body
  bound; the levers are coarser execution units (superblock chaining) and
  ultimately a JIT.

Pre-existing read-only probe knobs (were uncommitted; env-gated, observe-only):
  XENIA_RET_CAPTURE_PC/_REG/_MEM, LOG_RESUMES, LOG_WAITS, LOG_SIGNAL,
  FORCE_TID, STARVE_LIMIT, INCUMBENT_PICK, INSTR_PER_MS, DUMP_FRAME,
  DUMP_WGSL, BIND_LOG, CONST_LOG, DISPATCH_REC, AUDIT_PC_TRACE.

Tooling: sylph-run.sh (movie oracle loop, 180s default timeout),
  zq.py (DuckDB disasm/xref helper).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-07-03 07:43:53 +02:00
parent 5573ac1c43
commit 2c883e9d5e
13 changed files with 800 additions and 14 deletions

View File

@@ -909,6 +909,30 @@ impl KernelState {
/// Record a Set/Pulse/Release/etc. call against a handle. `aux` is the
/// previous signal state (or per-export-specific data).
pub fn audit_signal(&mut self, handle: u32, lr: u32, source: &'static str, aux: u64) {
// RE diagnostic (milestone-2 intro-video). `XENIA_LOG_SIGNAL=0x<va>`
// (or `0xffffffff` for all) logs every event signal/pulse targeting
// that object — to pin who, if anyone, signals the engine event
// 0x40D10214 that tid23 waits on (the worker-resume gate). Read-only.
{
use std::sync::OnceLock;
static SIG_T: OnceLock<u32> = OnceLock::new();
let t = *SIG_T.get_or_init(|| {
std::env::var("XENIA_LOG_SIGNAL")
.ok()
.and_then(|s| u32::from_str_radix(s.trim().trim_start_matches("0x"), 16).ok())
.unwrap_or(0)
});
if t != 0 && (t == u32::MAX || t == handle) {
let tid = self
.scheduler
.current_hw_id()
.and_then(|h| self.scheduler.tid(h))
.unwrap_or(0);
tracing::info!(
"SIGNAL src={source} handle={handle:#010x} tid={tid} lr={lr:#010x} prev_signaled={aux}"
);
}
}
if !self.audit.enabled {
return;
}