Files
xenia-rs/migration/claude-memory/project_xenia_rs_handle_audit.md
MechaCat02 e6d43a23ac chore: add migration/ bundle for cross-machine setup
Bundles state that lives OUTSIDE the xenia-rs repo so a fresh clone on
another machine can be brought up to identical configuration via
migration/setup.sh:

  - claude-memory/             ~/.claude/projects/-home-fabi-RE-Project-Sylpheed/memory/
                               (103 files, 1.1 MB - MEMORY.md + every
                                project_xenia_rs_*.md from audits
                                addis_signext through audit-058)
  - project-root/dot-claude/   <project-root>/.claude/settings.json
                               (Stop hook + permissions)
  - project-root/ppc-manual/   <project-root>/ppc-manual/
                               (PowerPC reference docs, 397 files, 3.7 MB)
  - project-root/run-canary.sh <project-root>/run-canary.sh
  - README.md                  Human-readable setup checklist
  - setup.sh                   Idempotent installer (also reclones
                               xenia-canary at pinned HEAD 6de80dffe)
  - MANIFEST.md                Per-file mapping + per-file-not-bundled
                               restoration recipe

Excluded from bundle (not shippable via git):
  - Sylpheed ISO (7.8 GB; copyright; manual copy required)
  - sylpheed.db (395 MB; regenerable from XEX via analysis tooling)
  - target/ build artifacts (rebuild on target)
  - audit-runs probe firehoses (.log/.stdout/.stderr ~11 GB; rerun if needed)
  - audit-runs memory dumps (.bin ~4.5 GB; rerun audit-026/027/029 if needed)
  - xenia-canary checkout (setup.sh reclones from
    git.mc02.dev/fabi/Xenia-Canary.git at HEAD 6de80dffe)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 21:38:38 +02:00

6.8 KiB

name, description, type, originSessionId
name description type originSessionId
xenia-rs handle-audit harness + post-2026-04-25 sync state Per-handle signal/wait/wake audit (—trace-handles), and the diagnostic finding that the previously-reported HLE sync gap no longer reproduces at -n 500M project f83e67b7-97f4-4222-a37f-e1720ab3ace6

Audit harness landed

xenia-kernel/src/audit.rsHandleAudit + HandleAuditTrail capture create/signal/wait/wake events per kernel handle, bounded ring of 32 entries each. KernelState::audit is enabled=false by default; flip via --trace-handles flag or XENIA_TRACE_HANDLES=1. Disabled is a single inline early-return in each record method — zero hot-path cost.

Hook sites (in xenia-kernel/src/exports.rs):

  • Create: nt_create_event, nt_create_semaphore, nt_create_timer
  • Signal: KeSetEvent, NtSetEvent, KePulseEvent, NtPulseEvent, KeReleaseSemaphore, NtReleaseSemaphore, NtSignalAndWaitForSingleObjectEx (signal half), signal_io_completion_event
  • Wait: do_wait_single, do_wait_multiple (one record per handle in the wait set)
  • Wake: inside wake_eligible_waiters (separate records for manual-reset fan-out vs auto-reset/semaphore single-wake)

Diagnostic dump in xenia-app/src/main.rs::dump_thread_diagnostic prints the audit trail at end-of-run when audit is enabled. Highlights <NO_SIGNALS_DESPITE_WAITS> (smoking gun for missing signal source) and <SUSPECT> (handles called out in the original deadlock report).

Diagnostic finding (2026-04-25)

The HLE sync gap previously reported at ~7.5M cycles on Sylpheed boot is no longer reproducing. Verified:

  • xenia-rs exec sylpheed.iso --halt-on-deadlock -n 500_000_000EXIT=0, no halt fired, no scheduler.deadlock_halts or scheduler.deadlock_recoveries counters appear.
  • VdSwap=1 fires at ~22M instructions, VdSwap=2 at ~30M instructions; matches the post-Tier-4 baseline.
  • Audit data confirms the originally-suspect handles (0x10FC, 0x1014, 0x1104, 0x10DC, 0x10F0) all do receive signals: e.g., 0x10FC = Event/Auto with 1 signal (NtSetEvent from tid=4) + 1 wake; 0x1014 = Semaphore with 15 signals / 15 wakes / 16 waits.
  • Threads still parked at end-of-run (tids 2/3/4/5/6/10/13/14/16/18) are in normal worker-idle states (event+semaphore producer/consumer with timeouts, or "service exits on stop-event" with no shutdown signal — both expected).

