UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
StallDetector.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "Containers/Array.h"
6#include "Containers/Set.h"
8#include "CoreTypes.h"
11#include "HAL/CriticalSection.h"
13#include "Logging/LogMacros.h"
14#include "Misc/Build.h"
15#include "Misc/ScopeLock.h"
17
18#include <atomic>
19
20#ifndef STALL_DETECTOR
21 #if WITH_EDITOR && ( PLATFORM_WINDOWS || PLATFORM_UNIX ) && !UE_BUILD_SHIPPING && COUNTERSTRACE_ENABLED && !USING_THREAD_SANITISER
22 #define STALL_DETECTOR 1
23 #else
24 #define STALL_DETECTOR 0
25 #endif
26#endif // STALL_DETECTOR
27
28#if STALL_DETECTOR
29
33#define SCOPE_STALL_COUNTER(InName, InBudgetSeconds) \
34 static_assert(UE_ARRAY_COUNT(PREPROCESSOR_TO_STRING(InName)) <= UE::StallDetectorScopeMaxNameLength, "Scope name must be less than UE::StallDetectorScopeMaxNameLength characters long "); \
35 static UE::FStallDetectorStats PREPROCESSOR_JOIN(StallDetectorStats, __LINE__)(TEXT(#InName), InBudgetSeconds, UE::EStallDetectorReportingMode::Disabled); \
36 UE::FStallDetector PREPROCESSOR_JOIN(ScopeStallDetector, __LINE__)(PREPROCESSOR_JOIN(StallDetectorStats, __LINE__));
37
41#define SCOPE_STALL_REPORTER(InName, InBudgetSeconds) \
42 static_assert(UE_ARRAY_COUNT(PREPROCESSOR_TO_STRING(InName)) <= UE::StallDetectorScopeMaxNameLength, "Scope name must be less than UE::StallDetectorScopeMaxNameLength characters long "); \
43 static UE::FStallDetectorStats PREPROCESSOR_JOIN(StallDetectorStats, __LINE__)(TEXT(#InName), InBudgetSeconds, UE::EStallDetectorReportingMode::First); \
44 UE::FStallDetector PREPROCESSOR_JOIN(ScopeStallDetector, __LINE__)(PREPROCESSOR_JOIN(StallDetectorStats, __LINE__));
45
51#define SCOPE_STALL_REPORTER_ALWAYS(InName, InBudgetSeconds) \
52 static_assert(UE_ARRAY_COUNT(PREPROCESSOR_TO_STRING(InName)) <= UE::StallDetectorScopeMaxNameLength, "Scope name must be less than UE::StallDetectorScopeMaxNameLength characters long "); \
53 static UE::FStallDetectorStats PREPROCESSOR_JOIN(StallDetectorStats, __LINE__)(TEXT(#InName), InBudgetSeconds, UE::EStallDetectorReportingMode::Always); \
54 UE::FStallDetector PREPROCESSOR_JOIN(ScopeStallDetector, __LINE__)(PREPROCESSOR_JOIN(StallDetectorStats, __LINE__));
55
59#define SCOPE_STALL_DETECTOR_PAUSE() \
60 UE::FStallDetectorPause PREPROCESSOR_JOIN(ScopeStallDetectorPause, __LINE__);
61
62#else // STALL_DETECTOR
63
64#define SCOPE_STALL_COUNTER(InName, InBudgetSeconds)
65#define SCOPE_STALL_REPORTER(InName, InBudgetSeconds)
66#define SCOPE_STALL_REPORTER_ALWAYS(InName, InBudgetSeconds)
67#define SCOPE_STALL_DETECTOR_PAUSE()
68
69#endif // STALL_DETECTOR
70
71#if STALL_DETECTOR
72
74
78namespace UE
79{
80 class FStallDetector;
81
82 // Stall detected event is fired on a worker thread when it is detected that a stall scope has been active for too long.
83 // Fired from a worker thread.
85 {
87 FStringView StatName;
89 uint32 ThreadId;
91 uint64 UniqueID;
94 };
96
97 // Stall completed event is fired synchronously on the stalling thread after it recovers from the stall.
98 // It may be fired without a matching StallDetected event in the case that the background detector's resolution
99 // is too low or that thread is blocked for some reason.
101 {
103 uint32 ThreadId;
105 FStringView StatName;
107 double BudgetSeconds;
109 double OverbudgetSeconds;
111 uint64 UniqueID;
118 bool bWasTriggered;
119 };
121
126 {
127 Disabled,
128 First,
129 Always
130 };
131
132 static constexpr SIZE_T StallDetectorStatNameBufferSize = 256;
133 static constexpr int32 StallDetectorMaxBacktraceEntries = 32;
134
136
141 {
142 friend class FStallDetectorRunnable;
143
144 public:
149
154
159
160 struct TabulatedResult
161 {
162 const TCHAR* Name = TEXT("");
163 double BudgetSeconds = 0.0;
165 double OverageSeconds = 0.0;
166 double OverageRatio = 0.0;
167 };
169
170 // The name to refer to this callsite in the codebase
171 const TCHAR* Name;
172
173 // The budgeted time we tolerate without sending a report
174 const double BudgetSeconds;
175
176 // Drives the behavior about what to do when a budget is violated (triggered)
178
179 // Has this been reported yet, this is different than the trigger count for coherency reasons
180 bool bReported;
181
182 // The total number of times all callsites have been triggered
183 static CORE_API FCountersTrace::FCounterAtomicInt TotalTriggeredCount;
184
185 // The total number of reports that have been sent
186 static CORE_API FCountersTrace::FCounterAtomicInt TotalReportedCount;
187
188 private:
189 // The number of times this callsite has been triggered
191 FCountersTrace::TCounter<int64, TraceCounterType_Int> TriggerCount;
192
193 // The cumulative overage time for this callsite
195 FCountersTrace::TCounter<double, TraceCounterType_Float> OverageSeconds;
196
197 // Guards access to the stats from multiple threads, for coherency
199 };
200
205 class FStallTimer
206 {
207 public:
212
216 CORE_API void Reset(const double InSeconds, const double InRemainingSeconds);
217
221 CORE_API void Check(const double InSeconds, double& OutDeltaSeconds, double& OutOverageSeconds);
222
226 CORE_API void Pause(const double InSeconds);
227
231 CORE_API void Resume(const double InSeconds);
232
233 private:
234 // To track pause/unpause calls
236
237 // The timestamp of when we last called Reset() or Check()
238 double LastCheckSeconds;
239
240 // The time remaining before we we go beyond the remaining time
241 double RemainingSeconds;
242
243 // Guards access to internal state from multiple threads
244 FCriticalSection Section;
245 };
246
250 class FStallDetector
251 {
252 friend class FStallDetectorRunnable;
253
254 public:
259
264
270 CORE_API void CheckAndReset();
271
275 CORE_API void Pause(const double InSeconds);
276
280 CORE_API void Resume(const double InSeconds);
281
285 FStallDetector* GetParent()
286 {
287 return Parent;
288 }
289
293 static CORE_API double Seconds();
294
298 static CORE_API void Startup();
299
303 static CORE_API void Shutdown();
304
308 static CORE_API bool IsRunning();
309
316
323
324 private:
327
328 // The time provided, the deadline
329 FStallDetectorStats& Stats;
330
331 // A stall detector on the same thread with a longer lifetime if any
333
334 // Thread it was constructed on, and to stack trace when budgeted time is elapsed
335 uint32 ThreadId;
336
337 // Did we actually start the detector (was the thread started at construction time)
338 bool bStarted;
339
340 // Persistent usage mode
341 bool bPersistent;
342
343 // Track whether a stall was detected from the background thread.
344 // This is protected by the same mutex which protects the registered stall detector instances.
345 // Only set from background thread, can be reset from another thread with CheckAndReset
346 bool bTriggered;
347
348 // The timer data for this detector
349 FStallTimer Timer;
350
351 // Unique ID given to a StallDetector
352 uint64 UniqueID;
353
360 CORE_API double Check(bool bFinalCheck, double InCheckSeconds);
361 };
362
367 {
368 public:
371 bool IsPaused() const;
372
373 private:
374 bool bPaused;
375 };
376
377 static constexpr TCHAR StallDetectorCounterPrefix[] = TEXT("StallDetector/");
378 static constexpr TCHAR StallDetectorTriggerCountSuffix[] = TEXT(" TriggerCount");
379 static constexpr TCHAR StallDetectorOverageTimeSuffix[] = TEXT(" OverageSeconds");
382} // namespace UE
383#endif // STALL_DETECTOR
#define TEXT(x)
Definition Platform.h:1272
FPlatformTypes::SIZE_T SIZE_T
An unsigned integer the same size as a pointer, the same as UPTRINT.
Definition Platform.h:1150
FPlatformTypes::TCHAR TCHAR
Either ANSICHAR or WIDECHAR, depending on whether the platform supports wide characters or the requir...
Definition Platform.h:1135
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::uint64 uint64
A 64-bit unsigned integer.
Definition Platform.h:1117
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
UE::FPlatformRecursiveMutex FCriticalSection
Definition CriticalSection.h:53
#define DECLARE_TS_MULTICAST_DELEGATE_OneParam(DelegateName, Param1Type)
Definition DelegateCombinations.h:50
#define DECLARE_LOG_CATEGORY_EXTERN(CategoryName, DefaultVerbosity, CompileTimeVerbosity)
Definition LogMacros.h:361
#define UE_ARRAY_COUNT(array)
Definition UnrealTemplate.h:212
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition Array.h:670
Definition Atomic.h:538
bool IsPaused()
Definition AdvancedWidgetsModule.cpp:13