From 6bf9ab86ffcf976e17df7efaf82be88ce111e5fb Mon Sep 17 00:00:00 2001 From: hypermist Date: Mon, 12 Oct 2026 19:57:56 +1300 Subject: [PATCH] perf(agc): keep adjacent ranges one import serves as one region of the cached address space A V# spanning two registered ranges dissolved the shared space into the build's own regions (about 10k regions copied, sorted and looked up per build in Killing Floor 3), although the import covering the run binds it in place. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Uzy15wqYTt6iWyxYXEzUWo --- .../Graphics/src/GuestBufferMemory.cpp | 14 +++++++ .../libSceAgcDriver/tests/BdaResources.cpp | 37 +++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp b/core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp index ec5d3a4f5..3080945cd 100644 --- a/core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp +++ b/core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp @@ -2257,6 +2257,20 @@ void GuestBufferMemory::AcquireRegistered() { publish = false; spaces.unpublished.fetch_add(1, std::memory_order_relaxed); } else { + std::size_t kept = 0; + for (std::size_t index = 0; index < regions.size(); ++index) { + auto& region = regions[index]; + if (kept != 0) { + auto& previous = regions[kept - 1]; + if (region.direct != nullptr && previous.direct == region.direct && previous.end == region.begin && previous.writable == region.writable && region.mirror == nullptr && previous.mirror == nullptr && !region.sparse && !previous.sparse && region.end <= region.direct->base + region.direct->bytes) { + previous.end = region.end; + continue; + } + } + if (kept != index) regions[kept] = std::move(region); + ++kept; + } + regions.erase(regions.begin() + static_cast(kept), regions.end()); for (const auto& region : regions) { if (region.direct != nullptr || region.mirror != nullptr) ranges.push_back(addressRange(region)); } diff --git a/core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp b/core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp index cca74f789..5a1f81054 100644 --- a/core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp +++ b/core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp @@ -175,6 +175,42 @@ void failedImportRemapTests(const Context& context, const BdaTestAccess& access) ::operator delete(block, std::align_val_t{piece}); } +void spaceImportRunTests(const Context& context) { + constexpr std::size_t piece = 65536; + void* block = ::operator new(2 * piece, std::align_val_t{piece}); + const auto first = reinterpret_cast(block); + std::memset(block, 0x3c, 2 * piece); + auto importing = context; + importing.hostImportAlignment = piece; + const auto change = [&](std::uint8_t* range, bool add) { + auto* mutation = GuestAllocations::GuestAllocationsBegin_nid_postfix(); + if (add) GuestAllocations::GuestAllocationsAdd_nid_postfix(mutation, range, piece, true, false, true); + else GuestAllocations::GuestAllocationsRemove_nid_postfix(mutation, range); + GuestAllocations::GuestAllocationsEnd_nid_postfix(mutation); + }; + auto* guest = static_cast(block); + change(guest, true); + change(guest + piece, true); + for (int build = 0; build < 2; ++build) { + const auto before = AddressSpaceCounters(); + GuestBufferMemory leased(importing); + leased.AcquireRegistered(); + leased.AddReadable(first + piece - 256, 512); + leased.Upload(true); + std::uint32_t adjustment = 0; + const auto view = leased.Descriptor(first + piece - 256, 512, adjustment); + Require(view.buffer != VK_NULL_HANDLE && view.range == 512 + adjustment, "a V# across one import's ranges has no descriptor"); + const auto ranges = leased.AddressRanges(); + Require(std::any_of(ranges.begin(), ranges.end(), [&](const auto& range) { return range.begin <= first && first + 2 * piece <= range.end; }), "one import's adjacent ranges are not one BDA table entry"); + leased.WriteBack(); + const auto after = AddressSpaceCounters(); + if (after.enabled && build == 1) Require(after.hits == before.hits + 1 && after.dissolvedOverlap == before.dissolvedOverlap, "a V# across one import's ranges dissolved the cached address space"); + } + change(guest, false); + change(guest + piece, false); + ::operator delete(block, std::align_val_t{piece}); +} + void importWindowTests(const Context& context) { constexpr std::size_t piece = 65536; constexpr std::size_t window = 2 * piece; @@ -1202,6 +1238,7 @@ void RunBdaResourceTests(const Context& context, const BdaTestAccess& access) { importCrossingTests(context, access); importSpanTests(context); failedImportRemapTests(context, access); + spaceImportRunTests(context); importWindowTests(context); heapMirrorTests(context, access); importedHeapMirrorTests(context, access);