Files
xenia-rs/zq.py
MechaCat02 2c883e9d5e [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>
2026-07-03 07:43:53 +02:00

67 lines
2.8 KiB
Python
Executable File

#!/usr/bin/env python3
"""Sylpheed static-analysis helper over DuckDB `sylpheed.db`.
Hides the gotchas: DECIMAL bounds (DuckDB rejects 0x literals), read-only connect,
and the fact that the engine vtable / rdata is NOT in the DB (read it from guest
memory with `xenia-rs exec ... --dump-addr=0x<va>` instead).
Usage:
zq.py dis <lo_hex> <hi_hex> # disassemble [lo,hi)
zq.py fn <pc_hex> # function containing pc (address,name,end)
zq.py xref <target_hex> # xrefs whose target == addr (callers)
zq.py callers <vtable_off_dec> # call-sites of vtable slot at byte offset N
# (finds `lwz r11, N(r11)` + reports the fn)
zq.py grep <substr> # instructions whose operands LIKE %substr%
zq.py find <word_hex> # instructions whose raw word == value (e.g. a ptr)
"""
import duckdb, sys
DB = '/home/fabi/RE - Project Sylpheed/xenia-rs/sylpheed.db'
c = duckdb.connect(DB, read_only=True)
H = lambda x: '0x%08x' % x
def _fn(pc):
r = c.execute('SELECT address,name,end_address FROM functions WHERE address<=? AND end_address>? '
'ORDER BY address DESC LIMIT 1', [pc, pc]).fetchall()
return f'{r[0][1]}({H(r[0][0])})' if r else '?'
def main():
if len(sys.argv) < 2:
print(__doc__); return
cmd = sys.argv[1]
if cmd == 'dis':
lo, hi = int(sys.argv[2], 16), int(sys.argv[3], 16)
for a, m, o in c.execute('SELECT address,mnemonic,operands FROM instructions '
'WHERE address>=? AND address<? ORDER BY address', [lo, hi]).fetchall():
print(H(a), m, o)
elif cmd == 'fn':
print(_fn(int(sys.argv[2], 16)))
elif cmd == 'xref':
t = int(sys.argv[2], 16)
for s, k, i, sf in c.execute('SELECT source,kind,instruction,source_func FROM xrefs '
'WHERE target=? ORDER BY source', [t]).fetchall():
print(H(s), k, 'in', _fn(s), ':', i)
elif cmd == 'callers':
off = int(sys.argv[2]) # decimal byte offset, e.g. 196 for vtable[49]
pat = f'r11, {off}(r11)'
for (a,) in c.execute("SELECT address FROM instructions WHERE mnemonic='lwz' AND operands=? "
'ORDER BY address', [pat]).fetchall():
print(H(a), 'in', _fn(a))
elif cmd == 'grep':
sub = sys.argv[2]
for a, m, o in c.execute("SELECT address,mnemonic,operands FROM instructions "
"WHERE operands LIKE ? ORDER BY address", [f'%{sub}%']).fetchall():
print(H(a), m, o, ' in', _fn(a))
elif cmd == 'find':
w = int(sys.argv[2], 16)
for (a,) in c.execute('SELECT address FROM instructions WHERE raw=? ORDER BY address', [w]).fetchall():
print(H(a))
else:
print(__doc__)
if __name__ == '__main__':
main()