Skip to content

Avoid repeated archive scans for missing pipeline bases - #1825

Closed
socram03 wants to merge 1 commit into
seedds:mainfrom
socram03:fix/pipeline-archive-miss-cache
Closed

socram03 wants to merge 1 commit into
seedds:mainfrom
socram03:fix/pipeline-archive-miss-cache

Conversation

@socram03

@socram03 socram03 commented Nov 8, 2026 •

Copy link
Copy Markdown
Contributor

What and why

Busy OoT scenes can spend more time searching pipeline archives than rendering. When the hybrid demand-build table is full, draws keep using a pulling stand-in and repeatedly scan every archive for the same missing layout-specific base. Successful bases are cached; absent ones are not.

Cache those misses under the existing base key and lock. A repeated non-compiling probe returns immediately, while demand compilation can still build the base and a completed positive result always wins. The archives are loaded once, so these entries remain valid for the process and are never persisted. See the reference entry.

In earlier OoT v131072 city runs, CPU translation fell from ~114 to ~6.4 ms/frame and failed archive searches from 9,208 to 5 per 300 frames; I saw roughly stable 30 FPS afterward. Those runs used bd979ced3ae6 with local frame-step/packaging changes. Camera, route and cache warmth differed, so this is supporting evidence, not a controlled benchmark on the PR base.

Checked

On Apple M5 / macOS 27.0.1 / Xcode 27.2, the host builds and the archive suite passes 242 checks plus its fresh-process test with Metal validation. The regression verifies one scan for 100 misses, independent layout keys and later successful compilation. Its two lookup-count assertions fail on the unmodified PR base, 028a2631.

Full-suite failures and coverage limits
  • The full Metal suite encountered two failures also reproduced on the base: t_present_crop SIGSEGV and an intermittent t_feedback timestamp assertion. Three candidate feedback reruns passed.
  • LLVM 23.1.4 checked all 259 sources: candidate and base have identical 248-finding multisets. The committed 240-finding ratchet fails on both, including the base CI run. Pinned Ruff/Pyright pass with zero new or stale findings.
  • Python tools: 1,392 tests, 23 skips, one environment-switch-table failure. CI also reports six Xcode-fixture errors because its synthetic RomFS.img is absent. Both failure types reproduce on the unmodified PR base (028a2631), locally and in the base CI run. Documentation checks pass.
  • regress.py impact names Breath of the Wild, Tears of the Kingdom and Pokémon Scarlet; 149 profiles lack manifests. Those three, OoT and Wonder were selected for coverage, but only the manual OoT build is available, and regress.py check cannot discover its layout. No fresh harness gameplay/shader result is claimed.

Docs

  • Reference entry, game note and regenerated symptom index.
  • No shader-chain tool changed.
  • No game files, keys or extracted data in the change or attachments.

When hybrid demand fills the bounded build queue, draws can repeatedly scan every archive for the same missing base. Remember absent bases under the existing base lock, without suppressing demand compilation or overriding a completed base.

Add a regression for repeated misses, independent layout keys and later successful compilation. Record the earlier OoT city measurements with their uncontrolled gameplay limits.
@github-actions github-actions Bot added nvn NVN on Metal and its tests (dm/gfx/nvn, dm/gfx/tests) docs Documentation game: 0400486024DEC000 A game labels Nov 8, 2026
@socram03 socram03 changed the title Cache absent pipeline bases during non-compiling archive probes Avoid repeated archive scans for missing pipeline bases Nov 8, 2026
@sleepyeyedjoe

Copy link
Copy Markdown
Contributor

Tested on a MacBook Pro M4 Pro (24 GB, macOS 27.0.1), Ocarina of Time 0400486024DEC000 v131072, handheld mode, real play (not a replay). It fixes the Castle Town drop here.

Setup

Before (first visit to the Market, without the PR)

  • Entering the Market, the frame step collapsed to about 12 fps. In the worst period, frame time p50 was 84 ms and p95 118 ms, against GPU p50 26 ms and submit+present 0.8 ms.
  • pipelines up to frame 7800: archive lookups found none 49,044 / 17,079 ms; draws with a hybrid pipeline 212,820; in flight 384 for the rest of the session.
  • Main thread 854 ms/s, against 391 ms/s in Hyrule Field just before.
  • Game time ran at 0.605 of real time over that stretch.
  • It recovered by itself after about 3 minutes, as the queued bases were built.

After (second visit, with the PR)

  • Frame time p50 16–20 ms and p95 20–32 ms over about 75 s in the Market (frames 1200–5400), GPU p50 12–16 ms.
  • Found none per 300 frames: 427 in the period of the scene load, then 5–57.
  • The table was still full (in flight 384) and the hybrid draws were still 40k–158k per 300 frames. So the saturated case your PR describes was hit, and the repeated probes were gone.
  • Main thread 440–600 ms/s. Game time 1.000 of real time.

