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>
168 lines
6.3 KiB
Markdown
168 lines
6.3 KiB
Markdown
# Persistence experiment — `XENIA_CACHE_PERSIST=1` impact on matched-prefix
|
|
|
|
## Setup
|
|
|
|
* Binary: `xenia-rs/target/release/xrs-c10` (active C+10 build, both engines).
|
|
* Window: 50M instructions per boot.
|
|
* Flag: `XENIA_CACHE_PERSIST=1`; mount falls back to `$HOME/.local/share/xenia-rs/cache`
|
|
because `XDG_DATA_HOME` is empty on the host.
|
|
* Comparison baseline: C+10 default-tmpdir digest
|
|
`instructions=50000002 imports=40465 swaps=1 draws=0` (with stable-digest md5
|
|
`b8fa0e0460359a4f660adb7605e053de`); event log
|
|
`xenia-rs/audit-runs/phase-c10-NtQueryFullAttributesFile/canary.jsonl`.
|
|
* Diff tool: `xenia-rs/tools/diff-events/diff_events.py --tid-map 6=1`.
|
|
|
|
## Boot-by-boot digests
|
|
|
|
| boot | mode | instructions | imports | swaps | draws |
|
|
|---|---|---|---|---|---|
|
|
| C+10 baseline (default tmpdir) | wipe-on-boot | 50000002 | 40465 | 1 | 0 |
|
|
| Persist boot 1 (cold persist) | persistent | **50000003** | **40485** | 1 | 0 |
|
|
| Persist boot 2 (warm persist) | persistent | 50000003 | 40485 | 1 | 0 |
|
|
|
|
The persistence path is +1 instruction / +20 imports over the default-tmpdir
|
|
baseline. Warm boot is identical to cold boot at the digest level (no
|
|
regression observed at 50M; AUDIT-053's regression was at 500M+).
|
|
|
|
## On-disk cache state per boot
|
|
|
|
### After persist boot 1 (cold)
|
|
|
|
Total: 7 files / 1.4 MB.
|
|
|
|
```
|
|
d 4096 /access ← BUG: should be 240 B file (canary)
|
|
d 4096 /ignore ← BUG: not in canary's cache
|
|
d 4096 /recent ← BUG: should be 160 B file (canary)
|
|
d 4096 /d4ea4615
|
|
d 4096 /d4ea4615/e
|
|
d 4096 /69d8e45c
|
|
d 4096 /69d8e45c/9
|
|
d 4096 /69d8e45c/e
|
|
d 4096 /aab216c3
|
|
d 4096 /aab216c3/5
|
|
d 4096 /aab216c3/a
|
|
f 2400 /d4ea4615e46ee8ca.tmp
|
|
f 5784 /69d8e45ce534ffea.tmp
|
|
f 12288 /69d8e45c9355f2f8.tmp
|
|
f 12288 /69d8e45c973a5c0a.tmp
|
|
f 12288 /aab216c35ee70e0a.tmp
|
|
f 614400 /aab216c3a2c8c185.tmp
|
|
f 685464 /69d8e45c939a9dcc.tmp
|
|
```
|
|
|
|
Notable:
|
|
* `access`, `ignore`, `recent` exist as DIRECTORIES (bug #2).
|
|
* `.tmp` flat journals exist (cache-build path is firing).
|
|
* Hash subdirectories exist (AUDIT-054's `FILE_DIRECTORY_FILE` handling works).
|
|
* **Hierarchical leaf files** (e.g. `d4ea4615/e/46ee8ca`) **do not exist** —
|
|
the `.tmp` → leaf rename is being silently dropped (bug #1).
|
|
|
|
### After persist boot 2 (warm)
|
|
|
|
Total: 7 files / 1.6 MB (`.tmp` files grew).
|
|
|
|
| file | boot 1 | boot 2 | growth | canary's equivalent leaf size |
|
|
|---|---|---|---|---|
|
|
| `d4ea4615e46ee8ca.tmp` | 2400 | 2800 | +400 | 400 B (`d4ea4615/e/46ee8ca`) |
|
|
| `69d8e45ce534ffea.tmp` | 5784 | 6748 | +964 | 964 B (`69d8e45c/e/534ffea`) |
|
|
| `69d8e45c9355f2f8.tmp` | 12288 | 14336 | +2048 | 2048 B (`69d8e45c/9/355f2f8`) |
|
|
| `69d8e45c973a5c0a.tmp` | 12288 | 14336 | +2048 | 2048 B (`69d8e45c/9/73a5c0a`) |
|
|
| `aab216c35ee70e0a.tmp` | 12288 | 14336 | +2048 | 2048 B (`aab216c3/5/ee70e0a`) |
|
|
| `aab216c3a2c8c185.tmp` | 614400 | 716800 | +102400 | 102400 B (`aab216c3/a/2c8c185`) |
|
|
| `69d8e45c939a9dcc.tmp` | 685464 | 799708 | +114244 | 114244 B (`69d8e45c/9/39a9dcc`) |
|
|
|
|
**The per-boot growth of each `.tmp` file exactly matches the byte size of the
|
|
corresponding canary hierarchical leaf.** Strong indirect evidence that the
|
|
`.tmp` contains the same data as canary's leaf but is being appended on each
|
|
boot instead of being renamed-to-leaf and consumed.
|
|
|
|
This is exactly AUDIT-053's "journal-style appends per boot" pattern. AUDIT-053
|
|
predicted a `runtime_error` regression at warm-start because the version header
|
|
would go stale; in the 50M window of this experiment, that regression has not
|
|
yet manifested (AUDIT-054's report had it at 500M+).
|
|
|
|
## Phase A diff vs C+10 canary baseline
|
|
|
|
Command:
|
|
|
|
```
|
|
python3 xenia-rs/tools/diff-events/diff_events.py \
|
|
--canary xenia-rs/audit-runs/phase-c10-NtQueryFullAttributesFile/canary.jsonl \
|
|
--ours xenia-rs/audit-runs/cache-subsystem-plan/persist-warm-events.jsonl \
|
|
--tid-map 6=1
|
|
```
|
|
|
|
Result:
|
|
|
|
```
|
|
| canary_tid | ours_tid | matched | canary_total | ours_total | first_divergence_at |
|
|
|---|---|---|---|---|---|
|
|
| 6 | 1 | 102404 | 315020 | 108471 | 102404 |
|
|
```
|
|
|
|
**Matched-prefix unchanged from C+10 baseline (102404).**
|
|
|
|
Divergence event:
|
|
|
|
```
|
|
canary [6][102404] kernel.return NtQueryFullAttributesFile return_value=0
|
|
ours [1][102404] kernel.return NtQueryFullAttributesFile return_value=0xC0000034
|
|
```
|
|
|
|
Pre-context shows both engines reach the same path query
|
|
`cache:\d4ea4615\e\46ee8ca` byte-for-byte, but ours returns NOT_FOUND because
|
|
that leaf doesn't exist on disk (only the flat `.tmp` does).
|
|
|
|
## Conclusion
|
|
|
|
Persistence is **necessary but not sufficient**. The plan's Stage 1 (rename
|
|
fix) is required to convert `.tmp` flat journals into hierarchical leaves. Stage
|
|
2 (top-level file misclassification) is required to fix the `access`/`ignore`/
|
|
`recent` directory-vs-file bug. Stage 3 (flip default) follows after both
|
|
bugs are addressed.
|
|
|
|
Expected matched-prefix advance after all three stages: hundreds-to-thousands
|
|
of events, until a non-cache divergence appears.
|
|
|
|
## Reproduction commands
|
|
|
|
```bash
|
|
cd "/home/fabi/RE - Project Sylpheed"
|
|
|
|
# Clean cache for cold start
|
|
rm -rf ~/.local/share/xenia-rs/cache
|
|
|
|
# Boot 1 (cold)
|
|
XENIA_CACHE_PERSIST=1 ./xenia-rs/target/release/xrs-c10 check \
|
|
-n 50000000 --stable-digest --out /tmp/digest-boot1.json \
|
|
"Project Sylpheed - Arc of Deception (USA, Europe) (En,Ja).iso"
|
|
|
|
# Inspect resulting cache layout
|
|
find ~/.local/share/xenia-rs/cache -mindepth 1 -printf '%y %s\t%p\n' | sort
|
|
|
|
# Boot 2 (warm) — same command, no rm
|
|
XENIA_CACHE_PERSIST=1 ./xenia-rs/target/release/xrs-c10 check \
|
|
-n 50000000 --stable-digest --out /tmp/digest-boot2.json \
|
|
"Project Sylpheed - Arc of Deception (USA, Europe) (En,Ja).iso"
|
|
|
|
# Boot 2 with Phase A event log
|
|
XENIA_CACHE_PERSIST=1 ./xenia-rs/target/release/xrs-c10 exec \
|
|
-n 50000000 --quiet \
|
|
--phase-a-event-log xenia-rs/audit-runs/cache-subsystem-plan/persist-warm-events.jsonl \
|
|
"Project Sylpheed - Arc of Deception (USA, Europe) (En,Ja).iso"
|
|
|
|
# Diff
|
|
python3 xenia-rs/tools/diff-events/diff_events.py \
|
|
--canary xenia-rs/audit-runs/phase-c10-NtQueryFullAttributesFile/canary.jsonl \
|
|
--ours xenia-rs/audit-runs/cache-subsystem-plan/persist-warm-events.jsonl \
|
|
--tid-map 6=1
|
|
```
|
|
|
|
## State at session end
|
|
|
|
`~/.local/share/xenia-rs/cache/` is left in its post-boot-2 state (7 `.tmp`
|
|
files, ~1.6 MB, 3 directories that should be files, 7 empty hash subdirs).
|
|
Next session should `rm -rf ~/.local/share/xenia-rs/cache` before Stage 1
|
|
work to start from a clean slate.
|