heap_tracker: use linear-time mapping eviction

This commit is contained in:
Liam 2023-12-27 01:02:51 -05:00
parent ddda76f9b0
commit adb2af0a2b
2 changed files with 28 additions and 9 deletions

View File

@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm> #include <fstream>
#include <vector> #include <vector>
#include "common/heap_tracker.h" #include "common/heap_tracker.h"
@ -11,11 +11,25 @@ namespace Common {
namespace { namespace {
constexpr s64 MaxResidentMapCount = 0x8000; s64 GetMaxPermissibleResidentMapCount() {
// Default value.
s64 value = 65530;
// Try to read how many mappings we can make.
std::ifstream s("/proc/sys/vm/max_map_count");
s >> value;
// Print, for debug.
LOG_INFO(HW_Memory, "Current maximum map count: {}", value);
// Allow 20000 maps for other code and to account for split inaccuracy.
return std::max<s64>(value - 20000, 0);
}
} // namespace } // namespace
HeapTracker::HeapTracker(Common::HostMemory& buffer) : m_buffer(buffer) {} HeapTracker::HeapTracker(Common::HostMemory& buffer)
: m_buffer(buffer), m_max_resident_map_count(GetMaxPermissibleResidentMapCount()) {}
HeapTracker::~HeapTracker() = default; HeapTracker::~HeapTracker() = default;
void HeapTracker::Map(size_t virtual_offset, size_t host_offset, size_t length, void HeapTracker::Map(size_t virtual_offset, size_t host_offset, size_t length,
@ -74,8 +88,8 @@ void HeapTracker::Unmap(size_t virtual_offset, size_t size, bool is_separate_hea
} }
// Erase from map. // Erase from map.
it = m_mappings.erase(it);
ASSERT(--m_map_count >= 0); ASSERT(--m_map_count >= 0);
it = m_mappings.erase(it);
// Free the item. // Free the item.
delete item; delete item;
@ -94,8 +108,8 @@ void HeapTracker::Protect(size_t virtual_offset, size_t size, MemoryPermission p
this->SplitHeapMap(virtual_offset, size); this->SplitHeapMap(virtual_offset, size);
// Declare tracking variables. // Declare tracking variables.
const VAddr end = virtual_offset + size;
VAddr cur = virtual_offset; VAddr cur = virtual_offset;
VAddr end = virtual_offset + size;
while (cur < end) { while (cur < end) {
VAddr next = cur; VAddr next = cur;
@ -167,7 +181,7 @@ bool HeapTracker::DeferredMapSeparateHeap(size_t virtual_offset) {
it->tick = m_tick++; it->tick = m_tick++;
// Check if we need to rebuild. // Check if we need to rebuild.
if (m_resident_map_count > MaxResidentMapCount) { if (m_resident_map_count > m_max_resident_map_count) {
rebuild_required = true; rebuild_required = true;
} }
@ -193,8 +207,12 @@ void HeapTracker::RebuildSeparateHeapAddressSpace() {
ASSERT(!m_resident_mappings.empty()); ASSERT(!m_resident_mappings.empty());
// Unmap so we have at least 4 maps available. // Dump half of the mappings.
const size_t desired_count = std::min(m_resident_map_count, MaxResidentMapCount - 4); //
// Despite being worse in theory, this has proven to be better in practice than more
// regularly dumping a smaller amount, because it significantly reduces average case
// lock contention.
const size_t desired_count = std::min(m_resident_map_count, m_max_resident_map_count) / 2;
const size_t evict_count = m_resident_map_count - desired_count; const size_t evict_count = m_resident_map_count - desired_count;
auto it = m_resident_mappings.begin(); auto it = m_resident_mappings.begin();
@ -247,8 +265,8 @@ void HeapTracker::SplitHeapMapLocked(VAddr offset) {
// If resident, also insert into resident map. // If resident, also insert into resident map.
if (right->is_resident) { if (right->is_resident) {
m_resident_mappings.insert(*right);
m_resident_map_count++; m_resident_map_count++;
m_resident_mappings.insert(*right);
} }
} }

View File

@ -86,6 +86,7 @@ private:
private: private:
Common::HostMemory& m_buffer; Common::HostMemory& m_buffer;
const s64 m_max_resident_map_count;
std::shared_mutex m_rebuild_lock{}; std::shared_mutex m_rebuild_lock{};
std::mutex m_lock{}; std::mutex m_lock{};