Repository navigation
perf(agc): take the host import budget from the device's memory budget - #6479
Merged
oneandonlydean merged 40 commits intoOct 19, 2026
Merged
Conversation
Every host import now names the path that asked for it: - map: the map-time import of a GPU mapping; - build: an address-based build's walk and its region imports; - access: a lookup through HostImportFor; - join: a join at bind; - segment: a storage image write-back segment; - expand: a DB expand's store. The APS5_TRACE_HOST_IMPORT ok line, the import failure line and the budget refusal report end with the requester, so a traced run splits its imports by path. HostImportCounters returns the imports made, refused and failed per requester, with the live count and bytes. agc_driver_graphics checks that each requester's imports, refusals and failures are counted under it.
A run without APS5_TRACE_HOST_IMPORT had no count of the imports it made or refused. When the driver stops, one line now gives the live imports and the imports made, refused and failed, in total and per requester: [gpu] host imports at shutdown: N live (M MiB); made ... (... MiB), refused ... (... MiB), failed ...; by requester (made/refused/failed): map a/b/c, build ..., access ..., join ..., segment ..., expand ... It prints only when an import was made, refused or failed. agc_driver_graphics checks the line's text.
The storage write-back overhang test read both surfaces straight from guest memory after FlushAllPending and WaitIdle. A write-back through a host import is only recorded there; a reader of guest memory calls FlushGpuWrites, which waits for the batch that holds it. The test passed because the split surface took the CPU write-back, whose SubmitAndWait also drained the first surface's recorded store. With both surfaces imported, neither store had landed when the test read them.
…blocks An import covered one registered range unless adjacent ranges filled a whole aligned 8 MiB window. A title that maps its GPU heap in 64 KiB pieces got one import per piece from every requester: Village held about 27,000 of them at its first scene, enough to fill the budget. The run of an address is now the largest aligned power-of-two block, from twice the import alignment up to the window, that holds the address and that continuing readable ranges fill exactly. A block over the budget steps down to the largest block that fits what is left of it, counting what the requester may evict, and nothing is tried when not even the address's own range fits, so a full budget costs one refusal per request as before. A block that would replace an import a build holds, or that fails (a refused Windows alias, vkAllocateMemory), steps down to the next smaller block. A failed block is remembered until one of its ranges changes, instead of pinning the span to single ranges for the session. An address-based build no longer asks for the ranges inside the block it just imported. A storage image over 64 adjacent pieces now finds its block import at write-back instead of importing every piece as a segment. The split write-back test keeps its two ranges apart with a 64 KiB window.
An address-based build asks for every registered GPU range whenever it rebuilds its address space, and at a full budget it was refused each one again: a title held at its default budget counted 304,394 refusals over about 12,000 ranges at its title screen. A request that may not evict (the build's walk, an import when a range is mapped) now remembers a refused run with the live bytes and the budget at the refusal. Until live imports drop below those bytes, the budget changes or one of the run's ranges changes, a request for that range is answered from memory, still counted as refused and also as remembered, and a remembered block is skipped, so a block stepped down for the budget keeps its import across registry changes. A request that may evict always tries again, and a new import forgets the refusals of the runs it covers. The shutdown report and the budget line print how many refusals were remembered.
Imports were held to a configured budget only. With APS5_HOST_IMPORT_MIB at 6864 on a 15.4 GB PC, Village's imports reached the NVIDIA driver's pinning ceiling of about 6.56 GiB, and from there every import was tried and failed at vkAllocateMemory, 992 times. Where the device enables VK_EXT_memory_budget, the budget is now also at most the host heap's reported budget less its other usage and an eighth, in 64 MiB steps, read at most once a second. A vkAllocateMemory failure within an eighth of the budget, or the third in a row, lowers the budget to the live imports, so later imports are refused or evict instead of failing; an isolated failure further below only marks its range failed, as before. A remembered refusal stays remembered while the budget does not grow.
|
Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.
Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.
|
…ite-back test Its registration and its command-line option followed the split write-back test's, where another open pull request adds its own. They now follow the copied-direct ordering and CMASK tests. No test changes.
Expand named a DB expand's store, but nothing passes it: main has no DB expand, and the open DB expand change stores its planes only where host imports already hold them, through HostImportOverlaps and the storage write-back, without making or retiring an import. The requester could never count, so the shutdown line always ended with expand 0/0/0. agc_driver_graphics checks the requester names and the shutdown report without it.
…import fails The host heap's VK_EXT_memory_budget report lowered a set APS5_HOST_IMPORT_MIB of 6400 MiB to 4480 MiB on Resident Evil Village (PPSA01556), where 6400 MiB runs without a vkAllocateMemory failure, and 85,047 imports were refused. A set APS5_HOST_IMPORT_MIB is now never lowered by the report, and the default is held to the report only once an import's vkAllocateMemory has failed. The failure ceiling is unchanged. The first time the report would lower the budget, a [gpu] host import budget line prints the heap's reported budget and usage and the live imports, and the refusal line names where its budget came from.
EagleBearerYS
added a commit
to EagleBearerYS/AnyPS5
that referenced
this pull request
Oct 15, 2026
11 tasks done
EagleBearerYS
added a commit
to EagleBearerYS/AnyPS5
that referenced
this pull request
Oct 16, 2026
This was referenced Oct 16, 2026
…al memory After a vkAllocateMemory failure the default import budget follows the host heap's VK_EXT_memory_budget report. A report that leaves imports no room made that budget 0, and the refusal memory reads a budget of 0 as none: an address-based build or an import when a range is mapped then skipped its remembered refusals and ran the whole import path again for every refused range, each time. The report's other usage grows with the copies and mirrors that stand in for refused imports, so the budget can reach 0 by itself once refusals pile up. The budget the report sets is now at least 1 byte. Nothing more is imported than at 0, and refusals are remembered again.
EagleBearerYS
added a commit
to EagleBearerYS/AnyPS5
that referenced
this pull request
Oct 16, 2026
The remembered refusal of a request that may evict expired on any budget change. A smaller budget can only keep the request refused, and boykopovar#6479 moves the budget in 64 MiB steps once a second, so the memory now ends only when the budget grows, as boykopovar#6479's stillRefused does.
EagleBearerYS
added a commit
to EagleBearerYS/AnyPS5
that referenced
this pull request
Oct 16, 2026
12 tasks done
9 tasks done
Main's sameRange for a failed import now takes this branch's import budget, as the HostImport overload does, so a recorded failure is compared against the run the budget would import again.
Main's sameRange for a failed import now takes the import budget, as the HostImport overload does, so a recorded failure is compared against the run the budget would import again.
importBudget keeps this branch's configuredBudget split and takes boykopovar#6472's HostImportBudget for the default; the host-import debt entry takes boykopovar#6472's budget sentence next to this branch's report and refusal sentences.
The host-import debt entry takes boykopovar#6472's budget sentence and keeps this branch's sentence on remembered refusals.
# Conflicts: # core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
# Conflicts: # docs/dev/debt/libSceAgcDriver.md
# Conflicts: # core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp # docs/dev/debt/libSceAgcDriver.md
# Conflicts: # docs/dev/debt/libSceAgcDriver.md
# Conflicts: # core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp # docs/dev/debt/libSceAgcDriver.md
12 tasks done
# Conflicts: # docs/dev/debt/libSceAgcDriver.md
# Conflicts: # core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
# Conflicts: # core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
12 tasks done
11 tasks done
12 tasks done
12 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Host imports were held to a configured budget only, not to what the driver can pin. A budget above the driver's limit makes every later import fail at
vkAllocateMemory; a budget below it refuses imports that would fit.VK_EXT_memory_budget, no budget is set and an import'svkAllocateMemoryhas failed, the effective budget is at most the host heap's reported budget, less that heap's usage by everything other than the imports, less an eighth of the budget, rounded down to 64 MiB. It is read at most once a second. A setAPS5_HOST_IMPORT_MIBis never lowered by the report, and before a failure main's default stands. Without the extension the configured budget applies, as before.vkAllocateMemoryfailure of an import within an eighth of the budget, or the third in a row, lowers the budget to the live imports. Later imports are then refused (and remembered, perf(agc): import adjacent host ranges as aligned blocks and stop re-trying budget refusals #6457) or evict, instead of failing. It prints once:[gpu] host import budget lowered to the N MiB live after vkAllocateMemory failed within an eighth of the budget.maxMemoryAllocationCount. NVIDIA's Windows driver reports 4,096, while Resident Evil Village held 27,167 live imports without allocation failures, so the reported value isn't where the driver fails.vkAllocateMemoryfailure turns the report on and counts toward the ceiling whatever its code, so a range a driver refuses for another reason counts too. An out-of-memory-only filter isn't safe: NVIDIA's pinning failures here were -2 (VK_ERROR_OUT_OF_DEVICE_MEMORY), and Mesa's RADV returnsVK_ERROR_INVALID_EXTERNAL_HANDLEwhen it can't pin a host pointer, so such a filter would turn the protection off there.APS5_HEAP_MIRROR_MIBbudget (24 GiB by default), as onmain. When this PR lowers the import budget, refused heaps move into mirrors. Deriving the mirror budget from the same report would be a follow-up.The device report no longer lowers a set budget, or the default before a failure. On Resident Evil Village (PPSA01556), on an RTX 3070 Laptop GPU with
APS5_HOST_IMPORT_MIB=6400, the host heap'sVK_EXT_memory_budgetreport lowered the import budget to 4480 MiB and refused 85,047 imports (115,203 MiB), although 6400 MiB runs without a singlevkAllocateMemoryfailure on that machine. The report's "other usage" includes the host-visible copies and heap mirrors that stand in for refused imports, so it grows with every refusal and pushes the next budget down. Now a setAPS5_HOST_IMPORT_MIBis never lowered by the report. Without a setting, the budget stays at main's default until an import'svkAllocateMemoryfails, and only then can the report lower it. The failure ceiling is unchanged: a failure within an eighth of the budget, or the third in a row, still lowers the budget to the live imports. The first time the report would lower the budget, a[gpu] host import budget: host heap ...line prints the heap's reported budget and usage and the live imports, and the refusal line names its budget's source.With #6472: #6472 changes how the default (configured) budget is computed. This PR lowers the effective budget on allocation failures whatever the configured value is, and lets the device's report cap it only when no budget is set and an import has failed, so the two compose. Textually they overlap on one declaration line in
GuestBufferMemory.hppand on the "Host import windows and budget" debt entry.This branch is on #6457's branch. This PR's own commits are 98c72e9 (the device budget), ac9ccfb (the report kept off a set budget, and off the default until an import fails) and a792802 (a report with no room leaves a 1-byte budget); the merges between them bring in #6457's newer commits.
Tested
Resident Evil Village (PPSA01556), Windows 11, RTX 3070 Laptop GPU (driver 617.42):
[gpu] host import budget: 5840 MiB live of 5840 MiB (APS5_HOST_IMPORT_MIB), then... 21138 imports (71872 MiB) refused so far, last 0x200200000+0x30000000.APS5_HOST_IMPORT_MIB=6864, imports failed at the driver instead, 992 times from 6,557.7 MiB live on:[gpu] host import of 0x23944b0000+0x10000 failed at vkAllocateMemory (-2); falling back to copies.Linux, lavapipe:
^agc598/598 at this commit (on its earlier base; the code is identical).BdaResources.cpp), red on perf(agc): import adjacent host ranges as aligned blocks and stop re-trying budget refusals #6457's code and green here:Windows 11, RTX 3070 Laptop GPU (driver 617.42):
agc_driver_graphics, with the new tests, passes 5 of 5. Each run logs both ceilings:[gpu] host import budget lowered to the 0.1 MiB live after vkAllocateMemory failed within an eighth of the budgetand... after vkAllocateMemory failed 3 times in a row.GitHub's runners, at this PR's commit 98c72e9 (later merges of #6457's branch bring only #6457's own changes): Linux, lavapipe:
^agc604 of 605, the one failure the known parallel-load flakeagc_driver_preparation_scope_settle(run). Windows, no Vulkan device: 597 of 599 (467 skip) (run). The two failures also fail onmainon that runner:agc_driver_pm4_replay_tool(0xc0000139), andagc_interpolant_mapping, which prints its pass and then times out at exit.maindoesn't build in full with MinGW since #5747 (alignas(65536)intests/execution/GpuIndirectArgumentsMisalignedWriterAhead.cpp), so the Windows sweep ran with #6452's fix for that test applied, for this check only.The report kept off a set budget (ac9ccfb):
importReportFloorTestsinagc_driver_graphicschecks that a set budget and main's default stay put while the report is low, and that the report lowers the default only after an import fails. Added alone on 9c4bb70's code it fails for both the set and the default case (Linux, lavapipe); eight newHostImportBudgetWithcases, which need the fix's API, cover the formula with Resident Evil Village's numbers. With the fix:ctest -R '^agc'605/605,agc_driver_graphics10 of 10. On GitHub's runnersagc_driver_graphicsand the tests run with it pass 5 of 5 on Linux and Windows (run). The run's Windows job is marked failed for two reasons outside this change: its arm on the previous code can't build the new tests, andguest_kqueuein the libkernel suite failed, as it has in our other Windows verify runs today on unrelated changes.A report with no room (a792802):
importDeviceBudgetTestschecks that such a report doesn't make the default budget 0, and the newimportReportRefusalMemoryTeststhat a second address-based build under it answers the refused ranges from the refusal memory. On GitHub's runners, with the previous commit's code the tests fail in every one of 3 runs on Linux and Windows ("a host heap report that leaves imports no room made the default import budget 0, which the refusal memory reads as no budget"); with the fix they pass 10 of 10 on both (run). Linux, lavapipe:ctest -R '^agc'605 of 605 (42 skipped).Checklist
main0029e62 (merges cleanly with fa9365c); no other open PR implements the same functions. Overlaps:NotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file (none added).mdfiles or images added to the repository (attach them to this PR)