Merge pull request #12358 from liamwhite/optimized-alloc

common: use memory holepunching when clearing memory
This commit is contained in:
liamwhite 2023-12-16 11:47:03 -05:00 committed by GitHub
commit fde8dc1652
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 42 additions and 17 deletions

View file

@ -11,10 +11,6 @@
#elif defined(__linux__) || defined(__FreeBSD__) // ^^^ Windows ^^^ vvv Linux vvv #elif defined(__linux__) || defined(__FreeBSD__) // ^^^ Windows ^^^ vvv Linux vvv
#ifdef ANDROID
#include <android/sharedmem.h>
#endif
#ifndef _GNU_SOURCE #ifndef _GNU_SOURCE
#define _GNU_SOURCE #define _GNU_SOURCE
#endif #endif
@ -193,6 +189,11 @@ public:
} }
} }
bool ClearBackingRegion(size_t physical_offset, size_t length) {
// TODO: This does not seem to be possible on Windows.
return false;
}
void EnableDirectMappedAddress() { void EnableDirectMappedAddress() {
// TODO // TODO
UNREACHABLE(); UNREACHABLE();
@ -442,9 +443,7 @@ public:
} }
// Backing memory initialization // Backing memory initialization
#ifdef ANDROID #if defined(__FreeBSD__) && __FreeBSD__ < 13
fd = ASharedMemory_create("HostMemory", backing_size);
#elif defined(__FreeBSD__) && __FreeBSD__ < 13
// XXX Drop after FreeBSD 12.* reaches EOL on 2024-06-30 // XXX Drop after FreeBSD 12.* reaches EOL on 2024-06-30
fd = shm_open(SHM_ANON, O_RDWR, 0600); fd = shm_open(SHM_ANON, O_RDWR, 0600);
#else #else
@ -455,7 +454,6 @@ public:
throw std::bad_alloc{}; throw std::bad_alloc{};
} }
#ifndef ANDROID
// Defined to extend the file with zeros // Defined to extend the file with zeros
int ret = ftruncate(fd, backing_size); int ret = ftruncate(fd, backing_size);
if (ret != 0) { if (ret != 0) {
@ -463,7 +461,6 @@ public:
strerror(errno)); strerror(errno));
throw std::bad_alloc{}; throw std::bad_alloc{};
} }
#endif
backing_base = static_cast<u8*>( backing_base = static_cast<u8*>(
mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)); mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
@ -552,6 +549,19 @@ public:
ASSERT_MSG(ret == 0, "mprotect failed: {}", strerror(errno)); ASSERT_MSG(ret == 0, "mprotect failed: {}", strerror(errno));
} }
bool ClearBackingRegion(size_t physical_offset, size_t length) {
#ifdef __linux__
// Set MADV_REMOVE on backing map to destroy it instantly.
// This also deletes the area from the backing file.
int ret = madvise(backing_base + physical_offset, length, MADV_REMOVE);
ASSERT_MSG(ret == 0, "madvise failed: {}", strerror(errno));
return true;
#else
return false;
#endif
}
void EnableDirectMappedAddress() { void EnableDirectMappedAddress() {
virtual_base = nullptr; virtual_base = nullptr;
} }
@ -623,6 +633,10 @@ public:
void Protect(size_t virtual_offset, size_t length, bool read, bool write, bool execute) {} void Protect(size_t virtual_offset, size_t length, bool read, bool write, bool execute) {}
bool ClearBackingRegion(size_t physical_offset, size_t length) {
return false;
}
void EnableDirectMappedAddress() {} void EnableDirectMappedAddress() {}
u8* backing_base{nullptr}; u8* backing_base{nullptr};
@ -698,6 +712,12 @@ void HostMemory::Protect(size_t virtual_offset, size_t length, bool read, bool w
impl->Protect(virtual_offset + virtual_base_offset, length, read, write, execute); impl->Protect(virtual_offset + virtual_base_offset, length, read, write, execute);
} }
void HostMemory::ClearBackingRegion(size_t physical_offset, size_t length, u32 fill_value) {
if (!impl || fill_value != 0 || !impl->ClearBackingRegion(physical_offset, length)) {
std::memset(backing_base + physical_offset, fill_value, length);
}
}
void HostMemory::EnableDirectMappedAddress() { void HostMemory::EnableDirectMappedAddress() {
if (impl) { if (impl) {
impl->EnableDirectMappedAddress(); impl->EnableDirectMappedAddress();

View file

@ -48,6 +48,8 @@ public:
void EnableDirectMappedAddress(); void EnableDirectMappedAddress();
void ClearBackingRegion(size_t physical_offset, size_t length, u32 fill_value);
[[nodiscard]] u8* BackingBasePointer() noexcept { [[nodiscard]] u8* BackingBasePointer() noexcept {
return backing_base; return backing_base;
} }

View file

@ -421,8 +421,9 @@ Result KMemoryManager::AllocateForProcess(KPageGroup* out, size_t num_pages, u32
} else { } else {
// Set all the allocated memory. // Set all the allocated memory.
for (const auto& block : *out) { for (const auto& block : *out) {
std::memset(m_system.DeviceMemory().GetPointer<void>(block.GetAddress()), fill_pattern, m_system.DeviceMemory().buffer.ClearBackingRegion(GetInteger(block.GetAddress()) -
block.GetSize()); Core::DramMemoryMap::Base,
block.GetSize(), fill_pattern);
} }
} }

View file

@ -81,6 +81,11 @@ void InvalidateInstructionCache(KernelCore& kernel, AddressType addr, u64 size)
} }
} }
void ClearBackingRegion(Core::System& system, KPhysicalAddress addr, u64 size, u32 fill_value) {
system.DeviceMemory().buffer.ClearBackingRegion(GetInteger(addr) - Core::DramMemoryMap::Base,
size, fill_value);
}
template <typename AddressType> template <typename AddressType>
Result InvalidateDataCache(AddressType addr, u64 size) { Result InvalidateDataCache(AddressType addr, u64 size) {
R_SUCCEED(); R_SUCCEED();
@ -1363,8 +1368,7 @@ Result KPageTableBase::MapInsecureMemory(KProcessAddress address, size_t size) {
// Clear all the newly allocated pages. // Clear all the newly allocated pages.
for (const auto& it : pg) { for (const auto& it : pg) {
std::memset(GetHeapVirtualPointer(m_kernel, it.GetAddress()), ClearBackingRegion(m_system, it.GetAddress(), it.GetSize(), m_heap_fill_value);
static_cast<u32>(m_heap_fill_value), it.GetSize());
} }
// Lock the table. // Lock the table.
@ -1570,8 +1574,7 @@ Result KPageTableBase::AllocateAndMapPagesImpl(PageLinkedList* page_list, KProce
// Clear all pages. // Clear all pages.
for (const auto& it : pg) { for (const auto& it : pg) {
std::memset(GetHeapVirtualPointer(m_kernel, it.GetAddress()), ClearBackingRegion(m_system, it.GetAddress(), it.GetSize(), m_heap_fill_value);
static_cast<u32>(m_heap_fill_value), it.GetSize());
} }
// Map the pages. // Map the pages.
@ -2159,8 +2162,7 @@ Result KPageTableBase::SetHeapSize(KProcessAddress* out, size_t size) {
// Clear all the newly allocated pages. // Clear all the newly allocated pages.
for (const auto& it : pg) { for (const auto& it : pg) {
std::memset(GetHeapVirtualPointer(m_kernel, it.GetAddress()), m_heap_fill_value, ClearBackingRegion(m_system, it.GetAddress(), it.GetSize(), m_heap_fill_value);
it.GetSize());
} }
// Map the pages. // Map the pages.