first intent to pinpoint performance decrease on virtual buffer table + multi-range

This commit is contained in:
CamilleLaVey
2026-09-17 06:12:25 -04:00
parent 64a307c6dc
commit 27bcaba75c
@@ -5,9 +5,7 @@
#include <atomic>
#include <limits>
#include <mutex>
#include <optional>
#include <vector>
#include <boost/container/small_vector.hpp>
@@ -28,23 +26,22 @@ using VirtualSegments = boost::container::small_vector<VirtualSegment, 8>;
class VirtualRangeCache {
public:
static constexpr size_t MAX_ENTRIES = 8192;
static constexpr size_t MAX_DEFERRED = 4096;
const VirtualSegments* Query(Tegra::MemoryManager& memory, GPUVAddr gpu_addr, u32 size) {
if (has_deferred.load(std::memory_order_acquire)) {
ApplyDeferred();
}
const u64 current = generation.load(std::memory_order_acquire);
if (entries.size() > MAX_ENTRIES) {
entries.clear();
}
const size_t as_id = memory.GetID();
const u64 key = MakeKey(as_id, gpu_addr);
const auto it = entries.find(key);
if (it != entries.end() && it->second.as_id == as_id &&
it->second.gpu_addr == gpu_addr && it->second.size == size) {
if (it != entries.end() && it->second.generation == current &&
it->second.as_id == as_id && it->second.gpu_addr == gpu_addr &&
it->second.size == size) {
return &it->second.segments;
}
Entry entry{};
entry.generation = current;
entry.as_id = as_id;
entry.gpu_addr = gpu_addr;
entry.size = size;
@@ -79,95 +76,27 @@ public:
return &result.first->second.segments;
}
void Unmap(size_t as_id, GPUVAddr gpu_addr, u64 size) {
if (size == 0) {
return;
void Unmap(size_t, GPUVAddr, u64 size) {
if (size != 0) {
generation.fetch_add(1, std::memory_order_release);
}
{
std::scoped_lock lock{deferred_mutex};
if (!deferred.empty()) {
DeferredUnmap& last = deferred.back();
if (last.as_id == as_id && last.gpu_addr + last.size == gpu_addr) {
last.size += size;
has_deferred.store(true, std::memory_order_release);
return;
}
}
if (deferred.size() >= MAX_DEFERRED) {
deferred.clear();
deferred_overflow = true;
} else {
deferred.push_back(DeferredUnmap{
.as_id = as_id,
.gpu_addr = gpu_addr,
.size = size,
});
}
}
has_deferred.store(true, std::memory_order_release);
}
private:
struct Entry {
VirtualSegments segments;
u64 generation{};
size_t as_id{};
GPUVAddr gpu_addr{};
u32 size{};
};
struct DeferredUnmap {
size_t as_id;
GPUVAddr gpu_addr;
u64 size;
};
static u64 MakeKey(size_t as_id, GPUVAddr gpu_addr) {
return (static_cast<u64>(as_id) << 48) ^ gpu_addr;
}
void ApplyDeferred() {
std::vector<DeferredUnmap> pending;
bool overflow = false;
{
std::scoped_lock lock{deferred_mutex};
has_deferred.store(false, std::memory_order_release);
pending.swap(deferred);
overflow = deferred_overflow;
deferred_overflow = false;
}
if (overflow) {
entries.clear();
return;
}
if (pending.empty() || entries.empty()) {
return;
}
for (auto it = entries.begin(); it != entries.end();) {
const Entry& entry = it->second;
const GPUVAddr entry_end = entry.gpu_addr + entry.size;
bool overlaps = false;
for (const DeferredUnmap& unmap : pending) {
if (unmap.as_id != entry.as_id) {
continue;
}
if (entry.gpu_addr < unmap.gpu_addr + unmap.size && unmap.gpu_addr < entry_end) {
overlaps = true;
break;
}
}
if (overlaps) {
it = entries.erase(it);
} else {
++it;
}
}
}
::Common::unordered_map<u64, Entry> entries;
std::vector<DeferredUnmap> deferred;
std::mutex deferred_mutex;
std::atomic<bool> has_deferred{false};
bool deferred_overflow{};
std::atomic<u64> generation{};
};
} // namespace VideoCommon