Skip to content

OoT-fps C-3: a submission's commit reads only the storage-write pages it noted, not all 16,384 slots - #2543

Closed
stan69b wants to merge 1 commit into
seedds:mainfrom
stan69b:pr/oot-fps-c3-commit-pages
Closed

stan69b wants to merge 1 commit into
seedds:mainfrom
stan69b:pr/oot-fps-c3-commit-pages

Conversation

@stan69b

@stan69b stan69b commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

OoT-fps batch, session C (submit-thread CPU per draw), item C-3. The ranked list of where the submit thread's time goes (C-1) is in #2542.

What changes

The pages a submission's storage buffers, texture→buffer copies and reports write are kept in an open-addressed set of 16,384 slots tagged with the submission (g_sbwp, sbw_note). At commit, gw_commit walked all 16,384 slots (256 KB) to find this submission's pages whenever there was one, and Ocarina of Time commits about 30 submissions a frame. The set now lists the slots a submission takes (g_sbw_list) and the commit reads only those. Which pages enter the running-write tables (g_gw, g_gwx) is unchanged, and the order they enter in does not change the tables. For every game.

Measured (M4 Pro, Kokiri Forest deck, standing, 640 draws a frame, encode thread on as on iOS)

instructions per draw (300-frame windows) submit M instructions / frame
main 8d44aaf 43.3k–43.7k 27.9–28.6
with C-2 (#2542) only 42.8k–43.9k 27.4–27.8
with C-2 and this PR 38.7k–39.3k 25.2–25.6

Checks

  • t_sbw gains checks of the list and the commit (39 checks; they need the list, so they do not build without it). t_ubp_running (25), t_nvn pass; test_docs OK.
  • scripts/regress.py check --baseline upstream/main --games 0400486024DEC000 on the stack of C-2 to C-5 (Apple M4, macOS 27.2; Ocarina of Time's title route from the unmerged ed769e9 smoke.tsv, as main has no route for it): shaders PASS (42848/42848, no MSL change), boot ok, fps p50 59.5 → 59.5, frame p99 17.82 → 17.81 ms, peak 2879 → 2872 MB, no new RED line. The check's status is REGRESSION because of its two screenshots (350 s, 385 s). They show different title backdrops (a forest at night vs Gerudo Desert; Lon Lon Ranch vs Lake Hylia), i.e. the backdrop rotation's timing, not a rendering difference. The same two screenshots were flagged between unrelated revisions on 2026-11-12 (0c07813 vs b8cb0bd), and with one run per revision the harness has no noise to compare against. A bit-exact replay check is not available for this game: DM_NVN_CAPTURE cannot capture its multiple NVN queues. Gameplay on the Kokiri Forest deck renders correctly in the bench runs. Other local NVN games (Echoes of Wisdom, Super Mario 3D All-Stars) were not run: pending.
  • iPhone 17 in Kakariko (C-2 to C-5 together, 512 ring, unattended back-to-back runs): instructions per draw 27,287 → 24,870 (−8.9 %), submit CPU a frame at the same clock 16.48 → 14.01 ms (−15 %); the batch's targets (a third, 30 %) are not reached. Table: OoT-fps C-3: a submission's commit reads only the storage-write pages it noted, not all 16,384 slots #2543 (comment)

… it noted, not all 16,384 slots

gw_commit walked every slot of the storage-write page set (g_sbwp, 16,384 slots, 256 KB) to find the
current submission's pages whenever it had one. Ocarina of Time makes about 30 submissions a frame, so the
walk ran about 30 times a frame. The set now lists the slots a submission takes (g_sbw_list) and the
commit reads only those; which pages enter the running-write tables is unchanged, and their order does not
change the tables.

Standing on the Kokiri Forest deck (M4 Pro, 640 draws a frame), with C-2: 43.3-43.7k -> 38.7-39.3k
instructions per draw on the submit thread.

t_sbw gains checks of the list and the commit (they need the list, so they do not build without it).
docs/reference/frame-rate.md entry, symptom index, game note line.
@dpadr

dpadr commented Nov 13, 2026

Copy link
Copy Markdown
Contributor

Tested on an M2 MacBook Air (16 GB, macOS 27.0, AC), Ocarina of Time, together with #2543 / #2542. We applied C-2 and C-3 on our test line (7f50222 base plus our own PR set) behind one runtime switch and ran an in-run A/B: alternating 240-frame phases on and off in the same run, along our scripted Kokiri Forest route to frame 12000 at handheld 1440x810, 60 fps cap. Two valid runs; a third ended early in an off phase (a stall we haven't attributed) and gave no data.

  • The submit thread does less work (both on together): −2.30 M cycles a frame [95% −3.51, −1.18] and −6.2 M instructions [−9.6, −3.6], with load −7 MB and store −4.75 MB a frame, in the run at 2.8 GHz. The other run (3.1 GHz) had the same sign within noise (−1.09 M cycles [−3.23, +0.01]).
  • C-2 hits on this game: 273 shared textures held views and 9,170 views were reused through them over the run, against 1,560 made by the serial cache.
  • Frame and GPU time: no change at these clocks (frame p50 −0.19 ms [−0.56, +0.23]): the submit thread isn't the limit on this machine when cool, so we expect it to show when the CPU is throttled.
  • No regressions: no red lines, no 1 s frames, no held waits. Our port needed two small adaptations because our base lacks newer main code (the nvn_owner.m module and 4c574a6's per-report tracking); on main the PRs apply as written. Unit tests t_view_reuse, t_sbw (switch on and off), t_nvn, t_feedback, t_gpuprof pass.

We couldn't separate C-2 from C-3 in this test; the desk estimate is about 0.25-0.33 ms for C-2 and 0.2-0.4 ms for C-3 of submit-thread time on this route.

@stan69b

stan69b commented Nov 13, 2026

Copy link
Copy Markdown
Contributor Author

iPhone 17, Kakariko Village: C-2 to C-5 together, before / after

Unattended runs with the batch's drive script (iphone_drive_batch.sh, 7 minutes each, the owner's save in Kakariko, the launcher's 30 fps cap, dynamic resolution, MetalFX, encode thread on). Both apps are oot-build-vis (b32f7fc1 + the visibility ring) with the ring at 512 (ALLOC_MAX * ALLOC_SHARE, as upstream b515089); the after app adds C-2, C-3, C-4 and C-5. Run order base, C, C, base. Medians of the 300-frame summary lines once in the village (first two windows skipped).

run instructions per draw cycles per draw draws a frame submit M instructions a frame submit CPU a frame submit thread clock fps frame p50 submit+present p50 GPU p50
base 1 26,790 10,341 2,691 71.2 12.69 ms 2.21 GHz 29.2 33.7 ms 13.2 ms 30.8 ms
C 1 (slow GPU state) 24,886 11,279 2,706 67.3 8.96 ms 3.34 GHz 12.6 80.0 ms 9.6 ms 69.7 ms
C 2 24,853 9,219 2,771 68.9 14.01 ms 1.84 GHz 28.0 34.9 ms 14.8 ms 31.7 ms
base 2 27,784 10,538 2,783 77.4 16.48 ms 1.78 GHz 25.3 38.8 ms 18.0 ms 34.9 ms
  • Instructions per draw: 27,287 → 24,870 (−8.9 %), the same in both C runs (24,886 and 24,853); on the Mac it was −11 %. The batch's target (a third fewer) is not reached.
  • Submit CPU a frame follows the submit thread's clock more than the instructions: C 2 against base 2 at about the same clock (1.84 / 1.78 GHz): 16.48 → 14.01 ms (−15 %); cycles per draw 10,440 → 9,219 (−12 %). The 30 % target is not reached.
  • C 1 fell into the slow GPU state session A also met with both of its builds (OoT-fps A-1: the queue replay and encode threads declare the frame's deadline, so iOS no longer runs them on efficiency cores at 30 fps #2569: GPU 66-80 ms for the same draws, CPU at 3.3 GHz, 9-13 fps); only its instructions per draw compare.
  • Screenshots of all four runs show the village rendered the same way; the C runs log no red line the base runs do not (the only one in both is the pipeline archive pieces built for a later iOS). env.txt restored after every run; save untouched.

What is left of the submit thread's cost per draw (C-1's ranking in #2542): argument blocks (encode_args own time, pool_gpu, img_binding), pass opens (rp_begin_ex), render-condition operands (rc_value), state records and pipeline lookup, a few percent each, plus the residency commits (res_commit, about 8 %) and new render targets' textures (#2566's area).

@seedds

seedds commented Nov 13, 2026

Copy link
Copy Markdown
Owner

Landed on main as f63ecbd, with you credited as co-author. The code and the new t_sbw checks are as you wrote them. The docs give this change's own share (42.8–43.9k → 38.7–39.3k instructions per draw, with #2542 on both sides) instead of naming the unmerged C-2. PR #2458 (PucaVaz) made the same list change a day earlier, so it is credited too. t_sbw, t_ubp_running, t_nvn and test_docs pass. Thank you!

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

Labels

docs Documentation game: 0400486024DEC000 A game 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.

3 participants