diff --git a/src/common/heap_tracker.cpp b/src/common/heap_tracker.cpp index b72abb16d8..4475ab5f0e 100644 --- a/src/common/heap_tracker.cpp +++ b/src/common/heap_tracker.cpp @@ -31,7 +31,9 @@ s64 GetMaxPermissibleResidentMapCount() { } // namespace HeapTracker::HeapTracker(Common::HostMemory& buffer) - : m_buffer(buffer), m_max_resident_map_count(GetMaxPermissibleResidentMapCount()) {} + : m_buffer(buffer), + m_has_hardware_buffer_backing(!buffer.BackingHardwareBuffers().empty()), + m_max_resident_map_count(GetMaxPermissibleResidentMapCount()) {} HeapTracker::~HeapTracker() = default; void HeapTracker::Map(size_t virtual_offset, size_t host_offset, size_t length, @@ -85,7 +87,8 @@ void HeapTracker::Unmap(size_t virtual_offset, size_t size, bool is_separate_hea // If resident, erase from resident map. if (item->is_resident) { - ASSERT(--m_resident_map_count >= 0); + m_resident_map_count -= this->HostMapCount(item->paddr, item->size); + ASSERT(m_resident_map_count >= 0); m_resident_mappings.erase(m_resident_mappings.iterator_to(*item)); } @@ -191,7 +194,7 @@ bool HeapTracker::DeferredMapSeparateHeap(size_t virtual_offset) { // This map is now resident. it->is_resident = true; - m_resident_map_count++; + m_resident_map_count += this->HostMapCount(it->paddr, it->size); m_resident_mappings.insert(*it); } @@ -213,17 +216,17 @@ void HeapTracker::RebuildSeparateHeapAddressSpace() { // 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. - std::size_t const desired_count = (std::min)(m_resident_map_count, m_max_resident_map_count) / 2; - std::size_t const evict_count = m_resident_map_count - desired_count; + s64 const desired_count = (std::min)(m_resident_map_count, m_max_resident_map_count) / 2; auto it = m_resident_mappings.begin(); - for (size_t i = 0; i < evict_count && it != m_resident_mappings.end(); i++) { + while (m_resident_map_count > desired_count && it != m_resident_mappings.end()) { // Unmark and unmap. it->is_resident = false; m_buffer.Unmap(it->vaddr, it->size, false); // Advance. - ASSERT(--m_resident_map_count >= 0); + m_resident_map_count -= this->HostMapCount(it->paddr, it->size); + ASSERT(m_resident_map_count >= 0); it = m_resident_mappings.erase(it); } } @@ -245,6 +248,7 @@ void HeapTracker::SplitHeapMapLocked(VAddr offset) { // Cache the original values. auto* const left = std::addressof(*it); const size_t orig_size = left->size; + const s64 orig_host_map_count = this->HostMapCount(left->paddr, orig_size); // Adjust the left map. const size_t left_size = offset - left->vaddr; @@ -266,11 +270,20 @@ void HeapTracker::SplitHeapMapLocked(VAddr offset) { // If resident, also insert into resident map. if (right->is_resident) { - m_resident_map_count++; + m_resident_map_count += this->HostMapCount(left->paddr, left->size) + + this->HostMapCount(right->paddr, right->size) - + orig_host_map_count; m_resident_mappings.insert(*right); } } +s64 HeapTracker::HostMapCount(PAddr paddr, size_t size) const { + if (!m_has_hardware_buffer_backing) { + return size != 0 ? 1 : 0; + } + return static_cast(m_buffer.BackingMapCount(paddr, size)); +} + HeapTracker::AddrTree::iterator HeapTracker::GetNearestHeapMapLocked(VAddr offset) { const SeparateHeapMap key{ .vaddr = offset, diff --git a/src/common/heap_tracker.h b/src/common/heap_tracker.h index 9cc25f7964..8be66a1d4d 100644 --- a/src/common/heap_tracker.h +++ b/src/common/heap_tracker.h @@ -85,10 +85,13 @@ private: AddrTree::iterator GetNearestHeapMapLocked(VAddr offset); + s64 HostMapCount(PAddr paddr, size_t size) const; + void RebuildSeparateHeapAddressSpace(); private: Common::HostMemory& m_buffer; + const bool m_has_hardware_buffer_backing; const s64 m_max_resident_map_count; std::shared_mutex m_rebuild_lock{}; diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index 01446d3fac..6b0065f16c 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp @@ -708,18 +708,11 @@ public: if (budget == 0) { return false; } - const AHardwareBuffer_Desc window_desc = MakeBlobDesc(window_size); - if (AHardwareBuffer_isSupported(&window_desc) == 0) { - return false; - } if (!ProbeAhbBacking(get_native_handle)) { return false; } const size_t aligned_backing = Common::AlignDown(backing_size, window_size); - const size_t region_size = (std::min)(budget, aligned_backing); - const size_t region_base = Common::AlignDown( - (std::min)(preferred_offset, aligned_backing - region_size), window_size); - const size_t num_windows = region_size / window_size; + const size_t max_windows = (std::min)(budget, aligned_backing) / window_size; std::vector buffers; std::vector buffer_fds; @@ -730,27 +723,33 @@ public: buffers.clear(); buffer_fds.clear(); }; - for (size_t i = 0; i < num_windows; ++i) { + for (size_t i = 0; i < max_windows; ++i) { const AHardwareBuffer_Desc desc = MakeBlobDesc(window_size); AHardwareBuffer* buffer{}; if (AHardwareBuffer_allocate(&desc, &buffer) != 0 || buffer == nullptr) { - cleanup(); - return false; + break; } - buffers.push_back(buffer); const NativeHandle* const handle = get_native_handle(buffer); if (handle == nullptr || handle->numFds < 1) { - cleanup(); - return false; + AHardwareBuffer_release(buffer); + break; } const int buffer_fd = handle->data[0]; const off_t buffer_len = lseek(buffer_fd, 0, SEEK_END); if (buffer_len < static_cast(window_size)) { - cleanup(); - return false; + AHardwareBuffer_release(buffer); + break; } + buffers.push_back(buffer); buffer_fds.push_back(buffer_fd); } + const size_t num_windows = buffers.size(); + if (num_windows == 0) { + return false; + } + const size_t region_size = num_windows * window_size; + const size_t region_base = Common::AlignDown( + (std::min)(preferred_offset, aligned_backing - region_size), window_size); u8* const base = static_cast(mmap(nullptr, backing_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0)); if (base == MAP_FAILED) { @@ -818,6 +817,29 @@ public: } } + size_t BackingMapCount(size_t host_offset, size_t length) const noexcept { + if (length == 0) { + return 0; + } + if (ahb_bytes == 0) { + return 1; + } + size_t count = 0; + while (length > 0) { + size_t chunk = length; + if (host_offset < ahb_base) { + chunk = (std::min)(chunk, ahb_base - host_offset); + } else if (host_offset < ahb_base + ahb_bytes) { + const size_t local = (host_offset - ahb_base) % ahb_window_size; + chunk = (std::min)(chunk, ahb_window_size - local); + } + host_offset += chunk; + length -= chunk; + ++count; + } + return count; + } + std::span AhbWindows() const noexcept { return ahb_windows; } @@ -1075,6 +1097,14 @@ std::span HostMemory::BackingHardwareBuffers() const noe #endif } +size_t HostMemory::BackingMapCount(size_t host_offset, size_t length) const noexcept { +#ifdef __ANDROID__ + return impl ? impl->BackingMapCount(host_offset, length) : (length != 0 ? 1 : 0); +#else + return length != 0 ? 1 : 0; +#endif +} + size_t HostMemory::BackingHardwareBufferWindowSize() const noexcept { #ifdef __ANDROID__ return impl ? impl->AhbWindowSize() : 0; diff --git a/src/common/host_memory.h b/src/common/host_memory.h index 13d4830028..a70ceebc20 100644 --- a/src/common/host_memory.h +++ b/src/common/host_memory.h @@ -71,6 +71,8 @@ public: return backing_size; } + [[nodiscard]] size_t BackingMapCount(size_t host_offset, size_t length) const noexcept; + [[nodiscard]] std::span BackingHardwareBuffers() const noexcept; [[nodiscard]] size_t BackingHardwareBufferWindowSize() const noexcept;