From 45f9d0f866eb86ac0be5574d0cba9feac4536221 Mon Sep 17 00:00:00 2001 From: tetrisgm <30949000+tetrisgm@users.noreply.github.com> Date: Wed, 19 Aug 2026 02:56:27 -0700 Subject: [PATCH] autocompile: pin the overlay flavor through the spawn env (PSX_OVERLAY_FLAVOR) The runtime pins the cache dir and captures path into the spawned compile's environment so the cache can never drift from where the loader reads - but not the FLAVOR. compile_overlays.py's --flavor defaults to 0 (play), so an instrumented (flavor 2) runtime spawned compiles whose shards its own loader then rejected: the overlay_loader_status message said it plainly - "this build reads ..._f2 but shards exist under ..._f0 -> ALL overlays run INTERPRETED". On mod-heavy titles (WipEout 3's framerate packages patch most of the game text) that is the difference between full speed and ~0.2x, misread as general slowness for weeks. The runtime now exports PSX_OVERLAY_FLAVOR alongside the other pins, and the tool honors it over --flavor, so each build population self-heals. Measured after the fix (instrumented, WipEout 3 ntsc120full8): shard loads 0 -> 8 (45 funcs), interpreted insns 6.6M/s -> 1.0M/s. Co-Authored-By: Claude Fable 5 --- runtime/src/autocompile.c | 10 ++++++++++ tools/compile_overlays.py | 13 +++++++++++++ 2 files changed, 23 insertions(+) diff --git a/runtime/src/autocompile.c b/runtime/src/autocompile.c index 2018428e..33641732 100644 --- a/runtime/src/autocompile.c +++ b/runtime/src/autocompile.c @@ -855,6 +855,16 @@ int autocompile_request(void) { if (s_cache_dir[0]) SetEnvironmentVariableA("PSX_OVERLAY_CACHE_DIR", s_cache_dir); if (s_captures[0]) SetEnvironmentVariableA("PSX_OVERLAY_CAPTURES", s_captures); SetEnvironmentVariableA("PSX_OVERLAY_LIVE_AUTOCOMPILE", "1"); + /* Pin the FLAVOR the same way: the tool's --flavor defaults to 0 (play), + * so an instrumented (flavor 2) runtime spawned a compile whose shards it + * could never load — the loader's flavor guard rejected them and EVERY + * overlay ran interpreted, forever, on debug builds. The child must + * always write the flavor this runtime reads. */ + { + char flavor_buf[16]; + snprintf(flavor_buf, sizeof flavor_buf, "%d", (int)PSX_OVERLAY_FLAVOR); + SetEnvironmentVariableA("PSX_OVERLAY_FLAVOR", flavor_buf); + } /* cmd.exe /C resolves the command via PATH and supports the relative * paths in the configured line (cwd = project root). The WHOLE command is diff --git a/tools/compile_overlays.py b/tools/compile_overlays.py index 8697f3bb..14709f49 100644 --- a/tools/compile_overlays.py +++ b/tools/compile_overlays.py @@ -5262,6 +5262,19 @@ def main(): if _env_cap != args.captures: print(f'[cache] PSX_OVERLAY_CAPTURES overrides --captures: {_env_cap}') args.captures = _env_cap + # Flavor is pinned by the spawning runtime the same way as the cache + # locations: --flavor defaults to 0 (play), so an instrumented (flavor 2) + # runtime used to spawn compiles whose shards its loader then rejected — + # every overlay ran interpreted on debug builds, silently. + _env_flavor = os.environ.get('PSX_OVERLAY_FLAVOR') + if _env_flavor: + try: + _fl = int(_env_flavor, 0) + except ValueError: + _fl = None + if _fl is not None and _fl != args.flavor: + print(f'[cache] PSX_OVERLAY_FLAVOR overrides --flavor: {_fl}') + args.flavor = _fl if not args.captures: ap.error('no captures file: set PSX_OVERLAY_CAPTURES (runtime injects it) ' 'or pass --captures for manual/offline use')