re: build the fast probe -- and it refutes the diagnosis that motivated it
Last iteration I blamed four failed runs on the probe sampling every ~41 s, slower than the title screen lasts, and withdrew three earlier conclusions on that basis. Building the fix tested the claim and killed it. The speedup is real and control-verified. One long-lived ffmpeg x11grab stream, raw RGB, glyph counted in numpy -- no per-sample process startup, no PNG encode, no convert -crop: wrapper `screenshot` 3.98 s per sample (emulator running) import -window root -> PPM 1.20 s long-lived x11grab stream 0.29 s 13.7x The counter is byte-identical to is_title.py: 753 on the committed title capture, 327 on the main menu. Pointed at a running game it says the opposite of what I expected: 332 frames in 85.3 s = 3.89 fps; max glyph 0 1674 frames in 420.0 s = 3.99 fps; max glyph 0 1674 consecutive samples over seven unbroken minutes, four per second, zero green-(A) pixels. Sampling rate was a real defect that happened not to be the cause. So "neither locale reaches the interactive title without a pad press" -- withdrawn last iteration for want of evidence -- is reinstated, now as a dense measurement, with its reach stated: a MID-RUN window only, silent about the boot title. Leading hypothesis, unconfirmed: the PRESS (A) plate appears only in the boot title window and the attract loop's title carries none, which is exactly what title_states_capture.sh was written to test. The experiment is to start the fast probe from t=0 rather than attach to a run already in progress. METHOD: fixing the instrument is how you test the explanation that blamed it -- a plausible mechanism is a hypothesis, and the fix is its experiment, not its proof.
This commit is contained in:
@@ -120,8 +120,18 @@ afterwards is using canary's own persistence, not patching its code.
|
|||||||
two-grab polling loop therefore samples every **~41 s**, against a title screen
|
two-grab polling loop therefore samples every **~41 s**, against a title screen
|
||||||
this corpus documents as lasting *a few seconds*. Four runs — two locales, two
|
this corpus documents as lasting *a few seconds*. Four runs — two locales, two
|
||||||
launch paths, two gamma settings — were all blinking slower than the event.
|
launch paths, two gamma settings — were all blinking slower than the event.
|
||||||
Everything below is the trail that led there; the conclusions it draws about the
|
🔴 **…and that diagnosis is itself refuted (same day).** The faster probe was
|
||||||
*game* are withdrawn. See [capture-harness-status](../re/capture-harness-status.md).
|
built — 3.98 s → **0.29 s** per sample, 13.7×, control-verified at 753/327 — and
|
||||||
|
at 3.99 fps for **420 continuous seconds (1 674 samples)** the interactive title
|
||||||
|
*still* never appeared. Sampling rate was a real defect and not the cause.
|
||||||
|
✅ So "the interactive title does not appear mid-run without a pad press" is
|
||||||
|
reinstated, now as a dense measurement. ⚠️ Its reach is a **mid-run** window; it
|
||||||
|
says nothing about the boot title.
|
||||||
|
🟡 Leading hypothesis, unconfirmed: the plate appears only in the **boot** title
|
||||||
|
window and the attract loop's title has none — which is precisely what
|
||||||
|
`title_states_capture.sh` was written to test. The experiment is to start the
|
||||||
|
fast probe from t=0, not attach to a run already in progress.
|
||||||
|
See [capture-harness-status](../re/capture-harness-status.md).
|
||||||
|
|
||||||
**🟡 Still not settled — two runs, and the reason moved again.**
|
**🟡 Still not settled — two runs, and the reason moved again.**
|
||||||
|
|
||||||
|
|||||||
@@ -510,3 +510,11 @@ agent's loop prompt, i.e. nowhere durable. See [`README.md`](README.md) for the
|
|||||||
classifies movie-vs-static on an *absolute* rmse threshold — so the gamma
|
classifies movie-vs-static on an *absolute* rmse threshold — so the gamma
|
||||||
change biased the very classifier the run depended on. Harness thresholds tuned
|
change biased the very classifier the run depended on. Harness thresholds tuned
|
||||||
on one output configuration are not portable to another.
|
on one output configuration are not portable to another.
|
||||||
|
* **Fixing the instrument is how you test the explanation that blamed it.** I
|
||||||
|
diagnosed four failed runs as "the probe samples slower than the event",
|
||||||
|
wrote it up, and withdrew three earlier conclusions on that basis. Building the
|
||||||
|
faster probe refuted it: at 100× the sampling density, over 420 unbroken
|
||||||
|
seconds, the event still never occurred. The diagnosis was a real defect that
|
||||||
|
happened not to be the cause — the most seductive kind, because fixing it feels
|
||||||
|
like confirmation. A plausible mechanism that explains a failure is a
|
||||||
|
hypothesis, and the fix is its experiment, not its proof.
|
||||||
|
|||||||
@@ -436,3 +436,13 @@ neighbourhood, not just the line.
|
|||||||
costs 10.8 s while the emulator runs (0.117 s idle, 92×). A title lasting a few
|
costs 10.8 s while the emulator runs (0.117 s idle, 92×). A title lasting a few
|
||||||
seconds would be missed. The observations stand; the conclusions drawn from
|
seconds would be missed. The observations stand; the conclusions drawn from
|
||||||
them do not. [`capture-harness-status.md`](capture-harness-status.md)
|
them do not. [`capture-harness-status.md`](capture-harness-status.md)
|
||||||
|
* "the boot harness fails because its polling loop samples every ~41 s, slower
|
||||||
|
than the title screen lasts" → **mine, and refuted by my own fix.** The
|
||||||
|
sampling defect was real (3.98 s → 0.29 s per sample, 13.7×, control-verified
|
||||||
|
at 753/327), but a probe running at 3.99 fps for **420 continuous seconds —
|
||||||
|
1 674 samples — still saw zero green-Ⓐ pixels.** Sampling rate was not the
|
||||||
|
cause. [`capture-harness-status.md`](capture-harness-status.md)
|
||||||
|
* ~~"neither locale reaches the interactive title without a pad press"~~ →
|
||||||
|
withdrawn last iteration for want of evidence, now **reinstated as a
|
||||||
|
measurement**: 1 674 dense samples over 420 s, English, zero glyph frames.
|
||||||
|
⚠️ Reach: a mid-run window only; it says nothing about the boot title.
|
||||||
|
|||||||
@@ -57,7 +57,61 @@ inflates that difference and biases every frame toward "movie". **The capture
|
|||||||
harness's tuning is coupled to the display settings** — changing gamma and
|
harness's tuning is coupled to the display settings** — changing gamma and
|
||||||
capture behaviour in one run confounds both.
|
capture behaviour in one run confounds both.
|
||||||
|
|
||||||
## The fix, not applied here
|
## 🔴 The fix works — and it REFUTES the diagnosis above
|
||||||
|
|
||||||
|
Built and measured (`tools/re-capture/fast_title_probe.py`): one long-lived
|
||||||
|
`ffmpeg` x11grab stream, raw RGB frames, glyph counted in numpy. No per-sample
|
||||||
|
process startup, no PNG encode, no `convert -crop`.
|
||||||
|
|
||||||
|
| probe | seconds per sample, emulator running |
|
||||||
|
|---|---|
|
||||||
|
| the wrapper `screenshot` | **3.98** |
|
||||||
|
| `import -window root` → PPM | 1.20 |
|
||||||
|
| **long-lived x11grab stream** | **0.29** |
|
||||||
|
|
||||||
|
**13.7× faster**, and the counter is control-verified against the committed
|
||||||
|
frames — it returns **753** on `live-title-press-a.png` and **327** on
|
||||||
|
`live-main-menu.png`, byte-identical to `is_title.py`.
|
||||||
|
|
||||||
|
Then it was pointed at a running game:
|
||||||
|
|
||||||
|
```
|
||||||
|
332 frames in 85.3 s = 3.89 fps; max glyph 0
|
||||||
|
1674 frames in 420.0 s = 3.99 fps; max glyph 0
|
||||||
|
```
|
||||||
|
|
||||||
|
**1 674 consecutive samples over seven unbroken minutes, four per second, and the
|
||||||
|
interactive title never appeared.** So the sampling rate was a real defect and
|
||||||
|
*not* the cause. The hypothesis on this page — that the harness was blinking
|
||||||
|
slower than the event — is **mine, and refuted by my own fix**.
|
||||||
|
|
||||||
|
## What that restores
|
||||||
|
|
||||||
|
Last iteration I withdrew three conclusions on the strength of that hypothesis.
|
||||||
|
The withdrawal was right at the time (15 samples at 41 s intervals cannot support
|
||||||
|
them) and is now **superseded by better evidence**: dense sampling says the
|
||||||
|
interactive title genuinely does not appear in a mid-run window. Reinstated as a
|
||||||
|
**measurement**, with its reach:
|
||||||
|
|
||||||
|
* ✅ over **420 continuous seconds**, English, `gamma_type = 2`, ~13 minutes into
|
||||||
|
a run with no pad input, **zero** frames carried the green Ⓐ glyph.
|
||||||
|
* ⚠️ Reach: this covers a **mid-run** window only. It says nothing about the
|
||||||
|
first minutes of boot.
|
||||||
|
|
||||||
|
## 🟡 The leading hypothesis, not confirmed
|
||||||
|
|
||||||
|
The corpus already suspects the answer. `title_states_capture.sh` exists to test
|
||||||
|
*"whether the interactive one draws `ptbtn00` (the PRESS Ⓐ plate) and the other
|
||||||
|
does not"* — i.e. the title appears **twice**: once at the end of the boot
|
||||||
|
sequence, and again from the attract loop, and only the first may carry the
|
||||||
|
plate. If so, the plate's window is early and one-shot, and no amount of
|
||||||
|
mid-run sampling will ever find it.
|
||||||
|
|
||||||
|
That is consistent with everything measured, and it is **not confirmed**. The
|
||||||
|
test is to start the fast probe *before* the boot title — from t=0 rather than
|
||||||
|
attaching to a run already in progress.
|
||||||
|
|
||||||
|
## The original fix note, kept
|
||||||
|
|
||||||
Make the probe cheap enough to sample faster than the title window: grab a small
|
Make the probe cheap enough to sample faster than the title window: grab a small
|
||||||
region rather than the full surface, drop the ImageMagick `convert` round trip,
|
region rather than the full surface, drop the ImageMagick `convert` round trip,
|
||||||
|
|||||||
34
tools/re-capture/fast_title_probe.py
Executable file
34
tools/re-capture/fast_title_probe.py
Executable file
@@ -0,0 +1,34 @@
|
|||||||
|
"""Fast title probe: one long-lived x11grab stream, ~3.5 fps, glyph count per frame.
|
||||||
|
|
||||||
|
Replaces the two-`screenshot` polling loop, which costs ~4-11 s per grab while
|
||||||
|
xenia runs and so samples every ~41 s -- slower than the title screen lasts.
|
||||||
|
Counter is byte-identical to is_title.py (controlled: 753 on the committed title
|
||||||
|
capture, 327 on the main menu).
|
||||||
|
"""
|
||||||
|
import subprocess, sys, time
|
||||||
|
import numpy as np
|
||||||
|
W,H = 1280,720
|
||||||
|
LIMIT = float(sys.argv[1]) if len(sys.argv)>1 else 120
|
||||||
|
NEED = int(sys.argv[2]) if len(sys.argv)>2 else 400
|
||||||
|
p = subprocess.Popen(["ffmpeg","-loglevel","error","-f","x11grab","-draw_mouse","0",
|
||||||
|
"-video_size",f"{W}x{H}","-i",":98","-r","4","-f","rawvideo","-pix_fmt","rgb24","-"],
|
||||||
|
stdout=subprocess.PIPE, bufsize=W*H*3*2)
|
||||||
|
n=W*H*3; t0=time.time(); frames=0; best=0; hits=0
|
||||||
|
while time.time()-t0 < LIMIT:
|
||||||
|
buf=p.stdout.read(n)
|
||||||
|
if len(buf)<n: break
|
||||||
|
a=np.frombuffer(buf,np.uint8).reshape(H,W,3).astype(int)
|
||||||
|
r,g,b=a[:,:,0],a[:,:,1],a[:,:,2]
|
||||||
|
c=int(((g>130)&(g-r>45)&(g-b>45)).sum())
|
||||||
|
frames+=1
|
||||||
|
if c>best:
|
||||||
|
best=c
|
||||||
|
if c>=NEED:
|
||||||
|
from PIL import Image
|
||||||
|
Image.fromarray(a.astype(np.uint8)).save("/sylph-home/re/shots/fast-title.png")
|
||||||
|
if c>=NEED:
|
||||||
|
hits+=1
|
||||||
|
if hits==1: print(f"TITLE at t={time.time()-t0:.1f}s glyph={c} (frame {frames})", flush=True)
|
||||||
|
p.kill()
|
||||||
|
dt=time.time()-t0
|
||||||
|
print(f"{frames} frames in {dt:.1f}s = {frames/dt:.2f} fps; max glyph {best}; hits {hits}")
|
||||||
Reference in New Issue
Block a user