From ddda76f9b0d16e8a6fbc92db9e26f25843b647ed Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 25 Dec 2023 23:21:08 -0500 Subject: core: track separate heap allocation for linux --- src/common/heap_tracker.h | 97 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 src/common/heap_tracker.h (limited to 'src/common/heap_tracker.h') diff --git a/src/common/heap_tracker.h b/src/common/heap_tracker.h new file mode 100644 index 000000000..cc16041d9 --- /dev/null +++ b/src/common/heap_tracker.h @@ -0,0 +1,97 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include +#include +#include + +#include "common/host_memory.h" +#include "common/intrusive_red_black_tree.h" + +namespace Common { + +struct SeparateHeapMap { + Common::IntrusiveRedBlackTreeNode addr_node{}; + Common::IntrusiveRedBlackTreeNode tick_node{}; + VAddr vaddr{}; + PAddr paddr{}; + size_t size{}; + size_t tick{}; + MemoryPermission perm{}; + bool is_resident{}; +}; + +struct SeparateHeapMapAddrComparator { + static constexpr int Compare(const SeparateHeapMap& lhs, const SeparateHeapMap& rhs) { + if (lhs.vaddr < rhs.vaddr) { + return -1; + } else if (lhs.vaddr <= (rhs.vaddr + rhs.size - 1)) { + return 0; + } else { + return 1; + } + } +}; + +struct SeparateHeapMapTickComparator { + static constexpr int Compare(const SeparateHeapMap& lhs, const SeparateHeapMap& rhs) { + if (lhs.tick < rhs.tick) { + return -1; + } else if (lhs.tick > rhs.tick) { + return 1; + } else { + return SeparateHeapMapAddrComparator::Compare(lhs, rhs); + } + } +}; + +class HeapTracker { +public: + explicit HeapTracker(Common::HostMemory& buffer); + ~HeapTracker(); + + void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perm, + bool is_separate_heap); + void Unmap(size_t virtual_offset, size_t size, bool is_separate_heap); + void Protect(size_t virtual_offset, size_t length, MemoryPermission perm); + u8* VirtualBasePointer() { + return m_buffer.VirtualBasePointer(); + } + + bool DeferredMapSeparateHeap(u8* fault_address); + bool DeferredMapSeparateHeap(size_t virtual_offset); + +private: + using AddrTreeTraits = + Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&SeparateHeapMap::addr_node>; + using AddrTree = AddrTreeTraits::TreeType; + + using TickTreeTraits = + Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&SeparateHeapMap::tick_node>; + using TickTree = TickTreeTraits::TreeType; + + AddrTree m_mappings{}; + TickTree m_resident_mappings{}; + +private: + void SplitHeapMap(VAddr offset, size_t size); + void SplitHeapMapLocked(VAddr offset); + + AddrTree::iterator GetNearestHeapMapLocked(VAddr offset); + + void RebuildSeparateHeapAddressSpace(); + +private: + Common::HostMemory& m_buffer; + + std::shared_mutex m_rebuild_lock{}; + std::mutex m_lock{}; + s64 m_map_count{}; + s64 m_resident_map_count{}; + size_t m_tick{}; +}; + +} // namespace Common -- cgit v1.2.3