Priority aging in xenia-cpu/scheduler.rs:pick_runnable
(effective_priority = base + age_bonus(now_round - last_run_round),
capped at +31, AGING_ROUNDS_PER_BONUS=1). Strict-priority was parking
priority=0 threads behind CPU-bound priority=15 audio mixer
(sub_824D1328 guest spinwait at PC=0x824d1404 on CPU5). Aging
eventually picks the starved thread, breaking the producer-consumer
cycle that caused 5-tid wedge at PC=0x824ac578 since AUDIT-049 (10 May).
Cascade observed: tid=13 clean exit; events 121K -> 13M (107x); last
host_ns 767ms -> 51,011ms (66x); 8 new threads spawn; VdSwap 1 -> 2.
Complete two-day iterate sequence (2026-05-27 -> 2026-05-28):
- 2.F: VdSwap drain timeout 900ms -> 1ms (xenia-gpu/handle.rs); 876x
perf win on VdSwap kernel callback
- 2.H: vA0000000 physical heap bucket added (state.rs, exports.rs);
ctx_ptrs now in 0xA0000000-0xBFFFFFFF range matching canary
- 2.L: Phase-A diff harness categorized [return_value mismatch],
[status mismatch], [args_resolved.path mismatch] tags
(tools/diff-events/diff_events.py); closes reading-error #41
(silent test-harness state leak invalidating trace diffs)
- 2.M: always-on exit-thread-state.json sibling to Phase-A JSONL
(event_log.rs + xenia-app/main.rs); closes reading-error #42
(Phase-A blind to blocked-forever waits)
- 2.Q: signal.match kernel instrumentation in NtSetEvent /
NtReleaseSemaphore / KeSetEvent / KeReleaseSemaphore
(exports.rs); emits target_handle + waiter_count + waiter_tids
- 2.T: wake.requested kernel instrumentation in wake_eligible_waiters
(exports.rs); emits target_tid + transition + new_state
- 2.V: scheduler priority aging (xenia-cpu/scheduler.rs) [keystone]
Plus accumulated WIP from earlier May (contention_manifest,
phase_b_snapshot, xam/xaudio enhancements, analysis db, xex loader,
xenia-app main loop, etc.). Audit-runs/ artifacts remain untracked
per project convention.
Tests: 300 xenia-cpu / 227 xenia-kernel / 5 xenia-app / 19 xenia-path
/ 30+ smaller suites -- all PASS, 0 regressions. Determinism preserved
(2x cold runs bit-identical at 13,003,881 events post-2.V).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
4.9 KiB
4.9 KiB
address, classification, confidence, last_audit, aliases
| address | classification | confidence | last_audit | aliases | ||
|---|---|---|---|---|---|---|
| 0x82452DC0 | normal_callee | high | 063 |
|
sub_82452DC0 — work-submitter / cluster-root
Synopsis
Central work-submission function. All AUDIT-049–060 γ-wedge chains and AUDIT-058 vtable-activation chains funnel through this function. Receives a request (likely a file-IO descriptor + completion XEvent) and dispatches it via 9 direct callees + 1 indirect call. In canary it fires ~3.21× more often than in ours per AUDIT-056 — the upstream gate is in its caller, not in it.
Evidence
- AUDIT-050 enumerated 9 direct targets at
blsites:0x8245AE50, 0x82452068, 0x82452200, 0x8245B000, 0x8245B078, 0x82454A40, 0x82452AB8, 0x82454918, 0x82452EC4, plus 1ind_call. - AUDIT-051 found a predicate gate at
+0x78:0x82452E2C beq cr6, 0x82452E88, controlled bysub_8245B000(r3)returning 1 iff[r3+0]≠0 AND [r3+4]≠0. The 80-byte stack-local struct lives atr31+96. - AUDIT-052 found
[r3+0]/[r3+4]are halves of a hash key formatted intocache:\<HASH1>\<X>\<HASH2>paths — i.e. the struct holds a content hash for cache resolution. Predicate refuted as the bug. - AUDIT-055 probed
sub_8245B078's body with a cache override: body executes correctly; divergence is upstream. - AUDIT-056: fires canary 45/60s, ours 14/26s = 3.21× ratio. Sharpest specific divergence:
sub_8217FA08fromLR=0x82455E60(=sub_82455DF0+0x70) canary 20 / ours 0. - AUDIT-059: tid=13 itself fires
sub_82452DC0once at LR=0x821cb1d0(fromsub_821CB030+0x19C) immediately before waiting on the file-IO completion XEvent. - AUDIT-060: confirmed convergence —
sub_8245FEB8 ← sub_824601A0 ← sub_82460118 ← sub_82452AB8 ← sub_82452DC0. The vptr-installer chain bottoms out here.
Activation
Direct bl from 34 static caller sites per AUDIT-051. Notable callers:
sub_821CB030+0x19C— drives the file-IO completion submission used bysilph::GamePart_Title::UImpl.sub_821CB030+0x2BC— second site in same fn.sub_821C4EB0chain (AUDIT-056 gate).sub_82173990+0x208(program-top frame).
Static graph
- Static callers: 34 sites across boot + tid=13 + UI cluster.
- Static callees (direct
bl): 9 functions above + 1 computed call. - The 9-target tree is the "worker activation surface".
sub_82452AB8is the gate leading to vptr installers;sub_8245B078,sub_8245B000are the cache-key/hash gates; the others are queue management.
Audit log
- AUDIT-063 (2026-05-12) — static reachability surveyed: among the 60 distinct callers of NtSet wrapper
0x824AA2F0, only 1 is reachable within 12 hops fromsub_82452DC0:sub_8245FEB8(γ-signaler C). The AUDIT-062 candidate trio (sub_822F2248,sub_822F1AA8,sub_821741C8) are NOT downstream. Confirms that the "producer-side worker-wake signal" canary path is the worker cluster (sub_82458B90/sub_8245EC10/sub_8245FEB8/sub_8245D9D8/sub_8245DA78) reached via the 4 worker threads spawned bysub_825070F0— and those threads are unspawned in ours (0 vs 8 in canary). [confirmed] - AUDIT-060 (2026-05-12) — confirmed as single funnel for AUDIT-058+059 chains; the work-submitter is alive and queues but the throughput is gated by
sub_821C4EB0early-exit per AUDIT-056. [confirmed] - AUDIT-059 (2026-05-11) — fires 8× in ours; one of those is tid=13 from
sub_821CB030+0x19Cright before waiting on the wedge XEvent. Work submitted but no signal returns. [confirmed] - AUDIT-056 (2026-05-10) — fires canary 45 / ours 14 in matched windows = 3.21× gap. Bug class refined to "δ-throughput". [confirmed]
- AUDIT-055 (2026-05-10) — proved
sub_8245B078body executes correctly; ruled out a downstream bug here. [confirmed] - AUDIT-052 (2026-05-10) — refuted AUDIT-051's "missing population" hypothesis. The struct is bit-identical to canary;
[r3+0]/[r3+4]are a content hash. [supersedes-AUDIT-051-claim] - AUDIT-051 (2026-05-10) — initially identified
+0x78predicate gate as bug. [STATUS: hypothesis falsified by AUDIT-052; the gate itself is real and named correctly, but it's not the bug] - AUDIT-050 (2026-05-10) — enumerated 9 direct targets + 1 indirect; framed as activation-surface root. [confirmed]
Open questions
- Why does
sub_82452DC0fire 3.21× less in ours? AUDIT-061 pivots to its callersub_821C4EB0's internal branches[+0x44, +0xE0]. - The 1 indirect call (computed) — what does it dispatch to, and does our static-analyzer miss any of its candidates?
Cross-references
- Callers: sub_821CB030, sub_821C4EB0
- Callees-of-interest: sub_82452AB8 (not yet dossierd),
sub_8245B078,sub_8245B000(cache-hash gate) - Audits: 049, 050, 051, 052, 053, 054, 055, 056, 057, 058, 059, 060
- Artifacts:
audit-runs/audit-050-*/,audit-runs/audit-056-producer-trace/,audit-runs/audit-059-gamma-wedge/,audit-runs/audit-060-fnptr-array-bootstrap/