Skip to content

HFW loading: fixed host-import budget forces a multi-GiB heap mirror and OOM #2809

Closed

Description

@tototomate123

Problem

On Linux/NVIDIA, HFW (PPSA01521) loading exceeds the fixed 6144 MiB host-import budget in Graphics/src/GuestBufferMemory.cpp::importAllocation. A 7488 MiB GPU-mapped guest allocation at 0x1313800000 is refused with 2268 MiB already imported. The fallback mirrors the whole heap, even though copying it costs more RAM than importing it in place.

Evidence

Linux x86-64, 32 GiB RAM, RTX 4070 SUPER, GCC 16.2.1; local HFW integration based on main de5e541d:

  • Default budget: /proc/<pid>/smaps shows a 7360 MiB resident /dev/nvidiactl buffer matching most of the refused heap. The original run was OOM-killed at about 29 GiB RSS. A repeat was stopped at 24.1 GiB RSS with roughly 5 GiB system memory available.
  • APS5_HOST_IMPORT_MIB=12288: the 7488 MiB allocation is imported successfully (9756 MiB live imports), no large heap mirror is created, and the run peaks at 15.2 GiB RSS with 6.25 GiB available. Loading proceeds to a separate shader-table planner failure (0x1280102200, GetImageResource / LoadAddressU32), without OOM.

These runs stop at different points, so this is not a same-frame benchmark or proof that no leak remains. It does identify and avoid one expensive whole-heap copy. No gameplay is reached.

Existing fix / related work

Open #290 already implements a RAM-derived default import budget, plus import windows and eviction. Its budget change would admit this heap on the tested 32 GiB machine; I have tested the 12 GiB environment override, not the full #290 branch. Please consider the budget adjustment independently if the broader change needs more review.

The closed HFW bring-up PR #1616 and its linked split PRs document the startup work. The measurements above also require local image-table experiments and the material-scan/depth-clear fixes; they are not results from unmodified main. No duplicate budget PR is submitted.

Other titles exceeding the fixed budget may benefit, but smaller games already fitting it will not automatically save RAM. Import failures and machines with less available memory still need a bounded fallback policy.

AI-assisted investigation and report: Codex.

