mirror of
https://github.com/tangerineturtle1/NX2navi.git
synced 2026-11-15 19:19:58 -04:00
Keep no spare block of video memory past a budget cap set for a test.
The headroom thread compared a heap's use with the driver's budget alone, so a run with NX2NAVI_VRAM_BUDGET_MB kept its spare blocks where the card the cap stands for keeps none, and such a run understated a small card (the audit's F-3-07). With a cap set, the device-local use is now also compared with 85 % of the capped budget, the figure the mirrors and the textures go by. Without a cap nothing changes: each heap's own figure decides as before. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
2
AUDIT.md
2
AUDIT.md
@@ -1531,7 +1531,7 @@ part `ccc31ad5`, F-4-01 `b933e3d9`, F-4-11 `e887a1d1`, F-6-01 `79661811`, F-6-03
|
||||
| F-3-04 | S3 | Audio (18), Kernel (3) | `audio_mixer.c` change events (~1213-1218, ~1296, ~1365) | Each call of the audio device's change-event commands makes a new kernel event, which takes a slot of the handle table (`MAX_H` 4096, fatal when full) and is never closed; events past the 16th are never signalled | Each call of those commands. Handles grew 112 → 116 and 112 → 117 across one reload (section 11.3); which calls took them was not traced | suspected; the handle growth is measured, its source is not | One shared event per kind, as the other audio commands already use | Low | L-25 | **Stability pass:** fixed by `d3a5c3c3`, `ef2e5e24` (F-3-16). |
|
||||
| F-3-05 | S3 | Services (5) | `ipc.c` domain objects (`objects[32]`, `ipc.h` ~54; CloseVirtualHandle ~428) | A domain's object table is never compacted and closing a virtual handle frees nothing; the 33rd object is answered with an unknown-command error | A domain session that opens and closes sub-objects repeatedly (the applet proxy), for instance at each return to the title | suspected; needs a run with `NX2NAVI_TRACE=ipc` counting the commands per title return | Free the slot on close and reuse it | Low | L-25 | **Stability pass:** fixed by `e9becc12`, `2c59addd` (F-3-17). |
|
||||
| F-3-06 | S4 | Platform | `platform/win32.c` `sleep_timer` (~478), `plat_file_pread` / `plat_file_pwrite` events (~1267, ~1526), `plat_thread_detach` (~73) | Per-thread timer and event handles are never closed when a thread exits, and a detached thread's small record stays. One "save commit" thread per changed Commit and one "camera speed" thread per search leak about two handles each | Every save and every sensitivity change | suspected; tens per hour against a limit of millions | Close them when the thread ends | None | L-26 | **Stability pass:** fixed on `next-0.10.0` by `222a025c`; `tests/thread_end_check.py` covers it. |
|
||||
| F-3-07 | S4 | GPU memory (12) | `vk_headroom.c` `room` (~112-120) | The headroom thread measures against the driver's budget, not the capped one, so under `NX2NAVI_VRAM_BUDGET_MB` it still keeps its spare blocks. A capped test run understates what a small card does | Any capped run | suspected (code read). The cap is a test switch | Compare against the smaller of the driver's budget and the cap | None outside capped runs | L-27 | **Stability pass:** still open. |
|
||||
| F-3-07 | S4 | GPU memory (12) | `vk_headroom.c` `room` (~112-120) | The headroom thread measures against the driver's budget, not the capped one, so under `NX2NAVI_VRAM_BUDGET_MB` it still keeps its spare blocks. A capped test run understates what a small card does | Any capped run | suspected (code read). The cap is a test switch | Compare against the smaller of the driver's budget and the cap | None outside capped runs | L-27 | **Stability pass:** changed after the 0.10.2 candidate: with a cap set, `room` also compares the device-local use with 85 % of the capped budget (`vk_mem_vram`), so a capped run keeps no spare block where the card it stands for keeps none. Without a cap nothing changes. Not run: a capped session is the user's to play. |
|
||||
| F-3-08 | S3 | Replay (11) | `vk_usnap.c` `vk_usnap_drop` (~433), `vk_usnap_begin` (~358), `arena_get` (~90) | With uniform snapshots switched off (`NX2NAVI_UBO_SNAPSHOT=0`, not the default) the GPU-write list is appended on every write and never pruned, and its linear scan slows without limit. In the default mode the list is pruned (199-250 entries at every snapshot) but the free arenas are never trimmed (3-6 arenas, 12-24 MiB measured) | Only with the switch off | suspected for the off mode; the default mode's sizes are measured and flat | Return early in `vk_usnap_drop` when snapshots are off; trim arenas idle for some submissions | None | L-29 | `3966d878`. Non-default mode only; not run in that mode. Not reproduced before, so not shown fixed. Regression: the route with the fixed exe: `p4_route` went through every segment with no FATAL and committed the save five times. Its frame rates cannot be compared with the baseline: the exe name is new and it has a pipeline cache folder of its own, so pipelines were still compiling on other threads (Kakariko 118.1 fps against 140.7; 17 frames over 25 ms in the 12 s after the reload, against 0 and 6) |
|
||||
| F-3-09 | S4 | Replay (11) | `vk_exec_draw.c` `mesh_ring_entry` (~5044-5053), `mesh_count_buf` (~4990) | The allocation handles of the mesh ring (48 KiB) and the count buffer (16 KiB) are dropped, so neither is ever freed | Once per process | suspected; a fixed 64 KiB | Keep the handles and destroy them at shutdown | None | L-30 | **Stability pass:** fixed on `next-0.10.0` by `a8c6e992` (`mesh_ring_release`). |
|
||||
| F-3-10 | S3 | Textures (13) | `vk_texture.c` `upload` (~2336-2342 with ~2272) | When a texture's storage is released during its upload it is uploaded as zeros, but the content hash already holds the bytes from before. If the game maps the same bytes back, `same_content` matches and the upload is skipped: the texture stays zero | Storage unmapped in the middle of an upload, then mapped again with equal content | suspected (code read) | Clear `chash_ok` whenever the bytes that reached the image are not the storage's (the same change as F-3-01) | Low | — | `054bd556`. Not reproduced before, so not shown fixed. Regression: the route with the fixed exe: `p4_route` went through every segment with no FATAL and committed the save five times. Its frame rates cannot be compared with the baseline: the exe name is new and it has a pipeline cache folder of its own, so pipelines were still compiling on other threads (Kakariko 118.1 fps against 140.7; 17 frames over 25 ms in the 12 s after the reload, against 0 and 6) |
|
||||
|
||||
@@ -125,7 +125,16 @@ static int room(const VkCtx *c, uint32_t type, VkDeviceSize block) {
|
||||
VmaBudget b[VK_MAX_MEMORY_HEAPS];
|
||||
vmaGetHeapBudgets(c->vma, b);
|
||||
const VmaBudget *h = &b[c->mem_props.memoryTypes[type].heapIndex];
|
||||
return h->budget && h->usage + 2 * block <= h->budget / 100 * 85;
|
||||
if (!h->budget || h->usage + 2 * block > h->budget / 100 * 85) return 0;
|
||||
// A budget taken as smaller for a test (NX2NAVI_VRAM_BUDGET_MB, vk_mem_vram) is what the mirrors and the textures
|
||||
// go by; measured against the driver's budget alone, a capped run kept its spare blocks where the card it stands
|
||||
// for keeps none. Only then: without a cap the heap's own figure above decides, heap by heap.
|
||||
uint64_t all = 0, used, capped;
|
||||
int exact;
|
||||
for (uint32_t i = 0; i < c->mem_props.memoryHeapCount && i < VK_MAX_MEMORY_HEAPS; i++)
|
||||
if (c->mem_props.memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) all += b[i].budget;
|
||||
if (vk_mem_vram(&used, &capped, &exact) && capped < all && used + 2 * block > capped / 100 * 85) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void drop_anchor(const VkCtx *c, uint32_t type) {
|
||||
|
||||
Reference in New Issue
Block a user