Merge pull request #4428 from hypermoist/perf/address-space-import-runs

perf(agc): keep adjacent ranges one import serves as one region of the cached address space
This commit is contained in:
Adrià 2026-10-13 16:18:14 +02:00 committed by GitHub
commit 759c66564f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 51 additions and 0 deletions

View File

@ -2258,6 +2258,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);