Activity

  1. fma-rc commented on Oct 10, 2026

    @fma-rc
    Contributor

    Same thing on a second title, with the budget as the only variable.

    Title: Astro Bot, PPSA21564, 01.007
    Host: Arch Linux (kernel 7.2.9), 31179 MiB RAM, RTX 5080 (16 GiB, NVIDIA 615.78.08), GCC 16.2.1, Release
    Build: unmodified main 262c031
    Settings: APS5_HOST_IMPORT_MIB as in the table, nothing else set

    Each run is 100 s from launch. Process memory is sampled every 5 s from /proc/<pid>/status and MemAvailable; the /dev/nvidiactl column is the resident size of those mappings in /proc/<pid>/smaps at 91 s.

    APS5_HOST_IMPORT_MIB refused by the budget peak RSS peak swap (process) lowest MemAvailable /dev/nvidiactl resident
    unset (6144), shader cache cold 4483 MiB live, 0x1000000000+0xc8000000 (3200 MiB) refused 30955 MiB 201 MiB 1045 MiB 7983 MiB
    unset (6144), shader cache warm same 35041 MiB 1206 MiB 1159 MiB 8327 MiB
    12288 7683 MiB live, 0x10c8000000+0x120000000 (4608 MiB) refused 26605 MiB 0 2740 MiB 4980 MiB
    16384 nothing 17841 MiB 0 6609 MiB 488 MiB

    What I see:

    • The title asks for imports that add up to 4483 + 3200 + 4608 = 12291 MiB. The default budget refuses the two large ranges, and 12288, the override tested above for HFW, still refuses the 4608 MiB one by 3 MiB.
    • Each refused range shows up as resident /dev/nvidiactl memory of about its size: 488 MiB with nothing refused, 4980 MiB with the 4608 MiB range refused, about 8000 MiB with both refused.
    • With everything imported the process peaks at 17.4 GiB instead of 30 to 34 GiB, and the machine keeps 6.5 GiB available instead of about 1 GiB. Only the two default runs swapped.
    • A refused range is asked for again and again: the log counts 290 refusals of the 4608 MiB range in the 12288 run and 3764 refusals in the warm default run.
    • The 16384 run, with all 12291 MiB imported on this 16 GiB card, ran the full 100 s without stopping.

    So no fixed number fits: 6144 costs this title 13 to 17 GiB of resident memory, and 12288 is enough for HFW's 9756 MiB but not for this one. Half of this machine's physical memory is 15589 MiB, which would admit all of it.

    Not established: these are not same-frame comparisons. The runs do not reach the same point after 100 s; the warm default run stopped between 75 and 80 s on an unrelated compute shader error (storage image access to depth/stencil surface 0x53a500000 is not implemented) and the other three were still running. Nothing here was measured on a machine with less RAM or on AMD, so I can't say where an import budget starts to make host allocations fail, which is what the fixed limit is there to prevent.

  2. fma-rc commented on Oct 11, 2026

    @fma-rc
    Contributor

    Another title where the fixed default decides the outcome: Hades II (PPSA36082, 01.006.000) on Linux, RTX 5080, 31 GiB RAM, main 06da117.

    Its GPU arena is a single 6144 MiB range and 512 MiB is already imported when it arrives, so the default budget refuses it: host import budget: 512 MiB live of 6144 MiB (APS5_HOST_IMPORT_MIB); 1 imports (6144 MiB) refused so far, last 0x260000000+0x180000000. In a 55 s run no window appeared and the title ended with SIGSEGV in its own libc memcpy, vmovdqu %xmm0,(%rdi) with rdi 0 and rdx 0x4000.

    With APS5_HOST_IMPORT_MIB=16384 and nothing else changed, seven runs of 20 to 60 s all ran to the timeout. In the one I looked at, the main menu is up at 30 s and the window title reports 59.94 fps.

  3. oneandonlydean commented on Oct 14, 2026

    @oneandonlydean
    Collaborator

    #290 is on main: the default import budget is now the larger of 6 GiB and half of system RAM, with import windows instead of whole-heap mirrors. Could you rerun these titles on current main and say whether the out-of-memory still happens?

  4. fma-rc commented on Oct 14, 2026

    @fma-rc
    Contributor

    Reran both of my titles on main 90d0cb4 with APS5_HOST_IMPORT_MIB unset, 100 s each, sampled as above (RTX 5080, 31 GiB RAM).

    title refused by the budget peak RSS lowest MemAvailable end
    Astro Bot (PPSA21564) nothing 17442 MiB 9462 MiB ran to the timeout
    Hades II (PPSA36082) nothing 13126 MiB 10021 MiB ran to the timeout

    Astro Bot's peak RSS on the default is now where it was with APS5_HOST_IMPORT_MIB=16384 before (17841 MiB), down from 30955 to 35041 MiB on the old 6144 default. Hades II no longer ends in the memcpy SIGSEGV. So for these two titles the out-of-memory is gone.

  5. oneandonlydean commented on Oct 14, 2026

    @oneandonlydean
    Collaborator

    Closing as fixed by #290: the reruns on current main above show no refused import and no out-of-memory. If PPSA01521 still runs out of memory on current main, reopen with the RSS numbers.

  6. ultraacademy657-dot commented on Oct 15, 2026

    @ultraacademy657-dot

    Related Windows/NVIDIA reproduction: large host-import refusal followed by heap-mirror allocation failure

    I'm reporting another reproduction of the host-import / heap-mirror memory problem, this time on Windows with an NVIDIA GPU. This may be related to #2809 and the behavior documented in #290.

    Environment

    • OS: Windows 11 x64, build 26200
    • GPU: NVIDIA GeForce RTX 3080, 10 GB VRAM
    • System RAM: 16 GB
    • AnyPS5 source: fa9365c, built locally with MinGW-w64 GCC 15.2.0
    • Effective host-import budget reported by AnyPS5: 6063 MiB
    • Test environment: inherited APS5_* variables were cleared; only APS5_TRACE_HOST_IMPORT=1 was enabled.

    Observed behavior

    During graphics initialization/presentation, AnyPS5 refuses to import a registered guest-memory range of 6544 MiB:

    [gpu] host import budget: 2000 MiB live of 6063 MiB (APS5_HOST_IMPORT_MIB); 1 imports (6544 MiB) refused so far, last 0x108a800000+0x199000000
    

    The address-based path then attempts to create a heap mirror for the range. The Vulkan allocation is 6,861,881,344 bytes, and the default allocation fails:

    vkAllocateMemory buffer: allocation=6861881344 memoryType=4 reclaimed=4194304 initialResult=-2 attempts=2
    

    -2 is VK_ERROR_OUT_OF_DEVICE_MEMORY. The presentation fails and the process terminates.

    The memory diagnostics show that the requested buffer's memoryTypeBits mask is 0x0000001b. Memory type 4 is allowed, but its allocation fails. Memory type 5 exposes DEVICE_LOCAL | HOST_VISIBLE | HOST_COHERENT, but is explicitly excluded by the mask:

    [gpu] local-mapped probe: allocation=6861881344 memoryTypeBits=0x0000001b
    [gpu] memory type 4: allowed=1 flags=0x0000000e heap=1 heapFlags=0x00000000 heapSize=8505315328
    [gpu] memory type 5: allowed=0 flags=0x00000007 heap=0 heapFlags=0x00000001 heapSize=10539237376
    

    Therefore, selecting type 5 is not a valid workaround for this particular buffer. The host-visible heap is approximately 7.92 GiB, and the default effective import budget leaves a 2 GiB reserve. Later log lines show live host imports reaching approximately 5774 MiB.

    Relation to existing work

    I understand that #290 introduced windowed host imports and budget-aware eviction, and that address-based builds can still require whole-range imports and fall back to heap mirrors when those imports are refused. I also found #1085, which addresses how failed heap-mirror allocations are reported.

    For transparency, the detailed memory-type output and the attempted host-visible/device-local fallback came from local, unmerged diagnostic changes on top of fa9365c. The original heap-mirror allocation failure is the primary issue; the additional fallback also fails because Vulkan excludes type 5 for this buffer.

    Question

    Is this an expected limitation of the current address-based memory path, or is there a supported way to handle this range without requiring a single host-visible allocation of approximately 6.4 GiB?

    I have not increased APS5_HOST_IMPORT_MIB, since allowing more imports without accounting for the remaining host-memory requirements could make the memory pressure worse. I would appreciate guidance on whether this case needs a different import strategy or additional investigation.

    Related: #290, #1085, #2809

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions