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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uzy15wqYTt6iWyxYXEzUWo
This commit is contained in:
hypermist 2026-10-12 19:57:56 +13:00
parent ea2bbefb2b
commit 6bf9ab86ff
2 changed files with 51 additions and 0 deletions

View File

@ -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<std::ptrdiff_t>(kept), regions.end());
for (const auto& region : regions) {
if (region.direct != nullptr || region.mirror != nullptr) ranges.push_back(addressRange(region));
}

View File

@ -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<std::uintptr_t>(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<std::uint8_t*>(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);