From 474f2dc26731cb385e5c8a3f1232f2bc0cc6f5ea Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Fri, 10 Oct 2025 17:34:03 -0700 Subject: [PATCH] FEX: Name remaining allocations as "Misc" This captures the remaining FEX allocations that /aren't/ coming from JEMalloc, allowing us to separate our mapped regions versus just jemalloc allocations. With some additional naming in jemalloc (which I'm not adding here) this gets us interesting results: ``` Misc resident: 54 MiB JEMalloc resident: 208 MiB ``` So 208MB of active jemalloc allocations in this particular case. These will be able to be tracked in heaptrack-like applications if careful. This should let us target down whatever live allocations we're keeping large amounts of data around if possible. --- FEXCore/Source/Interface/Core/CPUBackend.cpp | 4 +--- FEXCore/Source/Interface/Core/Dispatcher/Dispatcher.cpp | 2 ++ FEXCore/Source/Interface/Core/X86HelperGen.cpp | 4 +++- FEXCore/Source/Utils/Allocator.cpp | 8 ++++---- FEXCore/Source/Utils/Allocator/64BitAllocator.cpp | 5 +++++ .../LinuxEmulation/LinuxSyscalls/Seccomp/BPFEmitter.cpp | 2 ++ .../LinuxSyscalls/Seccomp/SeccompEmulator.cpp | 2 ++ .../LinuxEmulation/LinuxSyscalls/SignalDelegator.cpp | 1 + .../Tools/LinuxEmulation/LinuxSyscalls/ThreadManager.cpp | 6 ++++++ .../Tools/LinuxEmulation/LinuxSyscalls/Utils/Threads.cpp | 1 + Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Thread.cpp | 2 ++ 11 files changed, 29 insertions(+), 8 deletions(-) diff --git a/FEXCore/Source/Interface/Core/CPUBackend.cpp b/FEXCore/Source/Interface/Core/CPUBackend.cpp index d0e3edb82..4d1ec87b9 100644 --- a/FEXCore/Source/Interface/Core/CPUBackend.cpp +++ b/FEXCore/Source/Interface/Core/CPUBackend.cpp @@ -360,9 +360,7 @@ namespace CPU { LogMan::Msg::EFmt("Failed to mprotect last page of code buffer."); } -#ifndef _WIN32 - prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, Ptr, Size, "FEXMemJIT"); -#endif + FEXCore::Allocator::VirtualName("FEXMemJIT", reinterpret_cast(Ptr), Size); LookupCache = fextl::make_unique(); } diff --git a/FEXCore/Source/Interface/Core/Dispatcher/Dispatcher.cpp b/FEXCore/Source/Interface/Core/Dispatcher/Dispatcher.cpp index 2ec9f857b..cffa935fb 100644 --- a/FEXCore/Source/Interface/Core/Dispatcher/Dispatcher.cpp +++ b/FEXCore/Source/Interface/Core/Dispatcher/Dispatcher.cpp @@ -44,6 +44,8 @@ Dispatcher::Dispatcher(FEXCore::Context::ContextImpl* ctx) : Arm64Emitter(ctx, FEXCore::Allocator::VirtualAlloc(MAX_DISPATCHER_CODE_SIZE, true), MAX_DISPATCHER_CODE_SIZE) , CTX {ctx} { EmitDispatcher(); + + FEXCore::Allocator::VirtualName("FEXMem_Misc", reinterpret_cast(GetBufferBase()), MAX_DISPATCHER_CODE_SIZE); } Dispatcher::~Dispatcher() { diff --git a/FEXCore/Source/Interface/Core/X86HelperGen.cpp b/FEXCore/Source/Interface/Core/X86HelperGen.cpp index e68d1842c..295c84e08 100644 --- a/FEXCore/Source/Interface/Core/X86HelperGen.cpp +++ b/FEXCore/Source/Interface/Core/X86HelperGen.cpp @@ -51,7 +51,9 @@ void* X86GeneratedCode::AllocateGuestCodeSpace(size_t Size) { if (Is64BitMode()) { // 64bit mode can have its sigret handler anywhere - return FEXCore::Allocator::VirtualAlloc(Size); + auto Result = FEXCore::Allocator::VirtualAlloc(Size); + FEXCore::Allocator::VirtualName("FEXMem_Misc", reinterpret_cast(Result), Size); + return Result; } // First 64bit page diff --git a/FEXCore/Source/Utils/Allocator.cpp b/FEXCore/Source/Utils/Allocator.cpp index 99b223b9c..134983f11 100644 --- a/FEXCore/Source/Utils/Allocator.cpp +++ b/FEXCore/Source/Utils/Allocator.cpp @@ -53,7 +53,7 @@ void* FEX_mmap(void* addr, size_t length, int prot, int flags, int fd, off_t off } if (flags & MAP_ANONYMOUS) { - prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, Result, length, "FEXMem"); + VirtualName("FEXMem", Result, length); } return Result; } @@ -93,7 +93,7 @@ void* DisableSBRKAllocations() { // calls won't allocate any memory through that. void* AlignedBRK = reinterpret_cast(FEXCore::AlignUp(reinterpret_cast(StartingSBRK), FEXCore::Utils::FEX_PAGE_SIZE)); void* AfterBRK = - mmap(AlignedBRK, FEXCore::Utils::FEX_PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED_NOREPLACE | MAP_NORESERVE, -1, 0); + ::mmap(AlignedBRK, FEXCore::Utils::FEX_PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED_NOREPLACE | MAP_NORESERVE, -1, 0); if (AfterBRK == INVALID_PTR) { // Couldn't allocate the page after the aligned brk? This should never happen. // FEXCore::LogMan isn't configured yet so we just need to print the message. @@ -294,7 +294,7 @@ fextl::vector StealMemoryRegion(uintptr_t Begin, uintptr_t End) { --StackRegionIt; auto Alloc = - mmap(StackRegionIt->Ptr, StackRegionIt->Size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE | MAP_FIXED, -1, 0); + ::mmap(StackRegionIt->Ptr, StackRegionIt->Size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE | MAP_FIXED, -1, 0); LogMan::Throw::AFmt(Alloc != MAP_FAILED, "mmap({},{:x}) failed", fmt::ptr(StackRegionIt->Ptr), StackRegionIt->Size); LogMan::Throw::AFmt(Alloc == StackRegionIt->Ptr, "mmap returned {} instead of {}", Alloc, fmt::ptr(StackRegionIt->Ptr)); @@ -305,7 +305,7 @@ fextl::vector StealMemoryRegion(uintptr_t Begin, uintptr_t End) { // Block remaining memory gaps for (auto RegionIt = Regions.begin(); RegionIt != Regions.end(); ++RegionIt) { - auto Alloc = mmap(RegionIt->Ptr, RegionIt->Size, PROT_NONE, MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE | MAP_FIXED_NOREPLACE, -1, 0); + auto Alloc = ::mmap(RegionIt->Ptr, RegionIt->Size, PROT_NONE, MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE | MAP_FIXED_NOREPLACE, -1, 0); LogMan::Throw::AFmt(Alloc != MAP_FAILED, "mmap({},{:x}) failed", fmt::ptr(RegionIt->Ptr), RegionIt->Size); LogMan::Throw::AFmt(Alloc == RegionIt->Ptr, "mmap returned {} instead of {}", Alloc, fmt::ptr(RegionIt->Ptr)); diff --git a/FEXCore/Source/Utils/Allocator/64BitAllocator.cpp b/FEXCore/Source/Utils/Allocator/64BitAllocator.cpp index 1570d34c3..8d6e5942c 100644 --- a/FEXCore/Source/Utils/Allocator/64BitAllocator.cpp +++ b/FEXCore/Source/Utils/Allocator/64BitAllocator.cpp @@ -168,6 +168,7 @@ private: LOGMAN_THROW_A_FMT(Res != -1, "Couldn't mprotect region: {} '{}' Likely occurs when running out of memory or Maximum VMAs", errno, strerror(errno)); + FEXCore::Allocator::VirtualName("FEXMem_Misc", reinterpret_cast(ReservedRegion->Base), SizePlusManagedData); LiveVMARegion* LiveRange = new (reinterpret_cast(ReservedRegion->Base)) LiveVMARegion(); // Copy over the reserved data @@ -505,6 +506,8 @@ void OSAllocator_64Bit::AllocateMemoryRegions(fextl::vector(it.Ptr), ObjectAllocSize); + ObjectAlloc = new (it.Ptr) Alloc::ForwardOnlyIntrusiveArenaAllocator(it.Ptr, ObjectAllocSize); ReservedRegions = ObjectAlloc->new_construct(ReservedRegions, ObjectAlloc); LiveRegions = ObjectAlloc->new_construct(LiveRegions, ObjectAlloc); @@ -602,6 +605,8 @@ fextl::unique_ptr make_alloc_unique(FEXCore::Allocator::MemoryRegion& Base, A ERROR_AND_DIE_FMT("Couldn't allocate memory region"); } + FEXCore::Allocator::VirtualName("FEXMem_Misc", reinterpret_cast(ptr), MinPage); + // Remove the page from the base region. // Could be zero after this. Base.Size -= MinPage; diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Seccomp/BPFEmitter.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/Seccomp/BPFEmitter.cpp index 31ac61dce..a0b65c7e3 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Seccomp/BPFEmitter.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Seccomp/BPFEmitter.cpp @@ -384,6 +384,8 @@ uint64_t BPFEmitter::JITFilter(uint32_t flags, const sock_fprog* prog) { SetBuffer((uint8_t*)FEXCore::Allocator::mmap(nullptr, FuncSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0), FuncSize); + FEXCore::Allocator::VirtualName("FEXMem_Misc", reinterpret_cast(GetBufferBase()), FuncSize); + const auto CodeBegin = GetCursorAddress(); uint64_t Result = HandleEmission(flags, prog); diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Seccomp/SeccompEmulator.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/Seccomp/SeccompEmulator.cpp index 7530c5ed7..24e418793 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Seccomp/SeccompEmulator.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Seccomp/SeccompEmulator.cpp @@ -300,6 +300,8 @@ void SeccompEmulator::DeserializeFilters(FEXCore::Core::CpuStateFrame* Frame, in ::mprotect(Ptr, SFilter.CodeSize, PROT_READ | PROT_EXEC); + FEXCore::Allocator::VirtualName("FEXMem_Misc", reinterpret_cast(Ptr), SFilter.CodeSize); + auto& it = Filters.emplace_back(SeccompFilterInfo {(SeccompFilterFunc)Ptr, 1, SFilter.CodeSize, SFilter.FilterInstructions, SFilter.ShouldLog}); TotalFilterInstructions += SFilter.FilterInstructions; diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/SignalDelegator.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/SignalDelegator.cpp index 259325f03..6cab0b982 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/SignalDelegator.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/SignalDelegator.cpp @@ -995,6 +995,7 @@ void SignalDelegator::RegisterTLSState(FEX::HLE::ThreadStateObject* Thread) { // Set up our signal alternative stack // This is per thread rather than per signal Thread->SignalInfo.AltStackPtr = FEXCore::Allocator::mmap(nullptr, SIGSTKSZ * 16, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + FEXCore::Allocator::VirtualName("FEXMem_Misc", reinterpret_cast(Thread->SignalInfo.AltStackPtr), SIGSTKSZ * 16); stack_t altstack {}; altstack.ss_sp = reinterpret_cast(reinterpret_cast(Thread->SignalInfo.AltStackPtr) + 8); altstack.ss_size = SIGSTKSZ * 16 - 8; diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/ThreadManager.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/ThreadManager.cpp index c8210383a..b1c8429bf 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/ThreadManager.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/ThreadManager.cpp @@ -53,6 +53,8 @@ void ThreadManager::StatAlloc::Initialize() { goto err; } + FEXCore::Allocator::VirtualName("FEXMem_Misc", reinterpret_cast(Base), MAX_STATS_SIZE); + // Allocate a small working shared space for now, grow as necessary. { auto SharedBase = FEXCore::Allocator::mmap(Base, CurrentSize, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, 0); @@ -175,6 +177,9 @@ FEX::HLE::ThreadStateObject* ThreadManager::CreateThread(uint64_t InitialRIP, ui // Allocate the call-ret stack with guard pages on both sides auto AllocBase = reinterpret_cast(FEXCore::Allocator::mmap(nullptr, CALLRET_STACK_ALLOC_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)); + + FEXCore::Allocator::VirtualName("FEXMem_Misc", reinterpret_cast(AllocBase), CALLRET_STACK_ALLOC_SIZE); + // Set the base used for invalidation to the start past the guard pages ThreadStateObject->Thread->CallRetStackBase = reinterpret_cast(AllocBase + FEXCore::Utils::FEX_PAGE_SIZE); ::mprotect(ThreadStateObject->Thread->CallRetStackBase, FEXCore::Core::InternalThreadState::CALLRET_STACK_SIZE, PROT_READ | PROT_WRITE); @@ -199,6 +204,7 @@ FEX::HLE::ThreadStateObject* ThreadManager::CreateThread(uint64_t InitialRIP, ui const auto new_ldt_size = InheritThread->ldt_entry_count * FEX::HLE::SyscallHandler::LDT_ENTRY_SIZE; ThreadStateObject->ldt_entries = reinterpret_cast( FEXCore::Allocator::mmap(nullptr, new_ldt_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)); + FEXCore::Allocator::VirtualName("FEXMem_Misc", reinterpret_cast(ThreadStateObject->ldt_entries), new_ldt_size); ThreadStateObject->ldt_entry_count = InheritThread->ldt_entry_count; memcpy(ThreadStateObject->ldt_entries, InheritThread->ldt_entries, new_ldt_size); diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Utils/Threads.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/Utils/Threads.cpp index 289e01948..3af7ae17b 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Utils/Threads.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Utils/Threads.cpp @@ -32,6 +32,7 @@ void* StackTracker::AllocateStackObject() { if (Ptr == nullptr) { Ptr = FEXCore::Allocator::mmap(nullptr, FEX::LinuxEmulation::Threads::STACK_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + FEXCore::Allocator::VirtualName("FEXMem_Misc", reinterpret_cast(Ptr), FEX::LinuxEmulation::Threads::STACK_SIZE); } return Ptr; diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Thread.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Thread.cpp index d4a7ebbe8..414ac1c84 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Thread.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Thread.cpp @@ -190,6 +190,8 @@ uint64_t SyscallHandler::write_ldt(FEXCore::Core::CpuStateFrame* Frame, void* pt const auto new_ldt_entries = reinterpret_cast( FEXCore::Allocator::mmap(nullptr, new_ldt_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)); + FEXCore::Allocator::VirtualName("FEXMem_Misc", reinterpret_cast(new_ldt_entries), new_ldt_size); + if (old_ldt) { // Copy old entries if they existed. memcpy(new_ldt_entries, old_ldt, old_ldt_entries * LDT_ENTRY_SIZE);