# Load zone freezes forever: a failed host-memory import is retried on every use (~20k times) #218

Closed
opened 2026-11-07 16:27:32 +00:00 by imbahzor · 1 comment
imbahzor commented 2026-11-07 16:27:32 +00:00 (Migrated from github.com)

Summary

On a 16 GB PC, entering a certain load zone freezes the game for good (0.0–0.1 fps, never recovers). Each time, the same sequence shows up in the log:

  1. System RAM runs out (0.4–0.5 GB free). Hookshot itself has ~24 GB committed, and other processes use only ~1 GB.
  2. A pool import fails: vk: pool 0x7f6a46a000+0x2bf000 not imported. Since import_pool() returns false at vkAllocateMemory, the driver most likely can't pin more pages.
  3. Nothing remembers the failure. pool_lookup() imports the same range again on every later use, at 7–130 ms per attempt, on the Presentation Thread and on the game's worker threads.

Measured: 19,712 imports and 435 s of import time in one session, ~40 attempts/s, with one thread at ~90 % for the whole time.

This happens with the default 16 MB chunks and also with RX_VK_IMPORT_CHUNK_MB=0, so chunk rounding isn't the cause.

Suggested fix: keep a list of ranges whose import failed and don't retry them right away (back off, or retry only when free memory changes), and fall back to a slower path for those ranges instead of failing every frame. Logging the VkResult from vkAllocateMemory would also show whether the cause is OUT_OF_HOST_MEMORY, OUT_OF_DEVICE_MEMORY or INVALID_EXTERNAL_HANDLE.

Code: gpu/vk/vk_memory.cpp at commit 1c7c9c7: pool_lookup() (line 1072), the if (!ok) path (line 1156, which returns nullptr with no state kept), and import_pool() → vkAllocateMemory (line 147).

System

  • CPU: AMD Ryzen 5 1600X (6c/12t)
  • GPU: NVIDIA GeForce RTX 3060, Vulkan 1.4, driver 0x9b438000
  • RAM: 16 GB DDR4-2133. The page file is system-managed (commit limit 74.5 GB).
  • Windows 11 Pro 24H2 (build 26100)
  • Output: 3840x2160 fullscreen, frame_pacing=1, no upscaling or frame generation
  • Built with HookshotBuilder on 2026-11-07, from 1c7c9c7 ("Less stutter …, 8 GB mirrors restored"), with the shipped PGO profile

Evidence

Run 4: default settings

The failures appear at the load zone (logging stops after 16 lines):

vk: pool 0x7f76fe7000+0x1d000 not imported
vk: pool 0x7f6a46a000+0x2bf000 not imported
vk: pool 0x7f61fea000+0x153000 not imported

From then on, the same ranges are imported again and again (one log line per 256 imports):

vk: pool 0x7f61fea000+0x153000 imported in 15.1 ms (256 imports, 8208 ms in all)
vk: pool 0x7f6a46a000+0x2bf000 imported in 7.2 ms (768 imports, 14187 ms in all)
vk: pool 0x7f6a46a000+0x2bf000 imported in 8.1 ms (1024 imports, 17235 ms in all)
vk: pool 0x115a858000+0x72000 imported in 22.0 ms (2048 imports, 30073 ms in all)
...
vk: pool 0x1158f8e000+0x120000 imported in 23.2 ms (14592 imports, 320294 ms in all)
...
vk: pool 0x115a34d000+0x226000 imported in 35.3 ms (19712 imports, 435585 ms in all)
vi: 2788 frames presented (0.0 fps over the last 43.9 s, interval 1)
hid: the game read no controller for 6.2 s

The game process sat at ~109 % of one core, with one thread at 88 %.

Run 5: RX_VK_IMPORT_CHUNK_MB=0

The load got further, then a 213 MB pool failed, and the frame rate fell to 0.1 fps in the new area:

[EffectResLoadingThread] vk: pool 0x107f7f5000+0xd5b6000 imported in 118.0 ms (1024 imports, 57463 ms in all)
[EffectResLoadingThread] vk: pool 0x107f7f5000+0xd5b6000 not imported      (x16, then logging stops)
[Presentation Thread]    vk: pool 0x107f7f5000+0xd5b6000 imported in 129.7 ms (2560 imports, 230391 ms in all)
[Presentation Thread]    vi: 2743 frames presented (0.1 fps over the last 18.4 s, interval 1)

At that point: 1.0 GB free RAM, hookshot working set 5.9 GB, private 24.3 GB.

Run 6: default settings again

