The port s boot sequencer paces every screen off rest.t, which is the last hold keyframe rather than when a screen arrives. Measured on one cold boot: the container had no Xenia storage root at all, so this is a fresh profile with no shader cache, the slowest case. title build-in (first ink -> art fully drawn) 0.23 s title settled -> PRESS A plate on 2.247 s (disc declares 120 units) plate pulse period ~2.37 s main menu build-in 0.531 s B -> title 0.482 s A -> menu 3.763 s DO NOT AUTHOR, see below The title s rest.t is 251 units = 4.183 s and its art is finished at about 2 s, so a sequencer pacing off rest.t holds it roughly twice as long as the game does. Instrument controlled before the run: 9/9 on the content classifier including the movie-frame and difficulty-screen negatives, 4/4 on the plate detector; the run sampled 7.99 fps against a requested 8 with an independent one-shot grab cross-checking every 20 s. Records a refutation attempt of mine that FAILED. The probe s own marks gave a plate delay of 3.203 s against the corpus s 2.13 s, which on a cold-cache boot looked like a real effect. It was the instrument: the plate pulse period is an internal clock for presentation rate and measures 2.369 s here against the corpus s 2.3, so the run is not slowed, and re-measuring from content gives 2.247 s. The probe s title_static mark fires during the crossfade out of the attract movie, before the wordmark has drawn -- glyph was still 0 when it fired. Also a third independent reproduction of the A-path load stall: 13 frames, 1.53 s, surface mean 26.631 against the earlier 14/1.53 and 12/1.39 at 26.626. This boot had no shader cache, so it is not a warm-cache artefact. Noted that the earlier pair agreed to six decimals and mine agrees to three. Reach: one run. The menu build-in and B->title rest on it alone. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd
82 lines
2.7 KiB
Python
Executable File
82 lines
2.7 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Offline: when does each screen ARRIVE, and when does it SETTLE?
|
|
|
|
`rest.t` is the last hold keyframe, not when a screen stops moving -- the port
|
|
paces its boot sequencer off it and is late. This reads the timing probe's TSV
|
|
and reports, per screen segment:
|
|
|
|
arrive first frame the classifier labels that screen
|
|
settle first frame after `arrive` where inter-frame motion stays below the
|
|
quiet threshold for SETTLE_HOLD consecutive frames
|
|
dwell how long the label persists
|
|
|
|
The quiet threshold is CALIBRATED FROM THE RUN, not assumed: it is a multiple of
|
|
the motion floor observed while a label is stable and late in its segment.
|
|
"""
|
|
import sys
|
|
import numpy as np
|
|
|
|
SETTLE_HOLD = 4 # consecutive quiet frames before calling it settled
|
|
|
|
def main(path):
|
|
rows = []
|
|
meta = []
|
|
for ln in open(path):
|
|
if ln.startswith("#"):
|
|
meta.append(ln.rstrip())
|
|
continue
|
|
f = ln.rstrip("\n").split("\t")
|
|
if len(f) < 8:
|
|
continue
|
|
rows.append((float(f[0]), int(f[1]), float(f[2]), float(f[3]), f[7]))
|
|
if not rows:
|
|
print("no data rows"); return 2
|
|
t = np.array([r[0] for r in rows])
|
|
motion = np.array([r[3] for r in rows])
|
|
labels = [r[4] for r in rows]
|
|
n = len(rows)
|
|
fps = n / (t[-1] - t[0]) if t[-1] > t[0] else 0
|
|
print(f"{n} frames, {t[-1]-t[0]:.1f} s, {fps:.2f} fps")
|
|
for m in meta:
|
|
if m.startswith("#summary") or m.startswith("#event"):
|
|
print(" " + m)
|
|
|
|
valid = motion[motion >= 0]
|
|
if valid.size == 0:
|
|
print("no motion data"); return 2
|
|
floor = float(np.percentile(valid, 10))
|
|
quiet = max(floor * 3.0, 0.05)
|
|
print(f"\nmotion floor (10th pct) {floor:.4f} -> quiet threshold {quiet:.4f}")
|
|
|
|
# Segment by contiguous label.
|
|
segs = []
|
|
i = 0
|
|
while i < n:
|
|
j = i
|
|
while j + 1 < n and labels[j + 1] == labels[i]:
|
|
j += 1
|
|
segs.append((labels[i], i, j))
|
|
i = j + 1
|
|
|
|
print(f"\n{'screen':<14} {'arrive':>8} {'settle':>8} {'build-in':>9} {'leaves':>8} {'dwell':>8} {'frames':>7}")
|
|
for lab, a, b in segs:
|
|
if b - a < 2:
|
|
continue
|
|
settle = None
|
|
run = 0
|
|
for k in range(a, b + 1):
|
|
if 0 <= motion[k] < quiet:
|
|
run += 1
|
|
if run >= SETTLE_HOLD:
|
|
settle = t[k - SETTLE_HOLD + 1]
|
|
break
|
|
else:
|
|
run = 0
|
|
build = f"{settle - t[a]:9.3f}" if settle is not None else " -"
|
|
s = f"{settle:8.3f}" if settle is not None else " -"
|
|
print(f"{lab:<14} {t[a]:8.3f} {s} {build} {t[b]:8.3f} {t[b]-t[a]:8.3f} {b-a+1:7d}")
|
|
return 0
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main(sys.argv[1]))
|