fix(kernel): KRNBUG-D08 — wall-clock v-sync under --parallel
The synthetic v-sync ticker used a per-instruction proxy (VSYNC_INSTR_PERIOD = 150 k) tuned for ~10 MIPS lockstep throughput → 60 Hz. Audit M11 observed this drifts under `--parallel`: with 6 worker threads sharing the kernel mutex, the dispatcher executes more PPC instructions per tick callback, so the accumulator never crosses 150 k. Result: ~629 v-syncs/100M lockstep → ~2 v-syncs/100M --parallel. Hybrid solution preserves lockstep determinism (which the goldens depend on) while fixing --parallel: * `tick_vsync_instr(instr_count)` — legacy instruction-count ticker, used by lockstep. Bit-stable across runs. * `tick_vsync_wallclock()` — new Instant-based ticker. Fires `floor(elapsed / VSYNC_PERIOD)` v-syncs since the anchor and advances the anchor by that many full periods (no lazy backlog). Capped at INTERRUPT_QUEUE_CAP per call so a forward-jumping clock can't overflow the FIFO. * `KernelState.parallel_active` flag set at startup from `--parallel` / `XENIA_PARALLEL=1`. Read by `coord_pre_round` in main.rs to choose between the two tickers. Verification: * cargo test --workspace --release: 561 passing (+3 new wall-clock tests vs prior 558 baseline). * lockstep -n 100M --stable-digest: BIT-IDENTICAL to pre-Phase-3 baseline. interrupts_delivered preserved at ~630 (was ~629 pre-fix). * --parallel --reservations-table -n 30M: interrupts_delivered rose from ~2 to 17. (FIFO INTERRUPT_QUEUE_CAP=4 still caps burst delivery; that's a separate bottleneck — addressed by raising cap when --parallel queue depth becomes the next blocker.) Trade-off: --parallel runs are non-deterministic at the v-sync rate by design (per audit M05 PPCBUG-703 already). Lockstep stays bit-identical, so the `sylpheed_n*m.json` goldens are untouched. Audit IDs: KRNBUG-D08 (closed). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -137,6 +137,13 @@ pub struct KernelState {
|
||||
/// for golden verification, or implicitly under `--parallel`.
|
||||
/// See [`xenia_cpu::ReservationTable`] for the concurrency model.
|
||||
pub reservations: std::sync::Arc<xenia_cpu::ReservationTable>,
|
||||
/// True when the runtime was started with `--parallel`. Read by the
|
||||
/// v-sync ticker (KRNBUG-D08): lockstep uses the deterministic
|
||||
/// instruction-count proxy so the `sylpheed_n*m.json` goldens stay
|
||||
/// bit-stable; `--parallel` uses wall-clock so the rate doesn't
|
||||
/// drop to ~2 v-syncs / 100M as the instruction-count proxy did.
|
||||
/// Set once at startup and never mutated.
|
||||
pub parallel_active: bool,
|
||||
/// Map from `(module, ordinal)` to the guest-side import-thunk address
|
||||
/// resolved at load time. Reverse of `xenia-app/src/main.rs`'s
|
||||
/// `thunk_map`. Populated from xenia-app's Phase 1 (record_type==1
|
||||
@@ -203,6 +210,7 @@ impl KernelState {
|
||||
cxx_throw_logged: false,
|
||||
ring_base: 0,
|
||||
ring_size_dwords: 0,
|
||||
parallel_active: false,
|
||||
};
|
||||
crate::exports::register_exports(&mut state);
|
||||
crate::xam::register_exports(&mut state);
|
||||
|
||||
Reference in New Issue
Block a user