Same pattern: vk: pool 0x7f5f5f5000+0x394000 not imported, then 256 imports in 5 s, and the frame rate fell from 45.7 to 7.5 to 0.1 fps. At that point: 0.4 GB free RAM, hookshot working set 8.1 GB, private 24.3 GB, Memory Compression 2.0 GB, and the next largest other process 0.45 GB.

These appear even when the system isn't under memory pressure. A 64-byte storage buffer bind for compute program 612a27de13e44e79 takes 140–176 ms each time, at a new address each time. The pipeline is ready at 0.0 ms:

vk: slow descriptor 155.7 ms: storage buffer (written) 0x1044962000 size 0x40
vk: slow dispatch 155.9 ms: program 612a27de13e44e79 (picked at 0.1), pipeline at 0.1, descriptors at 155.8
... (x7 back to back)
vk: slow submit: 1107.4 ms: dispatch 1107.3

Successful imports take 57–86 ms each (vk: import 71.5 ms: commit+properties 35.3, buffer 0.0, allocate 36.2), so these stalls look like synchronous imports on first use. The worst first-visit frame broke down like this: slow submit: 1813.1 ms: draw 1676.9 descriptors 1406.9 texture lookups 889.5 uploads 593.9.

Not an issue: the pipeline cache works

Same route over three runs, restarting the game in between:

Run 1 Run 2 Run 3
mkw_vk_pipelines.bin at start 0 KB 55,568 KB 70,202 KB
Precompiled at start 15 gfx + 11 compute 1551 gfx + 120 compute 1675 gfx + 120 compute
Worst pipeline stall 9117 ms — 4.6 ms frame wait

Logs

The logs are attached:

  • run4_loadzone_log.txt: the freeze with default settings
  • run6_loadzone_log.txt: the freeze again with default settings
  • run1_log.txt – run3_log.txt: the pipeline cache runs

Run 5's log was overwritten; its numbers above were read from the live log.
run1_log.txt
run2_log.txt
run3_log.txt
run4_loadzone_log.txt
run6_loadzone_log.txt

