UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
MallocBinnedCommonUtils.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "CoreTypes.h"
8#include "Misc/App.h"
9#include "Stats/Stats.h"
11
12
13#if FRAMEPRO_ENABLED
14// Pushes a profiler scope if it's safe to do so without any new allocations.
16 {
17 public:
19 {
20 if (FFrameProProfiler::IsThreadContextReady() && GCycleStatsShouldEmitNamedEvents)
21 {
23 FFrameProProfiler::PushEvent(StatString);
24 }
25 }
26
28 {
29 if (StatString)
30 {
31 FFrameProProfiler::PopEvent(StatString);
32 }
33 }
34 private:
35 const ANSICHAR* StatString = nullptr;
36 };
37
38# define NOALLOC_SCOPE_CYCLE_COUNTER(Stat) FNoAllocScopeCycleCounter NoAllocCycleCounter_##Stat(#Stat)
39#else
40# define NOALLOC_SCOPE_CYCLE_COUNTER(Stat)
41#endif // ~FRAMEPRO_ENABLED
42
44{
45 template<int NumSmallPools>
47 {
49 {
51 for (uint32 Slot = 0; Slot < NumCachedBundles; Slot++)
52 {
53 if (!Bundles[InPoolIndex].FreeBundles[Slot])
54 {
55 if (!FPlatformAtomics::InterlockedCompareExchangePointer((void**)&Bundles[InPoolIndex].FreeBundles[Slot], InBundle, nullptr))
56 {
57 return true;
58 }
59 }
60 }
61 return false;
62 }
63
65 {
67 for (uint32 Slot = 0; Slot < NumCachedBundles; Slot++)
68 {
69 FMallocBinnedCommonBase::FBundleNode* Result = Bundles[InPoolIndex].FreeBundles[Slot];
70 if (Result)
71 {
72 if (FPlatformAtomics::InterlockedCompareExchangePointer((void**)&Bundles[InPoolIndex].FreeBundles[Slot], nullptr, Result) == Result)
73 {
74 return Result;
75 }
76 }
77 }
78 return nullptr;
79 }
80
81 private:
82 struct FBundlePointer
83 {
85
86 FBundlePointer()
87 {
89 }
90 };
91 static_assert(sizeof(FBundlePointer) == PLATFORM_CACHE_LINE_SIZE, "FBundlePointer should be the same size as a cache line");
92 alignas(PLATFORM_CACHE_LINE_SIZE) FBundlePointer Bundles[NumSmallPools];
93 };
94}
95
96
98{
99public:
100 template <class AllocType>
101 static void TrimThreadFreeBlockLists(AllocType& Allocator, typename AllocType::FPerThreadFreeBlockLists* FreeBlockLists)
102 {
103 if (FreeBlockLists)
104 {
106
107 for (int32 PoolIndex = 0; PoolIndex != AllocType::NUM_SMALL_POOLS; ++PoolIndex)
108 {
109 typename AllocType::FBundleNode* Bundles = FreeBlockLists->PopBundles(PoolIndex);
110 if (Bundles)
111 {
112 Allocator.FreeBundles(Bundles, PoolIndex);
113 }
114 }
115 }
116 }
117
118 template <class AllocType>
120 {
121 if (typename AllocType::FPerThreadFreeBlockLists* Lists = AllocType::FPerThreadFreeBlockLists::Get())
122 {
123 if (Lists->UpdateEpoch(Allocator.MemoryTrimEpoch.load(std::memory_order_relaxed)) || !bNewEpochOnly)
124 {
127
128 const double StartTimeInner = FPlatformTime::Seconds();
131
133 {
134 UE_LOG(LogMemory, Warning, TEXT("FMalloc%s took %6.2fms to wait for mutex AND trim."), Allocator.GetDescriptiveName(), WaitForTrimTime * 1000.0f);
135 }
136 }
137 }
138 }
139
140 template <class AllocType>
142 {
143 // Update the trim epoch so that threads cleanup their thread-local memory when going to sleep.
144 Allocator.MemoryTrimEpoch.fetch_add(1, std::memory_order_relaxed);
145
147
148 // Process thread-local memory caches from as many threads as possible without waking them up.
149 // Skip on desktop as we may have too many threads and this could cause some hitches.
151 {
152 UE::TUniqueLock FreeBlockLock(AllocType::GetFreeBlockListsRegistrationMutex());
153 for (typename AllocType::FPerThreadFreeBlockLists* BlockList : AllocType::GetRegisteredFreeBlockLists())
154 {
155 // If we're unable to lock, it's because the thread is currently active so it
156 // will do the flush itself when going back to sleep because we incremented the Epoch.
157 if (BlockList->TryLock())
158 {
159 // Only trim if the epoch has been updated, otherwise the thread already
160 // did the trimming when it went to sleep.
161 if (BlockList->UpdateEpoch(Allocator.MemoryTrimEpoch.load(std::memory_order_relaxed)))
162 {
164 }
165 BlockList->Unlock();
166 }
167 }
168 }
169
170 TFunction<void(ENamedThreads::Type CurrentThread)> Broadcast =
172 {
173 // We might already have updated the Epoch so we can skip doing anything costly (i.e. Mutex) in that case.
174 const bool bNewEpochOnly = true;
176 };
177
178 // Skip task threads on desktop platforms as it is too slow and they don't have much memory
180 {
182 }
183 else
184 {
186 }
187 }
188};
OODEFFUNC typedef void(OODLE_CALLBACK t_fp_OodleCore_Plugin_Free)(void *ptr)
#define PLATFORM_DESKTOP
Definition AndroidPlatform.h:33
int32 GCycleStatsShouldEmitNamedEvents
Definition CoreGlobals.cpp:462
#define TEXT(x)
Definition Platform.h:1272
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
FPlatformTypes::ANSICHAR ANSICHAR
An ANSI character. Normally a signed type.
Definition Platform.h:1131
#define PLATFORM_CACHE_LINE_SIZE
Definition Platform.h:938
#define QUICK_SCOPE_CYCLE_COUNTER(Stat)
Definition Stats.h:652
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
#define TRACE_CPUPROFILER_EVENT_SCOPE(Name)
Definition CpuProfilerTrace.h:528
#define UE_LOG(CategoryName, Verbosity, Format,...)
Definition LogMacros.h:270
float GMallocBinnedFlushThreadCacheMaxWaitTime
Definition MallocBinnedCommon.cpp:539
int32 GMallocBinnedFlushRegisteredThreadCachesOnOneThread
Definition MallocBinnedCommon.cpp:547
#define UE_DEFAULT_GMallocBinnedMaxBundlesBeforeRecycle
Definition MallocBinnedCommon.h:66
#define GMallocBinnedMaxBundlesBeforeRecycle
Definition MallocBinnedCommon.h:83
uint32_t uint32
Definition binka_ue_file_header.h:6
static CORE_API bool ShouldUseThreadingForPerformance()
Definition App.cpp:300
Definition MallocBinnedCommonUtils.h:98
static void TrimThreadFreeBlockLists(AllocType &Allocator, typename AllocType::FPerThreadFreeBlockLists *FreeBlockLists)
Definition MallocBinnedCommonUtils.h:101
static void FlushCurrentThreadCache(AllocType &Allocator, bool bNewEpochOnly=false)
Definition MallocBinnedCommonUtils.h:119
static void Trim(AllocType &Allocator)
Definition MallocBinnedCommonUtils.h:141
static void BroadcastSlow_OnlyUseForSpecialPurposes(bool bDoTaskThreads, bool bDoBackgroundThreads, TFunction< void(ENamedThreads::Type CurrentThread)> &Callback)
Definition TaskGraph.cpp:1897
Definition AndroidPlatformMisc.h:14
Definition UniqueLock.h:20
Type
Definition TaskGraphInterfaces.h:57
Definition MallocBinnedCommonUtils.h:44
static double Seconds()
Definition AndroidPlatformTime.h:20
static CORE_API bool SupportsMultithreading()
Definition GenericPlatformProcess.cpp:656
Definition MallocBinnedCommon.h:188
Definition MallocBinnedCommonUtils.h:47
FMallocBinnedCommonBase::FBundleNode * PopBundle(uint32 InPoolIndex)
Definition MallocBinnedCommonUtils.h:64
bool PushBundle(uint32 InPoolIndex, FMallocBinnedCommonBase::FBundleNode *InBundle)
Definition MallocBinnedCommonUtils.h:48