UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
AllocLogRecordingPlayback.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3/*=============================================================================
4 AllocLogRecordingPlayback.h: Allocation recording and playback to/from log files
5=============================================================================*/
6
7#pragma once
8
9#include "CoreMinimal.h"
10#include "Misc/FileHelper.h"
11
12/*
13 * Representation of an alloc or free operation. Derive from this struct to add
14 * items such as size and alignment. Override the three methods to log or parse
15 * the values of custom items. A new line character must be added to the end once
16 * all items have been written to the string buffer.
17 */
19{
22 bool bIsFree;
23
25 {
26 return FCStringAnsi::Sprintf(Dest, "Operation,FrameNumber,AllocIndex");
27 }
28
30 {
31 return FCStringAnsi::Sprintf(Dest, "%s,%d,%lld", bIsFree ? "Free" : "Alloc", FrameNumber, AllocIndex);
32 }
33
35 {
36 if (ValueStrings.Num() < 3)
37 {
38 return -1;
39 }
40
41 if (ValueStrings[0] == TEXT("Alloc"))
42 {
43 bIsFree = false;
44 }
45 else if (ValueStrings[0] == TEXT("Free"))
46 {
47 bIsFree = true;
48 }
49 else
50 {
51 return -1;
52 }
53
56 return 3;
57 }
58};
59
60/*
61 * Define a modifier class like below and supply it to TAllocRecordingLog to complete the template.
62 * Create an instance of the completed TAllocRecordingLog before any allocation of interest is done.
63 * Inject RecordAlloc and RecordFree to your allocator wherever appropriate.
64 *
65 * class FModifier
66 * {
67 * // Initialize custom member variables
68 * FModifier(...);
69 *
70 * bool ShouldRecordAlloc(const FAllocOp& Op) const;
71 *
72 * static void HandleFatalError(const TCHAR* Message);
73 *
74 * static void HandleDisplayMessage(const TCHAR* Message);
75 * };
76 */
77template <typename FModifier, typename FAllocOp>
78class TAllocRecordingLog : public FModifier
79{
80protected:
81 using FModifier::ShouldRecordAlloc;
82 using FModifier::HandleFatalError;
83 using FModifier::HandleDisplayMessage;
84
85 void WriteLineBuffer(int32 NumCharacters)
86 {
87 if (NumCharacters > 0 && NumCharacters < MAX_SPRINTF)
88 {
89 OutputFile->Serialize((void*)LineBuffer, NumCharacters);
90 }
91 }
92
96
98
99public:
100 template <typename... ArgTypes>
101 TAllocRecordingLog(const FString& Filename, ArgTypes&&... Args)
102 : FModifier(Forward<ArgTypes>(Args)...)
104 {
105 OutputFile = MakeShareable(IFileManager::Get().CreateFileWriter(*Filename));
106 if (!OutputFile)
107 {
108 HandleFatalError(*FString::Printf(TEXT("Failed to create allocation log file \"%s\". Capture will not start."), *Filename));
109 }
110 HandleDisplayMessage(*FString::Printf(TEXT("Recording allocations to file: %s"), *Filename));
111 WriteLineBuffer(FAllocOp::WriteHeader(LineBuffer));
112 }
113
114 template <typename... ArgTypes>
116 {
117 FAllocOp Op(Forward<ArgTypes>(Args)...);
118 Op.bIsFree = false;
119 if (ShouldRecordAlloc(Op))
120 {
122 Op.AllocIndex = CurrentAllocationIndex++;
123 Op.FrameNumber = GFrameNumberRenderThread;
124 WriteLineBuffer(Op.WriteValueStrings(LineBuffer));
125 return Op.AllocIndex;
126 }
127 return INDEX_NONE;
128 }
129
130 void RecordFree(int64 AllocIndex)
131 {
132 if (AllocIndex != INDEX_NONE)
133 {
135 FAllocOp Op;
136 Op.bIsFree = true;
137 Op.AllocIndex = AllocIndex;
138 Op.FrameNumber = GFrameNumberRenderThread;
139 WriteLineBuffer(Op.WriteValueStrings(LineBuffer));
140 }
141 }
142};
143
144/*
145 * Define a modifier class like below and supply it to TAllocPlaybackLog to complete the template.
146 * Create an instance of the completed TAllocPlaybackLog. Call Load to load an allocation log
147 * generated by your specialized TAllocRecordingLog. Call Play to playback recorded allocations
148 * and frees. Record and write out profiling data as you see fit.
149 *
150 * class FModifier
151 * {
152 * typedef <...> FAllocType;
153 *
154 * // Initialize custom member variables
155 * FModifier(...);
156 *
157 * int32 OnPlaybackStart();
158 * void OnPlaybackEnd(int32 NumAllocOpsReplayed);
159 *
160 * void OnNewPlaybackFrame();
161 * void OnEndPlaybackFrame();
162 *
163 * void OnFree(const FAllocType& Allocation);
164 * FAllocType OnAlloc(const FAllocOp& Op);
165 *
166 * static bool IsValidAllocation(const FAllocType& Allocation);
167 *
168 * static void HandleFatalError(const TCHAR* Message);
169 * static void HandleErrorMessage(const TCHAR* Message);
170 * };
171 */
172template <typename FModifier, typename FAllocOp>
173class TAllocPlaybackLog : public FModifier
174{
175protected:
176 using FFilterType = typename FAllocOp::FFilterType;
177 using FAllocType = typename FModifier::FAllocType;
178
179 using FModifier::HandleFatalError;
180 using FModifier::HandleErrorMessage;
181 using FModifier::OnPlaybackStart;
182 using FModifier::OnPlaybackEnd;
183 using FModifier::OnNewPlaybackFrame;
184 using FModifier::OnEndPlaybackFrame;
185 using FModifier::OnFree;
186 using FModifier::OnAlloc;
187 using FModifier::IsValidAllocation;
188
191
192public:
193 template <typename... ArgTypes>
195 : FModifier(Forward<ArgTypes>(Args)...)
196 , CurrentFilter(InFilter)
197 {}
198
199 void Load(FString& Filename)
200 {
203 {
204 HandleFatalError(*FString::Printf(TEXT("Failed to load alloc log %s"), *Filename));
205 }
206
208 for (int32 LineIndex = 1; LineIndex < AllocLog.Num(); ++LineIndex)
209 {
210 const FString& Line = AllocLog[LineIndex];
212 Line.ParseIntoArray(ValueStrings, TEXT(","));
213
214 FAllocOp Op;
215 if (Op.ParseValueStrings(ValueStrings) < 0)
216 {
217 continue;
218 }
219
220 if (Op.bIsFree)
221 {
222 // Check there's a corresponding allocation and get the filter
223 const FFilterType* FilterFind = AllocFilters.Find(Op.AllocIndex);
224 if (!FilterFind)
225 {
226 // Filter this free out. There is no preceding corresponding alloc
227 continue;
228 }
229 Op.SetFilter(*FilterFind);
230 }
231 else
232 {
233 AllocFilters.Add(Op.AllocIndex, Op.GetFilter());
234 }
235
236 // Check filter
237 if (Op.MatchFilter(CurrentFilter))
238 {
239 Ops.Add(Op);
240 }
241 }
242 }
243
244 void Play(int32 MaxOpCount = INT32_MAX)
245 {
246 const int32 NumIterations = OnPlaybackStart();
247 const int32 OpCount = FMath::Min(MaxOpCount, Ops.Num());
248 bool bStartNewFrame = true;
250
251 for (int32 Iteration = 0; Iteration < NumIterations; ++Iteration)
252 {
253 for (int32 OpIndex = 0; OpIndex < OpCount; ++OpIndex)
254 {
255 const FAllocOp& Op = Ops[OpIndex];
256
257 if (bStartNewFrame)
258 {
260 bStartNewFrame = false;
261 }
262
263 if (Op.bIsFree)
264 {
265 FAllocType* AllocEntry = AllocMap.Find(Op.AllocIndex);
266 if (AllocEntry)
267 {
268 OnFree(*AllocEntry);
269 AllocMap.Remove(Op.AllocIndex);
270 }
271 }
272 else
273 {
274 FAllocType Allocation = OnAlloc(Op);
275 if (IsValidAllocation(Allocation))
276 {
277 if (!AllocMap.Find(Op.AllocIndex))
278 {
279 AllocMap.Add(Op.AllocIndex, MoveTemp(Allocation));
280 }
281 else
282 {
283 OnFree(Allocation);
284 HandleErrorMessage(*FString::Printf(TEXT("Duplicated allocation with index %lld found. This should not happen. The log may be corrupted."), Op.AllocIndex));
285 }
286 }
287 }
288
289 // If the last op of the frame, end the frame
290 int32 NextFrameNumber = OpIndex < OpCount - 1 ? Ops[OpIndex + 1].FrameNumber : -1;
291 if (Op.FrameNumber != NextFrameNumber)
292 {
294 bStartNewFrame = true;
295 }
296 }
297 }
298
299 OnPlaybackEnd(OpCount);
300 }
301};
#define MAX_SPRINTF
Definition CString.h:15
uint32 GFrameNumberRenderThread
Definition CoreGlobals.cpp:427
@ INDEX_NONE
Definition CoreMiscDefines.h:150
#define TEXT(x)
Definition Platform.h:1272
FPlatformTypes::int64 int64
A 64-bit signed integer.
Definition Platform.h:1127
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
SharedPointerInternals::TRawPtrProxy< ObjectType > MakeShareable(ObjectType *InObject)
Definition SharedPointer.h:1947
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
UE::FPlatformRecursiveMutex FCriticalSection
Definition CriticalSection.h:53
UE_INTRINSIC_CAST UE_REWRITE constexpr std::remove_reference_t< T > && MoveTemp(T &&Obj) noexcept
Definition UnrealTemplate.h:520
FRWLock Lock
Definition UnversionedPropertySerialization.cpp:921
virtual void Serialize(void *V, int64 Length)
Definition Archive.h:1689
Definition ScopeLock.h:141
static CORE_API IFileManager & Get()
Definition FileManagerGeneric.cpp:1072
Definition AllocLogRecordingPlayback.h:174
TArray< FAllocOp > Ops
Definition AllocLogRecordingPlayback.h:190
typename FModifier::FAllocType FAllocType
Definition AllocLogRecordingPlayback.h:177
void Load(FString &Filename)
Definition AllocLogRecordingPlayback.h:199
typename FAllocOp::FFilterType FFilterType
Definition AllocLogRecordingPlayback.h:176
void Play(int32 MaxOpCount=INT32_MAX)
Definition AllocLogRecordingPlayback.h:244
FFilterType CurrentFilter
Definition AllocLogRecordingPlayback.h:189
TAllocPlaybackLog(FFilterType InFilter, ArgTypes &&... Args)
Definition AllocLogRecordingPlayback.h:194
Definition AllocLogRecordingPlayback.h:79
FCriticalSection CS
Definition AllocLogRecordingPlayback.h:94
ANSICHAR LineBuffer[MAX_SPRINTF]
Definition AllocLogRecordingPlayback.h:97
void WriteLineBuffer(int32 NumCharacters)
Definition AllocLogRecordingPlayback.h:85
TSharedPtr< FArchive > OutputFile
Definition AllocLogRecordingPlayback.h:95
void RecordFree(int64 AllocIndex)
Definition AllocLogRecordingPlayback.h:130
int64 RecordAlloc(ArgTypes &&... Args)
Definition AllocLogRecordingPlayback.h:115
int64 CurrentAllocationIndex
Definition AllocLogRecordingPlayback.h:93
TAllocRecordingLog(const FString &Filename, ArgTypes &&... Args)
Definition AllocLogRecordingPlayback.h:101
Definition Array.h:670
UE_REWRITE SizeType Num() const
Definition Array.h:1144
UE_NODEBUG UE_FORCEINLINE_HINT SizeType Add(ElementType &&Item)
Definition Array.h:2696
UE_NODEBUG UE_FORCEINLINE_HINT bool Find(const ElementType &Item, SizeType &Index) const
Definition Array.h:1302
Definition UnrealString.h.inl:34
Definition SharedPointer.h:692
Definition AllocLogRecordingPlayback.h:19
bool bIsFree
Definition AllocLogRecordingPlayback.h:22
int32 FrameNumber
Definition AllocLogRecordingPlayback.h:21
int64 AllocIndex
Definition AllocLogRecordingPlayback.h:20
int32 WriteValueStrings(ANSICHAR *Dest) const
Definition AllocLogRecordingPlayback.h:29
static int32 WriteHeader(ANSICHAR *Dest)
Definition AllocLogRecordingPlayback.h:24
int32 ParseValueStrings(const TArray< FString > &ValueStrings)
Definition AllocLogRecordingPlayback.h:34
static CORE_API bool LoadFileToStringArray(TArray< FString > &Result, const TCHAR *Filename)
Definition FileHelper.cpp:302
static UE_FORCEINLINE_HINT int32 Atoi(const CharType *String)
Definition CString.h:1173
static UE_FORCEINLINE_HINT int64 Atoi64(const CharType *String)
Definition CString.h:1179
static int32 Sprintf(CharType *Dest, const FmtType &Fmt, Types... Args)
Definition CString.h:569