re: second freeze at ~96s with the inducer on; T74/T75 signature withdrawn

Run 2 put the inducer on from flight start and froze ~96s in, against 670s
clean with it off -- n=2, contrast sharp, confounder (elapsed mission time)
still untouched.

Withdraws last iteration's 'T74/T75 move off a semaphore onto an event' as the
signature to chase: it does not reproduce. In run 2 they are on XEvent while
HEALTHY and stay there. The healthy state varies between instants, so a
one-sample-per-state diff cannot separate a freeze transition from ordinary
variation -- I read a difference of samples as a difference of states.

Reproduces across both: T68 and T69 go from not-waiting to waiting, T69 on a
semaphore and T68 on an event both times. And 21 of 24 threads unchanged in run
2 (17 of 24 in run 1), so 'not a whole-emulator stall' now has two independent
captures behind it.

Next: repeat the capture several times within one healthy run to establish which
thread states are stable before reading any frozen diff.
This commit is contained in:
Sylpheed RE agent
2026-08-25 10:10:14 +00:00
parent a1820b1335
commit 7323eb9d39
2 changed files with 133 additions and 0 deletions

View File

@@ -0,0 +1,85 @@
=== healthy: 22 wait frames ===
T106 Wait n=1 xe::kernel::XEvent
T105 Wait n=1 xe::kernel::XEvent
T104 Wait n=1 xe::kernel::XEvent
T97 Wait n=1 xe::kernel::XEvent
T96 Wait n=1 xe::kernel::XEvent
T80 WaitMultiple n=2 xe::kernel::XEvent, xe::kernel::XSemaphore
T79 WaitMultiple n=2 xe::kernel::XEvent, xe::kernel::XSemaphore
T78 WaitMultiple n=2 xe::kernel::XEvent, xe::kernel::XSemaphore
T77 Wait n=1 xe::kernel::XEvent
T76 WaitMultiple n=2 xe::kernel::XEvent, xe::kernel::XTimer
T75 Wait n=1 xe::kernel::XEvent
T74 Wait n=1 xe::kernel::XEvent
T71 Wait n=1 xe::kernel::XEvent
T67 Wait n=1 xe::kernel::XEvent
T66 Wait n=1 xe::kernel::XEvent
T65 WaitMultiple n=2 xe::kernel::XEvent, xe::kernel::XSemaphore
T64 WaitMultiple n=2 xe::kernel::XEvent, xe::kernel::XSemaphore
T63 Wait n=1 xe::kernel::XSemaphore
T62 Wait n=1 xe::kernel::XEvent
T61 Wait n=1 xe::kernel::XEvent
T50 Wait n=1 xe::kernel::XEvent
T36 WaitMultiple n=2 xe::kernel::XEvent, xe::kernel::XEvent
--- objects waited on:
xe::kernel::XEvent 22
xe::kernel::XSemaphore 6
xe::kernel::XTimer 1
=== frozen: 23 wait frames ===
T106 Wait n=1 xe::kernel::XEvent
T105 Wait n=1 xe::kernel::XEvent
T104 Wait n=1 xe::kernel::XEvent
T97 Wait n=1 xe::kernel::XEvent
T96 Wait n=1 xe::kernel::XEvent
T80 WaitMultiple n=2 xe::kernel::XEvent, xe::kernel::XSemaphore
T79 WaitMultiple n=2 xe::kernel::XEvent, xe::kernel::XSemaphore
T78 WaitMultiple n=2 xe::kernel::XEvent, xe::kernel::XSemaphore
T77 Wait n=1 xe::kernel::XEvent
T76 WaitMultiple n=2 xe::kernel::XEvent, xe::kernel::XTimer
T75 Wait n=1 xe::kernel::XEvent
T74 Wait n=1 xe::kernel::XEvent
T71 Wait n=1 xe::kernel::XEvent
T69 Wait n=1 xe::kernel::XSemaphore
T68 Wait n=1 xe::kernel::XEvent
T67 Wait n=1 xe::kernel::XEvent
T66 Wait n=1 xe::kernel::XEvent
T65 WaitMultiple n=2 xe::kernel::XEvent, xe::kernel::XSemaphore
T64 WaitMultiple n=2 xe::kernel::XEvent, xe::kernel::XSemaphore
T63 Wait n=1 xe::kernel::XSemaphore
T62 Wait n=1 xe::kernel::XEvent
T61 Wait n=1 xe::kernel::XEvent
T50 Wait n=1 xe::kernel::XEvent
--- objects waited on:
xe::kernel::XEvent 21
xe::kernel::XSemaphore 7
xe::kernel::XTimer 1
=== healthy -> frozen ===
xe::kernel::XEvent 22 -> 21 CHANGED
xe::kernel::XSemaphore 6 -> 7 CHANGED
xe::kernel::XTimer 1 -> 1
=== per-thread healthy -> frozen ===
thread healthy frozen
T106 Wait(XEvent) Wait(XEvent)
T105 Wait(XEvent) Wait(XEvent)
T104 Wait(XEvent) Wait(XEvent)
T97 Wait(XEvent) Wait(XEvent)
T96 Wait(XEvent) Wait(XEvent)
T80 WaitMultiple(XEvent,XSemaphore) WaitMultiple(XEvent,XSemaphore)
T79 WaitMultiple(XEvent,XSemaphore) WaitMultiple(XEvent,XSemaphore)
T78 WaitMultiple(XEvent,XSemaphore) WaitMultiple(XEvent,XSemaphore)
T77 Wait(XEvent) Wait(XEvent)
T76 WaitMultiple(XEvent,XTimer) WaitMultiple(XEvent,XTimer)
T75 Wait(XEvent) Wait(XEvent)
T74 Wait(XEvent) Wait(XEvent)
T71 Wait(XEvent) Wait(XEvent)
T69 -- Wait(XSemaphore) <-- CHANGED
T68 -- Wait(XEvent) <-- CHANGED
T67 Wait(XEvent) Wait(XEvent)
T66 Wait(XEvent) Wait(XEvent)
T65 WaitMultiple(XEvent,XSemaphore) WaitMultiple(XEvent,XSemaphore)
T64 WaitMultiple(XEvent,XSemaphore) WaitMultiple(XEvent,XSemaphore)
T63 Wait(XSemaphore) Wait(XSemaphore)
T62 Wait(XEvent) Wait(XEvent)
T61 Wait(XEvent) Wait(XEvent)
T50 Wait(XEvent) Wait(XEvent)
T36 WaitMultiple(XEvent,XEvent) -- <-- CHANGED

