re: clean run reproduces; startup was eating a third of the window

Second consecutive run with no stall flag on any sample, which confirms that
disabling the periodic rescan is what fixed the freezes. Nine losses, four
flicker increases all correctly rejected, and zero confirmed arrivals. The
trustworthy negative now extends to 240 s of verified-live flight, roughly 132
game-seconds, so nothing arrives past the route table's t=90 or t=120 entries
either.

The flicker rate is worth noting: about one spurious increase per minute. That
is the rate at which the old rule would have been manufacturing arrivals.

The arithmetic of the run exposed a waste. Boot finished at 249 s, the probe ran
240 s, and the turn's 595 s cap fired, leaving about 100 s unaccounted for
between them -- the witness calibration and the initial craft enumeration.

enumerate_craft was iterating every 4-byte word of 32 MB in Python, eight
million steps, to find fourteen fixed needles. Replaced with bytes.find() per
definition VA, which is the same search at C speed and is what the vtable scan
already did. Not yet run.

If that recovers most of the hundred seconds the observation window grows from
about 240 s to about 340 s, roughly 187 game-seconds, which would finally reach
the t=170 route entry -- the first of the schedule's later arrivals that no run
has yet been able to observe.
This commit is contained in:
Sylpheed RE agent
2026-08-24 18:31:51 +00:00
parent d674fee457
commit 14385ae170
3 changed files with 66 additions and 13 deletions

View File

@@ -39,24 +39,32 @@ def scan_vt(fd, size, vt):
return sorted(out)
def enumerate_craft(fd, defs, want):
"""Heavy: full heap scan. Returns [(base, unit, roster_off)]."""
"""Full heap scan. Returns [(base, unit, roster_off)].
Was iterating every 4-byte word of 32 MB in Python -- 8 million steps -- and
the startup cost worked out at roughly 100 s of wall-clock, which is a third
of the observation window a turn can afford. Each definition VA is a fixed
4-byte needle, so bytes.find() does the same search at C speed.
"""
lo, hi = gmem.va_to_off(entities2.ENT_VA_LO), gmem.va_to_off(entities2.ENT_VA_HI)
out, pos = [], lo
while pos < hi:
m = min(1 << 24, hi - pos)
blob = os.pread(fd, m, pos)
for k in range(0, len(blob) - 3, 4):
nm = defs.get(blob[k:k+4])
if not nm: continue
base = pos + k - DELTA
head = os.pread(fd, WIN, base)
own = None
for j in range(0, len(head) - 3, 4):
(p,) = struct.unpack_from('>I', head, j)
if p in want: own = want[p]; break
out.append((base, nm, own))
for needle, nm in defs.items():
i = blob.find(needle)
while i != -1:
if (pos + i) % 4 == 0:
base = pos + i - DELTA
head = os.pread(fd, WIN, base)
own = None
for j in range(0, len(head) - 3, 4):
(p,) = struct.unpack_from('>I', head, j)
if p in want: own = want[p]; break
out.append((base, nm, own))
i = blob.find(needle, i + 1)
pos += m
return out
return sorted(out)
def alive(fd, base):
try: return struct.unpack('>f', os.pread(fd, 4, base + HULL))[0] > 0