Why: likely a combination of the IRQ-injection stack-pad fix (2026-04-24) and Tier-4 perf work (2026-04-25) shifted scheduler timing past the previous deadlock window.

How to apply: APC + Mutant infrastructure (KeInitializeApc=0x6D, KeInsertQueueApc=0x7A, NtQueueApcThread=0xE3, KeAlertThread=0x4F, KeInitializeMutant=0x72, KeReleaseMutant=0x87, NtCreateMutant=0xD4, NtReleaseMutant=0xF2 — all in canary xboxkrnl_threading.cc) was planned but DEFERRED — the audit data did not point to a missing kernel API. Implement only when a future regression actually requires it.

Resolve fill-ins landed (2026-04-25)

xenia-gpu/src/edram.rs gained: write_sample_32bpp, write_rect_32bpp, read_sample_64bpp, write_sample_64bpp, write_rect_64bpp, fill_rect_64bpp. 64bpp helpers use Canary's doubled-pitch convention (pitch_tiles_32bpp << 1).

xenia-gpu/src/resolve.rs copy_to_memory now handles:

  1. 64bpp sources via new is_64bpp_bitwise_equivalent (k_16_16_16_16, k_16_16_16_16_FLOAT, k_32_32_FLOAT). Two write_u32 per pixel; bpp_log2 = 3 for tiled offset.
  2. MSAA averaging (k01/k23/k0123) via per-format decode/average/encode helpers:
    • k_8_8_8_8/k_8_8_8_8_GAMMA: per-byte rounded unsigned mean
    • k_2_10_10_10: per-field rounded mean (widths 2/10/10/10)
    • k_16_16_FLOAT, k_16_16_16_16_FLOAT: half-float decode → fp32 sum → encode
    • k_32_FLOAT, k_32_32_FLOAT: bitcast → fp32 sum → bitcast
    • k_16_16_16_16: per-16-bit-field rounded mean

xenia-gpu/src/gpu_system.rs clear-paint dispatches to fill_rect_64bpp for 64bpp sources, using RB_COLOR_CLEAR_LO (lo) + RB_COLOR_CLEAR (hi) per Canary draw_util.cc:1302-1303.

Endian k8in64/k8in128 and copy_dest_exp_bias != 0 remain on backlog (rare on first-pixels path); current code preserves the pre-existing warn+skip behavior for both.

wgpu→ShadowEdram readback — deferred, foundation in place

ShadowEdram write APIs (write_rect_32bpp, write_rect_64bpp) are the foundational data-structure work the future readback retile path will use. The cross-thread plumbing (UiBridge request_rt_readback / poll_rt_readback, per-RT offscreen wgpu textures in xenos_pipeline.rs, copy_texture_to_buffer + map_async callback) is deferred: Sylpheed's current boot path fires no Xenos draws, so wiring the cross-thread readback today would land speculative code that can't be exercised against a real game flow. The plan file at /home/fabi/.claude/plans/please-address-the-hle-eager-pixel.md Section 2 has the full design (ReadbackState, OffscreenRt, RtCache).

Verification (2026-04-25 session)

  • cargo test --workspace --release386 tests pass (was 369 baseline; +17 new for audit, edram, resolve).
  • xenia-rs check sylpheed.iso -n 2_000_000 --expect crates/xenia-app/tests/golden/sylpheed_n2m.json — clean in both default block-cache mode and XENIA_FORCE_PER_INSTR=1 per-instruction mode.
  • xenia-rs exec sylpheed.iso --halt-on-deadlock -n 500_000_000EXIT=0, no deadlock counters tripped.
  • cargo bench -p xenia-cputight_alu_loop=119.86 MIPS, loadstore_loop=95.67 MIPS, mmio_storm=70.08 MIPS (all at or above the prior post-Tier-4 baseline of 114.8 / 91.8 / 67.8).

Files touched this session

  • New: xenia-rs/crates/xenia-kernel/src/audit.rs.
  • Modified: xenia-kernel/src/lib.rs (mod), state.rs (KernelState::audit + helpers), exports.rs (hook calls at create/signal/wait/wake sites). xenia-app/src/main.rs (--trace-handles flag, audit dump in dump_thread_diagnostic, env var XENIA_TRACE_HANDLES). xenia-gpu/src/edram.rs (new 32bpp+64bpp write APIs + fill_rect_64bpp + tests). xenia-gpu/src/resolve.rs (is_64bpp_bitwise_equivalent + 64bpp source path + MSAA averaging + half-float helpers + tests). xenia-gpu/src/gpu_system.rs (64bpp clear-paint dispatch).