mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-10-07 14:26:36 +00:00
first intent to pinpoint performance decrease on virtual buffer table + multi-range
This commit is contained in:
@@ -5,9 +5,7 @@
|
|||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <mutex>
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <boost/container/small_vector.hpp>
|
#include <boost/container/small_vector.hpp>
|
||||||
|
|
||||||
@@ -28,23 +26,22 @@ using VirtualSegments = boost::container::small_vector<VirtualSegment, 8>;
|
|||||||
class VirtualRangeCache {
|
class VirtualRangeCache {
|
||||||
public:
|
public:
|
||||||
static constexpr size_t MAX_ENTRIES = 8192;
|
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) {
|
const VirtualSegments* Query(Tegra::MemoryManager& memory, GPUVAddr gpu_addr, u32 size) {
|
||||||
if (has_deferred.load(std::memory_order_acquire)) {
|
const u64 current = generation.load(std::memory_order_acquire);
|
||||||
ApplyDeferred();
|
|
||||||
}
|
|
||||||
if (entries.size() > MAX_ENTRIES) {
|
if (entries.size() > MAX_ENTRIES) {
|
||||||
entries.clear();
|
entries.clear();
|
||||||
}
|
}
|
||||||
const size_t as_id = memory.GetID();
|
const size_t as_id = memory.GetID();
|
||||||
const u64 key = MakeKey(as_id, gpu_addr);
|
const u64 key = MakeKey(as_id, gpu_addr);
|
||||||
const auto it = entries.find(key);
|
const auto it = entries.find(key);
|
||||||
if (it != entries.end() && it->second.as_id == as_id &&
|
if (it != entries.end() && it->second.generation == current &&
|
||||||
it->second.gpu_addr == gpu_addr && it->second.size == size) {
|
it->second.as_id == as_id && it->second.gpu_addr == gpu_addr &&
|
||||||
|
it->second.size == size) {
|
||||||
return &it->second.segments;
|
return &it->second.segments;
|
||||||
}
|
}
|
||||||
Entry entry{};
|
Entry entry{};
|
||||||
|
entry.generation = current;
|
||||||
entry.as_id = as_id;
|
entry.as_id = as_id;
|
||||||
entry.gpu_addr = gpu_addr;
|
entry.gpu_addr = gpu_addr;
|
||||||
entry.size = size;
|
entry.size = size;
|
||||||
@@ -79,95 +76,27 @@ public:
|
|||||||
return &result.first->second.segments;
|
return &result.first->second.segments;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Unmap(size_t as_id, GPUVAddr gpu_addr, u64 size) {
|
void Unmap(size_t, GPUVAddr, u64 size) {
|
||||||
if (size == 0) {
|
if (size != 0) {
|
||||||
return;
|
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:
|
private:
|
||||||
struct Entry {
|
struct Entry {
|
||||||
VirtualSegments segments;
|
VirtualSegments segments;
|
||||||
|
u64 generation{};
|
||||||
size_t as_id{};
|
size_t as_id{};
|
||||||
GPUVAddr gpu_addr{};
|
GPUVAddr gpu_addr{};
|
||||||
u32 size{};
|
u32 size{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DeferredUnmap {
|
|
||||||
size_t as_id;
|
|
||||||
GPUVAddr gpu_addr;
|
|
||||||
u64 size;
|
|
||||||
};
|
|
||||||
|
|
||||||
static u64 MakeKey(size_t as_id, GPUVAddr gpu_addr) {
|
static u64 MakeKey(size_t as_id, GPUVAddr gpu_addr) {
|
||||||
return (static_cast<u64>(as_id) << 48) ^ 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;
|
::Common::unordered_map<u64, Entry> entries;
|
||||||
std::vector<DeferredUnmap> deferred;
|
std::atomic<u64> generation{};
|
||||||
std::mutex deferred_mutex;
|
|
||||||
std::atomic<bool> has_deferred{false};
|
|
||||||
bool deferred_overflow{};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace VideoCommon
|
} // namespace VideoCommon
|
||||||
|
|||||||
Reference in New Issue
Block a user