[iterate-2G] db16cyc spin-hint cooperative yield: unblock title-screen 0x10a0 gate

The silph title state machine (tid13) blocked on event 0x10a0, never signaled.
Root: the event's producer chain runs on the silph worker (entry 0x821C4AD0,
our tid14), which was starved. tid14 shares a HW slot with a guest spinlock/
barrier participant (sub_824D1328, entry 0x824D2940) that busy-spins on the
db16cyc hint `or r31,r31,r31` (encoding 0x7FFFFB78) at 0x824D140C. Under our
round-robin lockstep the spinner consumed its whole block every round and
starved the co-located tid14 (only 9 progress hits over 200M instr) — so the
producer never reached the event-create/duplicate/signal dance the canary
oracle performs (handle F80000E8 set by the submitter F8000044 via a duplicated
handle).

Fix (canary-faithful): recognize the db16cyc spin hint exactly as canary's
InstrEmit_orx does (code 0x7FFFFB78 -> DelayExecution) and surface it as a new
StepResult::Yield. The scheduler's yield_current() promotes every Ready peer on
the slot past STARVE_LIMIT so begin_slot_visit picks one next round, then they
reset and the spinner reclaims the slot — fair alternation, no priority
inversion, pure function of slot state (deterministic).

Result (lockstep, cache-persist, -n 200M): tid14 progresses past its old stall
into a real wait; tid13 advances off 0x10a0 to a new event; hub/submitter
re-enter their wait loops. imports 280k->592k, packets 124M->164M, swaps 1->2.
draws still 0 (the splash's first draw is a further-upstream gate).

Determinism preserved (two cold n50m runs byte-identical). n50m golden
re-baselined (imports 90296->339766, swaps 1->2; draws unchanged 0). n2m
golden unchanged (db16cyc not reached in first 2M). Tests 670/670.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-06-13 10:38:17 +02:00
parent f3b7e8b760
commit de21c7a544
31 changed files with 433587 additions and 3 deletions

View File

@@ -2619,6 +2619,10 @@ fn worker_prologue(
match result {
StepResult::Continue => {}
StepResult::Yield => {
// db16cyc spin-wait hint (per-instruction path): yield the slot.
kernel.scheduler.yield_current();
}
StepResult::SystemCall => {
tracing::warn!("SYSCALL at {:#010x} (hw={})", pc, hw_id);
}
@@ -2698,6 +2702,11 @@ fn worker_epilogue(
match result {
StepResult::Continue => {}
StepResult::Yield => {
// db16cyc spin-wait hint: hand the slot to a Ready peer so the
// spinner doesn't starve the co-located thread it is waiting on.
kernel.scheduler.yield_current();
}
StepResult::SystemCall => {
let last_pc = block.instrs.last().map(|i| i.addr).unwrap_or(pc_before);
tracing::warn!("SYSCALL at {:#010x} (hw={})", last_pc, hw_id);
@@ -3638,6 +3647,9 @@ fn dispatch_graphics_interrupts(
isr_instrs += 1;
match r {
StepResult::Continue => {}
// db16cyc inside the synchronous ISR has no slot to yield —
// the ISR runs to completion on the borrowed context.
StepResult::Yield => {}
StepResult::SystemCall => {
tracing::warn!("graphics ISR hit `sc` instruction; aborting");
break;

View File

@@ -1,9 +1,9 @@
{
"instructions": 50000003,
"imports": 90296,
"instructions": 50000000,
"imports": 339766,
"unimpl": 0,
"draws": 0,
"swaps": 1,
"swaps": 2,
"unique_render_targets": 0,
"shader_blobs_live": 0,
"texture_cache_entries": 0