mirror of
https://github.com/libretro/virtualjaguar-libretro.git
synced 2026-11-07 04:36:00 -10:00
Gates G1-G5 before releases default the emulation thread On: threaded twins for the 20 app tests without one, every CI platform, the Studio 60 Hz measurement, Windows/Linux/120 Hz reports and a two-week nightly window. Three PRs: 5a twins, 5b evidence record, 5c the flip (last). The inline loop is retired only after a default-on release ships. Co-authored-by: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
06fa8a7193
commit
43383a050a
1 file changed
+106
@@ -0,0 +1,106 @@
|
||||
# Emulation thread, Phase 5 plan (qualify the stable default)
|
||||
|
||||
Issue: #1039 (part of #967 / #254). Design of record: [app-emulation-thread-design.md](app-emulation-thread-design.md), section 8 "Rollout". Earlier phases: [1](app-emulation-thread-plan-phase1.md), [2](app-emulation-thread-plan-phase2.md), [3](app-emulation-thread-plan-phase3.md), [4](app-emulation-thread-plan-phase4.md).
|
||||
|
||||
**Goal:** the 4.0 release turns Settings > Interface > Emulation thread **On by default**, on evidence, with the inline loop still selectable. This phase is mostly qualification. The only behaviour change is the last PR, which flips the release default.
|
||||
|
||||
**Not in this phase:**
|
||||
- **Retiring the inline loop** (`stepEmulation`, `Pacer`, the inline branch of `runInteractive`). #1039's rule replaces the phase 4 plan's "Retiring the inline loop (phase 5)": remove it only after a stable release has shipped default-on without regressions. That follow-up issue is filed when the evidence exists, not before.
|
||||
- **Changing Frame pacing's default.** It stays Jaguar rate unless decision 1 below says otherwise.
|
||||
|
||||
## Where it stands (2026-10-31, develop @ fe80b36a)
|
||||
|
||||
- **Phases 1–4 are merged.** Nothing is switched off while threaded: `no_threaded_limits` enforces this statically in CI. Mode B is in (#1125, #1128).
|
||||
- **Nightlies default On since phase 3d** (about 2026-10-24); releases and `dev` builds default Off. No threading issue has been filed since. That is a week with no reports, not qualification evidence.
|
||||
- **Headless runs stay inline whatever the default** (`app.cpp`, the `emuThreadThisRun_` decision). Flipping a channel's default therefore changes no existing test's mode, and the inline tests keep covering the fallback.
|
||||
- **CI coverage today:**
|
||||
- 82 tests carry `LABELS emu_thread`. They run in all seven `app.yml` configurations: macOS arm64, Linux x86_64 (dev and nightly channel), Linux aarch64, Windows x86_64 MinGW, Windows ARM64, and MSVC (experimental).
|
||||
- The TSan job runs `ctest -L emu_thread` on Linux. On the merged mode B code, 82 of 82 pass, re-run on the Studio.
|
||||
- **Windowed coverage today:** the Studio's 60 Hz panel (macOS) only. Headless CI never has vsync, so the late latch and mode B are exercised on Windows and Linux only by unit tests with fake clocks.
|
||||
|
||||
## Gates
|
||||
|
||||
Each gate lists its evidence. Gates 1–3 are work in this repo; gates 4 and 5 are evidence that has to come in. The flip (PR 5c) opens only when every gate is met or the maintainer waives it in writing on #1039.
|
||||
|
||||
| Gate | Met when | Evidence goes to |
|
||||
|---|---|---|
|
||||
| **G1 coverage** | Every headless test that runs the app with content has a `_threaded` twin, or a line here saying why it is mode-specific | PR 5a |
|
||||
| **G2 platforms** | G1's twins pass on every `app.yml` configuration: the six required ones, plus MSVC, which may stay experimental. TSan stays green | PR 5a CI |
|
||||
| **G3 Studio, 60 Hz** | The phase 4 measurement passes its bar (below) and the transition runs recover. The phase 1 gate (`emu_thread_gate_check.sh`) passes on the 4.0 candidate | #1128 comment, then the evidence table here |
|
||||
| **G4 other displays** | At least one windowed report each for Windows, Linux and a 120 Hz panel, threaded, with no regression against inline | #1039 comments |
|
||||
| **G5 nightly window** | Two weeks of nightlies with no open threading regression; any report is fixed or shown not to be a threading issue | #1039 |
|
||||
|
||||
**G3 bar** (phase 4, Task 8):
|
||||
- Mode B event→present within ~2 ms of inline on every title, Cybermorph included.
|
||||
- No periodic repeat in mode B.
|
||||
- No new underruns.
|
||||
- CPU within +5% of mode A.
|
||||
- PAL reports the `ratio` fallback.
|
||||
|
||||
Mode A must not regress against the phase 1 numbers.
|
||||
|
||||
### G1: tests without a threaded twin
|
||||
|
||||
Taken from `ctest --show-only=json-v1` at fe80b36a. These are tests whose command runs `virtualjaguar` with content and passes no `--emu-thread`, and that have no `_threaded` twin.
|
||||
|
||||
| Area | Tests | Twin |
|
||||
|---|---|---|
|
||||
| Smoke | `smoke_cd`, `smoke_boot_cart_rom`, `smoke_disc_insert_cart_hidden`, `smoke_bad_option`, `smoke_locked_option` | add |
|
||||
| Cheats | `cheat_state`, `cheat_apply_control`, `cheat_persist_{save,restart,control}`, `cheat_tempest_{lives,control}`, `cheat_community_install` | add. The persist chain needs its own data directory and fixtures |
|
||||
| Overlay | `controls_overlay_{default,keyboard,dismissed,rebound}` | add |
|
||||
| Netplay | `netplay_pair_shared` | add (the other pair tests already have one) |
|
||||
|
||||
Mode-specific by design, so no twin:
|
||||
- `gdb_inline_halt*`, `neuro_app_inline`, `netplay_pair_mixed` (one peer each way), `emu_thread_default_smoke_*`.
|
||||
- `tv_menu_headless` and `tv_script_windowed_only`: a headless TV script always runs inline (`app.cpp`).
|
||||
- `native_menu_dump`: no content.
|
||||
- `netplay_discovery`: skipped in CI.
|
||||
|
||||
The `*_e2e` tests (`input_e2e`, `devices_e2e`, `bios_e2e`, `debug_scan_e2e`, `debug_op_e2e`) drive `CoreHost` directly, not the app loop. Their threaded counterparts are `core_host_thread` and `emu_thread_e2e`.
|
||||
|
||||
**Shutdown.** These already cover it:
|
||||
- `emu_thread_unit` covers shutdown races.
|
||||
- `gdb_threaded_halt` covers SIGTERM mid-halt.
|
||||
- `debug_e2e_threaded` covers the 3 s join while halted.
|
||||
|
||||
5a adds one headless case: quit while a slow load `call()` is in flight (`VJ_TEST_SLOW_CALL_MS`, as `smoke_busy_threaded` uses). It must exit 0 within the join timeout with no owner violation.
|
||||
|
||||
## PRs
|
||||
|
||||
- **5a `test(app)`: threaded twins (G1, G2).**
|
||||
- The twins listed above go through the registration each area already uses: the `_threaded` loop in `VJEmuThreadTests.cmake`, the twin helper in `VJAchTests.cmake`, or the same pattern added to `VJCheatTests.cmake` and `VJSmokeTests.cmake`.
|
||||
- Each twin carries `LABELS emu_thread`, so the TSan job runs it.
|
||||
- Each twin must reach the same pass regex as its inline original. A twin that needs a different expectation is a finding, not a test tweak.
|
||||
- Fix any real failure in its own PR, outside 5a.
|
||||
- Refs #1039.
|
||||
- **5b `docs(app)`: qualification record.**
|
||||
- The evidence table below, filled from G3–G5.
|
||||
- A short "Reporting a threading problem" note in the README's "Emulation thread" section: how to report (the About window's version and channel line, the perf note, `--emu-thread off` to compare).
|
||||
- One pinned comment on #1039 asking nightly users for G4 reports.
|
||||
- Refs #1039.
|
||||
- **5c `feat(app)`: releases default the emulation thread On (the flip, last).**
|
||||
- `emuThreadDefaultFor("release")` returns true. `VJ_EMU_THREAD_DEFAULT_VALUE` follows in `app/CMakeLists.txt`, and the `static_assert` in `build_channel.h` and the `emu_thread_default_unit` / `emu_thread_default_smoke_*` expectations change with it.
|
||||
- Unchanged:
|
||||
- a stored `ui.emu_thread` choice still wins;
|
||||
- `--emu-thread off` still runs inline for one run;
|
||||
- a failed thread start still falls back inline.
|
||||
- Docs: design doc section 8 "Shipped (phase 5)" and the README.
|
||||
- The 4.0 release notes say how to turn the thread off.
|
||||
- Closes #1039 (and #967 if the maintainer agrees that the retirement follow-up is filed separately).
|
||||
|
||||
## Decisions for the maintainer
|
||||
|
||||
| | Question | Recommendation |
|
||||
|---|---|---|
|
||||
| 1 | **Frame pacing default:** keep Jaguar rate for 4.0, or default nightlies to Match display now so feedback accrues? | Default **nightlies** to Match display after G3 passes; keep Jaguar rate for the 4.0 release. Mode B's only windowed evidence is one 60 Hz macOS panel. |
|
||||
| 2 | **`dev` channel after the flip:** Off (today) or On? | **On**, with 5c. Phase 3 kept `dev` Off so PR artifacts behave like releases; after the flip that same reason means On. |
|
||||
| 3 | **G4 without volunteers:** if no Windows, Linux or 120 Hz report arrives, does the flip wait? | Wait for **Windows** (the largest user base), or waive in writing on #1039. Linux and 120 Hz can ship on unit-test coverage plus the inline fallback. |
|
||||
| 4 | **G5 length:** two weeks of nightlies? | Two weeks, starting when 5a merges, so the twins have run on every PR in that time. |
|
||||
|
||||
## Evidence
|
||||
|
||||
Filled in by 5b. One row per run: build ID, host, display, arm, title, numbers, and a raw-trace path under `vj-eval/`.
|
||||
|
||||
| Date | Build | Host / display | What | Result |
|
||||
|---|---|---|---|---|
|
||||
| | | | | |
|
||||
Reference in new issue
Block a user