Ark Server API (ASA) - Wiki
Loading...
Searching...
No Matches
LowLevelMemTracker.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"
6#include "LowLevelMemTrackerDefines.h" // LLM_ENABLED_IN_CONFIG
7#include "ProfilingDebugging/TagTrace.h"
8
9#ifndef PLATFORM_SUPPORTS_LLM
10#define PLATFORM_SUPPORTS_LLM 1
11#endif
12
13// LLM is currently incompatible with PLATFORM_USES_FIXED_GMalloc_CLASS, because LLM is activated way too early
14// This is not a problem, because fixed GMalloc is only used in Test/Shipping builds
15#define LLM_ENABLED_ON_PLATFORM (PLATFORM_SUPPORTS_LLM && !PLATFORM_USES_FIXED_GMalloc_CLASS)
16
17#ifdef ENABLE_LOW_LEVEL_MEM_TRACKER
18#error ENABLE_LOW_LEVEL_MEM_TRACKER is now a derived define that should not be defined separately. Define LLM_ENABLED_IN_CONFIG (build environment only) or LLM_ENABLED_ON_PLATFORM (build environment or c++ header) instead.
19#endif
20#define ENABLE_LOW_LEVEL_MEM_TRACKER (LLM_ENABLED_IN_CONFIG && LLM_ENABLED_ON_PLATFORM)
21
23
24// Public defines configuring LLM; see also private defines in LowLevelMemTracker.cpp
25
26// LLM_ALLOW_ASSETS_TAGS: Set to 1 to enable run-time toggling of AssetTags reporting, 0 to disable.
27// Enabling the define causes extra cputime costs to track costs even when AssetTags are toggled off.
28// When defined on, the feature can be toggled on at runtime with commandline -llmtagsets=assets.
29// Toggling the feature on causes a huge number of stat ids to be created and has a high cputime cost.
30// When defined on and runtime-toggled on, AssetTags report the asset that is in scope for each allocation
31// LLM Assets can be viewed in game using 'Stat LLMAssets'.
32#ifndef LLM_ALLOW_ASSETS_TAGS
33 #define LLM_ALLOW_ASSETS_TAGS 0
34#endif
35
36// LLM_ALLOW_STATS: Set to 1 to allow stats to be used as tags, 0 to disable.
37// When enabled LLM_SCOPED_TAG_WITH_STAT macros are enabled and create an LLM tag per stat at the cost of more LLM
38// memory usage per allocation. Turning this on uses the same amount of memory per allocation as LLM_ALLOW_NAMES_TAGS.
39// Turning both of them on has no extra cost.
40#ifndef LLM_ALLOW_STATS
41 #define LLM_ALLOW_STATS 0
42#endif
43
44// Enable stat tags if: (1) Stats or (2) Asset tags are allowed (asset tags use the stat macros to record asset scopes)
45#define LLM_ENABLED_STAT_TAGS (LLM_ALLOW_STATS || LLM_ALLOW_ASSETS_TAGS)
46
47#include "Containers/Array.h"
48#include "Containers/ArrayView.h"
49#include "HAL/CriticalSection.h"
50#include "HAL/PlatformCrt.h"
51#include "HAL/PlatformMisc.h"
52#include "Templates/AlignmentTemplates.h"
53#include "Templates/UnrealTemplate.h"
54#include "UObject/NameTypes.h"
55#include "UObject/UnrealNames.h"
56
57#include <atomic>
58
59#if DO_CHECK
60
61namespace UE::LLMPrivate
62{
63
64bool HandleAssert(bool bLog, const TCHAR* Format, ...);
65
66// LLMEnsure's use of this generates a bool per callsite by passing a lambda which uniquely instantiates the template.
67template <typename Type>
68bool TrueOnFirstCallOnly(const Type&)
69{
70 static bool bValue = true;
71 bool Result = bValue;
72 bValue = false;
73 return Result;
74}
75
76} // UE::LLMPrivate
77
78#if !USING_CODE_ANALYSIS
79 #define LLMTrueOnFirstCallOnly UE::LLMPrivate::TrueOnFirstCallOnly([]{})
80#else
81 #define LLMTrueOnFirstCallOnly false
82#endif
83
84#define LLMCheckMessage(expr) TEXT("LLM check failed: %s [File:%s] [Line: %d]\r\n"), TEXT(#expr), TEXT(__FILE__), __LINE__
85#define LLMCheckfMessage(expr, format) TEXT("LLM check failed: %s [File:%s] [Line: %d]\r\n") format TEXT("\r\n"), TEXT(#expr), TEXT(__FILE__), __LINE__
86#define LLMEnsureMessage(expr) TEXT("LLM ensure failed: %s [File:%s] [Line: %d]\r\n"), TEXT(#expr), TEXT(__FILE__), __LINE__
87
88#define LLMCheck(expr) do { if (UNLIKELY(!(expr))) { UE::LLMPrivate::HandleAssert(true, LLMCheckMessage(expr)); FPlatformMisc::RaiseException(1); } } while(false)
89#define LLMCheckf(expr,format,...) do { if (UNLIKELY(!(expr))) { UE::LLMPrivate::HandleAssert(true, LLMCheckfMessage(expr, format), ##__VA_ARGS__); FPlatformMisc::RaiseException(1); } } while(false)
90#define LLMEnsure(expr) (LIKELY(!!(expr)) || UE::LLMPrivate::HandleAssert(LLMTrueOnFirstCallOnly, LLMEnsureMessage(expr)))
91
92#else
93
94#define LLMCheck(expr)
95#define LLMCheckf(expr,...)
96#define LLMEnsure(expr) (!!(expr))
97
98#endif
99
100#define LLM_TAG_TYPE uint8
101
102// estimate the maximum amount of memory LLM will need to run on a game with around 4 million allocations.
103// Make sure that you have debug memory enabled on consoles (on screen warning will show if you don't)
104// (currently only used on PS4 to stop it reserving a large chunk up front. This will go away with the new memory system)
105#define LLM_MEMORY_OVERHEAD (600LL*1024*1024)
106
107/*
108 * LLM Trackers
109 */
110enum class ELLMTracker : uint8
111{
112 Platform,
113 Default,
114
115 Max,
116};
117
118/*
119 * optional tags that need to be enabled with -llmtagsets=x,y,z on the commandline
120 */
121enum class ELLMTagSet : uint8
122{
123 None,
124 Assets,
125 AssetClasses,
126
127 Max, // note: see FLowLevelMemTracker::ShouldReduceThreads and IsAssetTagForAssets if you add any asset-style tagsets
128};
129
130// Do not add to these macros. Please use the LLM_DECLARE_TAG family of macros below to create new tags.
131#define LLM_ENUM_GENERIC_TAGS(macro)
132 macro(Untagged, "Untagged", NAME_None, NAME_None, -1)
133 macro(Paused, "Paused", NAME_None, NAME_None, -1)
134 macro(Total, "Total", GET_STATFNAME(STAT_TotalLLM), GET_STATFNAME(STAT_TrackedTotalSummaryLLM), -1)
135 macro(Untracked, "Untracked", GET_STATFNAME(STAT_UntrackedLLM), GET_STATFNAME(STAT_TrackedTotalSummaryLLM), -1)
136 macro(PlatformTotal, "Total", GET_STATFNAME(STAT_PlatformTotalLLM), NAME_None, -1)
137 macro(TrackedTotal, "TrackedTotal", GET_STATFNAME(STAT_TrackedTotalLLM), GET_STATFNAME(STAT_TrackedTotalSummaryLLM), -1)
138 macro(UntaggedTotal, "Untagged", GET_STATFNAME(STAT_UntaggedTotalLLM), NAME_None, -1)
139 macro(WorkingSetSize, "WorkingSetSize", GET_STATFNAME(STAT_WorkingSetSizeLLM), GET_STATFNAME(STAT_TrackedTotalSummaryLLM), -1)
140 macro(PagefileUsed, "PagefileUsed", GET_STATFNAME(STAT_PagefileUsedLLM), GET_STATFNAME(STAT_TrackedTotalSummaryLLM), -1)
141 macro(PlatformTrackedTotal, "TrackedTotal", GET_STATFNAME(STAT_PlatformTrackedTotalLLM), NAME_None, -1)
142 macro(PlatformUntaggedTotal, "Untagged", GET_STATFNAME(STAT_PlatformUntaggedTotalLLM), NAME_None, -1)
143 macro(PlatformUntracked, "Untracked", GET_STATFNAME(STAT_PlatformUntrackedLLM), NAME_None, -1)
144 macro(PlatformOverhead, "LLMOverhead", GET_STATFNAME(STAT_PlatformOverheadLLM), NAME_None, -1)
145 macro(PlatformOSAvailable, "OSAvailable", GET_STATFNAME(STAT_PlatformOSAvailableLLM), NAME_None, -1)
146 macro(FMalloc, "FMalloc", GET_STATFNAME(STAT_FMallocLLM), NAME_None, -1)
147 macro(FMallocUnused, "FMallocUnused", GET_STATFNAME(STAT_FMallocUnusedLLM), GET_STATFNAME(STAT_EngineSummaryLLM), -1)
148 macro(ThreadStack, "ThreadStack", GET_STATFNAME(STAT_ThreadStackLLM), GET_STATFNAME(STAT_EngineSummaryLLM), -1)
149 macro(ThreadStackPlatform, "ThreadStack", GET_STATFNAME(STAT_ThreadStackPlatformLLM), NAME_None, -1)
150 macro(ProgramSizePlatform, "ProgramSize", GET_STATFNAME(STAT_ProgramSizePlatformLLM), NAME_None, -1)
151 macro(ProgramSize, "ProgramSize", GET_STATFNAME(STAT_ProgramSizeLLM), GET_STATFNAME(STAT_EngineSummaryLLM), -1)
152 macro(BackupOOMMemoryPoolPlatform, "OOMBackupPool", GET_STATFNAME(STAT_OOMBackupPoolPlatformLLM), NAME_None, -1)
153 macro(BackupOOMMemoryPool, "OOMBackupPool", GET_STATFNAME(STAT_OOMBackupPoolLLM), GET_STATFNAME(STAT_EngineSummaryLLM), -1)
154 macro(GenericPlatformMallocCrash, "GenericPlatformMallocCrash", GET_STATFNAME(STAT_GenericPlatformMallocCrashLLM), GET_STATFNAME(STAT_EngineSummaryLLM), -1)
155 macro(GenericPlatformMallocCrashPlatform, "GenericPlatformMallocCrash", GET_STATFNAME(STAT_GenericPlatformMallocCrashPlatformLLM), GET_STATFNAME(STAT_EngineSummaryLLM), -1)
156 /* Any low-level memory that is not tracked in any other category. */
157 macro(EngineMisc, "EngineMisc", GET_STATFNAME(STAT_EngineMiscLLM), GET_STATFNAME(STAT_EngineSummaryLLM), -1)
158 /* Any task kicked off from the task graph that doesn't have its own category. Should be fairly low. */
159 macro(TaskGraphTasksMisc, "TaskGraphMiscTasks", GET_STATFNAME(STAT_TaskGraphTasksMiscLLM), GET_STATFNAME(STAT_EngineSummaryLLM), -1)
160 macro(LinearAllocator, "LinearAllocator", GET_STATFNAME(STAT_LinearAllocatorLLM), NAME_None, -1)
161 macro(Audio, "Audio", GET_STATFNAME(STAT_AudioLLM), GET_STATFNAME(STAT_AudioSummaryLLM), -1)
162 macro(AudioMisc, "AudioMisc", GET_STATFNAME(STAT_AudioMiscLLM), GET_STATFNAME(STAT_AudioSummaryLLM), ELLMTag::Audio)
163 macro(AudioSoundWaves, "AudioSoundWaves", GET_STATFNAME(STAT_AudioSoundWavesLLM), GET_STATFNAME(STAT_AudioSummaryLLM), ELLMTag::Audio)
164 macro(AudioSoundWaveProxies, "AudioSoundWaveProxies", GET_STATFNAME(STAT_AudioSoundWaveProxiesLLM), GET_STATFNAME(STAT_AudioSummaryLLM), ELLMTag::Audio)
165 macro(AudioMixer, "AudioMixer", GET_STATFNAME(STAT_AudioMixerLLM), GET_STATFNAME(STAT_AudioSummaryLLM), ELLMTag::Audio)
166 macro(AudioMixerPlugins, "AudioMixerPlugins", GET_STATFNAME(STAT_AudioMixerPluginsLLM), GET_STATFNAME(STAT_AudioSummaryLLM), ELLMTag::Audio)
167 macro(AudioPrecache, "AudioPrecache", GET_STATFNAME(STAT_AudioPrecacheLLM), GET_STATFNAME(STAT_AudioSummaryLLM), ELLMTag::Audio)
168 macro(AudioDecompress, "AudioDecompress", GET_STATFNAME(STAT_AudioDecompressLLM), GET_STATFNAME(STAT_AudioSummaryLLM), ELLMTag::Audio)
169 macro(AudioRealtimePrecache, "AudioRealtimePrecache", GET_STATFNAME(STAT_AudioRealtimePrecacheLLM), GET_STATFNAME(STAT_AudioSummaryLLM), ELLMTag::Audio)
170 macro(AudioFullDecompress, "AudioFullDecompress", GET_STATFNAME(STAT_AudioFullDecompressLLM), GET_STATFNAME(STAT_AudioSummaryLLM), ELLMTag::Audio)
171 macro(AudioStreamCache, "AudioStreamCache", GET_STATFNAME(STAT_AudioStreamCacheLLM), GET_STATFNAME(STAT_AudioSummaryLLM), ELLMTag::Audio)
172 macro(AudioStreamCacheCompressedData, "AudioStreamCacheCompressedData",GET_STATFNAME(STAT_AudioStreamCacheCompressedDataLLM), GET_STATFNAME(STAT_AudioSummaryLLM), ELLMTag::Audio)
173 macro(AudioSynthesis, "AudioSynthesis", GET_STATFNAME(STAT_AudioSynthesisLLM), GET_STATFNAME(STAT_AudioSummaryLLM), ELLMTag::Audio)
174 macro(RealTimeCommunications, "RealTimeCommunications", GET_STATFNAME(STAT_RealTimeCommunicationsLLM), NAME_None, -1)
175 macro(FName, "FName", GET_STATFNAME(STAT_FNameLLM), GET_STATFNAME(STAT_EngineSummaryLLM), -1)
176 macro(Networking, "Networking", GET_STATFNAME(STAT_NetworkingLLM), GET_STATFNAME(STAT_NetworkingSummaryLLM), -1)
177 macro(Meshes, "Meshes", GET_STATFNAME(STAT_MeshesLLM), GET_STATFNAME(STAT_MeshesSummaryLLM), -1)
178 macro(Stats, "Stats", GET_STATFNAME(STAT_StatsLLM), GET_STATFNAME(STAT_EngineSummaryLLM), -1)
179 macro(Shaders, "Shaders", GET_STATFNAME(STAT_ShadersLLM), GET_STATFNAME(STAT_EngineSummaryLLM), -1)
180 macro(PSO, "PSO", GET_STATFNAME(STAT_PSOLLM), GET_STATFNAME(STAT_EngineSummaryLLM), -1)
181 macro(Textures, "Textures", GET_STATFNAME(STAT_TexturesLLM), GET_STATFNAME(STAT_TexturesSummaryLLM), -1)
182 macro(TextureMetaData, "TextureMetaData", GET_STATFNAME(STAT_TextureMetaDataLLM), GET_STATFNAME(STAT_TexturesSummaryLLM), -1)
183 macro(VirtualTextureSystem, "VirtualTextureSystem", GET_STATFNAME(STAT_VirtualTextureSystemLLM), GET_STATFNAME(STAT_TexturesSummaryLLM), -1)
184 macro(RenderTargets, "RenderTargets", GET_STATFNAME(STAT_RenderTargetsLLM), GET_STATFNAME(STAT_EngineSummaryLLM), -1)
185 macro(SceneRender, "SceneRender", GET_STATFNAME(STAT_SceneRenderLLM), GET_STATFNAME(STAT_EngineSummaryLLM), -1)
186 macro(RHIMisc, "RHIMisc", GET_STATFNAME(STAT_RHIMiscLLM), GET_STATFNAME(STAT_EngineSummaryLLM), -1)
187 macro(AsyncLoading, "AsyncLoading", GET_STATFNAME(STAT_AsyncLoadingLLM), GET_STATFNAME(STAT_EngineSummaryLLM), -1)
188 /* UObject is a catch-all for all Engine and game memory that is not tracked in any other category. */
189 /* it includes any class inherited from UObject and anything that is serialized by that class including properties. */
190 /* Note that this stat doesn't include Mesh or Animation data which are tracked separately. */
191 /* It is correlated to the number of Objects placed in the Level. */
192 macro(UObject, "UObject", GET_STATFNAME(STAT_UObjectLLM), GET_STATFNAME(STAT_UObjectSummaryLLM), -1)
193 macro(Animation, "Animation", GET_STATFNAME(STAT_AnimationLLM), GET_STATFNAME(STAT_AnimationSummaryLLM), -1)
194 /* This is the UStaticMesh class and related properties, and does not include the actual mesh data. */
195 macro(StaticMesh, "StaticMesh", GET_STATFNAME(STAT_StaticMeshLLM), GET_STATFNAME(STAT_StaticMeshSummaryLLM), ELLMTag::Meshes)
196 macro(Materials, "Materials", GET_STATFNAME(STAT_MaterialsLLM), GET_STATFNAME(STAT_MaterialsSummaryLLM), -1)
197 macro(Particles, "Particles", GET_STATFNAME(STAT_ParticlesLLM), GET_STATFNAME(STAT_ParticlesSummaryLLM), -1)
198 macro(Niagara, "Niagara", GET_STATFNAME(STAT_NiagaraLLM), GET_STATFNAME(STAT_NiagaraSummaryLLM), -1)
199 macro(GPUSort, "GPUSort", GET_STATFNAME(STAT_GPUSortLLM), GET_STATFNAME(STAT_EngineSummaryLLM), -1)
200 macro(GC, "GC", GET_STATFNAME(STAT_GCLLM), GET_STATFNAME(STAT_EngineSummaryLLM), -1)
201 macro(UI, "UI", GET_STATFNAME(STAT_UILLM), GET_STATFNAME(STAT_UISummaryLLM), -1)
202 macro(NavigationRecast, "NavigationRecast", GET_STATFNAME(STAT_NavigationRecastLLM), GET_STATFNAME(STAT_NavigationSummaryLLM), -1)
203 macro(Physics, "Physics", GET_STATFNAME(STAT_PhysicsLLM), GET_STATFNAME(STAT_PhysicsSummaryLLM), -1)
204 macro(PhysX, "PhysX", GET_STATFNAME(STAT_PhysXLLM), GET_STATFNAME(STAT_PhysXSummaryLLM), ELLMTag::Physics)
205 macro(PhysXGeometry, "PhysXGeometry", GET_STATFNAME(STAT_PhysXGeometryLLM), GET_STATFNAME(STAT_PhysXSummaryLLM), ELLMTag::Physics)
206 macro(PhysXTrimesh, "PhysXTrimesh", GET_STATFNAME(STAT_PhysXTrimeshLLM), GET_STATFNAME(STAT_PhysXSummaryLLM), ELLMTag::Physics)
207 macro(PhysXConvex, "PhysXConvex", GET_STATFNAME(STAT_PhysXConvexLLM), GET_STATFNAME(STAT_PhysXSummaryLLM), ELLMTag::Physics)
208 macro(PhysXAllocator, "PhysXAllocator", GET_STATFNAME(STAT_PhysXAllocatorLLM), GET_STATFNAME(STAT_PhysXSummaryLLM), ELLMTag::Physics)
209 macro(PhysXLandscape, "PhysXLandscape", GET_STATFNAME(STAT_PhysXLandscapeLLM), GET_STATFNAME(STAT_PhysXSummaryLLM), ELLMTag::Physics)
210 macro(Chaos, "Chaos", GET_STATFNAME(STAT_ChaosLLM), GET_STATFNAME(STAT_ChaosSummaryLLM), ELLMTag::Physics)
211 macro(ChaosGeometry, "ChaosGeometry", GET_STATFNAME(STAT_ChaosGeometryLLM), GET_STATFNAME(STAT_ChaosSummaryLLM), ELLMTag::Physics)
212 macro(ChaosAcceleration, "ChaosAcceleration", GET_STATFNAME(STAT_ChaosAccelerationLLM), GET_STATFNAME(STAT_ChaosSummaryLLM), ELLMTag::Physics)
213 macro(ChaosParticles, "ChaosParticles", GET_STATFNAME(STAT_ChaosParticlesLLM), GET_STATFNAME(STAT_ChaosSummaryLLM), ELLMTag::Physics)
214 macro(ChaosLandscape, "ChaosLandscape", GET_STATFNAME(STAT_ChaosLandscapeLLM), GET_STATFNAME(STAT_ChaosSummaryLLM), ELLMTag::Physics)
215 macro(ChaosTrimesh, "ChaosTrimesh", GET_STATFNAME(STAT_ChaosTrimeshLLM), GET_STATFNAME(STAT_ChaosSummaryLLM), ELLMTag::Physics)
216 macro(ChaosConvex, "ChaosConvex", GET_STATFNAME(STAT_ChaosConvexLLM), GET_STATFNAME(STAT_ChaosSummaryLLM), ELLMTag::Physics)
217 macro(ChaosScene, "ChaosScene", GET_STATFNAME(STAT_ChaosSceneLLM), GET_STATFNAME(STAT_ChaosSummaryLLM), ELLMTag::Physics)
218 macro(ChaosUpdate, "ChaosUpdate", GET_STATFNAME(STAT_ChaosUpdateLLM), GET_STATFNAME(STAT_ChaosSummaryLLM), ELLMTag::Physics)
219 macro(ChaosActor, "ChaosActor", GET_STATFNAME(STAT_ChaosActorLLM), GET_STATFNAME(STAT_ChaosSummaryLLM), ELLMTag::Physics)
220 macro(ChaosBody, "ChaosBody", GET_STATFNAME(STAT_ChaosBodyLLM), GET_STATFNAME(STAT_ChaosSummaryLLM), ELLMTag::Physics)
221 macro(ChaosConstraint, "ChaosConstraint", GET_STATFNAME(STAT_ChaosConstraintLLM), GET_STATFNAME(STAT_ChaosSummaryLLM), ELLMTag::Physics)
222 macro(ChaosMaterial, "ChaosMaterial", GET_STATFNAME(STAT_ChaosMaterialLLM), GET_STATFNAME(STAT_ChaosSummaryLLM), ELLMTag::Physics)
223 macro(EnginePreInitMemory, "EnginePreInit", GET_STATFNAME(STAT_EnginePreInitLLM), GET_STATFNAME(STAT_EngineSummaryLLM), -1)
224 macro(EngineInitMemory, "EngineInit", GET_STATFNAME(STAT_EngineInitLLM), GET_STATFNAME(STAT_EngineSummaryLLM), -1)
225 macro(RenderingThreadMemory, "RenderingThread", GET_STATFNAME(STAT_RenderingThreadLLM), GET_STATFNAME(STAT_EngineSummaryLLM), -1)
226 macro(LoadMapMisc, "LoadMapMisc", GET_STATFNAME(STAT_LoadMapMiscLLM), GET_STATFNAME(STAT_EngineSummaryLLM), -1)
227 macro(StreamingManager, "StreamingManager", GET_STATFNAME(STAT_StreamingManagerLLM), GET_STATFNAME(STAT_EngineSummaryLLM), -1)
228 macro(GraphicsPlatform, "Graphics", GET_STATFNAME(STAT_GraphicsPlatformLLM), NAME_None, -1)
229 macro(FileSystem, "FileSystem", GET_STATFNAME(STAT_FileSystemLLM), GET_STATFNAME(STAT_EngineSummaryLLM), -1)
230 macro(Localization, "Localization", GET_STATFNAME(STAT_LocalizationLLM), GET_STATFNAME(STAT_EngineSummaryLLM), -1)
231 macro(AssetRegistry, "AssetRegistry", GET_STATFNAME(STAT_AssetRegistryLLM), GET_STATFNAME(STAT_EngineSummaryLLM), -1)
232 macro(ConfigSystem, "ConfigSystem", GET_STATFNAME(STAT_ConfigSystemLLM), GET_STATFNAME(STAT_EngineSummaryLLM), -1)
233 macro(InitUObject, "InitUObject", GET_STATFNAME(STAT_InitUObjectLLM), GET_STATFNAME(STAT_EngineSummaryLLM), -1)
234 macro(VideoRecording, "VideoRecording", GET_STATFNAME(STAT_VideoRecordingLLM), GET_STATFNAME(STAT_EngineSummaryLLM), -1)
235 macro(Replays, "Replays", GET_STATFNAME(STAT_ReplaysLLM), GET_STATFNAME(STAT_NetworkingSummaryLLM), ELLMTag::Networking)
236 macro(MaterialInstance, "MaterialInstance", GET_STATFNAME(STAT_MaterialInstanceLLM), GET_STATFNAME(STAT_EngineSummaryLLM), -1)
237 macro(SkeletalMesh, "SkeletalMesh", GET_STATFNAME(STAT_SkeletalMeshLLM), GET_STATFNAME(STAT_EngineSummaryLLM), ELLMTag::Meshes)
238 macro(InstancedMesh, "InstancedMesh", GET_STATFNAME(STAT_InstancedMeshLLM), GET_STATFNAME(STAT_EngineSummaryLLM), ELLMTag::Meshes)
239 macro(Landscape, "Landscape", GET_STATFNAME(STAT_LandscapeLLM), GET_STATFNAME(STAT_EngineSummaryLLM), ELLMTag::Meshes)
240 macro(CsvProfiler, "CsvProfiler", GET_STATFNAME(STAT_CsvProfilerLLM), GET_STATFNAME(STAT_EngineSummaryLLM), -1)
241 macro(MediaStreaming, "MediaStreaming", GET_STATFNAME(STAT_MediaStreamingLLM), GET_STATFNAME(STAT_MediaStreamingSummaryLLM), -1)
242 macro(ElectraPlayer, "ElectraPlayer", GET_STATFNAME(STAT_ElectraPlayerLLM), GET_STATFNAME(STAT_MediaStreamingSummaryLLM), ELLMTag::MediaStreaming)
243 macro(WMFPlayer, "WMFPlayer", GET_STATFNAME(STAT_WMFPlayerLLM), GET_STATFNAME(STAT_MediaStreamingSummaryLLM), ELLMTag::MediaStreaming)
244 macro(PlatformMMIO, "MMIO", GET_STATFNAME(STAT_PlatformMMIOLLM), NAME_None, -1)
245 macro(PlatformVM, "Virtual Memory", GET_STATFNAME(STAT_PlatformVMLLM), NAME_None, -1)
246 macro(CustomName, "CustomName", GET_STATFNAME(STAT_CustomName), NAME_None, -1)
247
248/*
249 * Enum values to be passed in to LLM_SCOPE() macro
250 */
251enum class ELLMTag : LLM_TAG_TYPE
252{
253#define LLM_ENUM(Enum,Str,Stat,Group,Parent) Enum,
254 LLM_ENUM_GENERIC_TAGS(LLM_ENUM)
255#undef LLM_ENUM
256
257 GenericTagCount,
258
259 //------------------------------
260 // Platform tags
261 PlatformTagStart = 111,
262 PlatformTagEnd = 149,
263
264 //------------------------------
265 // Project tags
266 ProjectTagStart = 150,
267 ProjectTagEnd = 255,
268
269 // anything above this value is treated as an FName for a stat section
270};
271static_assert( ELLMTag::GenericTagCount <= ELLMTag::PlatformTagStart,
272 "too many LLM tags defined -- Instead of adding a new tag and updating the limits, please use the LLM_DECLARE_TAG macros below");
273
274static constexpr uint32 LLM_TAG_COUNT = 256;
275static constexpr uint32 LLM_CUSTOM_TAG_START = (int32)ELLMTag::PlatformTagStart;
276static constexpr uint32 LLM_CUSTOM_TAG_END = (int32)ELLMTag::ProjectTagEnd;
277static constexpr uint32 LLM_CUSTOM_TAG_COUNT = LLM_CUSTOM_TAG_END + 1 - LLM_CUSTOM_TAG_START;
278
279/**
280 * Passed in to OnLowLevelAlloc to specify the type of allocation. Used to track FMalloc total
281 * and pausing for a specific allocation type.
282 */
283enum class ELLMAllocType
284{
285 None = 0,
286 FMalloc,
287 System,
288
289 Count
290};
291
292extern const ANSICHAR* LLMGetTagNameANSI(ELLMTag Tag);
293extern const TCHAR* LLMGetTagName(ELLMTag Tag);
294UE_DEPRECATED(4.27, "This function was an unused implementation detail; contact Epic if you need to keep its functionality.")
295extern FName LLMGetTagStatGroup(ELLMTag Tag);
296UE_DEPRECATED(4.27, "This function was an unused implementation detail; contact Epic if you need to keep its functionality.")
297extern FName LLMGetTagStat(ELLMTag Tag);
298
299/*
300 * LLM utility macros
301 */
302#define LLM(x) x
303#define LLM_IF_ENABLED(x) if (!FLowLevelMemTracker::bIsDisabled) { x; }
304#define SCOPE_NAME PREPROCESSOR_JOIN(LLMScope,__LINE__)
305
306///////////////////////////////////////////////////////////////////////////////////////
307// These are the main macros to use externally when tracking memory
308///////////////////////////////////////////////////////////////////////////////////////
309
310/**
311 * LLM scope macros
312 */
313#define LLM_SCOPE(Tag) FLLMScope SCOPE_NAME(Tag, false /* bIsStatTag */, ELLMTagSet::None, ELLMTracker::Default);
314 UE_MEMSCOPE(Tag)
315#define LLM_TAGSET_SCOPE(Tag, TagSet) FLLMScope SCOPE_NAME(Tag, false /* bIsStaTag */, TagSet, ELLMTracker::Default);
316#define LLM_SCOPE_BYNAME(Tag) static FName PREPROCESSOR_JOIN(LLMScope_Name,__LINE__)(Tag);
317 FLLMScope SCOPE_NAME(PREPROCESSOR_JOIN(LLMScope_Name,__LINE__), false /* bIsStatTag */, ELLMTagSet::None, ELLMTracker::Default);
318 UE_MEMSCOPE(PREPROCESSOR_JOIN(LLMScope_Name,__LINE__));
319#define LLM_SCOPE_BYTAG(TagDeclName) FLLMScope SCOPE_NAME(PREPROCESSOR_JOIN(LLMTagDeclaration_, TagDeclName).GetUniqueName(), false /* bIsStatTag */, ELLMTagSet::None, ELLMTracker::Default);
320 UE_MEMSCOPE(PREPROCESSOR_JOIN(LLMTagDeclaration_,TagDeclName).GetUniqueName());
321#define LLM_SCOPE_RENDER_RESOURCE(Tag) static const FString PREPROCESSOR_JOIN(LLMScope_NamePrefix,__LINE__)(TEXT("RenderResources."));
322 FName PREPROCESSOR_JOIN(LLMScope_Name,__LINE__)(PREPROCESSOR_JOIN(LLMScope_NamePrefix, __LINE__) + (Tag ? Tag : TEXT("Unknown")));
323 FLLMScope SCOPE_NAME(PREPROCESSOR_JOIN(LLMScope_Name,__LINE__), false /* bIsStatTag */, ELLMTagSet::Assets, ELLMTracker::Default, false /* bOverride */);
324#define LLM_PLATFORM_SCOPE(Tag) FLLMScope SCOPE_NAME(Tag, false /* bIsStatTag */, ELLMTagSet::None, ELLMTracker::Platform);
325#define LLM_PLATFORM_SCOPE_BYNAME(Tag) static FName PREPROCESSOR_JOIN(LLMScope_Name,__LINE__)(Tag);
326 FLLMScope SCOPE_NAME(PREPROCESSOR_JOIN(LLMLLMScope_NameScope,__LINE__), false /* bIsStatTag */, ELLMTagSet::None, ELLMTracker::Platform);
327#define LLM_PLATFORM_SCOPE_BYTAG(TagDeclName) FLLMScope SCOPE_NAME(PREPROCESSOR_JOIN(LLMTagDeclaration_, TagDeclName).GetUniqueName(), false /* bIsStatTag */, ELLMTagSet::None, ELLMTracker::Platform);
328
329 /**
330 * LLM Pause scope macros
331 */
332#define LLM_SCOPED_PAUSE_TRACKING(AllocType) FLLMPauseScope SCOPE_NAME(ELLMTag::Untagged, false /* bIsStatTag */, 0, ELLMTracker::Max, AllocType);
333#define LLM_SCOPED_PAUSE_TRACKING_FOR_TRACKER(Tracker, AllocType) FLLMPauseScope SCOPE_NAME(ELLMTag::Untagged, false /* bIsStatTag */, 0, Tracker, AllocType);
334#define LLM_SCOPED_PAUSE_TRACKING_WITH_ENUM_AND_AMOUNT(Tag, Amount, Tracker, AllocType) FLLMPauseScope SCOPE_NAME(Tag, false /* bIsStatTag */, Amount, Tracker, AllocType);
335
336/**
337 * LLM realloc scope macros. Used when reallocating a pointer and you wish to retain the tagging from the source pointer
338 */
339#define LLM_REALLOC_SCOPE(Ptr) FLLMScopeFromPtr SCOPE_NAME(Ptr, ELLMTracker::Default);
340#define LLM_REALLOC_PLATFORM_SCOPE(Ptr) FLLMScopeFromPtr SCOPE_NAME(Ptr, ELLMTracker::Platform);
341
342/**
343 * LLM tag dumping, to help with identifying mis-tagged items. Probably don't want to check in with these in use!
344 */
345#define LLM_DUMP_TAG() FLowLevelMemTracker::Get().DumpTag(ELLMTracker::Default,__FILE__,__LINE__)
346#define LLM_DUMP_PLATFORM_TAG() FLowLevelMemTracker::Get().DumpTag(ELLMTracker::Platform,__FILE__,__LINE__)
347
348/**
349 * Define a tag which can be used in LLM_SCOPE_BYTAG or referenced by name in other LLM_SCOPEs.
350 * @param UniqueNameWithUnderscores - Modified version of the name of the tag. Used for looking up by name,
351 * must be unique across all tags passed to LLM_DEFINE_TAG, LLM_SCOPE, or ELLMTag.
352 * The modification: the usual separator / for parents must be replaced with _ in LLM_DEFINE_TAGs.
353 * @param DisplayName - (Optional) - The name to display when tracing the tag; joined with "/" to the name of its
354 * parent if it has a parent, or NAME_None to use the UniqueName.
355 * @param ParentTagName - (Optional) - The unique name of the parent tag, or NAME_None if it has no parent.
356 * @param StatName - (Optional) - The name of the stat to populate with this tag's amount when publishing LLM data each
357 * frame, or NAME_None if no stat should be populated.
358 * @param SummaryStatName - (Optional) - The name of the stat group to add on this tag's amount when publishing LLM
359 * data each frame, or NAME_None if no stat group should be added to.
360 */
361#define LLM_DEFINE_TAG(UniqueNameWithUnderscores, ...) FLLMTagDeclaration PREPROCESSOR_JOIN(LLMTagDeclaration_, UniqueNameWithUnderscores)(TEXT(#UniqueNameWithUnderscores), ##__VA_ARGS__)
362
363 /**
364 * Declare a tag defined by LLM_DEFINE_TAG. It is used in LLM_SCOPE_BYTAG or referenced by name in other LLM_SCOPEs.
365 * @param UniqueName - The name of the tag for looking up by name, must be unique across all tags passed to
366 * LLM_DEFINE_TAG, LLM_SCOPE, or ELLMTag.
367 * @param ModuleName - (Optional, only in LLM_DECLARE_TAG_API) - The MODULENAME_API symbol to use to declare module
368 * linkage, aka ENGINE_API. If omitted, no module linkage will be used and the tag will create link errors if
369 * used from another module.
370 */
371#define LLM_DECLARE_TAG(UniqueNameWithUnderscores) extern FLLMTagDeclaration PREPROCESSOR_JOIN(LLMTagDeclaration_, UniqueNameWithUnderscores)
372#define LLM_DECLARE_TAG_API(UniqueNameWithUnderscores, ModuleAPI) extern ModuleAPI FLLMTagDeclaration PREPROCESSOR_JOIN(LLMTagDeclaration_, UniqueNameWithUnderscores)
373
374/** Get the unique Name of a Tag. It can be passed to functions such as OnLowLevelAlloc that take a Tag UniqueName. */
375#define LLM_TAG_NAME(UniqueNameWithUnderscores) (PREPROCESSOR_JOIN(LLMTagDeclaration_, UniqueNameWithUnderscores).GetUniqueName())
376
377/**
378 * The BootStrap versions of LLM_DEFINE_TAG, LLM_SCOPE_BYTAG, and LLM_DECLARE_TAG support use in scopes during global
379 * c++ constructors, before Main. These tags are slightly more expensive (even when LLM is disabled) in all
380 * configurations other than shipping, because they use a function static rather than a global variable.
381 */
382#define LLM_DEFINE_BOOTSTRAP_TAG(UniqueNameWithUnderscores, ...)
383 FLLMTagDeclaration& PREPROCESSOR_JOIN(GetLLMTagDeclaration_, UniqueNameWithUnderscores)()
384 {
385 static FLLMTagDeclaration PREPROCESSOR_JOIN(LLMTagDeclaration_, UniqueNameWithUnderscores)(TEXT(#UniqueNameWithUnderscores), ##__VA_ARGS__);
386 return PREPROCESSOR_JOIN(LLMTagDeclaration_, UniqueNameWithUnderscores);
387 }
388#define LLM_SCOPE_BY_BOOTSTRAP_TAG(TagDeclName) FLLMScope SCOPE_NAME(PREPROCESSOR_JOIN(GetLLMTagDeclaration_, TagDeclName)().GetUniqueName(), false /* bIsStatTag */, ELLMTagSet::None, ELLMTracker::Default);
389 UE_MEMSCOPE(PREPROCESSOR_JOIN(GetLLMTagDeclaration_,TagDeclName)().GetUniqueName());
390#define LLM_DECLARE_BOOTSTRAP_TAG(UniqueNameWithUnderscores) extern FLLMTagDeclaration& PREPROCESSOR_JOIN(GetLLMTagDeclaration_, UniqueNameWithUnderscores)();
391#define LLM_DECLARE_BOOTSTRAP_TAG_API(UniqueNameWithUnderscores, ModuleAPI) extern ModuleAPI FLLMTagDeclaration& PREPROCESSOR_JOIN(GetLLMTagDeclaration_, UniqueNameWithUnderscores)();
392
393typedef void*(*LLMAllocFunction)(size_t);
394typedef void(*LLMFreeFunction)(void*, size_t);
395
396class FLLMTagDeclaration;
397
398struct FLLMTagSetAllocationFilter;
399
400namespace UE::LLMPrivate
401{
402
403class FLLMCsvProfilerWriter;
404class FLLMCsvWriter;
405class FLLMThreadState;
406class FLLMTraceWriter;
407class FLLMTracker;
408class FTagData;
409class FTagDataArray;
410class FTagDataNameMap;
411
412namespace AllocatorPrivate
413{
414 struct FBin;
415 struct FPage;
416}
417/**
418 * The allocator LLM uses to allocate internal memory. Uses platform defined
419 * allocation functions to grab memory directly from the OS.
420 */
421class FLLMAllocator
422{
423public:
424 FLLMAllocator();
425 ~FLLMAllocator();
426
427 static FLLMAllocator*& Get();
428
429 void Initialise(LLMAllocFunction InAlloc, LLMFreeFunction InFree, int32 InPageSize);
430 void Clear();
431 void* Alloc(size_t Size);
432 void* Malloc(size_t Size);
433 void Free(void* Ptr, size_t Size);
434 void* Realloc(void* Ptr, size_t OldSize, size_t NewSize);
435 int64 GetTotal() const;
436
437 template <typename T, typename... ArgsType>
438 T* New(ArgsType&&... Args)
439 {
440 T* Ptr = reinterpret_cast<T*>(Alloc(sizeof(T)));
441 new (Ptr) T(Forward<ArgsType>(Args)...);
442 return Ptr;
443 }
444
445 template <typename T>
446 void Delete(T* Ptr)
447 {
448 if (Ptr)
449 {
450 Ptr->~T();
451 Free(Ptr, sizeof(T));
452 }
453 }
454
455 LLMAllocFunction GetPlatformAlloc()
456 {
457 return PlatformAlloc;
458 }
459 LLMFreeFunction GetPlatformFree()
460 {
461 return PlatformFree;
462 }
463
464private:
465 void* AllocPages(size_t Size);
466 void FreePages(void* Ptr, size_t Size);
467 int32 GetBinIndex(size_t Size) const;
468
469 FCriticalSection CriticalSection;
470 LLMAllocFunction PlatformAlloc;
471 LLMFreeFunction PlatformFree;
472 AllocatorPrivate::FBin* Bins;
473 int64 Total;
474 int32 PageSize;
475 int32 NumBins;
476
477 friend struct UE::LLMPrivate::AllocatorPrivate::FPage;
478 friend struct UE::LLMPrivate::AllocatorPrivate::FBin;
479};
480
481enum class ETagReferenceSource
482{
483 Scope,
484 Declare,
485 EnumTag,
486 CustomEnumTag,
487 FunctionAPI,
488 ImplicitParent
489};
490
491} // UE::LLMPrivate
492
493struct UE_DEPRECATED(4.27, "FLLMCustomTag was an implementation detail that has been modified, switch to FLLMTagInfo or to your own local struct") FLLMCustomTag
494{
495 int32 Tag;
496 const TCHAR* Name;
497 FName StatName;
498 FName SummaryStatName;
499};
500
501/** A convenient struct for gathering the fields needed to report in RegisterProjectTag */
502struct FLLMTagInfo
503{
504 const TCHAR* Name;
505 FName StatName; // shows in the LLMFULL stat group
506 FName SummaryStatName; // shows in the LLM summary stat group
507 int32 ParentTag = -1;
508};
509
510/** The main LLM tracker class. */
511class FLowLevelMemTracker
512{
513public:
514
515 /** Get the singleton, which makes sure that we always have a valid object */
516 inline static FLowLevelMemTracker& Get()
517 {
518 if (TrackerInstance)
519 return *TrackerInstance;
520 else
521 return Construct();
522 }
523
524 static FLowLevelMemTracker& Construct();
525
526 static bool IsEnabled();
527
528 /**
529 * We always start up running, but if the commandline disables us, we will do it later after main
530 * (can't get the commandline early enough in a cross-platform way).
531 */
532 void ProcessCommandLine(const TCHAR* CmdLine);
533
534 /** Return the total amount of memory being tracked. */
535 uint64 GetTotalTrackedMemory(ELLMTracker Tracker);
536
537 /**
538 * Records the use of memory that was allocated for a pointer.
539 *
540 * @param Tracker Which tracker to use, the high-level default tracker for regular engine allocations, or the
541 * low-level platform tracker for memory management systems.
542 * @param Ptr The pointer that was allocated.
543 * @param Size The size of the memory that was allocated for the pointer.
544 * @param DefaultTag The tag to use if there is no tag already in scope on the callstack.
545 * @param AllocType Type of allocation, FMalloc for regular allocations done through GMalloc, System for others.
546 * @param bTrackInMemPro Whether to pass the allocation/free information on to FMemProProfiler.
547 */
548 void OnLowLevelAlloc(ELLMTracker Tracker, const void* Ptr, uint64 Size, ELLMTag DefaultTag = ELLMTag::Untagged,
549 ELLMAllocType AllocType = ELLMAllocType::None, bool bTrackInMemPro = true);
550 void OnLowLevelAlloc(ELLMTracker Tracker, const void* Ptr, uint64 Size, FName DefaultTag,
551 ELLMAllocType AllocType = ELLMAllocType::None, bool bTrackInMemPro = true);
552
553 /**
554 * Records the release of memory that was allocated for a pointer.
555 *
556 * @param Tracker Which tracker to use, the high-level default tracker for regular engine allocations, or the
557 * low-level platform tracker for memory management systems.
558 * @param Ptr The pointer that was freed.
559 * @param AllocType Type of allocation, FMalloc for regular allocations done through GMalloc, System for others.
560 * @param bTrackInMemPro Whether to pass the allocation/free information on to FMemProProfiler.
561 */
562 void OnLowLevelFree(ELLMTracker Tracker, const void* Ptr,
563 ELLMAllocType AllocType = ELLMAllocType::None, bool bTrackInMemPro = true);
564
565 /**
566 * Records an allocation or release of memory by a system that is not directly associated with a single pointer.
567 *
568 * @param Tracker Which tracker to use, the high-level default tracker for regular engine allocations, or the
569 * low-level platform tracker for memory management systems.
570 * @param DeltaMemory The amount of memory that was allocated (positive) or freed (negative)
571 * @param DefaultTag The tag to use if there is no tag already in scope on the callstack.
572 * @param AllocType Type of allocation, FMalloc for regular allocations done through GMalloc, System for others.
573 */
574 void OnLowLevelChangeInMemoryUse(ELLMTracker Tracker, int64 DeltaMemory, ELLMTag DefaultTag = ELLMTag::Untagged, ELLMAllocType AllocType = ELLMAllocType::None);
575 void OnLowLevelChangeInMemoryUse(ELLMTracker Tracker, int64 DeltaMemory, FName DefaultTag, ELLMAllocType AllocType = ELLMAllocType::None);
576
577 /** Call if an allocation is moved in memory, such as in a defragger. */
578 void OnLowLevelAllocMoved(ELLMTracker Tracker, const void* Dest, const void* Source,
579 ELLMAllocType AllocType = ELLMAllocType::None);
580
581 /** Updates memory stats and optionally publishes them to observers. */
582 void UpdateStatsPerFrame(const TCHAR* LogName=nullptr);
583 /** Updates memory stats. */
584 void Tick();
585
586 /** Optionally set the amount of memory taken up before the game starts for executable and data segments .*/
587 void SetProgramSize(uint64 InProgramSize);
588
589 /** console command handler */
590 bool Exec(const TCHAR* Cmd, FOutputDevice& Ar);
591
592 /** Report whether the given TagSet is active, e.g. AssetTracking. */
593 bool IsTagSetActive(ELLMTagSet Set);
594
595 /** For some tag sets, it's really useful to reduce threads, to attribute allocations to assets, for instance. */
596 bool ShouldReduceThreads();
597
598 /** Get the top active tag for the given tracker */
599 UE_DEPRECATED(4.27, "Tags have been changed to FNames and the old ELLMTag is now only the top-level coarse tag. Use GetActivateTagData instead to get the current Tag instead of its toplevel parent.")
600 int64 GetActiveTag(ELLMTracker Tracker);
601
602 /** Get an opaque identifier for the top active tag for the given tracker. */
603 const UE::LLMPrivate::FTagData* GetActiveTagData(ELLMTracker Tracker, ELLMTagSet TagSet = ELLMTagSet::None);
604
605 /** Register custom ELLMTags. */
606 void RegisterPlatformTag(int32 Tag, const TCHAR* Name, FName StatName, FName SummaryStatName, int32 ParentTag = -1);
607 void RegisterProjectTag(int32 Tag, const TCHAR* Name, FName StatName, FName SummaryStatName, int32 ParentTag = -1);
608
609 /** Get all tags being tracked. */
610 TArray<const UE::LLMPrivate::FTagData*> GetTrackedTags(ELLMTagSet TagSet = ELLMTagSet::None);
611
612 /** Get all tags being tracked by the given tracker. */
613 TArray<const UE::LLMPrivate::FTagData*> GetTrackedTags(ELLMTracker Tracker, ELLMTagSet TagSet = ELLMTagSet::None);
614
615 void GetTrackedTagsNamesWithAmount(TMap<FName, uint64>& TagsNamesWithAmount, ELLMTracker Tracker, ELLMTagSet TagSet);
616 void GetTrackedTagsNamesWithAmountFiltered(TMap<FName, uint64>& TagsNamesWithAmount, ELLMTracker Tracker, ELLMTagSet TagSet, TArray<FLLMTagSetAllocationFilter>& Filters);
617
618 /** Look up the ELLMTag associated with the given display name. */
619 bool FindTagByName(const TCHAR* Name, uint64& OutTag, ELLMTagSet InTagSet = ELLMTagSet::None) const;
620
621 UE_DEPRECATED(4.27, "Use FindTagDisplayName instead")
622 const TCHAR* FindTagName(uint64 Tag) const;
623
624 /** Get the display name for the given ELLMTag. */
625 FName FindTagDisplayName(uint64 Tag) const;
626
627 /** Get the display name for the given FTagData. */
628 FName GetTagDisplayName(const UE::LLMPrivate::FTagData* TagData) const;
629
630 /** Get the path name for the given FTagData from a chain of its parents' display names. */
631 FString GetTagDisplayPathName(const UE::LLMPrivate::FTagData* TagData) const;
632
633 /** Get the unique identifier name for the given FTagData. */
634 FName GetTagUniqueName(const UE::LLMPrivate::FTagData* TagData) const;
635
636 /** Get the amount of memory for an ELLMTag from the given tracker. */
637 int64 GetTagAmountForTracker(ELLMTracker Tracker, ELLMTag Tag, bool bPeakAmount = false);
638
639 /** Get the amount of memory for a FTagData from the given tracker. */
640 int64 GetTagAmountForTracker(ELLMTracker Tracker, const UE::LLMPrivate::FTagData* TagData, bool bPeakAmount = false);
641
642 int64 GetTagAmountForTracker(ELLMTracker Tracker, FName Tag, ELLMTagSet TagSet, bool bPeakAmount = false);
643
644 /** Set the amount of memory for an ELLMTag for a given tracker and optionally update the total tracked memory. */
645 void SetTagAmountForTracker(ELLMTracker Tracker, ELLMTag Tag, int64 Amount, bool bAddToTotal);
646
647 /** Dump the display name of the current TagData for the given tracker to the output. */
648 uint64 DumpTag(ELLMTracker Tracker, const char* FileName, int LineNumber);
649
650 /** Publishes the active LLM stats in the active frame, useful for single targeted LLM snapshots. */
651 void PublishDataSingleFrame();
652
653 enum class EDumpFormat
654 {
655 PlainText,
656 CSV,
657 };
658 void DumpToLog(EDumpFormat DumpFormat = EDumpFormat::PlainText, FOutputDevice* OutputDevice = nullptr);
659
660 void OnPreFork();
661
662private:
663 FLowLevelMemTracker();
664
665 ~FLowLevelMemTracker();
666
667 /**
668 * Allocation and Setup of the data required for tracking allocations is done as late as possible to prevent
669 * exercising allocation code too early. Note that as late as possible for tracking allocations is still earlier
670 * than ParseCommandLine, so we do not complete all initialization in this function (e.g. features required only
671 * for Update are omitted). Initialization done here will be torn down in ParseCommandLine if LLM is disabled.
672 */
673 void BootstrapInitialise();
674
675 bool IsBootstrapping() const { return bIsBootstrapping; }
676
677 /** Free all memory. This will put the tracker into a permanently disabled state. */
678 void Clear();
679 void InitialiseProgramSize();
680
681 class UE::LLMPrivate::FLLMTracker* GetTracker(ELLMTracker Tracker);
682
683 void TickInternal();
684 void UpdateTags();
685 void SortTags(UE::LLMPrivate::FTagDataArray*& OutOldTagDatas);
686 void PublishDataPerFrame(const TCHAR* LogName);
687
688 void RegisterCustomTagInternal(int32 Tag, ELLMTagSet TagSet, const TCHAR* Name, FName StatName, FName SummaryStatName, int32 ParentTag = -1);
689 /**
690 * Called during C++ global static initialization when GMalloc is available (and hence FNames are unavailable)
691 * Creates the subset of tags necessary to record allocations during GMalloc and FName construction
692 */
693 void BootstrapTagDatas();
694 /** Called when we have detected enabled in processcommandline, or as late as possible if callers access features that require full initialisation before then */
695 void FinishInitialise();
696 void InitialiseTagDatas_SetLLMTagNames();
697 void InitialiseTagDatas_FinishRegister();
698 void InitialiseTagDatas();
699 void ClearTagDatas();
700 void RegisterTagDeclaration(FLLMTagDeclaration& TagDeclaration);
701 UE::LLMPrivate::FTagData& RegisterTagData(FName Name, FName DisplayName, FName ParentName, FName StatName, FName SummaryStatName, bool bHasEnumTag, ELLMTag EnumTag, bool bIsStatTag, UE::LLMPrivate::ETagReferenceSource ReferenceSource, ELLMTagSet TagSet = ELLMTagSet::None);
702 /** Construct if not yet done the data on the given FTagData that relies on the presence of other TagDatas */
703 void FinishConstruct(UE::LLMPrivate::FTagData* TagData, UE::LLMPrivate::ETagReferenceSource ReferenceSource);
704 void ReportDuplicateTagName(UE::LLMPrivate::FTagData* TagData, UE::LLMPrivate::ETagReferenceSource ReferenceSource);
705
706 const UE::LLMPrivate::FTagData* FindOrAddTagData(ELLMTag EnumTag, UE::LLMPrivate::ETagReferenceSource ReferenceSource = UE::LLMPrivate::ETagReferenceSource::FunctionAPI);
707 const UE::LLMPrivate::FTagData* FindOrAddTagData(FName Name, ELLMTagSet TagSet, bool bIsStatData=false, UE::LLMPrivate::ETagReferenceSource ReferenceSource = UE::LLMPrivate::ETagReferenceSource::FunctionAPI);
708 const UE::LLMPrivate::FTagData* FindTagData(ELLMTag EnumTag, UE::LLMPrivate::ETagReferenceSource ReferenceSource = UE::LLMPrivate::ETagReferenceSource::FunctionAPI);
709 const UE::LLMPrivate::FTagData* FindTagData(FName Name, ELLMTagSet TagSet, UE::LLMPrivate::ETagReferenceSource ReferenceSource = UE::LLMPrivate::ETagReferenceSource::FunctionAPI);
710
711 friend class FLLMPauseScope;
712 friend class FLLMScope;
713 friend class FLLMScopeFromPtr;
714 friend class UE::LLMPrivate::FLLMCsvWriter;
715 friend class UE::LLMPrivate::FLLMTracker;
716 friend class UE::LLMPrivate::FLLMThreadState;
717 friend class UE::LLMPrivate::FLLMTraceWriter;
718 friend class UE::LLMPrivate::FLLMCsvProfilerWriter;
719 friend void GlobalRegisterTagDeclaration(FLLMTagDeclaration& TagDeclaration);
720
721 UE::LLMPrivate::FLLMAllocator Allocator;
722 /** All TagDatas that have been constructed, in an array sorted by TagData->GetIndex() */
723 UE::LLMPrivate::FTagDataArray* TagDatas;
724 /** Map from TagData->GetName() to TagData for all names, used to handle LLM_SCOPE with FName */
725 UE::LLMPrivate::FTagDataNameMap* TagDataNameMap;
726 /** Array to Map from ELLMTag to the TagData for that tag, used to handle LLM_SCOPE with ELLMTag */
727 UE::LLMPrivate::FTagData** TagDataEnumMap;
728
729 UE::LLMPrivate::FLLMTracker* Trackers[static_cast<int32>(ELLMTracker::Max)];
730
731 mutable FRWLock TagDataLock;
732 FCriticalSection UpdateLock;
733
734 uint64 ProgramSize;
735 int64 MemoryUsageCurrentOverhead;
736 int64 MemoryUsagePlatformTotalUntracked;
737
738 bool ActiveSets[(int32)ELLMTagSet::Max];
739
740 bool bFirstTimeUpdating;
741 bool bCanEnable;
742 bool bCsvWriterEnabled;
743 bool bTraceWriterEnabled;
744 bool bInitialisedTracking;
745 bool bIsBootstrapping;
746 bool bFullyInitialised;
747 bool bConfigurationComplete;
748 bool bTagAdded;
749 bool bAutoPublish;
750 bool bPublishSingleFrame;
751
752 static FLowLevelMemTracker* TrackerInstance;
753public: // really internal but needs to be visible for LLM_IF_ENABLED macro
754 static bool bIsDisabled;
755};
756
757/** LLM scope for tracking memory. */
758class FLLMScope
759{
760public:
761 FLLMScope(FName TagName, bool bIsStatTag, ELLMTagSet InTagSet, ELLMTracker InTracker, bool bOverride = true)
762 {
763 if (!FLowLevelMemTracker::bIsDisabled)
764 {
765 Init(TagName, bIsStatTag, InTagSet, InTracker, bOverride);
766 }
767 }
768 FLLMScope(ELLMTag TagEnum, bool bIsStatTag, ELLMTagSet InTagSet, ELLMTracker InTracker, bool bOverride = true)
769 {
770 if (!FLowLevelMemTracker::bIsDisabled)
771 {
772 Init(TagEnum, bIsStatTag, InTagSet, InTracker, bOverride);
773 }
774
775 }
776
777 FLLMScope(const UE::LLMPrivate::FTagData* TagData, bool bIsStatTag, ELLMTagSet Set, ELLMTracker Tracker, bool bOverride = true)
778 {
779 if (!FLowLevelMemTracker::bIsDisabled)
780 {
781 Init(TagData, bIsStatTag, Set, Tracker, bOverride);
782 }
783 }
784
785 ~FLLMScope()
786 {
787 if (bEnabled)
788 {
789 Destruct();
790 }
791 }
792
793protected:
794 void Init(FName TagName, bool bIsStatTag, ELLMTagSet InTagSet, ELLMTracker InTracker, bool bOverride = true);
795 void Init(ELLMTag TagEnum, bool bIsStatTag, ELLMTagSet InTagSet, ELLMTracker InTracker, bool bOverride = true);
796 void Init(const UE::LLMPrivate::FTagData* TagData, bool bIsStatTag, ELLMTagSet InTagSet, ELLMTracker InTracker, bool bOverride = true);
797 void Destruct();
798
799 ELLMTracker Tracker{};
800 bool bEnabled = false;
801 ELLMTagSet TagSet;
802};
803
804/** LLM scope for pausing LLM (disables the allocation hooks). */
805class FLLMPauseScope
806{
807public:
808 FLLMPauseScope(FName TagName, bool bIsStatTag, uint64 Amount, ELLMTracker TrackerToPause, ELLMAllocType InAllocType);
809 FLLMPauseScope(ELLMTag TagEnum, bool bIsStatTag, uint64 Amount, ELLMTracker TrackerToPause, ELLMAllocType InAllocType);
810 ~FLLMPauseScope();
811protected:
812 void Init(FName TagName, ELLMTag EnumTag, bool bIsEnumTag, bool bIsStatTag, uint64 Amount,
813 ELLMTracker TrackerToPause, ELLMAllocType InAllocType);
814 ELLMTracker PausedTracker;
815 ELLMAllocType AllocType;
816 bool bEnabled;
817};
818
819/** LLM scope for inheriting tag from the given address. */
820class FLLMScopeFromPtr
821{
822public:
823 FLLMScopeFromPtr(void* Ptr, ELLMTracker Tracker);
824 ~FLLMScopeFromPtr();
825protected:
826 ELLMTracker Tracker;
827 bool bEnabled[static_cast<int32>(ELLMTagSet::Max)];
828
829private:
830 inline void DisableAll()
831 {
832 FMemory::Memzero(bEnabled);
833 }
834};
835
836/** Global instances to provide information about a tag to LLM. */
837class FLLMTagDeclaration
838{
839public:
840 FLLMTagDeclaration(const TCHAR* InCPPName, const FName InDisplayName=NAME_None, FName InParentTagName = NAME_None, FName InStatName = NAME_None, FName InSummaryStatName = NAME_None, ELLMTagSet TagSet = ELLMTagSet::None);
841 FName GetUniqueName() const { return UniqueName; }
842
843 typedef void (*FCreationCallback)(FLLMTagDeclaration&);
844protected:
845
846 static void AddCreationCallback(FCreationCallback InCallback);
847 static void ClearCreationCallbacks();
848 static TArrayView<FCreationCallback> GetCreationCallbacks();
849 static FLLMTagDeclaration* GetList();
850
851 void Register();
852
853protected:
854 void ConstructUniqueName();
855
856 const TCHAR* CPPName;
857 FName UniqueName;
858 FName DisplayName;
859 FName ParentTagName;
860 FName StatName;
861 FName SummaryStatName;
862 ELLMTagSet TagSet;
863 FLLMTagDeclaration* Next = nullptr;
864
865 friend class FLowLevelMemTracker;
866 friend class FTagTrace;
867};
868
869/** Used to filter Tag allocations specifying a Name that matches in a TagSet, or TagSet alone or just by Name. */
870struct FLLMTagSetAllocationFilter
871{
872 /** Tag name to match */
873 FName Name;
874 /** Tag set to match */
875 ELLMTagSet TagSet;
876};
877
878#else
879
880#define LLM(...)
881#define LLM_IF_ENABLED(...)
882#define LLM_SCOPE(...)
883#define LLM_TAGSET_SCOPE(...)
884#define LLM_SCOPE_BYNAME(...)
885#define LLM_SCOPE_BYTAG(...)
886#define LLM_SCOPE_RENDER_RESOURCE(...)
887#define LLM_PLATFORM_SCOPE(...)
888#define LLM_PLATFORM_SCOPE_BYNAME(...)
889#define LLM_PLATFORM_SCOPE_BYTAG(...)
890#define LLM_REALLOC_SCOPE(...)
891#define LLM_REALLOC_PLATFORM_SCOPE(...)
892#define LLM_SCOPED_PAUSE_TRACKING(...)
893#define LLM_SCOPED_PAUSE_TRACKING_FOR_TRACKER(...)
894#define LLM_SCOPED_PAUSE_TRACKING_WITH_ENUM_AND_AMOUNT(...)
895#define LLM_DUMP_TAG()
896#define LLM_DUMP_PLATFORM_TAG()
897#define LLM_DEFINE_TAG(...)
898#define LLM_DECLARE_TAG(...)
899#define LLM_DECLARE_TAG_API(...)
900#define LLM_DEFINE_BOOTSTRAP_TAG(...)
901#define LLM_SCOPE_BY_BOOTSTRAP_TAG(...)
902#define LLM_DECLARE_BOOTSTRAP_TAG(...)
903#define LLM_DECLARE_BOOTSTRAP_TAG_API(...)
904
905#endif // #if ENABLE_LOW_LEVEL_MEM_TRACKER
#define PLATFORM_SUPPORTS_LLM
#define ENABLE_LOW_LEVEL_MEM_TRACKER
#define LLM_ENABLED_ON_PLATFORM
#define LLM_ENABLED_IN_CONFIG
#define PLATFORM_USES_FIXED_GMalloc_CLASS
Definition Platform.h:413