Repository navigation
Shared textures no live object resolves to are retired when GPU memory runs short: Ocarina of Time no longer freezes after the talk with Saria - #1455
Conversation
…memory guard) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016qteK29T18U8p1c9LsVY8g
…y runs short: Ocarina of Time no longer freezes after the talk with Saria A game may leave the descriptors of the textures it finalized registered; every texture pool walk resolved them and kept their shared textures, and a game that keeps its pools and loads the next scene elsewhere in them never let them go. Ocarina of Time (Switch 2) lost the live objects of 2,000 to 2,500 shared textures at once after the talk with Saria; textures went from 5 to 16 GB, the residency set passed the working set, and the GPU faulted, hung or the Mac froze. alias_retire_idle: above 85 % of the working set, shared textures no live object (or a view one holds) resolves to, idle for 64 submissions by lookups for live objects only (g_alias_lseen), are retired, the longest idle first, down to 75 %. A finalized descriptor over a retired key resolves to nothing; a live object over it gets a new texture filled from its storage. DM_NVN_ALIAS_RETIRE=0 turns it off; DM_NVN_WS_MB tries another working set (a 16 GB Mac's on a larger one). Tests: t_alias_retire (new: 6 checks, both encoding modes; 3 with the switch off), t_image_alias, t_cpu_storage, t_cpu_tex, t_linear_readback. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
bc60437 to
49a3d44
Compare
…ort) over seedds#1453 (GPU-only pool render targets in one placement heap): both kept Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013SzykpcKm2eZPvPjGPKx1C
… of uploaded textures) over seedds#1453 and seedds#1455 pool_heap_texture's fill takes seedds#1455's again argument (0: the placement is new). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013SzykpcKm2eZPvPjGPKx1C
…red pool buffers no longer pile up) over seedds#1447, seedds#1453 and seedds#1455 alias_let_go also clears seedds#1455's lookup stamps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013SzykpcKm2eZPvPjGPKx1C
|
Tested on main 75c1a8c, with #1453, #1332 and #1446 also applied, on an M4 MacBook with 24 GB (Metal's working set 18,186 MB), from the Kokiri Forest autosave at Link's house, in two scripted runs: 10 minutes in the house; and from a fresh load, out of the door, through Saria's greeting and 10 minutes of walking around the house.
|
…argument (the build check compiles every gfx test) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks @PucaVaz, that is a useful result. Your runs agree with the PR's design: on today's main the residency set stays at 4.9–5.4 GB, far below the 85 % trigger, so nothing is retired and there is no cost. The freeze after Saria was measured before main's Ocarina changes (raw pool table, textures made only when read, and the rest), which keep that scene well within the working set now. On main this PR no longer fixes a freeze you can reproduce. It is a safety net for a game, or a smaller Mac, that does reach the working set with textures nothing live holds. The build check failure was mine. Two other gfx tests ( I will update the description to say this plainly. If you would rather not carry a safety net that main does not currently need, closing it is fine with me. |
…atedSize currentAllocatedSize counts each no-copy buffer in full however many cover the same pages: 50 over one 64 MB region add 3,200 MB. In Ocarina of Time's Kokiri Forest on a 24 GB Mac it read 17.3 GB within a minute or a few, with 6.5 GB in the residency set and the driver's In use system memory near 7.7 GB, so the guard stopped the game each time. With its stop raised past Metal's working set, the refused commit was followed by InnocentVictim command buffer errors. The guard now reads the set's own size, so an addition counts from its commit. A large burst is seen one commit later than before, and the timer sees the size at the last commit. Checked: t_res_guard, both runs. Ocarina of Time v131072 on an M6 Mac with 24 GB, on main with seedds#1357, seedds#1390, seedds#1391, seedds#1453 and seedds#1455: about 49 minutes and 170,400 frames through Kokiri Forest and the Great Deku Tree, currentAllocatedSize at about 20 GB, driver in use at most 9.5 GB, wired about 10 GB, no GPU errors. Not checked: other games, a smaller Mac.
|
Closing this: on today's main, Ocarina of Time no longer comes near its working set after the talk with Saria (PucaVaz's runs and mine: residency about 5 GB, nothing retired), so there is nothing for this to catch. Main's own memory changes fixed the freeze at its source. Thanks for testing it. |
… note; pool tables take only the IDs a change reaches) over the translator rollback seedds#1455's idle retirement notes its serial change through ser_note, as main's takeover now does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013SzykpcKm2eZPvPjGPKx1C
…atedSize currentAllocatedSize counts each no-copy buffer in full however many cover the same pages: 50 over one 64 MB region add 3,200 MB. In Ocarina of Time's Kokiri Forest on a 24 GB Mac it read 17.3 GB within a minute or a few, with 6.5 GB in the residency set and the driver's In use system memory near 7.7 GB, so the guard stopped the game each time. With its stop raised past Metal's working set, the refused commit was followed by InnocentVictim command buffer errors. The guard now reads the set's own size, so an addition counts from its commit. A large burst is seen one commit later than before, and the timer sees the size at the last commit. Checked: t_res_guard, both runs. Ocarina of Time v131072 on an M6 Mac with 24 GB, on main with seedds#1357, seedds#1390, seedds#1391, seedds#1453 and seedds#1455: about 49 minutes and 170,400 frames through Kokiri Forest and the Great Deku Tree, currentAllocatedSize at about 20 GB, driver in use at most 9.5 GB, wired about 10 GB, no GPU errors. Not checked: other games, a smaller Mac.
- Reconcile upstream PRs (seedds#1455, seedds#1447, seedds#1394, seedds#1439, seedds#1489, seedds#1590, seedds#1663) and commits (ffebfd5, e5f1ade) against local fork - Confirm PRs seedds#1455, seedds#1447, seedds#1394, and seedds#1439 are already implemented in ad99858 - Establish that host-only renderer optimizations require zero shader rebuilds and reuse the 42,854-entry b-dc815e0f38ca.img library - Establish that native subword stores (ffebfd5) affect only 515 shaders and leverage cas.db compilation caching - Rank candidates for base M3 Normal + Handheld (>=40 FPS target, ideal 60 FPS) and identify the top three candidates - Recommend the smallest independently verifiable first optimization (host-only PSO archive epoch separation from PR seedds#1590) - Update documentation index, plan, changelog, and known issues
What and why
A game may leave the descriptors of the textures it finalized registered in its texture pool. Every pool walk resolves them, which kept their shared textures (
g_alias) and refreshed their last-use stamp. A shared texture left the table only when its pool was finalized or another texture took over its storage. A game that keeps its pools and loads the next scene elsewhere in them does neither.The Legend of Zelda: Ocarina of Time (Switch 2,
0400486024DEC000v131072, profile in #1299) keeps about 12,000 such descriptors. After the talk with Saria in Kokiri Forest, 2,000 to 2,500 shared textures lost their live object at once. Textures went from 5 GB to 10–16 GB, and the residency set passed the 18.2 GB working set of a 24 GB M5 Pro. The GPU then faulted (PageFault) or hung, macOS ignored every later submission, or the submit thread blocked in the kernel with the Mac frozen.alias_retire_idle(nvn_mtl.m, at the start of each submission) runs when the residency set holds more than 85 % of the working set. It retires shared textures that no live texture object (or a view one holds) resolves to and that no lookup for a live object has used for 64 submissions, the longest idle first, until the set is down to 75 %.g_alias_lseen). Reclaiming by any lookup keeps every texture a stale descriptor names. DM_CTL poolstat and texstat, and what fills Ocarina of Time's GPU working set (iPad out of memory at 8,259 of 8,192 MB) #1436 notes that reclaiming by lookup idleness alone retired targets in use.tex_init_fill).DM_NVN_ALIAS_RETIRE=0turns it off.DM_NVN_WS_MBsets another working set for it and forrestop, to try a smaller Mac's budget on a larger one: a 16 GB Mac recommends about 10.7 GB.A game within its budget is unchanged: nothing is retired below 85 %.
This is complementary to #1393 (
pool_skip_retired, a profile key that gives finalized IDs the dummy) and #1404. Here the rule is general, and it acts only under memory pressure, on textures no live object holds.Measured
Ocarina of Time, 24 GB M5 Pro, repeated replays of the scene after Saria:
DM_NVN_ALIAS_RETIRE=0on the same replay: 16.6 GB of textures and a freeze.DM_NVN_WS_MB=10700(a 16 GB Mac's budget) the game stayed within it.Checked
0400486024DEC000, update v131072, SDK 22.2.8), with the profile from [WIP] The Legend of Zelda: Ocarina of Time (Switch 2, 0400486024DEC000, v0, SDK 22.2.8) runs on the Mac through the title movie into Kokiri Forest #1299 — Kokiri Forest, the talk with Saria, the Great Deku Tree in and out, several sessions of 5 to 15 minutes; compared withrestop/ the memory report lines, frame times and screenshots.make -C dm/gfx/tests GAME=<id> check_t_alias_retire(new): 6 checks with direct and deferred encoding, and 3 withDM_NVN_ALIAS_RETIRE=0. It covers:t_image_alias(318),t_cpu_storage(32),t_cpu_tex(20),t_linear_readback(24),test_docs.py.scripts/regress.py check --gameson other games; only Ocarina of Time was available here. The change only acts above 85 % of the working set, so games within their budget should see none. A game that keeps drawing with finalized descriptors for long under memory pressure would read the dummy for them; the reference entry lists this limit.Docs
docs/reference/rendering.mdentry, andpython3 dm/tools/docs_symptoms.pywas run (the symptom index)