## Summary On a 16 GB PC, entering a certain load zone freezes the game for good (0.0–0.1 fps, never recovers). Each time, the same sequence shows up in the log: 1. System RAM runs out (0.4–0.5 GB free). Hookshot itself has ~24 GB committed, and other processes use only ~1 GB. 2. A pool import fails: `vk: pool 0x7f6a46a000+0x2bf000 not imported`. Since `import_pool()` returns false at `vkAllocateMemory`, the driver most likely can't pin more pages. 3. Nothing remembers the failure. `pool_lookup()` imports the same range again on every later use, at 7–130 ms per attempt, on the Presentation Thread and on the game's worker threads. Measured: **19,712 imports and 435 s of import time** in one session, ~40 attempts/s, with one thread at ~90 % for the whole time. This happens with the default 16 MB chunks and also with `RX_VK_IMPORT_CHUNK_MB=0`, so chunk rounding isn't the cause. **Suggested fix:** keep a list of ranges whose import failed and don't retry them right away (back off, or retry only when free memory changes), and fall back to a slower path for those ranges instead of failing every frame. Logging the `VkResult` from `vkAllocateMemory` would also show whether the cause is `OUT_OF_HOST_MEMORY`, `OUT_OF_DEVICE_MEMORY` or `INVALID_EXTERNAL_HANDLE`. Code: `gpu/vk/vk_memory.cpp` at commit `1c7c9c7`: `pool_lookup()` (line 1072), the `if (!ok)` path (line 1156, which returns `nullptr` with no state kept), and `import_pool()` → `vkAllocateMemory` (line 147). ## System - CPU: AMD Ryzen 5 1600X (6c/12t) - GPU: NVIDIA GeForce RTX 3060, Vulkan 1.4, driver `0x9b438000` - RAM: **16 GB** DDR4-2133. The page file is system-managed (commit limit 74.5 GB). - Windows 11 Pro 24H2 (build 26100) - Output: 3840x2160 fullscreen, `frame_pacing=1`, no upscaling or frame generation - Built with HookshotBuilder on 2026-11-07, from `1c7c9c7` ("Less stutter …, 8 GB mirrors restored"), with the shipped PGO profile ## Evidence ### Run 4: default settings The failures appear at the load zone (logging stops after 16 lines): ``` vk: pool 0x7f76fe7000+0x1d000 not imported vk: pool 0x7f6a46a000+0x2bf000 not imported vk: pool 0x7f61fea000+0x153000 not imported ``` From then on, the same ranges are imported again and again (one log line per 256 imports): ``` vk: pool 0x7f61fea000+0x153000 imported in 15.1 ms (256 imports, 8208 ms in all) vk: pool 0x7f6a46a000+0x2bf000 imported in 7.2 ms (768 imports, 14187 ms in all) vk: pool 0x7f6a46a000+0x2bf000 imported in 8.1 ms (1024 imports, 17235 ms in all) vk: pool 0x115a858000+0x72000 imported in 22.0 ms (2048 imports, 30073 ms in all) ... vk: pool 0x1158f8e000+0x120000 imported in 23.2 ms (14592 imports, 320294 ms in all) ... vk: pool 0x115a34d000+0x226000 imported in 35.3 ms (19712 imports, 435585 ms in all) vi: 2788 frames presented (0.0 fps over the last 43.9 s, interval 1) hid: the game read no controller for 6.2 s ``` The game process sat at ~109 % of one core, with one thread at 88 %. ### Run 5: `RX_VK_IMPORT_CHUNK_MB=0` The load got further, then a 213 MB pool failed, and the frame rate fell to 0.1 fps in the new area: ``` [EffectResLoadingThread] vk: pool 0x107f7f5000+0xd5b6000 imported in 118.0 ms (1024 imports, 57463 ms in all) [EffectResLoadingThread] vk: pool 0x107f7f5000+0xd5b6000 not imported (x16, then logging stops) [Presentation Thread] vk: pool 0x107f7f5000+0xd5b6000 imported in 129.7 ms (2560 imports, 230391 ms in all) [Presentation Thread] vi: 2743 frames presented (0.1 fps over the last 18.4 s, interval 1) ``` At that point: 1.0 GB free RAM, hookshot working set 5.9 GB, private 24.3 GB. ### Run 6: default settings again Same pattern: `vk: pool 0x7f5f5f5000+0x394000 not imported`, then 256 imports in 5 s, and the frame rate fell from 45.7 to 7.5 to 0.1 fps. At that point: 0.4 GB free RAM, hookshot working set 8.1 GB, private 24.3 GB, Memory Compression 2.0 GB, and the next largest other process 0.45 GB. ## Probably related: recurring ~150 ms descriptor stalls These appear even when the system isn't under memory pressure. A 64-byte storage buffer bind for compute program `612a27de13e44e79` takes 140–176 ms each time, at a new address each time. The pipeline is ready at 0.0 ms: ``` vk: slow descriptor 155.7 ms: storage buffer (written) 0x1044962000 size 0x40 vk: slow dispatch 155.9 ms: program 612a27de13e44e79 (picked at 0.1), pipeline at 0.1, descriptors at 155.8 ... (x7 back to back) vk: slow submit: 1107.4 ms: dispatch 1107.3 ``` Successful imports take 57–86 ms each (`vk: import 71.5 ms: commit+properties 35.3, buffer 0.0, allocate 36.2`), so these stalls look like synchronous imports on first use. The worst first-visit frame broke down like this: `slow submit: 1813.1 ms: draw 1676.9 descriptors 1406.9 texture lookups 889.5 uploads 593.9`. ## Not an issue: the pipeline cache works Same route over three runs, restarting the game in between: | | Run 1 | Run 2 | Run 3 | |---|---|---|---| | `mkw_vk_pipelines.bin` at start | 0 KB | 55,568 KB | 70,202 KB | | Precompiled at start | 15 gfx + 11 compute | 1551 gfx + 120 compute | 1675 gfx + 120 compute | | Worst pipeline stall | 9117 ms | — | 4.6 ms frame wait | ## Logs The logs are attached: - `run4_loadzone_log.txt`: the freeze with default settings - `run6_loadzone_log.txt`: the freeze again with default settings - `run1_log.txt` – `run3_log.txt`: the pipeline cache runs Run 5's log was overwritten; its numbers above were read from the live log. [run1_log.txt](https://github.com/user-attachments/files/34523730/run1_log.txt) [run2_log.txt](https://github.com/user-attachments/files/34523727/run2_log.txt) [run3_log.txt](https://github.com/user-attachments/files/34523729/run3_log.txt) [run4_loadzone_log.txt](https://github.com/user-attachments/files/34523731/run4_loadzone_log.txt) [run6_loadzone_log.txt](https://github.com/user-attachments/files/34523728/run6_loadzone_log.txt)
shayderrr commented 2026-11-07 17:14:25 +00:00 (Migrated from github.com)

Fixed in #240 , try now.

Fixed in #240 , try now.
Commenting is not possible because the repository is archived.
No milestone
No assignees
1 participant
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
MagicBeanDev/Hookshot#218
No description provided.