View File

@@ -1042,3 +1042,51 @@ unpacking and comparing every word in Python takes **~4.2 s per pass**.
**The experiment that would settle it:** alternate inducer-on and inducer-off
windows within one run, several runs, and compare freeze rate per unit of
*mission* time. Cheap now that `watch` is event-driven.
## ✅ 2026-08-25 — second freeze, and it REFUTES the signature I named
Ran the control's opposite: inducer **on from the moment flight begins**
(`freeze_waitobj.sh run` with `SYLPH_INDUCE=1`, launched detached so no `timeout`
can kill the process group).
| run | inducer | outcome |
|---|---|---|
| 1 | off for 670 s, then on | clean 670 s, then **frozen 54 s** after it started |
| 2 | **on from flight start** (10:07:20) | **frozen ~96 s later** (10:08:56) |
Both freezes land inside the 27255 s band the old heavy-probe runs froze in,
and the one long clean stretch is the only window with no inducer. **n=2, and the
contrast is now sharp** — but it is still two runs, the confounder (elapsed
mission time) is untouched, and the alternating-window test is what would settle
it.
### 🔴 WITHDRAWN: "T74/T75 move off a semaphore onto an event"
Last iteration I called that "the pair to chase — the only threads that change
what *kind* of object they wait for". **It does not reproduce.** In run 2, T74
and T75 sit on `Wait(XEvent)` in the *healthy* capture and stay there when
frozen.
The reason is a sampling error I should have caught: the **healthy** state is not
fixed either. Run 1 happened to catch T74/T75 on a semaphore; run 2 caught them
on an event. A one-sample-per-state comparison cannot tell a freeze transition
from ordinary variation between two instants, and I read a difference of samples
as a difference of states.
### ✅ What DOES reproduce across both freezes
**T68 and T69 go from not-waiting to waiting, in both runs** — and T69 lands on
an `XSemaphore` both times, T68 on an `XEvent` both times. Everything else is
run-specific: run 1 also parked T105/T67, run 2 instead dropped T36 out of its
wait.
And in both runs the great majority of threads are untouched — 17 of 24 in run 1,
**21 of 24** in run 2 — which keeps the one structural claim that has now
survived two independent captures: **the freeze is not a whole-emulator stall.**
Data: `data/waitobj-s02.txt` (run 1), `data/waitobj-s02-inducer.txt` (run 2).
**Still open:** whether T68/T69 are cause or consequence; one sample per state
cannot say. The fix for the error above applies here too — **repeat the capture
several times within a single healthy run** to learn which thread states are
stable before reading any frozen diff as meaningful.