Skip to content

Opt-in pacing switches for the iPhone judder: DM_PCORE, DM_RT60, DM_ITV_LATCH (not fully tested) - #1713

Closed
oliverames wants to merge 3 commits into
seedds:mainfrom
oliverames:mkw-pacing-optins
Closed

oliverames wants to merge 3 commits into
seedds:mainfrom
oliverames:mkw-pacing-optins

Conversation

@oliverames

@oliverames oliverames commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

What and why

Three opt-in pacing switches for the iPhone judder after about 30 to 70 s of a Mario Kart World 1.8.0 race, in one PR because they touch the same scheduler and present code and are tried together. Nothing changes unless a switch is set.

  • DM_PCORE=1: the busiest guest threads get a time-constraint declaration, to keep them on the Performance cores.
  • DM_RT60=1: the scheduler declaration keeps the base vsync period when the game flips its present interval.
  • DM_ITV_LATCH=1: hold present interval 2 while the game oscillates between 1 and 2.

Not fully tested. On Mario Kart World 1.8.0 on an iPhone19,4 (2026-11-07), DM_RT60=1 made no visible difference to the slowdown, DM_ITV_LATCH=1 cut the interval flips (12 against 58 in comparable stretches) and didn't change the GPU's slowdown, and DM_PCORE=1's effect isn't measured. On a build with the host's frame step (the base game since main 7d8dcdf82) DM_ITV_LATCH and DM_RT60 do nothing, because present_itv returns the step and rt_period_ns keeps the cap's deadline. So they are here as opt-in knobs, not as a fix. Replaces #1699, #1700 and #1701.

Checked

  • dm/tools/env_switches.py --check shows no problem for the three new switches (the check exits 0 on this branch, rebased onto main ab41d6a17 on 2026-11-10)
  • python3 dm/tools/tests/test_docs.py passes
  • Not run on a Mac host build or scripts/regress.py check --games
  • Not measured as an improvement on a device

Front ends

No front-end interface change.

Docs

docs/env_switches.tsv rows for all three; docs/development.md notes.

@oliverames

Copy link
Copy Markdown
Contributor Author

Rebased onto main 7f50222: one conflict in hle_nvn.c (kept main's window_interval and its comment, kept the latch inside present_itv). Tests: t_nvn 248 checks 0 failed, t_gfx_suspend 22 checks 0 failed, test_docs 11 OK; env_switches --check flags only main's DM_NVN_BC_ALIAS and DM_YIELD_CLOCK, none of ours.

@oliverames
oliverames force-pushed the mkw-pacing-optins branch 2 times, most recently from 2e80b49 to f3e143b Compare November 10, 2026 00:52
oliverames pushed a commit to oliverames/nxnative that referenced this pull request Nov 10, 2026
…me on an iPhone, and the phone restarts some minutes later (Mario Kart World 1.8.0, iOS 27.3 beta); open

On an iPhone 19,4 the picture stopped 2 to 3 s into a race, 184 s after launch, with the overlay at 0 fps, the process alive, no [RED] line and no GPU error. Every thread waited and none spun. The state dump has the replay thread in iokit_user_client_trap under res_commit (pool_res, with g_mu held by its caller and g_res_mu across the call) and the GPU's completion queue waiting for a mutex in post_complete, with the main fence at submitted 206262 / completed 206256.

Ending the app did not end the process. The system's stack report 15 minutes later still has it with one thread, NVN queue replay, in an uninterruptible kernel wait with a read-write lock held and a kernel thread blocked on it, and the phone at 7.2 GB wired and 34 MB free. The phone then restarted itself.

It happened twice in four runs of one build (main 04811a6 with PRs seedds#1709, seedds#1695, seedds#1262, seedds#1599 and seedds#1713 merged): in that race, and an hour later at the title's demo with no button pressed, 353 s after launch, with the same thread state. Both came in a scene load (1,840 allocations added to the residency set in 678 commits in the 300 frames before the second). With main's 6f50de0 and 12a44e0 added, four races did not freeze, which is too few to say it is gone. The game makes about five residency commits a frame in a race. No fix: the entry says what was ruled out, what the host could change, and what to collect from the phone (SIGALRM for the host's dump, then systemCrashLogs). The game note links it under Open.
Oliver Ames added 3 commits November 10, 2026 09:00
…declaration, to keep them on the performance cores

Off by default and not yet shown to help: a Mario Kart World run on an iPhone left the performance
cores about a minute in with thermal state nominal (mean clock 3.8 to 1.65 GHz, 55% to 12% of CPU time on
performance cores). iOS has no core affinity; a time-constraint declaration is what the scheduler places on
a fast core. The three busiest guest threads without one get a 60 Hz declaration of 1.5x their measured
per-frame CPU, once each, from the CPU sampler's window.
…riod when the game flips its present interval

Off by default. On Mario Kart World 1.8.0 on an iPhone 19,4 it made no visible difference to the slowdown (2026-11-07). Mario Kart World on an iPhone flips its present interval 1 and 2 about 350
times in 20 s after a late frame, re-declaring 16.7 / 33.3 ms to the scheduler each time, and around those flips the
process left the performance cores (mean clock 3.5 to 1.6 GHz, thermal fair).
…lates between 1 and 2

Off by default. On Mario Kart World 1.8.0 on an iPhone 19,4 it cut the interval flips (12 against 58 in comparable stretches) and did not change the GPU's slowdown (2026-11-07). Mario Kart World on an iPhone flips its present interval about 350 times in
20 s after a late frame, which shows the screen at alternating 16.7 / 33.3 ms periods. The latch holds interval 2 until
the game has asked for 1 for DM_ITV_LATCH_MS (3000), so the screen runs one steady 30 fps.
@oliverames

Copy link
Copy Markdown
Contributor Author

Closing this. Since main's 6815810, Mario Kart World 1.8.0 runs under the host's frame step, and as this PR's description says, DM_RT60 and DM_ITV_LATCH do nothing there. DM_PCORE was never measured as an improvement, so it isn't worth keeping on its own. Thanks!

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

Labels

docs Documentation host The Horizon host: SVCs, services, threads, memory (dm/host) nvn NVN on Metal and its tests (dm/gfx/nvn, dm/gfx/tests)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant