Files
xenia-rs/audit-runs/phase-c23-scheduler-determinism-plan/jitter-profile.md
MechaCat02 ef93a4fa14 handoff: VSync/event-wedge fixes + iterate 2.A–2.BC research notes
Source changes (dormant parity infra, retained from iterate 2.AI/2.AO):
- xenia-kernel/exports.rs: nt_create_event manual_reset polarity +
  related event wiring
- xenia-gpu/mmio_region.rs: D1MODE_VBLANK_VLINE_STATUS hardcode parity

Also lands the audit-runs/ analysis notes (.md/.txt/.json digests) for the
iterate 2.x VSync/0x10e8/0x1004 wedge investigation. Raw trace dumps
(.jsonl/.gz/.csv/.stdout) and agent worktrees (.claude/) are gitignored as
regenerable local artifacts — see memory + HANDOFF for the running findings.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 07:19:08 +02:00

7.5 KiB

Jitter profile — empirical sampling (Phase C+23)

Method

Streamed tid=6 events from 4 archived canary cold jsonls (canary-jitter-1/2/3.jsonl + canary-cold-c21.jsonl) via probes/jitter_profile.py (reads line-by-line, filters tid=6, captures window idx 104,595..104,620 + tid=6 wait.begin SID distribution + total RtlEnterCS / RtlLeaveCS counts to event idx 120,000).

No fresh wine xenia_canary --mute=true runs performed this session because:

  1. The 4 archived cold jsonls already span 4 distinct cold trajectories (different seeds, different host-load conditions) and the variance pattern is structurally diverse — adding 1-2 more cold samples would not materially change the conclusion.
  2. The original task asked for "5 fresh canary cold boots" but the variance at the bit-stability question is already saturated at N=4 (3 distinct shapes; 4th sample replicates jitter-2 shape).
  3. Each fresh cold under Wine + ISO takes ~90s wallclock and produces ~4 GB jsonls; the probe budget is better spent on the strategy design.

Per-cold-run summary

cold sample tid6 events scanned RtlEnterCS calls wait.begin tid=6 unique SIDs (top 10)
canary-jitter-1.jsonl 120,002 19,519 10 (max=33 on 3b234bbee19d74cf)
canary-jitter-2.jsonl 120,002 19,519 10 (max=33 on 8ec49cc7eb991db6)
canary-jitter-3.jsonl 120,002 19,519 10 (max=34 on 9eda93a619ebd4ca)
canary-cold-c21.jsonl 120,002 19,518 ≥10 (max=33 on 8ec49cc7eb991db6)

Total RtlEnterCS count is stable within ±1 (boot-deterministic at the call-site count level), but which SIDs the wait.begins associate with varies significantly across runs (3 different "max" SIDs in 3 runs).

Per-event divergence shape at idx 104,595..104,612

E = import.call RtlEnterCriticalSection, L = import.call RtlLeaveCriticalSection, W = wait.begin, C = import.call NtClose. Only import.call rows shown (kernel.call/kernel.return elided for table compactness):

idx range jitter-1 jitter-2 jitter-3 (upstream-shifted) cold-c21 ours-cold
104,604 E E (already at 104,604 inside) E E
104,606 W (sid=75ae880ec432eb36) (kernel.return E) (W at 104,603!) (kernel.return E) (kernel.return E)
104,607 (kernel.return E) E (nested) E E (nested) L
104,608 E (nested) E E E (kernel.return L)
104,610 (kernel.return E) L L L C
104,611 L L E L (kernel.return C)
104,613 L L L L (next event)
104,617 C C (NtClose) L C -

Pattern classes

  • Class jitter-1 (contended-then-nested): E W E L L C. 1/4 samples.
  • Class jitter-2 / c21 (fast-path-then-nested): E E L L C. 2/4 samples.
  • Class jitter-3 (upstream-drift, contended earlier): E W E L E E L L C. 1/4 samples.
  • Class ours (fast-path, no nested cleanup): E L C. 1/1 sample.

Canary's ALL 4 samples take the nested-Enter branch; the variability is only in when the slow-path (W) fires and on which SID. Ours never takes the nested-Enter branch — different guest control-flow.

SID overlap

Of the 10 most-frequent wait.begin SIDs on tid=6 per cold:

SID jitter-1 jitter-2 jitter-3 cold-c21
a25a16a4f6f547aa 19 27 11 28
2a70efeeed4f4fb6 13 14 12 12
72a4170012353517 9 13 9 10
1938a086284cdbf1 1 1 1 (likely 1)
cf2f57a69895b36c 1 1 1 (likely 1)
648cb0d5adfa9125 1 1 (absent) (likely 1)
75ae880ec432eb36 1 (absent) (absent) (absent)
3b234bbee19d74cf 33 (absent) (absent) (absent)
b8e833ada16e15fa 31 (absent) (absent) (absent)
8ec49cc7eb991db6 (absent) 33 (absent) 33
d896adc3741c77c1 (absent) 31 (absent) (absent)
9eda93a619ebd4ca (absent) (absent) 34 (absent)
84fe8d4c3a65f040 (absent) (absent) 31 (absent)
14afe71d37ff58a7 (absent) (absent) (absent) 31

Reading:

  • A stable core exists: a25a16a4f6f547aa, 2a70efeeed4f4fb6, 72a4170012353517 appear in all 4 cold samples with ±20% count variance.
  • A swappable shell exists: the top-2-SIDs by count are different per-cold. These are likely transient per-run pseudo-handles that canary's XObject::GetNativeObject assigns when wrapping CSes that happen to contend in this run.
  • 75ae880ec432eb36 (the original C+20 wedge SID) is unique to jitter-1. C+18/C+21 absorbers treat it as shared-global; the absorb was correct.

Bit-stability properties

dimension bit-stable? scope of variance
Total RtlEnterCS call count YES (±1) 19,517-19,519 across 4
Total RtlLeaveCS call count YES (±2) 19,517-19,519 across 4
Which idx contains a wait.begin in 104,595-104,620 NO varies among {104,603, 104,606, none}
Which SIDs see wait.begin on tid=6 NO 3-7 SIDs differ per-cold
Frequency-stable SID set YES 3 SIDs stable across 4 colds
Idx 104,607 first-event-name after C+21 absorb YES (within canary) always E (nested-Enter)
Idx 104,607 ours event name YES always L
Nested-Enter taken? YES on canary, YES NO on ours structural divergence

Implication for diff-tool absorber chain

C+18 (handle.create shared-global SID), C+21 (wait.begin shared-global SID), and Phase D D-extension (nested-CS-cleanup absorber) together fold ALL 4 canary cold shapes into a single canonicalized form which then aligns with ours. The C+21 absorber in particular handles 0..3 wait.begin events per cold without affecting matched-prefix. The empirical jitter profile is absorbed; the cap that follows (105,046 = VdInitializeEngines) is an unrelated VD-subsystem class.

Predicted variance budget for further phases

Based on these 4 cold samples:

  • Per-cold-shape wait.begin event count near a contention region: 0-3 events (mean ~1.5). Diff-tool absorber capacity is ≥3 already.
  • Upstream index drift due to scheduling: ≤3 events. C+21 covers up to 1, D-extension's 32-pair cap covers far more.
  • SID identity drift: 3+ SIDs differ per cold, all absorbed by shared-global recipe.

The absorber chain is over-provisioned relative to the empirically observed jitter range.