Caveat

  • This is not a controlled A/B. The second visit started with 489 more pipelines prepared before the first frame (the first visit's builds, through pso_user.tsv). That explains part of the lower GPU time.
  • The found-none count with a full table is the direct effect of the PR. It fell from ~49k to tens per 300 frames.
  • I tried an A/B replay of a scene load (old and new host). Both stalled the same way. The replay ran no prepare step before the first frame, so its pulling bases were still pending and no draw used a stand-in. It never reached the code this PR changes.

Know-It-All-Brother added a commit to Know-It-All-Brother/nxnative that referenced this pull request Nov 9, 2026
FeReuss pushed a commit to FeReuss/nxnative-oot that referenced this pull request Nov 10, 2026
…ns for missing pipeline bases

t_pso_archive.m, the game note and two reference pages took both sides (new test functions and entries on both).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Fasen24-AI added a commit to Fasen24-AI/swordboiMacNative that referenced this pull request Nov 10, 2026
…eedds#1825 (process-local miss cache for base-pipeline lookups), seedds#1368 (native mesh pipelines in the prewarm manifest, 73 M rows), seedds#1842 (DM_NVN_ISOLATE_TASK)

Upstream pull requests applied in this commit (their authors' work, brought onto this tree with a three-way merge; the description is in each PR):
- seedds#1368 by nanotchec (closed): Ocarina of Time: prewarm native mesh pipelines before attacks and enemies appear
- seedds#1825 by socram03 (open): Avoid repeated archive scans for missing pipeline bases
- seedds#1842 by ycarogabriel-lgtm (open): Ocarina of Time: opt-in task isolation (DM_NVN_ISOLATE_TASK), the Hi-Z task a5288 in command buffers of its own, a workaround for its GPU hangs on an M1
- seedds#1844 by nawangwe (closed): Shader libraries compile with -fwrapv: Ocarina of Time's mesh-shader models no longer take their ambient light from the wrong probe texels
seedds added a commit that referenced this pull request Nov 10, 2026
…ask for it skips the search, a non-compiling one returning nil and a compiling one going straight to the compiler. With the build table full, every draw of a pipeline whose build it refused searched every archive file again; Ocarina of Time's castle town market fell from about 114 to 6.4 ms of CPU translation a frame (PR #1825)

Co-authored-by: Marcos Susaña <66887817+socram03@users.noreply.github.com>
@seedds

seedds commented Nov 10, 2026

Copy link
Copy Markdown
Owner

Landed on main as 2f131ed, with you credited as co-author. Thank you for the diagnosis and the fix, and thanks to sleepyeyedjoe for the M4 Pro run, which hit the full-table case directly.

Your cache went in as you wrote it, with two refinements:

  • A miss is recorded whenever the archives lack the base, whether or not the caller compiles. If a compile then fails, later non-compiling asks still skip the search.
  • A compiling build whose base is a known miss goes straight to the compiler. Each build the full table turned away no longer searches every archive file once more before compiling. The test checks this too.

The docs are shorter: the game note keeps one "Resolved" line under Frame rate with both testers' measurements and their limits, and the reference entry is now Archive searches repeated while the build table is full.

Checked: check_t_pso_archive on main passes 338 checks plus the 6 fresh-process tests. Without the cache, its lookup-count checks fail.

@seedds seedds closed this Nov 10, 2026
oliverames pushed a commit to oliverames/nxnative that referenced this pull request Nov 10, 2026
… first asked for, so the next start's prepare step builds it (from HookLink)

pso_user.tsv took a pipeline's row only once its build finished. While a hybrid draw drew with its shader pair's pulling pipeline, the pipeline it wanted was built in the background; on an iPhone 18 Pro Max (HookLink's measurement) that took 5-50 s with the game running, against about 1 s in the prepare step. Castle Town asked for about 400 pipelines and finished about 60 a minute, so what was unbuilt when the run ended was never listed and the next start did not build it.

demand_record writes the row when the hybrid draw first asks for the pipeline, once per key. The later row from the built pipeline is the same line and pso_user_record drops it. DM_PSO_DEMAND_RECORD=0 keeps the old order. Added t_pso_demand_record, the reference entry, the switch row and the game note line.

Ported from HookLink's commit 0ad4e1a (https://github.com/dsi-hub/nxnative/tree/hooklink, project https://github.com/dsi-hub/HookLink), without its archive-miss memory (b3471d5) and keyed demand table (b15d36f): main has an archive-miss memory of its own (g_pbase_miss, PR seedds#1825) and no keyed demand table, so the call goes next to main's pso_pend_demand and runs for every stand-in draw, not only when no build is pending.

Co-authored-by: dsi-hub <260802842+dsi-hub@users.noreply.github.com>
@socram03
socram03 deleted the fix/pipeline-archive-miss-cache branch November 10, 2026 21:05
betogzo added a commit to betogzo/nxnative that referenced this pull request Nov 10, 2026
…emembered for the run, so Ocarina of Time's castle town market no longer searches every archive file at each draw while the build table is full (PR seedds#1825); GPU timestamp reports per segment for every game, without the idle time between a submission's command buffers (gpu_timestamps leaves the game's profile); short sleeps are polls; x18 system register accesses go through K18

Tests: see the cherry-pick of PR seedds#2219 that follows.
dsi-hub pushed a commit to dsi-hub/nxnative that referenced this pull request Nov 11, 2026
…ask for it skips the search, a non-compiling one returning nil and a compiling one going straight to the compiler. With the build table full, every draw of a pipeline whose build it refused searched every archive file again; Ocarina of Time's castle town market fell from about 114 to 6.4 ms of CPU translation a frame (PR seedds#1825)

Co-authored-by: Marcos Susaña <66887817+socram03@users.noreply.github.com>
(cherry picked from commit 2f131ed)
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