Skip to content

fix(vcores): the core-wait escape at 2 s, not 250 ms (#1929) - #2127

Merged
NotRexed merged 2 commits into
mainfrom
fix/vcore-escape-2s
Nov 11, 2026
Merged

NotRexed merged 2 commits into
mainfrom
fix/vcore-escape-2s

Conversation

@NotRexed

Copy link
Copy Markdown
Owner

Part of #1929. When a guest thread has waited too long for a virtual core, the scheduler lets it run without one (an "escape"). The holder is still running on that core, so the two threads share per-core state. That race is the risk #1929 is about.

On current main (after 9f42700, "WaitAny's scan makes no vcore checkpoint while it holds mw_lock"), the waits that reach 250 ms end by themselves within about 1.2 s. The 250 ms escape fires anyway, 6-8 times per run. This raises both defaults (HOS_VCORE_ESCAPE_US, HOS_VCORE_ESCAPE_EQ_US) to 2 s. The escape stays as a deadlock breaker, and either value can still be set from the environment.

A/B, measured on current main: 25-minute route (Kokiri Forest, Hyrule Field, Kakariko), RTX 4060 Ti, docked 1440p, two rounds each, alternating.

run escapes longest core wait p99 p99.9 max frame crashes
250 ms, round 1 8 251 ms 28.9 ms 81.1 ms 641 ms 0
2 s, round 1 0 909 ms 28.6 ms 81.4 ms 619 ms 0
250 ms, round 2 6 252 ms 27.5 ms 77.4 ms 584 ms 0
2 s, round 2 0 1162 ms 27.4 ms 77.3 ms 573 ms 0

The longer waits do not show up as longer frames: the worst frame is the same or shorter at 2 s. An earlier A/B with a 5 s escape, before 9f42700, did produce 5 s frames. Those long holds are gone on current main.

🤖 Generated with Claude Code

An escape runs a waiting thread with no virtual core while the holder still runs on it, so two threads share per-core state. On current main the waits that reached 250 ms ended by themselves within 1.2 s, so the 250 ms escape fired 6-8 times a run for nothing. Measured A/B: 0 escapes at 2 s in both rounds, frame times the same or better. The escape stays as a deadlock breaker.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
NotRexed added a commit that referenced this pull request Nov 11, 2026
…once (flaky JSONDecodeError) (#2130)

`tests/test_release_scripts.py` fails now and then on Linux, as it did
on main at 364d199 and on #2127. The failing test is
`test_tag_pushed_by_hand_gets_its_release_and_sums`; the stand-in `gh`
hits `json.decoder.JSONDecodeError: Expecting value: line 1 column 1`
when it reads its state file.

The cause: `scripts/release_files.sh check` runs two `gh` calls at the
same time (`cmp -s <(sums "$id") <(uploaded "$id")`). Every stand-in
call appends itself to `calls` and rewrites the state file with
`open(STATE, "w")`. So one call can read the file while the other has
just truncated it.

The stand-in now:
- holds an exclusive `fcntl` lock for the whole call, so calls take
turns and no entry in `calls` is lost;
- writes its state to a temporary file and moves it into place with
`os.replace`.

The test is the only thing changed; the release scripts stay as they
are. It needs `jq` and only runs on Linux, so this was not run locally;
CI checks it.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@mooki000

Copy link
Copy Markdown
Contributor

Measured after the merge on Linux (Arch, RTX 4090, NVIDIA 615.78.08, headless): the issue's start (fresh profile, Start
about 95 s into the title, 165 s per run), the build of this pull request's commit with HOS_VCORE_ESCAPE_US/_EQ_US
set to 250000 (the old default) against the same build as merged, three runs each, interleaved in one sitting. Not
exclusive: load average 4-8 at the start of four runs, 20 and 66 at the other two.

escapes per run longest core wait crashes after Start: fps / 1% low / worst frame
250 ms 7, 8, 2 251, 251, 251 ms 0 59.9 / 37.1 / 104 ms
2 s 0, 0, 0 983, 947, 1162 ms 0 59.8 / 33.2 / 76 ms

The same as on your route: no escapes at 2 s, the longest waits end within 1.2 s, frame times the same within the spread.
At a first start (the button-prompt textures written again; 30 s, three runs each) it was 1, 6 and 1 escapes at 250 ms
and none at 2 s. Where the waits over 250 ms came from on this machine, and two host waits that keep a core, are in my
comment on #1929.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants