2020-09-24 00:43:27 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "AllocationsProvider.h"
2020-11-25 12:48:47 -04:00
# include "AllocationsQuery.h"
2021-01-28 08:10:57 -04:00
# include "Common/Utils.h"
2020-12-07 14:21:21 -04:00
# include "Containers/ArrayView.h"
2022-03-21 08:09:19 -04:00
# include "Misc/PathViews.h"
2022-05-05 06:14:08 -04:00
# include "Model/MetadataProvider.h"
2021-09-22 12:25:29 -04:00
# include "ProfilingDebugging/MemoryTrace.h"
2022-05-05 06:14:08 -04:00
# include "SbTree.h"
2020-11-25 12:48:47 -04:00
# include "TraceServices/Containers/Allocators.h"
2021-01-06 05:44:12 -04:00
# include "TraceServices/Model/Callstack.h"
2020-11-25 12:48:47 -04:00
2022-05-05 06:14:08 -04:00
# include <limits>
2021-03-18 08:11:50 -04:00
////////////////////////////////////////////////////////////////////////////////////////////////////
# define INSIGHTS_SLOW_CHECK(expr) //check(expr)
# define INSIGHTS_DEBUG_WATCH 0
2022-02-07 11:28:45 -05:00
// Action to be executed when a match is found.
# define INSIGHTS_DEBUG_WATCH_FOUND break // just log
//#define INSIGHTS_DEBUG_WATCH_FOUND return // log and ignore events
//#define INSIGHTS_DEBUG_WATCH_FOUND UE_DEBUG_BREAK(); break
2021-03-18 08:11:50 -04:00
2022-02-22 04:14:31 -05:00
// Initial reserved number for long living allocations.
# define INSIGHTS_LLA_RESERVE 0
//#define INSIGHTS_LLA_RESERVE (64 * 1024)
2021-03-18 08:11:50 -04:00
// Use optimized path for the short living allocations.
// If enabled, caches the short living allocations, as there is a very high chance to be freed in the next few "free" events.
// ~66% of all allocs are expected to have an "event distance" < 64 events
// ~70% of all allocs are expected to have an "event distance" < 512 events
# define INSIGHTS_USE_SHORT_LIVING_ALLOCS 1
2022-02-22 04:14:31 -05:00
# define INSIGHTS_SLA_USE_ADDRESS_MAP 0
2021-03-18 08:11:50 -04:00
// Use optimized path for the last alloc.
// If enabled, caches the last added alloc, as there is a high chance to be freed in the next "free" event.
[Insights]
- TraceServices: Changed ReadNetProfilerProvider, ReadMemoryProvider, ReadDiagnosticsProvider to return a pointer to the respective provider (instead of a reference). Can return nullptr. The UI should not assume the provider exists.
- TraceServices: Added GetNetProfilerProviderName, GetMemoryProviderName, GetDiagnosticsProviderName, GetAllocationsProviderName to return name of respective provider.
- TraceServices: Added ReadModuleProvider + GetModuleProviderName, ReadCallstacksProvider + GetCallstacksProviderName to access respective providers.
- TraceServices: Added a default empty implementation to IModule for GenerateReports, GetLoggers and GetCommandLineArgument.
- TraceServices: Changed FAnalysisService::StartAnalysis to not create default providers for Memory (LLM Stats), NetProfiler and Diagnostics, but to allow the respective modules (FMemoryModule, FNetProfilerModule, FDiagnosticsModule) to create the providers.
- TraceInsights: Fixed UI code to check if the Memory, NetProfiler and Diagnostics provider are available.
#rb Catalin.Dragoiu, Johan.Berg
#ROBOMERGE-SOURCE: CL 16967698 in //UE5/Main/...
#ROBOMERGE-BOT: STARSHIP (Main -> Release-Engine-Test) (v838-16927207)
[CL 16967704 by ionut matasaru in ue5-release-engine-test branch]
2021-07-27 08:19:49 -04:00
// ~10% to ~30% of all allocs are expected to have an "event distance" == 1 event ("free" event follows the "alloc" event immediately)
2021-03-18 08:11:50 -04:00
# define INSIGHTS_USE_LAST_ALLOC 1
# define INSIGHTS_VALIDATE_ALLOC_EVENTS 0
2022-05-05 06:14:08 -04:00
# define INSIGHTS_DEBUG_METADATA 0
2021-03-18 08:11:50 -04:00
////////////////////////////////////////////////////////////////////////////////////////////////////
2020-11-13 05:29:37 -04:00
namespace TraceServices
{
2021-01-28 08:10:57 -04:00
constexpr uint32 MaxLogMessagesPerErrorType = 100 ;
2021-03-18 08:11:50 -04:00
# if INSIGHTS_DEBUG_WATCH
static uint64 GWatchAddresses [ ] =
{
// add here addresses to watch
2022-02-07 11:28:45 -05:00
0x0ull ,
2021-03-18 08:11:50 -04:00
} ;
# endif // INSIGHTS_DEBUG_WATCH
2020-11-25 12:48:47 -04:00
////////////////////////////////////////////////////////////////////////////////////////////////////
// FAllocationsProviderLock
////////////////////////////////////////////////////////////////////////////////////////////////////
thread_local FAllocationsProviderLock * GThreadCurrentAllocationsProviderLock ;
thread_local int32 GThreadCurrentReadAllocationsProviderLockCount ;
thread_local int32 GThreadCurrentWriteAllocationsProviderLockCount ;
void FAllocationsProviderLock : : ReadAccessCheck ( ) const
{
checkf ( GThreadCurrentAllocationsProviderLock = = this & & ( GThreadCurrentReadAllocationsProviderLockCount > 0 | | GThreadCurrentWriteAllocationsProviderLockCount > 0 ) ,
TEXT ( " Trying to READ from allocations provider outside of a READ scope " ) ) ;
}
void FAllocationsProviderLock : : WriteAccessCheck ( ) const
{
checkf ( GThreadCurrentAllocationsProviderLock = = this & & GThreadCurrentWriteAllocationsProviderLockCount > 0 ,
TEXT ( " Trying to WRITE to allocations provider outside of an EDIT/WRITE scope " ) ) ;
}
void FAllocationsProviderLock : : BeginRead ( )
{
check ( ! GThreadCurrentAllocationsProviderLock | | GThreadCurrentAllocationsProviderLock = = this ) ;
checkf ( GThreadCurrentWriteAllocationsProviderLockCount = = 0 , TEXT ( " Trying to lock allocations provider for READ while holding EDIT/WRITE access " ) ) ;
if ( GThreadCurrentReadAllocationsProviderLockCount + + = = 0 )
{
GThreadCurrentAllocationsProviderLock = this ;
RWLock . ReadLock ( ) ;
}
}
void FAllocationsProviderLock : : EndRead ( )
{
check ( GThreadCurrentReadAllocationsProviderLockCount > 0 ) ;
if ( - - GThreadCurrentReadAllocationsProviderLockCount = = 0 )
{
RWLock . ReadUnlock ( ) ;
GThreadCurrentAllocationsProviderLock = nullptr ;
}
}
void FAllocationsProviderLock : : BeginWrite ( )
{
check ( ! GThreadCurrentAllocationsProviderLock | | GThreadCurrentAllocationsProviderLock = = this ) ;
checkf ( GThreadCurrentReadAllocationsProviderLockCount = = 0 , TEXT ( " Trying to lock allocations provider for EDIT/WRITE while holding READ access " ) ) ;
if ( GThreadCurrentWriteAllocationsProviderLockCount + + = = 0 )
{
GThreadCurrentAllocationsProviderLock = this ;
RWLock . WriteLock ( ) ;
}
}
void FAllocationsProviderLock : : EndWrite ( )
{
check ( GThreadCurrentWriteAllocationsProviderLockCount > 0 ) ;
if ( - - GThreadCurrentWriteAllocationsProviderLockCount = = 0 )
{
RWLock . WriteUnlock ( ) ;
GThreadCurrentAllocationsProviderLock = nullptr ;
}
}
2020-12-16 10:26:59 -04:00
////////////////////////////////////////////////////////////////////////////////////////////////////
// FTagTracker
////////////////////////////////////////////////////////////////////////////////////////////////////
2022-03-21 08:09:19 -04:00
FTagTracker : : FTagTracker ( IAnalysisSession & InSession )
: Session ( InSession )
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////
2021-11-29 08:19:57 -05:00
void FTagTracker : : AddTagSpec ( TagIdType InTag , TagIdType InParentTag , const TCHAR * InDisplay )
2020-12-16 10:26:59 -04:00
{
if ( ensure ( ! TagMap . Contains ( InTag ) ) )
{
2022-03-21 08:09:19 -04:00
FStringView Display ( InDisplay ) ;
FString DisplayName ;
TStringBuilder < 128 > FullName ;
if ( Display . Contains ( TEXT ( " / " ) ) )
{
DisplayName = FPathViews : : GetPathLeaf ( Display ) ;
FullName = Display ;
// It is possible to define a child tag in runtime using only a string, even if the parent tag does not yet
// exist. We need to find the correct parent or store it to the side until the parent tag is announced.
if ( InParentTag = = ~ 0 )
{
const FStringView Parent = FPathViews : : GetPathLeaf ( FPathViews : : GetPath ( Display ) ) ;
for ( auto EntryPair : TagMap )
{
const auto Entry = EntryPair . Get < 1 > ( ) ;
const uint32 Id = EntryPair . Get < 0 > ( ) ;
if ( Parent . Equals ( Entry . Display ) )
{
InParentTag = Id ;
break ;
}
}
// If parent tag is still unknown here, create a temporary entry here
if ( InParentTag = = ~ 0 )
{
PendingTags . Emplace ( InTag , Parent ) ;
}
}
}
else
{
DisplayName = Display ;
BuildTagPath ( FullName , Display , InParentTag ) ;
}
const FTagEntry & Entry = TagMap . Emplace ( InTag , FTagEntry {
Session . StoreString ( DisplayName ) ,
Session . StoreString ( FullName . ToString ( ) ) ,
InParentTag
} ) ;
// Check if this new tag has been referenced before by a child tag
for ( auto Pending : PendingTags )
{
const FString & Name = Pending . Get < 1 > ( ) ;
const TagIdType ReferencingId = Pending . Get < 0 > ( ) ;
if ( Name . Equals ( DisplayName ) )
{
TagMap [ ReferencingId ] . ParentTag = InTag ;
}
}
2022-05-05 06:14:08 -04:00
2022-02-07 11:28:45 -05:00
if ( ! InDisplay | | * InDisplay = = TEXT ( ' \0 ' ) )
{
UE_LOG ( LogTraceServices , Warning , TEXT ( " [MemAlloc] Tag with id %u has invalid display name (ParentTag=%u)! " ) , InTag , InParentTag ) ;
}
2022-03-21 08:09:19 -04:00
else
{
UE_LOG ( LogTraceServices , Verbose , TEXT ( " [MemAlloc] Added Tag '%s' ('%s') " ) , Entry . Display , Entry . FullPath ) ;
}
2020-12-16 10:26:59 -04:00
}
else
{
+ + NumErrors ;
2021-01-28 08:10:57 -04:00
if ( NumErrors < = MaxLogMessagesPerErrorType )
{
UE_LOG ( LogTraceServices , Error , TEXT ( " [MemAlloc] Tag with id %u (ParentTag=%u, Display=%s) already added! " ) , InTag , InParentTag , InDisplay ) ;
}
2020-12-16 10:26:59 -04:00
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
2022-03-21 08:09:19 -04:00
void FTagTracker : : BuildTagPath ( FStringBuilderBase & OutString , FStringView Name , TagIdType ParentTagId )
{
if ( const FTagEntry * ParentEntry = TagMap . Find ( ParentTagId ) )
{
BuildTagPath ( OutString , ParentEntry - > Display , ParentEntry - > ParentTag ) ;
OutString < < TEXT ( " / " ) ;
}
OutString < < Name ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
2021-11-29 08:19:57 -05:00
void FTagTracker : : PushTag ( uint32 InThreadId , uint8 InTracker , TagIdType InTag )
2020-12-16 10:26:59 -04:00
{
const uint32 TrackerThreadId = GetTrackerThreadId ( InThreadId , InTracker ) ;
2022-03-21 08:09:19 -04:00
FThreadState & State = TrackerThreadStates . FindOrAdd ( TrackerThreadId ) ;
2020-12-16 10:26:59 -04:00
State . TagStack . Push ( InTag ) ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FTagTracker : : PopTag ( uint32 InThreadId , uint8 InTracker )
{
const uint32 TrackerThreadId = GetTrackerThreadId ( InThreadId , InTracker ) ;
2022-03-21 08:09:19 -04:00
FThreadState * State = TrackerThreadStates . Find ( TrackerThreadId ) ;
2021-11-18 14:37:34 -05:00
if ( State & & ! State - > TagStack . IsEmpty ( ) )
2020-12-16 10:26:59 -04:00
{
2021-11-18 14:37:34 -05:00
INSIGHTS_SLOW_CHECK ( ( State - > TagStack . Top ( ) & 0x80000000 ) = = 0 ) ;
2020-12-16 10:26:59 -04:00
State - > TagStack . Pop ( ) ;
}
else
{
+ + NumErrors ;
2021-01-28 08:10:57 -04:00
if ( NumErrors < = MaxLogMessagesPerErrorType )
{
UE_LOG ( LogTraceServices , Error , TEXT ( " [MemAlloc] Tag stack on Thread %u (Tracker=%u) is already empty! " ) , InThreadId , InTracker ) ;
}
2020-12-16 10:26:59 -04:00
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
2021-11-29 08:19:57 -05:00
TagIdType FTagTracker : : GetCurrentTag ( uint32 InThreadId , uint8 InTracker ) const
2020-12-16 10:26:59 -04:00
{
const uint32 TrackerThreadId = GetTrackerThreadId ( InThreadId , InTracker ) ;
2022-03-21 08:09:19 -04:00
const FThreadState * State = TrackerThreadStates . Find ( TrackerThreadId ) ;
2020-12-16 10:26:59 -04:00
if ( ! State | | State - > TagStack . IsEmpty ( ) )
{
return 0 ; // Untagged
}
2021-11-29 08:19:57 -05:00
return State - > TagStack . Top ( ) & ~ PtrTagMask ;
2020-12-16 10:26:59 -04:00
}
////////////////////////////////////////////////////////////////////////////////////////////////////
2021-11-29 08:19:57 -05:00
const TCHAR * FTagTracker : : GetTagString ( TagIdType InTag ) const
2020-12-16 10:26:59 -04:00
{
2022-03-21 08:09:19 -04:00
const FTagEntry * Entry = TagMap . Find ( InTag ) ;
2021-11-29 08:19:57 -05:00
return Entry ? Entry - > Display : TEXT ( " Unknown " ) ;
2020-12-16 10:26:59 -04:00
}
////////////////////////////////////////////////////////////////////////////////////////////////////
2022-03-21 08:09:19 -04:00
void FTagTracker : : EnumerateTags ( TFunctionRef < void ( const TCHAR * , const TCHAR * , TagIdType , TagIdType ) > Callback ) const
{
2022-05-05 06:14:08 -04:00
for ( const auto & EntryPair : TagMap )
2022-03-21 08:09:19 -04:00
{
const TagIdType Id = EntryPair . Get < 0 > ( ) ;
const FTagEntry & Entry = EntryPair . Get < 1 > ( ) ;
Callback ( Entry . Display , Entry . FullPath , Id , Entry . ParentTag ) ;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
2021-11-29 08:19:57 -05:00
void FTagTracker : : PushTagFromPtr ( uint32 InThreadId , uint8 InTracker , TagIdType InTag )
2020-12-16 10:26:59 -04:00
{
const uint32 TrackerThreadId = GetTrackerThreadId ( InThreadId , InTracker ) ;
2022-03-21 08:09:19 -04:00
FThreadState & State = TrackerThreadStates . FindOrAdd ( TrackerThreadId ) ;
2021-11-29 08:19:57 -05:00
State . TagStack . Push ( InTag | PtrTagMask ) ;
2020-12-16 10:26:59 -04:00
}
////////////////////////////////////////////////////////////////////////////////////////////////////
2021-11-18 14:37:34 -05:00
void FTagTracker : : PopTagFromPtr ( uint32 InThreadId , uint8 InTracker )
2020-12-16 10:26:59 -04:00
{
const uint32 TrackerThreadId = GetTrackerThreadId ( InThreadId , InTracker ) ;
2022-03-21 08:09:19 -04:00
FThreadState * State = TrackerThreadStates . Find ( TrackerThreadId ) ;
2021-11-18 14:37:34 -05:00
if ( State & & ! State - > TagStack . IsEmpty ( ) )
2020-12-16 10:26:59 -04:00
{
2021-11-29 08:19:57 -05:00
INSIGHTS_SLOW_CHECK ( ( State - > TagStack . Top ( ) & PtrTagMask ) ! = 0 ) ;
2021-03-17 09:37:09 -04:00
State - > TagStack . Pop ( ) ;
2020-12-16 10:26:59 -04:00
}
else
{
+ + NumErrors ;
2021-01-28 08:10:57 -04:00
if ( NumErrors < = MaxLogMessagesPerErrorType )
{
2021-11-18 14:37:34 -05:00
UE_LOG ( LogTraceServices , Error , TEXT ( " [MemAlloc] Tag stack on Thread %u (Tracker=%u) is already empty! " ) , InThreadId , InTracker ) ;
2021-01-28 08:10:57 -04:00
}
2020-12-16 10:26:59 -04:00
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
2021-11-18 14:37:34 -05:00
bool FTagTracker : : HasTagFromPtrScope ( uint32 InThreadId , uint8 InTracker ) const
2020-12-16 10:26:59 -04:00
{
const uint32 TrackerThreadId = GetTrackerThreadId ( InThreadId , InTracker ) ;
2022-03-21 08:09:19 -04:00
const FThreadState * State = TrackerThreadStates . Find ( TrackerThreadId ) ;
2022-02-07 11:28:45 -05:00
return State & & ( State - > TagStack . Num ( ) > 0 ) & & ( ( State - > TagStack . Top ( ) & PtrTagMask ) ! = 0 ) ;
2020-12-16 10:26:59 -04:00
}
2020-11-25 12:48:47 -04:00
////////////////////////////////////////////////////////////////////////////////////////////////////
// IAllocationsProvider::FAllocation
////////////////////////////////////////////////////////////////////////////////////////////////////
2020-09-24 00:43:27 -04:00
2021-11-24 07:21:25 -05:00
uint32 IAllocationsProvider : : FAllocation : : GetStartEventIndex ( ) const
{
const auto * Inner = ( const FAllocationItem * ) this ;
return Inner - > StartEventIndex ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
uint32 IAllocationsProvider : : FAllocation : : GetEndEventIndex ( ) const
{
const auto * Inner = ( const FAllocationItem * ) this ;
return Inner - > EndEventIndex ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
2020-09-24 00:43:27 -04:00
double IAllocationsProvider : : FAllocation : : GetStartTime ( ) const
{
const auto * Inner = ( const FAllocationItem * ) this ;
return Inner - > StartTime ;
}
2020-11-25 12:48:47 -04:00
////////////////////////////////////////////////////////////////////////////////////////////////////
2020-09-24 00:43:27 -04:00
double IAllocationsProvider : : FAllocation : : GetEndTime ( ) const
{
const auto * Inner = ( const FAllocationItem * ) this ;
return Inner - > EndTime ;
}
2020-11-25 12:48:47 -04:00
////////////////////////////////////////////////////////////////////////////////////////////////////
2020-09-24 00:43:27 -04:00
uint64 IAllocationsProvider : : FAllocation : : GetAddress ( ) const
{
const auto * Inner = ( const FAllocationItem * ) this ;
return Inner - > Address ;
}
2020-11-25 12:48:47 -04:00
////////////////////////////////////////////////////////////////////////////////////////////////////
2020-12-04 07:02:31 -04:00
uint64 IAllocationsProvider : : FAllocation : : GetSize ( ) const
2020-09-24 00:43:27 -04:00
{
const auto * Inner = ( const FAllocationItem * ) this ;
2020-12-04 07:02:31 -04:00
return Inner - > GetSize ( ) ;
2020-09-24 00:43:27 -04:00
}
2020-11-25 12:48:47 -04:00
////////////////////////////////////////////////////////////////////////////////////////////////////
2020-12-04 07:02:31 -04:00
uint32 IAllocationsProvider : : FAllocation : : GetAlignment ( ) const
2020-11-25 12:48:47 -04:00
{
const auto * Inner = ( const FAllocationItem * ) this ;
2020-12-04 07:02:31 -04:00
return Inner - > GetAlignment ( ) ;
2020-11-25 12:48:47 -04:00
}
////////////////////////////////////////////////////////////////////////////////////////////////////
2022-02-07 11:28:45 -05:00
uint32 IAllocationsProvider : : FAllocation : : GetCallstackId ( ) const
2020-09-24 00:43:27 -04:00
{
const auto * Inner = ( const FAllocationItem * ) this ;
2022-02-07 11:28:45 -05:00
return Inner - > CallstackId ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
uint32 IAllocationsProvider : : FAllocation : : GetFreeCallstackId ( ) const
{
const auto * Inner = ( const FAllocationItem * ) this ;
return Inner - > FreeCallstackId ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
uint32 IAllocationsProvider : : FAllocation : : GetMetadataId ( ) const
{
const auto * Inner = ( const FAllocationItem * ) this ;
return Inner - > MetadataId ;
2020-09-24 00:43:27 -04:00
}
2020-11-25 12:48:47 -04:00
////////////////////////////////////////////////////////////////////////////////////////////////////
2021-11-29 08:19:57 -05:00
TagIdType IAllocationsProvider : : FAllocation : : GetTag ( ) const
2020-09-24 00:43:27 -04:00
{
const auto * Inner = ( const FAllocationItem * ) this ;
return Inner - > Tag ;
}
2021-09-22 12:25:29 -04:00
////////////////////////////////////////////////////////////////////////////////////////////////////
HeapId IAllocationsProvider : : FAllocation : : GetRootHeap ( ) const
{
const auto * Inner = ( const FAllocationItem * ) this ;
return Inner - > RootHeap ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
bool IAllocationsProvider : : FAllocation : : IsHeap ( ) const
{
const auto * Inner = ( const FAllocationItem * ) this ;
return Inner - > IsHeap ( ) ;
}
2020-11-25 12:48:47 -04:00
////////////////////////////////////////////////////////////////////////////////////////////////////
// IAllocationsProvider::FAllocations
////////////////////////////////////////////////////////////////////////////////////////////////////
2020-09-24 00:43:27 -04:00
void IAllocationsProvider : : FAllocations : : operator delete ( void * Address )
{
2020-11-25 12:48:47 -04:00
auto * Inner = ( const FAllocationsImpl * ) Address ;
delete Inner ;
2020-09-24 00:43:27 -04:00
}
2020-11-25 12:48:47 -04:00
////////////////////////////////////////////////////////////////////////////////////////////////////
2020-09-24 00:43:27 -04:00
uint32 IAllocationsProvider : : FAllocations : : Num ( ) const
{
2020-11-25 12:48:47 -04:00
auto * Inner = ( const FAllocationsImpl * ) this ;
return ( uint32 ) ( Inner - > Items . Num ( ) ) ;
2020-09-24 00:43:27 -04:00
}
2020-11-25 12:48:47 -04:00
////////////////////////////////////////////////////////////////////////////////////////////////////
2020-09-24 00:43:27 -04:00
const IAllocationsProvider : : FAllocation * IAllocationsProvider : : FAllocations : : Get ( uint32 Index ) const
{
2020-11-25 12:48:47 -04:00
checkSlow ( Index < Num ( ) ) ;
2020-09-24 00:43:27 -04:00
2020-11-25 12:48:47 -04:00
auto * Inner = ( const FAllocationsImpl * ) this ;
return ( const FAllocation * ) ( Inner - > Items [ Index ] ) ;
2020-09-24 00:43:27 -04:00
}
2020-11-25 12:48:47 -04:00
////////////////////////////////////////////////////////////////////////////////////////////////////
// IAllocationsProvider::FQueryStatus
////////////////////////////////////////////////////////////////////////////////////////////////////
2020-09-24 00:43:27 -04:00
2020-11-25 12:48:47 -04:00
IAllocationsProvider : : FQueryResult IAllocationsProvider : : FQueryStatus : : NextResult ( ) const
2020-09-24 00:43:27 -04:00
{
auto * Inner = ( FAllocationsImpl * ) Handle ;
if ( Inner = = nullptr )
{
return nullptr ;
}
Handle = UPTRINT ( Inner - > Next ) ;
auto * Ret = ( FAllocations * ) Inner ;
2020-11-25 12:48:47 -04:00
return FQueryResult ( Ret ) ;
2020-09-24 00:43:27 -04:00
}
2021-03-18 08:11:50 -04:00
////////////////////////////////////////////////////////////////////////////////////////////////////
// FShortLivingAllocs
////////////////////////////////////////////////////////////////////////////////////////////////////
FShortLivingAllocs : : FShortLivingAllocs ( )
{
2022-02-22 04:14:31 -05:00
# if INSIGHTS_SLA_USE_ADDRESS_MAP
AddressMap . Reserve ( MaxAllocCount ) ;
# endif
2021-03-18 08:11:50 -04:00
AllNodes = new FNode [ MaxAllocCount ] ;
// Build the "unused" simple linked list.
FirstUnusedNode = AllNodes ;
for ( int32 Index = 0 ; Index < MaxAllocCount - 1 ; + + Index )
{
AllNodes [ Index ] . Next = & AllNodes [ Index + 1 ] ;
}
AllNodes [ MaxAllocCount - 1 ] . Next = nullptr ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
FShortLivingAllocs : : ~ FShortLivingAllocs ( )
{
2021-11-18 14:37:34 -05:00
Reset ( ) ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FShortLivingAllocs : : Reset ( )
{
2022-02-22 04:14:31 -05:00
# if INSIGHTS_SLA_USE_ADDRESS_MAP
2021-11-18 14:37:34 -05:00
AddressMap . Reset ( ) ;
2022-02-22 04:14:31 -05:00
# endif
2021-11-18 14:37:34 -05:00
2021-03-18 08:11:50 -04:00
FNode * Node = LastAddedAllocNode ;
while ( Node ! = nullptr )
{
delete Node - > Alloc ;
Node = Node - > Prev ;
}
2021-11-18 14:37:34 -05:00
2021-03-18 08:11:50 -04:00
delete [ ] AllNodes ;
2021-11-18 14:37:34 -05:00
AllNodes = nullptr ;
LastAddedAllocNode = nullptr ;
OldestAllocNode = nullptr ;
FirstUnusedNode = nullptr ;
AllocCount = 0 ;
2021-03-18 08:11:50 -04:00
}
////////////////////////////////////////////////////////////////////////////////////////////////////
FAllocationItem * FShortLivingAllocs : : FindRef ( uint64 Address )
{
2022-02-22 04:14:31 -05:00
# if INSIGHTS_SLA_USE_ADDRESS_MAP
2021-03-18 08:11:50 -04:00
FNode * * NodePtr = AddressMap . Find ( Address ) ;
return NodePtr ? ( * NodePtr ) - > Alloc : nullptr ;
# else
// Search linearly the list of allocations, backward, starting with most recent one.
// As the probability of finding a match for a "free" event is higher for the recent allocs,
// this could actually be faster than doing a O(log n) search in AddressMap.
FNode * Node = LastAddedAllocNode ;
while ( Node ! = nullptr )
{
if ( Node - > Alloc - > Address = = Address )
{
return Node - > Alloc ;
}
Node = Node - > Prev ;
}
return nullptr ;
# endif
}
////////////////////////////////////////////////////////////////////////////////////////////////////
2021-11-18 14:37:34 -05:00
FAllocationItem * FShortLivingAllocs : : AddAndRemoveOldest ( FAllocationItem * Alloc )
2021-03-18 08:11:50 -04:00
{
if ( FirstUnusedNode = = nullptr )
{
// Collection is already full.
INSIGHTS_SLOW_CHECK ( AllocCount = = MaxAllocCount ) ;
INSIGHTS_SLOW_CHECK ( OldestAllocNode ! = nullptr ) ;
INSIGHTS_SLOW_CHECK ( LastAddedAllocNode ! = nullptr ) ;
// Reuse the node of the oldest allocation for the new allocation.
FNode * NewNode = OldestAllocNode ;
// Remove the oldest allocation.
FAllocationItem * RemovedAlloc = OldestAllocNode - > Alloc ;
2022-02-22 04:14:31 -05:00
# if INSIGHTS_SLA_USE_ADDRESS_MAP
2021-03-18 08:11:50 -04:00
AddressMap . Remove ( RemovedAlloc - > Address ) ;
2022-02-22 04:14:31 -05:00
# endif
2021-03-18 08:11:50 -04:00
OldestAllocNode = OldestAllocNode - > Next ;
INSIGHTS_SLOW_CHECK ( OldestAllocNode ! = nullptr ) ;
OldestAllocNode - > Prev = nullptr ;
// Add the new node.
2022-02-22 04:14:31 -05:00
# if INSIGHTS_SLA_USE_ADDRESS_MAP
2021-03-18 08:11:50 -04:00
AddressMap . Add ( Alloc - > Address , NewNode ) ;
2022-02-22 04:14:31 -05:00
# endif
2021-03-18 08:11:50 -04:00
NewNode - > Alloc = Alloc ;
NewNode - > Next = nullptr ;
NewNode - > Prev = LastAddedAllocNode ;
LastAddedAllocNode - > Next = NewNode ;
LastAddedAllocNode = NewNode ;
return RemovedAlloc ;
}
else
{
INSIGHTS_SLOW_CHECK ( AllocCount < MaxAllocCount ) ;
+ + AllocCount ;
FNode * NewNode = FirstUnusedNode ;
FirstUnusedNode = FirstUnusedNode - > Next ;
// Add the new node.
2022-02-22 04:14:31 -05:00
# if INSIGHTS_SLA_USE_ADDRESS_MAP
2021-03-18 08:11:50 -04:00
AddressMap . Add ( Alloc - > Address , NewNode ) ;
2022-02-22 04:14:31 -05:00
# endif
2021-03-18 08:11:50 -04:00
NewNode - > Alloc = Alloc ;
NewNode - > Next = nullptr ;
NewNode - > Prev = LastAddedAllocNode ;
if ( LastAddedAllocNode )
{
LastAddedAllocNode - > Next = NewNode ;
}
else
{
OldestAllocNode = NewNode ;
}
LastAddedAllocNode = NewNode ;
return nullptr ;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
FAllocationItem * FShortLivingAllocs : : Remove ( uint64 Address )
{
2022-02-22 04:14:31 -05:00
# if INSIGHTS_SLA_USE_ADDRESS_MAP
FNode * Node = nullptr ;
if ( ! AddressMap . RemoveAndCopyValue ( Address , Node ) )
2021-03-18 08:11:50 -04:00
{
2022-02-22 04:14:31 -05:00
return nullptr ;
}
INSIGHTS_SLOW_CHECK ( Node & & Node - > Alloc & & Node - > Alloc - > Address = = Address ) ;
# else
// Search linearly the list of allocations, backward, starting with most recent one.
// As the probability of finding a match for a "free" event is higher for the recent allocs,
// this could actually be faster than doing a O(log n) search in AddressMap.
FNode * Node = LastAddedAllocNode ;
while ( Node ! = nullptr )
{
if ( Node - > Alloc - > Address = = Address )
2021-03-18 08:11:50 -04:00
{
2022-02-22 04:14:31 -05:00
break ;
2021-03-18 08:11:50 -04:00
}
2022-02-22 04:14:31 -05:00
Node = Node - > Prev ;
}
if ( ! Node )
{
return nullptr ;
}
# endif // INSIGHTS_SLA_USE_ADDRESS_MAP
2021-03-18 08:11:50 -04:00
2022-02-22 04:14:31 -05:00
INSIGHTS_SLOW_CHECK ( AllocCount > 0 ) ;
- - AllocCount ;
2021-03-18 08:11:50 -04:00
2022-02-22 04:14:31 -05:00
// Remove node.
if ( Node = = OldestAllocNode )
{
OldestAllocNode = OldestAllocNode - > Next ;
}
if ( Node = = LastAddedAllocNode )
{
LastAddedAllocNode = LastAddedAllocNode - > Prev ;
}
if ( Node - > Prev )
{
Node - > Prev - > Next = Node - > Next ;
}
if ( Node - > Next )
{
Node - > Next - > Prev = Node - > Prev ;
2021-03-18 08:11:50 -04:00
}
2022-02-22 04:14:31 -05:00
// Add the removed node to the "unused" list.
Node - > Next = FirstUnusedNode ;
FirstUnusedNode = Node ;
return Node - > Alloc ;
2021-03-18 08:11:50 -04:00
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FShortLivingAllocs : : Enumerate ( TFunctionRef < void ( const FAllocationItem & Alloc ) > Callback ) const
{
FNode * Node = LastAddedAllocNode ;
while ( Node ! = nullptr )
{
Callback ( * ( Node - > Alloc ) ) ;
Node = Node - > Prev ;
}
}
2021-09-22 12:25:29 -04:00
////////////////////////////////////////////////////////////////////////////////////////////////////
FAllocationItem * FShortLivingAllocs : : FindRange ( const uint64 Address ) const
{
//todo: Can we do better than iterating all the nodes?
FNode * Node = LastAddedAllocNode ;
while ( Node ! = nullptr )
{
if ( Node - > Alloc - > IsContained ( Address ) )
{
return Node - > Alloc ;
}
Node = Node - > Prev ;
}
return nullptr ;
}
2021-11-18 14:37:34 -05:00
////////////////////////////////////////////////////////////////////////////////////////////////////
// FHeapAllocs
////////////////////////////////////////////////////////////////////////////////////////////////////
FHeapAllocs : : FHeapAllocs ( )
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////
FHeapAllocs : : ~ FHeapAllocs ( )
{
Reset ( ) ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FHeapAllocs : : Reset ( )
{
for ( auto & KV : AddressMap )
{
FList & List = KV . Value ;
const FNode * Node = List . First ;
while ( Node ! = nullptr )
{
FNode * NextNode = Node - > Next ;
delete Node - > Alloc ;
delete Node ;
Node = NextNode ;
}
List . First = nullptr ;
List . Last = nullptr ;
}
AddressMap . Reset ( ) ;
AllocCount = 0 ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
FAllocationItem * FHeapAllocs : : FindRef ( uint64 Address )
{
FList * ListPtr = AddressMap . Find ( Address ) ;
if ( ListPtr )
{
// Search in reverse added order.
for ( const FNode * Node = ListPtr - > Last ; Node ! = nullptr ; Node = Node - > Prev )
{
if ( Address = = Node - > Alloc - > Address )
{
return Node - > Alloc ;
}
}
}
return nullptr ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FHeapAllocs : : Add ( FAllocationItem * Alloc )
{
FNode * Node = new FNode ( ) ;
Node - > Alloc = Alloc ;
Node - > Next = nullptr ;
FList & List = AddressMap . FindOrAdd ( Alloc - > Address ) ;
if ( List . Last = = nullptr )
{
List . First = Node ;
}
else
{
List . Last - > Next = Node ;
}
Node - > Prev = List . Last ;
List . Last = Node ;
+ + AllocCount ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
FAllocationItem * FHeapAllocs : : Remove ( uint64 Address )
{
FList * ListPtr = AddressMap . Find ( Address ) ;
if ( ListPtr )
{
// Remove the last added heap alloc.
check ( ListPtr - > Last ! = nullptr ) ;
FAllocationItem * Alloc = ListPtr - > Last - > Alloc ;
if ( ListPtr - > First = = ListPtr - > Last )
{
// Remove the entire linked list from the map (as it has only one node).
delete ListPtr - > Last ;
AddressMap . FindAndRemoveChecked ( Address ) ;
}
else
{
// Remove only the last node from the linked list of heap allocs with specified address.
FNode * LastNode = ListPtr - > Last ;
ListPtr - > Last = LastNode - > Prev ;
ListPtr - > Last - > Next = nullptr ;
delete LastNode ;
}
- - AllocCount ;
return Alloc ;
}
return nullptr ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FHeapAllocs : : Enumerate ( TFunctionRef < void ( const FAllocationItem & Alloc ) > Callback ) const
{
for ( const auto & KV : AddressMap )
{
// Iterate in same order as added.
for ( const FNode * Node = KV . Value . First ; Node ! = nullptr ; Node = Node - > Next )
{
Callback ( * Node - > Alloc ) ;
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
FAllocationItem * FHeapAllocs : : FindRange ( uint64 Address ) const
{
for ( const auto & KV : AddressMap )
{
// Search in reverse added order.
for ( const FNode * Node = KV . Value . Last ; Node ! = nullptr ; Node = Node - > Prev )
{
if ( Node - > Alloc - > IsContained ( Address ) )
{
return Node - > Alloc ;
}
}
}
return nullptr ;
}
2021-03-18 08:11:50 -04:00
////////////////////////////////////////////////////////////////////////////////////////////////////
// FLiveAllocCollection
////////////////////////////////////////////////////////////////////////////////////////////////////
FLiveAllocCollection : : FLiveAllocCollection ( )
{
2022-02-22 04:14:31 -05:00
# if INSIGHTS_LLA_RESERVE
LongLivingAllocs . Reserve ( INSIGHTS_LLA_RESERVE ) ;
# endif
2021-03-18 08:11:50 -04:00
}
////////////////////////////////////////////////////////////////////////////////////////////////////
FLiveAllocCollection : : ~ FLiveAllocCollection ( )
{
2021-11-18 14:37:34 -05:00
HeapAllocs . Reset ( ) ;
2021-03-18 08:11:50 -04:00
for ( const auto & KV : LongLivingAllocs )
{
const FAllocationItem * Allocation = KV . Value ;
delete Allocation ;
}
2021-11-18 14:37:34 -05:00
LongLivingAllocs . Reset ( ) ;
ShortLivingAllocs . Reset ( ) ;
2021-03-18 08:11:50 -04:00
# if INSIGHTS_USE_LAST_ALLOC
if ( LastAlloc )
{
delete LastAlloc ;
2021-11-18 14:37:34 -05:00
LastAlloc = nullptr ;
2021-03-18 08:11:50 -04:00
}
# endif
}
////////////////////////////////////////////////////////////////////////////////////////////////////
FAllocationItem * FLiveAllocCollection : : FindRef ( uint64 Address )
{
# if INSIGHTS_USE_LAST_ALLOC
if ( LastAlloc & & LastAlloc - > Address = = Address )
{
return LastAlloc ;
}
# endif
# if INSIGHTS_USE_SHORT_LIVING_ALLOCS
FAllocationItem * FoundShortLivingAlloc = ShortLivingAllocs . FindRef ( Address ) ;
if ( FoundShortLivingAlloc )
{
INSIGHTS_SLOW_CHECK ( FoundShortLivingAlloc - > Address = = Address ) ;
return FoundShortLivingAlloc ;
}
# endif
FAllocationItem * FoundLongLivingAlloc = LongLivingAllocs . FindRef ( Address ) ;
if ( FoundLongLivingAlloc )
{
INSIGHTS_SLOW_CHECK ( FoundLongLivingAlloc - > Address = = Address ) ;
return FoundLongLivingAlloc ;
}
return nullptr ;
}
2021-09-22 12:25:29 -04:00
////////////////////////////////////////////////////////////////////////////////////////////////////
2021-11-18 14:37:34 -05:00
FAllocationItem * FLiveAllocCollection : : FindHeapRef ( uint64 Address )
{
FAllocationItem * FoundHeapAlloc = HeapAllocs . FindRef ( Address ) ;
if ( FoundHeapAlloc )
{
INSIGHTS_SLOW_CHECK ( FoundHeapAlloc - > Address = = Address ) ;
return FoundHeapAlloc ;
}
return nullptr ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
FAllocationItem * FLiveAllocCollection : : FindByAddressRange ( uint64 Address )
2021-09-22 12:25:29 -04:00
{
# if INSIGHTS_USE_LAST_ALLOC
if ( LastAlloc & & LastAlloc - > IsContained ( Address ) )
{
return LastAlloc ;
}
# endif
2021-11-18 14:37:34 -05:00
# if INSIGHTS_USE_SHORT_LIVING_ALLOCS
FAllocationItem * FoundShortLivingAlloc = ShortLivingAllocs . FindRange ( Address ) ;
if ( FoundShortLivingAlloc )
{
INSIGHTS_SLOW_CHECK ( FoundShortLivingAlloc - > IsContained ( Address ) ) ;
return FoundShortLivingAlloc ;
}
# endif
2021-09-22 12:25:29 -04:00
for ( const auto & Alloc : LongLivingAllocs )
{
if ( Alloc . Value - > IsContained ( Address ) )
{
return Alloc . Value ;
}
}
return nullptr ;
}
2021-03-18 08:11:50 -04:00
////////////////////////////////////////////////////////////////////////////////////////////////////
2021-11-18 14:37:34 -05:00
FAllocationItem * FLiveAllocCollection : : FindHeapByAddressRange ( uint64 Address )
{
FAllocationItem * FoundHeapAlloc = HeapAllocs . FindRange ( Address ) ;
if ( FoundHeapAlloc )
{
INSIGHTS_SLOW_CHECK ( FoundHeapAlloc - > IsContained ( Address ) ) ;
return FoundHeapAlloc ;
}
return nullptr ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
FAllocationItem * FLiveAllocCollection : : AddNew ( uint64 Address )
{
FAllocationItem * Alloc = new FAllocationItem ( ) ;
Alloc - > Address = Address ;
Add ( Alloc ) ;
return Alloc ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FLiveAllocCollection : : Add ( FAllocationItem * Alloc )
2021-03-18 08:11:50 -04:00
{
+ + TotalAllocCount ;
if ( TotalAllocCount > MaxAllocCount )
{
MaxAllocCount = TotalAllocCount ;
}
# if INSIGHTS_USE_LAST_ALLOC
if ( LastAlloc )
{
// We have a new "last allocation".
// The previous one will be moved to the short living allocations.
2021-11-18 14:37:34 -05:00
FAllocationItem * PrevLastAlloc = LastAlloc ;
LastAlloc = Alloc ;
Alloc = PrevLastAlloc ;
2021-03-18 08:11:50 -04:00
}
else
{
2021-11-18 14:37:34 -05:00
LastAlloc = Alloc ;
return ;
2021-03-18 08:11:50 -04:00
}
# endif
# if INSIGHTS_USE_SHORT_LIVING_ALLOCS
2021-11-18 14:37:34 -05:00
Alloc = ShortLivingAllocs . AddAndRemoveOldest ( Alloc ) ;
if ( Alloc = = nullptr )
2021-03-18 08:11:50 -04:00
{
2021-11-18 14:37:34 -05:00
return ;
2021-03-18 08:11:50 -04:00
}
# endif
2021-11-18 14:37:34 -05:00
LongLivingAllocs . Add ( Alloc - > Address , Alloc ) ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
FAllocationItem * FLiveAllocCollection : : AddNewHeap ( uint64 Address )
{
FAllocationItem * NewAlloc = new FAllocationItem ( ) ;
NewAlloc - > Address = Address ;
AddHeap ( NewAlloc ) ;
2021-03-18 08:11:50 -04:00
return NewAlloc ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
2021-11-18 14:37:34 -05:00
void FLiveAllocCollection : : AddHeap ( FAllocationItem * HeapAlloc )
{
+ + TotalAllocCount ;
if ( TotalAllocCount > MaxAllocCount )
{
MaxAllocCount = TotalAllocCount ;
}
HeapAllocs . Add ( HeapAlloc ) ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
2021-03-18 08:11:50 -04:00
FAllocationItem * FLiveAllocCollection : : Remove ( uint64 Address )
{
# if INSIGHTS_USE_LAST_ALLOC
if ( LastAlloc & & LastAlloc - > Address = = Address )
{
FAllocationItem * RemovedAlloc = LastAlloc ;
LastAlloc = nullptr ;
INSIGHTS_SLOW_CHECK ( TotalAllocCount > 0 ) ;
- - TotalAllocCount ;
return RemovedAlloc ;
}
# endif
# if INSIGHTS_USE_SHORT_LIVING_ALLOCS
FAllocationItem * RemovedShortLivingAlloc = ShortLivingAllocs . Remove ( Address ) ;
if ( RemovedShortLivingAlloc )
{
INSIGHTS_SLOW_CHECK ( RemovedShortLivingAlloc - > Address = = Address ) ;
INSIGHTS_SLOW_CHECK ( TotalAllocCount > 0 ) ;
- - TotalAllocCount ;
return RemovedShortLivingAlloc ;
}
# endif
FAllocationItem * RemovedLongLivingAlloc ;
if ( LongLivingAllocs . RemoveAndCopyValue ( Address , RemovedLongLivingAlloc ) )
{
INSIGHTS_SLOW_CHECK ( RemovedLongLivingAlloc - > Address = = Address ) ;
INSIGHTS_SLOW_CHECK ( TotalAllocCount > 0 ) ;
- - TotalAllocCount ;
return RemovedLongLivingAlloc ;
}
return nullptr ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
2021-11-18 14:37:34 -05:00
FAllocationItem * FLiveAllocCollection : : RemoveHeap ( uint64 Address )
{
FAllocationItem * RemovedHeapAlloc = HeapAllocs . Remove ( Address ) ;
if ( RemovedHeapAlloc )
{
INSIGHTS_SLOW_CHECK ( RemovedHeapAlloc - > Address = = Address ) ;
INSIGHTS_SLOW_CHECK ( TotalAllocCount > 0 ) ;
- - TotalAllocCount ;
return RemovedHeapAlloc ;
}
return nullptr ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
2021-03-18 08:11:50 -04:00
void FLiveAllocCollection : : Enumerate ( TFunctionRef < void ( const FAllocationItem & Alloc ) > Callback ) const
{
2021-11-18 14:37:34 -05:00
HeapAllocs . Enumerate ( Callback ) ;
2021-03-18 08:11:50 -04:00
# if INSIGHTS_USE_LAST_ALLOC
if ( LastAlloc )
{
Callback ( * LastAlloc ) ;
}
# endif
# if INSIGHTS_USE_SHORT_LIVING_ALLOCS
ShortLivingAllocs . Enumerate ( Callback ) ;
# endif
for ( const auto & KV : LongLivingAllocs )
{
const FAllocationItem * Allocation = KV . Value ;
Callback ( * Allocation ) ;
}
}
2020-11-25 12:48:47 -04:00
////////////////////////////////////////////////////////////////////////////////////////////////////
// FAllocationsProvider
////////////////////////////////////////////////////////////////////////////////////////////////////
2020-09-24 00:43:27 -04:00
2022-05-05 06:14:08 -04:00
FAllocationsProvider : : FAllocationsProvider ( IAnalysisSession & InSession , FMetadataProvider & InMetadataProvider )
2021-01-06 05:44:12 -04:00
: Session ( InSession )
2022-05-05 06:14:08 -04:00
, MetadataProvider ( InMetadataProvider )
2022-03-21 08:09:19 -04:00
, TagTracker ( InSession )
2021-01-06 05:44:12 -04:00
, Timeline ( Session . GetLinearAllocator ( ) , 1024 )
, MinTotalAllocatedMemoryTimeline ( Session . GetLinearAllocator ( ) , 1024 )
, MaxTotalAllocatedMemoryTimeline ( Session . GetLinearAllocator ( ) , 1024 )
, MinLiveAllocationsTimeline ( Session . GetLinearAllocator ( ) , 1024 )
, MaxLiveAllocationsTimeline ( Session . GetLinearAllocator ( ) , 1024 )
, AllocEventsTimeline ( Session . GetLinearAllocator ( ) , 1024 )
, FreeEventsTimeline ( Session . GetLinearAllocator ( ) , 1024 )
2020-09-24 00:43:27 -04:00
{
2021-09-22 12:25:29 -04:00
HeapSpecs . AddZeroed ( 256 ) ;
2020-09-24 00:43:27 -04:00
}
2020-11-25 12:48:47 -04:00
////////////////////////////////////////////////////////////////////////////////////////////////////
2020-09-24 00:43:27 -04:00
FAllocationsProvider : : ~ FAllocationsProvider ( )
{
2021-09-22 12:25:29 -04:00
for ( uint8 RootHeapIdx = 0 ; RootHeapIdx < MaxRootHeaps ; + + RootHeapIdx )
2020-11-25 12:48:47 -04:00
{
2021-09-22 12:25:29 -04:00
if ( SbTree [ RootHeapIdx ] )
{
delete SbTree [ RootHeapIdx ] ;
SbTree [ RootHeapIdx ] = nullptr ;
}
if ( LiveAllocs [ RootHeapIdx ] )
{
delete LiveAllocs [ RootHeapIdx ] ;
LiveAllocs [ RootHeapIdx ] = nullptr ;
}
2020-11-25 12:48:47 -04:00
}
2020-09-24 00:43:27 -04:00
}
2020-11-25 12:48:47 -04:00
////////////////////////////////////////////////////////////////////////////////////////////////////
2021-09-22 12:25:29 -04:00
void FAllocationsProvider : : EditInit ( double InTime , uint8 InMinAlignment )
2020-09-24 00:43:27 -04:00
{
2020-12-04 07:02:31 -04:00
Lock . WriteAccessCheck ( ) ;
2020-11-25 12:48:47 -04:00
if ( bInitialized )
{
// error: already initialized
return ;
}
InitTime = InTime ;
MinAlignment = InMinAlignment ;
2022-02-22 04:14:31 -05:00
// Create system root heap structures for backwards compatibility (before heap description events)
AddHeapSpec ( EMemoryTraceRootHeap : : SystemMemory , 0 , TEXT ( " System memory " ) , EMemoryTraceHeapFlags : : Root ) ;
2020-11-25 12:48:47 -04:00
bInitialized = true ;
2020-12-04 07:02:31 -04:00
AdvanceTimelines ( InTime ) ;
2020-09-24 00:43:27 -04:00
}
2020-11-25 12:48:47 -04:00
////////////////////////////////////////////////////////////////////////////////////////////////////
2021-09-23 10:34:18 -04:00
void FAllocationsProvider : : AddHeapSpec ( HeapId Id , HeapId ParentId , const FStringView & Name , EMemoryTraceHeapFlags Flags )
{
2021-09-22 12:25:29 -04:00
if ( Id < MaxRootHeaps )
2020-11-25 12:48:47 -04:00
{
2021-11-18 14:37:34 -05:00
if ( Id = = 0 & & SbTree [ Id ] ! = nullptr )
{
// "System" root heap is already created. See class constructor.
check ( LiveAllocs [ Id ] ! = nullptr ) ;
}
else
{
check ( SbTree [ Id ] = = nullptr & & LiveAllocs [ Id ] = = nullptr ) ;
constexpr uint32 ColumnShift = 17 ; // 1<<17 = 128K
SbTree [ Id ] = new FSbTree ( Session . GetLinearAllocator ( ) , ColumnShift ) ;
LiveAllocs [ Id ] = new FLiveAllocCollection ( ) ;
}
2021-09-22 12:25:29 -04:00
FHeapSpec & RootHeapSpec = HeapSpecs [ Id ] ;
RootHeapSpec . Name = Session . StoreString ( Name ) ;
RootHeapSpec . Parent = nullptr ;
RootHeapSpec . Id = Id ;
RootHeapSpec . Flags = Flags ;
2020-11-25 12:48:47 -04:00
}
2021-09-22 12:25:29 -04:00
else
{
FHeapSpec & ParentSpec = HeapSpecs [ ParentId ] ;
if ( ParentSpec . Name = = nullptr )
{
2021-11-18 14:37:34 -05:00
UE_LOG ( LogTraceServices , Warning , TEXT ( " [MemAlloc] Parent heap id (%u) used before it was announced for heap %s. " ) , ParentId , * FString ( Name ) ) ;
2021-09-22 12:25:29 -04:00
}
FHeapSpec & NewSpec = HeapSpecs [ Id ] ;
NewSpec . Name = Session . StoreString ( Name ) ;
NewSpec . Parent = & ParentSpec ;
NewSpec . Id = Id ;
NewSpec . Flags = Flags ;
2020-11-25 12:48:47 -04:00
2021-09-22 12:25:29 -04:00
ParentSpec . Children . Add ( & NewSpec ) ;
}
2020-11-25 12:48:47 -04:00
}
////////////////////////////////////////////////////////////////////////////////////////////////////
2021-09-23 10:34:18 -04:00
void FAllocationsProvider : : EditHeapSpec ( HeapId Id , HeapId ParentId , const FStringView & Name , EMemoryTraceHeapFlags Flags )
{
Lock . WriteAccessCheck ( ) ;
AddHeapSpec ( Id , ParentId , Name , Flags ) ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
2022-02-07 11:28:45 -05:00
void FAllocationsProvider : : EditAlloc ( double Time , uint32 CallstackId , uint64 Address , uint64 InSize , uint32 InAlignment , HeapId RootHeap )
2020-11-25 12:48:47 -04:00
{
Lock . WriteAccessCheck ( ) ;
if ( ! bInitialized )
{
return ;
}
2020-12-04 07:02:31 -04:00
if ( Address = = 0 )
{
2022-02-07 11:28:45 -05:00
UE_LOG ( LogTraceServices , Warning , TEXT ( " [MemAlloc] Alloc at address 0 : Size=%llu, RootHeap=%u, Time=%f, CallstackId=%u " ) , InSize , RootHeap , Time , CallstackId ) ;
2020-12-04 07:02:31 -04:00
return ;
}
2021-09-23 10:34:18 -04:00
check ( RootHeap < MaxRootHeaps ) ;
if ( SbTree [ RootHeap ] = = nullptr )
{
2021-11-18 14:37:34 -05:00
UE_LOG ( LogTraceServices , Warning , TEXT ( " [MemAlloc] Invalid root heap id (%u). This heap has not yet been registered. " ) , RootHeap ) ;
return ;
2021-09-23 10:34:18 -04:00
}
2021-11-18 14:37:34 -05:00
2021-09-22 12:25:29 -04:00
SbTree [ RootHeap ] - > SetTimeForEvent ( EventIndex [ RootHeap ] , Time ) ;
2020-12-04 07:02:31 -04:00
2021-03-18 08:11:50 -04:00
AdvanceTimelines ( Time ) ;
2022-02-07 11:28:45 -05:00
const TagIdType Tag = TagTracker . GetCurrentTag ( CurrentSystemThreadId , CurrentTracker ) ;
2021-01-28 08:10:57 -04:00
2021-03-18 08:11:50 -04:00
# if INSIGHTS_DEBUG_WATCH
for ( int32 AddrIndex = 0 ; AddrIndex < UE_ARRAY_COUNT ( GWatchAddresses ) ; + + AddrIndex )
{
if ( GWatchAddresses [ AddrIndex ] = = Address )
{
2022-02-07 11:28:45 -05:00
UE_LOG ( LogTraceServices , Warning , TEXT ( " [MemAlloc][%u] Alloc 0x%llX : Size=%llu, Tag=%u, RootHeap=%u, Time=%f, CallstackId=%u " ) , CurrentTraceThreadId , Address , InSize , Tag , RootHeap , Time , CallstackId ) ;
INSIGHTS_DEBUG_WATCH_FOUND ;
2021-03-18 08:11:50 -04:00
}
}
2022-02-07 11:28:45 -05:00
# endif // INSIGHTS_DEBUG_WATCH
2021-03-18 08:11:50 -04:00
# if INSIGHTS_VALIDATE_ALLOC_EVENTS
2021-11-18 14:37:34 -05:00
FAllocationItem * AllocationPtr = LiveAllocs [ RootHeap ] - > FindRef ( Address ) ;
2021-03-18 08:11:50 -04:00
# else
2021-03-19 14:15:01 -04:00
FAllocationItem * AllocationPtr = nullptr ;
2021-03-18 08:11:50 -04:00
# endif
2021-03-19 14:15:01 -04:00
if ( ! AllocationPtr )
{
2021-11-18 14:37:34 -05:00
AllocationPtr = LiveAllocs [ RootHeap ] - > AddNew ( Address ) ;
2021-03-18 08:11:50 -04:00
FAllocationItem & Allocation = * AllocationPtr ;
2022-02-07 11:28:45 -05:00
2022-05-05 06:14:08 -04:00
uint32 MetadataId = MetadataProvider . InvalidMetadataId ;
{
FMetadataProvider : : FEditScopeLock _ ( MetadataProvider ) ;
MetadataId = MetadataProvider . PinAndGetId ( CurrentSystemThreadId ) ;
# if INSIGHTS_DEBUG_METADATA
if ( MetadataId ! = FMetadataProvider : : InvalidMetadataId & &
! TagTracker . HasTagFromPtrScope ( CurrentSystemThreadId , CurrentTracker ) )
{
const uint32 MetadataStackSize = MetadataProvider . GetMetadataStackSize ( CurrentSystemThreadId , MetadataId ) ;
check ( MetadataStackSize > 0 ) ;
uint16 MetaType ;
const void * MetaData ;
uint32 MetaDataSize ;
MetadataProvider . GetMetadata ( CurrentSystemThreadId , MetadataId , MetadataStackSize - 1 , MetaType , MetaData , MetaDataSize ) ;
if ( MetaType = = 0 ) // "MemTagId"
{
TagIdType MetaMemTag = * ( TagIdType * ) MetaData ;
ensure ( MetaMemTag = = Tag ) ;
}
}
# endif
}
2022-02-07 11:28:45 -05:00
INSIGHTS_SLOW_CHECK ( Allocation . Address = = Address ) ;
Allocation . SizeAndAlignment = FAllocationItem : : PackSizeAndAlignment ( InSize , InAlignment ) ;
2021-09-22 12:25:29 -04:00
Allocation . StartEventIndex = EventIndex [ RootHeap ] ;
2021-03-18 08:11:50 -04:00
Allocation . EndEventIndex = ( uint32 ) - 1 ;
Allocation . StartTime = Time ;
Allocation . EndTime = std : : numeric_limits < double > : : infinity ( ) ;
2022-02-07 11:28:45 -05:00
Allocation . CallstackId = CallstackId ;
Allocation . FreeCallstackId = 0 ; // no callstack yet
2022-05-05 06:14:08 -04:00
Allocation . MetadataId = MetadataId ;
2022-02-07 11:28:45 -05:00
Allocation . Reserved = 0 ;
2021-03-18 08:11:50 -04:00
Allocation . Tag = Tag ;
2021-09-22 12:25:29 -04:00
Allocation . RootHeap = RootHeap ;
2022-02-07 11:28:45 -05:00
Allocation . Flags = EMemoryTraceHeapAllocationFlags : : None ;
2021-03-18 08:11:50 -04:00
2021-09-22 12:25:29 -04:00
UpdateHistogramByAllocSize ( InSize ) ;
2021-03-18 08:11:50 -04:00
// Update stats for the current timeline sample.
2021-09-22 12:25:29 -04:00
TotalAllocatedMemory + = InSize ;
+ + TotalLiveAllocations ;
2021-03-18 08:11:50 -04:00
SampleMaxTotalAllocatedMemory = FMath : : Max ( SampleMaxTotalAllocatedMemory , TotalAllocatedMemory ) ;
2021-11-18 14:37:34 -05:00
SampleMaxLiveAllocations = FMath : : Max ( SampleMaxLiveAllocations , TotalLiveAllocations ) ;
2021-03-18 08:11:50 -04:00
+ + SampleAllocEvents ;
}
2021-03-19 14:15:01 -04:00
# if INSIGHTS_VALIDATE_ALLOC_EVENTS
2021-03-18 08:11:50 -04:00
else
2020-11-25 12:48:47 -04:00
{
+ + AllocErrors ;
2021-01-28 08:10:57 -04:00
if ( AllocErrors < = MaxLogMessagesPerErrorType )
{
2021-11-18 14:37:34 -05:00
UE_LOG ( LogTraceServices , Error , TEXT ( " [MemAlloc] Invalid ALLOC event (Address=0x%llX, Size=%llu, Tag=%u, RootHeap=%u, Time=%f)! " ) , Address , InSize , Tag , RootHeap , Time ) ;
2021-01-28 08:10:57 -04:00
}
2020-11-25 12:48:47 -04:00
}
2021-03-18 08:11:50 -04:00
# endif
2020-11-25 12:48:47 -04:00
+ + AllocCount ;
2022-02-22 04:14:31 -05:00
if ( EventIndex [ RootHeap ] ! = ~ 0u )
{
+ + EventIndex [ RootHeap ] ;
}
else
{
UE_LOG ( LogTraceServices , Error , TEXT ( " [MemAlloc] Too many events! " ) ) ;
bInitialized = false ; // ignore further events
}
2020-11-25 12:48:47 -04:00
}
////////////////////////////////////////////////////////////////////////////////////////////////////
2022-02-07 11:28:45 -05:00
void FAllocationsProvider : : EditFree ( double Time , uint32 CallstackId , uint64 Address , HeapId RootHeap )
2020-11-25 12:48:47 -04:00
{
Lock . WriteAccessCheck ( ) ;
if ( ! bInitialized )
{
return ;
}
2020-12-04 07:02:31 -04:00
if ( Address = = 0 )
2020-11-25 12:48:47 -04:00
{
2022-02-07 11:28:45 -05:00
UE_LOG ( LogTraceServices , Warning , TEXT ( " [MemAlloc] Free for address 0 : RootHeap=%u, Time=%f, CallstackId=%u " ) , RootHeap , Time , CallstackId ) ;
2020-11-25 12:48:47 -04:00
return ;
}
2021-09-23 10:34:18 -04:00
check ( RootHeap < MaxRootHeaps ) ;
if ( SbTree [ RootHeap ] = = nullptr )
{
2021-11-18 14:37:34 -05:00
UE_LOG ( LogTraceServices , Warning , TEXT ( " [MemAlloc] Invalid root heap id (%u). This heap has not yet been registered. " ) , RootHeap ) ;
return ;
2021-09-23 10:34:18 -04:00
}
2021-11-18 14:37:34 -05:00
2021-09-22 12:25:29 -04:00
SbTree [ RootHeap ] - > SetTimeForEvent ( EventIndex [ RootHeap ] , Time ) ;
2020-11-25 12:48:47 -04:00
2021-03-18 08:11:50 -04:00
AdvanceTimelines ( Time ) ;
# if INSIGHTS_DEBUG_WATCH
for ( int32 AddrIndex = 0 ; AddrIndex < UE_ARRAY_COUNT ( GWatchAddresses ) ; + + AddrIndex )
{
if ( GWatchAddresses [ AddrIndex ] = = Address )
{
2022-02-07 11:28:45 -05:00
UE_LOG ( LogTraceServices , Warning , TEXT ( " [MemAlloc][%u] Free 0x%llX : RootHeap=%u, Time=%f, CallstackId=%u " ) , CurrentTraceThreadId , Address , RootHeap , Time , CallstackId ) ;
INSIGHTS_DEBUG_WATCH_FOUND ;
2021-03-18 08:11:50 -04:00
}
}
# endif // INSIGHTS_DEBUG_WATCH
2021-09-22 12:25:29 -04:00
FAllocationItem * AllocationPtr = LiveAllocs [ RootHeap ] - > Remove ( Address ) ; // we take ownership of AllocationPtr
2021-11-18 14:37:34 -05:00
if ( ! AllocationPtr )
{
// Try to free a heap allocation.
AllocationPtr = LiveAllocs [ RootHeap ] - > RemoveHeap ( Address ) ; // we take ownership of AllocationPtr
INSIGHTS_SLOW_CHECK ( ! AllocationPtr | | AllocationPtr - > IsHeap ( ) ) ;
}
else
{
INSIGHTS_SLOW_CHECK ( ! AllocationPtr - > IsHeap ( ) ) ;
}
2021-03-18 08:11:50 -04:00
if ( AllocationPtr )
{
2021-09-22 12:25:29 -04:00
check ( EventIndex [ RootHeap ] > AllocationPtr - > StartEventIndex ) ;
AllocationPtr - > EndEventIndex = EventIndex [ RootHeap ] ;
2021-03-18 08:11:50 -04:00
AllocationPtr - > EndTime = Time ;
2022-02-07 11:28:45 -05:00
AllocationPtr - > FreeCallstackId = CallstackId ;
2021-03-18 08:11:50 -04:00
const uint64 OldSize = AllocationPtr - > GetSize ( ) ;
2021-09-22 12:25:29 -04:00
SbTree [ RootHeap ] - > AddAlloc ( AllocationPtr ) ; // SbTree takes ownership of AllocationPtr
2021-03-18 08:11:50 -04:00
uint32 EventDistance = AllocationPtr - > EndEventIndex - AllocationPtr - > StartEventIndex ;
UpdateHistogramByEventDistance ( EventDistance ) ;
2021-09-22 12:25:29 -04:00
// Update stats for the current timeline sample. (Heap allocations are already excluded)
if ( ! AllocationPtr - > IsHeap ( ) )
{
TotalAllocatedMemory - = OldSize ;
- - TotalLiveAllocations ;
SampleMinTotalAllocatedMemory = FMath : : Min ( SampleMinTotalAllocatedMemory , TotalAllocatedMemory ) ;
SampleMinLiveAllocations = FMath : : Min ( SampleMinLiveAllocations , TotalLiveAllocations ) ;
}
2021-03-18 08:11:50 -04:00
+ + SampleFreeEvents ;
}
else
2020-11-25 12:48:47 -04:00
{
+ + FreeErrors ;
2021-01-28 08:10:57 -04:00
if ( FreeErrors < = MaxLogMessagesPerErrorType )
{
2021-11-18 14:37:34 -05:00
UE_LOG ( LogTraceServices , Error , TEXT ( " [MemAlloc] Invalid FREE event (Address=0x%llX, RootHeap=%u, Time=%f)! " ) , Address , RootHeap , Time ) ;
2021-01-28 08:10:57 -04:00
}
2020-11-25 12:48:47 -04:00
}
2021-03-18 08:11:50 -04:00
+ + FreeCount ;
2022-02-22 04:14:31 -05:00
if ( EventIndex [ RootHeap ] ! = ~ 0u )
{
+ + EventIndex [ RootHeap ] ;
}
else
{
UE_LOG ( LogTraceServices , Error , TEXT ( " [MemAlloc] Too many events! " ) ) ;
bInitialized = false ; // ignore further events
}
2021-09-22 12:25:29 -04:00
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FAllocationsProvider : : EditUnmarkAllocationAsHeap ( double Time , uint64 Address , HeapId Heap )
{
Lock . WriteAccessCheck ( ) ;
2021-11-18 14:37:34 -05:00
# if INSIGHTS_DEBUG_WATCH
for ( int32 AddrIndex = 0 ; AddrIndex < UE_ARRAY_COUNT ( GWatchAddresses ) ; + + AddrIndex )
2021-09-22 12:25:29 -04:00
{
2021-11-18 14:37:34 -05:00
if ( GWatchAddresses [ AddrIndex ] = = Address )
{
2022-02-07 11:28:45 -05:00
UE_LOG ( LogTraceServices , Warning , TEXT ( " [MemAlloc][%u] HeapUnmarkAlloc 0x%llX : Heap=%u, Time=%f " ) , CurrentTraceThreadId , Address , Heap , Time ) ;
INSIGHTS_DEBUG_WATCH_FOUND ;
2021-11-18 14:37:34 -05:00
}
2021-09-22 12:25:29 -04:00
}
2022-02-07 11:28:45 -05:00
# endif // INSIGHTS_DEBUG_WATCH
2021-09-22 12:25:29 -04:00
2021-11-18 14:37:34 -05:00
HeapId RootHeap = FindRootHeap ( Heap ) ;
2021-09-22 12:25:29 -04:00
2021-11-18 14:37:34 -05:00
// Remove the heap allocation from the Live allocs.
FAllocationItem * Alloc = LiveAllocs [ RootHeap ] - > RemoveHeap ( Address ) ; // we take ownership of Alloc
if ( Alloc )
{
const uint64 Size = Alloc - > GetSize ( ) ;
const uint32 Alignment = Alloc - > GetAlignment ( ) ;
2022-02-07 11:28:45 -05:00
const uint32 CallstackId = Alloc - > CallstackId ;
const uint32 FreeCallstackId = 0 ; // unknown
2021-11-18 14:37:34 -05:00
// Re-add this allocation to the Live allocs.
LiveAllocs [ RootHeap ] - > Add ( Alloc ) ; // the Live allocs takes ownership of Alloc
2022-02-07 11:28:45 -05:00
// We cannot just unmark the allocation as heap, there is no timestamp support, instead fake a "free"
// event and an "alloc" event. Make sure the new allocation retains the tag from the original.
CurrentTracker = 1 ;
EditPushTagFromPtr ( CurrentSystemThreadId , CurrentTracker , Address ) ;
EditFree ( Time , FreeCallstackId , Address , RootHeap ) ;
EditAlloc ( Time , CallstackId , Address , Size , Alignment , RootHeap ) ;
EditPopTagFromPtr ( CurrentSystemThreadId , CurrentTracker ) ;
CurrentTracker = 0 ;
2021-11-18 14:37:34 -05:00
}
else
{
+ + HeapErrors ;
if ( HeapErrors < = MaxLogMessagesPerErrorType )
{
UE_LOG ( LogTraceServices , Error , TEXT ( " [MemAlloc] HeapUnmarkAlloc: Could not find address 0x%llX (Heap=%u, Time=%f)! " ) , Address , Heap , Time ) ;
}
}
2021-09-22 12:25:29 -04:00
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FAllocationsProvider : : EditMarkAllocationAsHeap ( double Time , uint64 Address , HeapId Heap , EMemoryTraceHeapAllocationFlags Flags )
{
Lock . WriteAccessCheck ( ) ;
2021-11-18 14:37:34 -05:00
# if INSIGHTS_DEBUG_WATCH
for ( int32 AddrIndex = 0 ; AddrIndex < UE_ARRAY_COUNT ( GWatchAddresses ) ; + + AddrIndex )
{
if ( GWatchAddresses [ AddrIndex ] = = Address )
{
2022-02-07 11:28:45 -05:00
UE_LOG ( LogTraceServices , Warning , TEXT ( " [MemAlloc][%u] HeapMarkAlloc 0x%llX : Heap=%u, Flags=%u, Time=%f " ) , CurrentTraceThreadId , Address , Heap , uint32 ( Flags ) , Time ) ;
INSIGHTS_DEBUG_WATCH_FOUND ;
2021-11-18 14:37:34 -05:00
}
}
2022-02-07 11:28:45 -05:00
# endif // INSIGHTS_DEBUG_WATCH
2021-11-18 14:37:34 -05:00
2021-09-22 12:25:29 -04:00
HeapId RootHeap = FindRootHeap ( Heap ) ;
2021-11-18 14:37:34 -05:00
// Remove the allocation from the Live allocs.
FAllocationItem * Alloc = LiveAllocs [ RootHeap ] - > Remove ( Address ) ;
2021-09-22 12:25:29 -04:00
if ( Alloc )
{
2021-11-18 14:37:34 -05:00
// Mark allocation as a "heap" allocation.
2021-09-22 12:25:29 -04:00
check ( EnumHasAnyFlags ( Flags , EMemoryTraceHeapAllocationFlags : : Heap ) ) ;
Alloc - > Flags = Flags ;
Alloc - > RootHeap = RootHeap ;
2021-11-18 14:37:34 -05:00
// Re-add it to the Live allocs as a heap allocation.
LiveAllocs [ RootHeap ] - > AddHeap ( Alloc ) ;
// Update stats. Remove this allocation from the total.
2021-09-22 12:25:29 -04:00
TotalAllocatedMemory - = Alloc - > GetSize ( ) ;
- - TotalLiveAllocations ;
SampleMinTotalAllocatedMemory = FMath : : Min ( SampleMinTotalAllocatedMemory , TotalAllocatedMemory ) ;
SampleMinLiveAllocations = FMath : : Min ( SampleMinLiveAllocations , TotalLiveAllocations ) ;
}
else
{
2021-11-18 14:37:34 -05:00
+ + HeapErrors ;
if ( HeapErrors < = MaxLogMessagesPerErrorType )
{
UE_LOG ( LogTraceServices , Error , TEXT ( " [MemAlloc] HeapMarkAlloc: Could not find address 0x%llX (Heap=%u, Flags=%u, Time=%f)! " ) , Address , Heap , uint32 ( Flags ) , Time ) ;
}
2021-09-22 12:25:29 -04:00
}
2020-11-25 12:48:47 -04:00
}
////////////////////////////////////////////////////////////////////////////////////////////////////
2020-12-04 07:02:31 -04:00
void FAllocationsProvider : : UpdateHistogramByAllocSize ( uint64 Size )
2020-11-25 12:48:47 -04:00
{
if ( Size > MaxAllocSize )
{
MaxAllocSize = Size ;
}
// HistogramIndex : Value Range
// 0 : [0]
// 1 : [1]
// 2 : [2 .. 3]
// 3 : [4 .. 7]
// ...
// i : [2^(i-1) .. 2^i-1], i > 0
// ...
2020-12-04 07:02:31 -04:00
// 64 : [2^63 .. 2^64-1]
uint32 HistogramIndexPow2 = 64 - FMath : : CountLeadingZeros64 ( Size ) ;
2020-11-25 12:48:47 -04:00
+ + AllocSizeHistogramPow2 [ HistogramIndexPow2 ] ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FAllocationsProvider : : UpdateHistogramByEventDistance ( uint32 EventDistance )
{
if ( EventDistance > MaxEventDistance )
{
MaxEventDistance = EventDistance ;
}
// HistogramIndex : Value Range
2020-12-04 07:02:31 -04:00
// 0 : [0]
// 1 : [1]
// 2 : [2 .. 3]
// 3 : [4 .. 7]
2020-11-25 12:48:47 -04:00
// ...
2020-12-04 07:02:31 -04:00
// i : [2^(i-1) .. 2^i-1], i > 0
2020-11-25 12:48:47 -04:00
// ...
2020-12-04 07:02:31 -04:00
// 32 : [2^31 .. 2^32-1]
uint32 HistogramIndexPow2 = 32 - FMath : : CountLeadingZeros ( EventDistance ) ;
2020-11-25 12:48:47 -04:00
+ + EventDistanceHistogramPow2 [ HistogramIndexPow2 ] ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
2020-12-04 07:02:31 -04:00
void FAllocationsProvider : : AdvanceTimelines ( double Time )
{
// If enough time has passed (since the current sample is started)...
2020-12-16 10:26:59 -04:00
if ( Time - SampleStartTimestamp > DefaultTimelineSampleGranularity )
2020-12-04 07:02:31 -04:00
{
// Add the current sample to the timelines.
Timeline . EmplaceBack ( SampleStartTimestamp ) ;
MinTotalAllocatedMemoryTimeline . EmplaceBack ( SampleMinTotalAllocatedMemory ) ;
MaxTotalAllocatedMemoryTimeline . EmplaceBack ( SampleMaxTotalAllocatedMemory ) ;
MinLiveAllocationsTimeline . EmplaceBack ( SampleMinLiveAllocations ) ;
MaxLiveAllocationsTimeline . EmplaceBack ( SampleMaxLiveAllocations ) ;
AllocEventsTimeline . EmplaceBack ( SampleAllocEvents ) ;
FreeEventsTimeline . EmplaceBack ( SampleFreeEvents ) ;
// Start a new sample.
SampleStartTimestamp = Time ;
SampleMinTotalAllocatedMemory = TotalAllocatedMemory ;
SampleMaxTotalAllocatedMemory = TotalAllocatedMemory ;
2021-09-22 12:25:29 -04:00
SampleMinLiveAllocations = TotalLiveAllocations ;
SampleMaxLiveAllocations = TotalLiveAllocations ;
2020-12-04 07:02:31 -04:00
SampleAllocEvents = 0 ;
SampleFreeEvents = 0 ;
// If the previous sample is well distanced in time...
2020-12-16 10:26:59 -04:00
if ( Time - SampleEndTimestamp > DefaultTimelineSampleGranularity )
2020-12-04 07:02:31 -04:00
{
// Add an intermediate "flat region" sample.
Timeline . EmplaceBack ( SampleEndTimestamp ) ;
MinTotalAllocatedMemoryTimeline . EmplaceBack ( TotalAllocatedMemory ) ;
MaxTotalAllocatedMemoryTimeline . EmplaceBack ( TotalAllocatedMemory ) ;
2021-09-22 12:25:29 -04:00
MinLiveAllocationsTimeline . EmplaceBack ( TotalLiveAllocations ) ;
MaxLiveAllocationsTimeline . EmplaceBack ( TotalLiveAllocations ) ;
2020-12-04 07:02:31 -04:00
AllocEventsTimeline . EmplaceBack ( 0 ) ;
FreeEventsTimeline . EmplaceBack ( 0 ) ;
}
}
SampleEndTimestamp = Time ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
2021-09-22 12:25:29 -04:00
HeapId FAllocationsProvider : : FindRootHeap ( HeapId Heap ) const
{
const FHeapSpec * RootHeap = & HeapSpecs [ Heap ] ;
while ( RootHeap - > Parent ! = nullptr )
{
RootHeap = RootHeap - > Parent ;
}
return RootHeap - > Id ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
2021-11-29 08:19:57 -05:00
void FAllocationsProvider : : EditPushTag ( uint32 ThreadId , uint8 Tracker , TagIdType Tag )
2021-03-18 08:11:50 -04:00
{
EditAccessCheck ( ) ;
2021-11-18 14:37:34 -05:00
TagTracker . PushTag ( ThreadId , Tracker , Tag ) ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FAllocationsProvider : : EditPopTag ( uint32 ThreadId , uint8 Tracker )
{
EditAccessCheck ( ) ;
2022-02-22 04:14:31 -05:00
2021-11-18 14:37:34 -05:00
TagTracker . PopTag ( ThreadId , Tracker ) ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FAllocationsProvider : : EditPushTagFromPtr ( uint32 ThreadId , uint8 Tracker , uint64 Ptr )
{
EditAccessCheck ( ) ;
// Currently only system root heap is affected by reallocs, so limit search.
2021-09-23 10:34:18 -04:00
FLiveAllocCollection * Allocs = LiveAllocs [ EMemoryTraceRootHeap : : SystemMemory ] ;
2021-11-18 14:37:34 -05:00
if ( ensure ( Allocs ) )
2021-09-23 10:34:18 -04:00
{
FAllocationItem * Alloc = Allocs - > FindRef ( Ptr ) ;
2021-11-29 08:19:57 -05:00
const TagIdType Tag = Alloc ? Alloc - > Tag : 0 ; // If ptr is not found use "Untagged"
2021-11-18 14:37:34 -05:00
TagTracker . PushTagFromPtr ( ThreadId , Tracker , Tag ) ;
}
else
{
+ + MiscErrors ;
if ( MiscErrors < = MaxLogMessagesPerErrorType )
{
UE_LOG ( LogTraceServices , Error , TEXT ( " [MemAlloc] Invalid Ptr for MemoryScopePtr event (Ptr=0x%llX)! " ) , Ptr ) ;
}
2021-09-23 10:34:18 -04:00
}
2021-03-17 09:37:09 -04:00
}
2021-03-18 08:11:50 -04:00
////////////////////////////////////////////////////////////////////////////////////////////////////
2021-11-18 14:37:34 -05:00
void FAllocationsProvider : : EditPopTagFromPtr ( uint32 ThreadId , uint8 Tracker )
2021-03-18 08:11:50 -04:00
{
EditAccessCheck ( ) ;
2021-11-18 14:37:34 -05:00
TagTracker . PopTagFromPtr ( ThreadId , Tracker ) ;
2021-03-17 09:37:09 -04:00
}
2021-03-18 08:11:50 -04:00
////////////////////////////////////////////////////////////////////////////////////////////////////
2020-12-16 10:26:59 -04:00
void FAllocationsProvider : : EditOnAnalysisCompleted ( double Time )
2020-12-04 07:02:31 -04:00
{
Lock . WriteAccessCheck ( ) ;
if ( ! bInitialized )
{
return ;
}
2020-12-16 10:26:59 -04:00
#if 0
const bool bResetTimelineAtEnd = false ;
// Add all live allocs to SbTree (with infinite end time).
uint64 LiveAllocsTotalSize = 0 ;
2021-03-18 08:11:50 -04:00
LiveAllocs . Enumerate ( [ ] ( const FAllocationItem & Alloc )
2020-12-16 10:26:59 -04:00
{
2021-03-18 08:11:50 -04:00
FAllocationItem * AllocationPtr = const_cast < FAllocationItem * > ( & Alloc ) ;
2020-12-16 10:26:59 -04:00
LiveAllocsTotalSize + = AllocationPtr - > GetSize ( ) ;
// Assign same event index to all live allocs at the end of the session.
AllocationPtr - > EndEventIndex = EventIndex ;
SbTree - > AddAlloc ( AllocationPtr ) ;
uint32 EventDistance = AllocationPtr - > EndEventIndex - AllocationPtr - > StartEventIndex ;
UpdateHistogramByEventDistance ( EventDistance ) ;
2021-03-18 08:11:50 -04:00
} ) ;
//TODO: LiveAllocs.RemoveAll();
2020-12-16 10:26:59 -04:00
check ( TotalAllocatedMemory = = LiveAllocsTotalSize ) ;
if ( bResetTimelineAtEnd )
{
AdvanceTimelines ( Time + 10 * DefaultTimelineSampleGranularity ) ;
2021-09-22 12:25:29 -04:00
const uint32 LiveAllocsTotalCount = TotalLiveAllocations ;
2020-12-16 10:26:59 -04:00
LiveAllocs . Empty ( ) ;
// Update stats for the last timeline sample (reset to zero).
TotalAllocatedMemory = 0 ;
SampleMinTotalAllocatedMemory = 0 ;
SampleMinLiveAllocations = 0 ;
SampleFreeEvents + = LiveAllocsTotalCount ;
}
# endif
// Flush the last cached timeline sample.
2020-12-04 07:02:31 -04:00
AdvanceTimelines ( std : : numeric_limits < double > : : infinity ( ) ) ;
2020-12-16 10:26:59 -04:00
#if 0
DebugPrint ( ) ;
# endif
2021-09-22 12:25:29 -04:00
for ( const FSbTree * Tree : SbTree )
{
if ( Tree )
{
Tree - > Validate ( ) ;
}
}
2022-02-07 11:28:45 -05:00
2022-02-22 04:14:31 -05:00
//TODO: shrink live allocs buffers
2022-02-07 11:28:45 -05:00
if ( AllocErrors > 0 )
{
UE_LOG ( LogTraceServices , Error , TEXT ( " [MemAlloc] ALLOC event errors: %u " ) , AllocErrors ) ;
}
if ( FreeErrors > 0 )
{
UE_LOG ( LogTraceServices , Error , TEXT ( " [MemAlloc] FREE event errors: %u " ) , FreeErrors ) ;
}
if ( HeapErrors > 0 )
{
UE_LOG ( LogTraceServices , Error , TEXT ( " [MemAlloc] HEAP event errors: %u " ) , HeapErrors ) ;
}
if ( MiscErrors > 0 )
{
UE_LOG ( LogTraceServices , Error , TEXT ( " [MemAlloc] Other errors: %u " ) , MiscErrors ) ;
}
if ( TagTracker . GetNumErrors ( ) > 0 )
{
UE_LOG ( LogTraceServices , Error , TEXT ( " [MemAlloc] TagTracker errors: %u " ) , TagTracker . GetNumErrors ( ) ) ;
}
2022-02-22 04:14:31 -05:00
uint64 TotalEventCount = 0 ;
for ( uint32 RootHeap = 0 ; RootHeap < MaxRootHeaps ; + + RootHeap )
{
TotalEventCount + = EventIndex [ RootHeap ] ;
}
UE_LOG ( LogTraceServices , Log , TEXT ( " [MemAlloc] Analysis Completed (%llu events, %llu allocs, %llu frees) " ) , TotalEventCount , AllocCount , FreeCount ) ;
2021-09-22 12:25:29 -04:00
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FAllocationsProvider : : EnumerateRootHeaps ( TFunctionRef < void ( HeapId Id , const FHeapSpec & ) > Callback ) const
{
2022-02-07 11:28:45 -05:00
for ( const FHeapSpec & Spec : HeapSpecs )
{
if ( Spec . Parent = = nullptr & & Spec . Name ! = nullptr )
{
Callback ( Spec . Id , Spec ) ;
}
}
2020-12-04 07:02:31 -04:00
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FAllocationsProvider : : GetTimelineIndexRange ( double StartTime , double EndTime , int32 & StartIndex , int32 & EndIndex ) const
{
using PageType = const TPagedArrayPage < double > ;
PageType * PageData = Timeline . GetPages ( ) ;
if ( PageData )
{
const int32 NumPoints = static_cast < int32 > ( Timeline . Num ( ) ) ;
const int32 NumPages = static_cast < int32 > ( Timeline . NumPages ( ) ) ;
TArrayView < PageType , int32 > Pages ( PageData , NumPages ) ;
const int32 StartPageIndex = Algo : : UpperBoundBy ( Pages , StartTime , [ ] ( PageType & Page ) { return Page . Items [ 0 ] ; } ) - 1 ;
if ( StartPageIndex < 0 )
{
StartIndex = - 1 ;
}
else
{
PageType & Page = PageData [ StartPageIndex ] ;
TArrayView < double > PageValues ( Page . Items , static_cast < int32 > ( Page . Count ) ) ;
const int32 Index = Algo : : UpperBound ( PageValues , StartTime ) - 1 ;
check ( Index > = 0 ) ;
StartIndex = StartPageIndex * static_cast < int32 > ( Timeline . GetPageSize ( ) ) + Index ;
check ( Index < NumPoints ) ;
}
const int32 EndPageIndex = Algo : : UpperBoundBy ( Pages , EndTime , [ ] ( PageType & Page ) { return Page . Items [ 0 ] ; } ) - 1 ;
if ( EndPageIndex < 0 )
{
EndIndex = - 1 ;
}
else
{
PageType & Page = PageData [ EndPageIndex ] ;
TArrayView < double > PageValues ( Page . Items , static_cast < int32 > ( Page . Count ) ) ;
const int32 Index = Algo : : UpperBound ( PageValues , EndTime ) - 1 ;
check ( Index > = 0 ) ;
EndIndex = EndPageIndex * static_cast < int32 > ( Timeline . GetPageSize ( ) ) + Index ;
check ( Index < NumPoints ) ;
}
}
else
{
StartIndex = - 1 ;
EndIndex = - 1 ;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FAllocationsProvider : : EnumerateMinTotalAllocatedMemoryTimeline ( int32 StartIndex , int32 EndIndex , TFunctionRef < void ( double Time , double Duration , uint64 Value ) > Callback ) const
{
const int32 NumPoints = Timeline . Num ( ) ;
StartIndex = FMath : : Max ( StartIndex , 0 ) ;
EndIndex = FMath : : Min ( EndIndex + 1 , NumPoints ) ; // make it exclusive
if ( StartIndex < EndIndex )
{
auto TimeIt = Timeline . GetIteratorFromItem ( StartIndex ) ;
auto ValueIt = MinTotalAllocatedMemoryTimeline . GetIteratorFromItem ( StartIndex ) ;
double PrevTime = * TimeIt ;
uint64 PrevValue = * ValueIt ;
+ + TimeIt ;
+ + ValueIt ;
for ( int32 Index = StartIndex + 1 ; Index < EndIndex ; + + Index , + + TimeIt , + + ValueIt )
{
const double Time = * TimeIt ;
Callback ( PrevTime , Time - PrevTime , PrevValue ) ;
PrevTime = * TimeIt ;
PrevValue = * ValueIt ;
}
if ( EndIndex < NumPoints )
{
const double Time = * TimeIt ;
Callback ( PrevTime , Time - PrevTime , PrevValue ) ;
}
else
{
Callback ( PrevTime , std : : numeric_limits < double > : : infinity ( ) , PrevValue ) ;
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FAllocationsProvider : : EnumerateMaxTotalAllocatedMemoryTimeline ( int32 StartIndex , int32 EndIndex , TFunctionRef < void ( double Time , double Duration , uint64 Value ) > Callback ) const
{
const int32 NumPoints = Timeline . Num ( ) ;
StartIndex = FMath : : Max ( StartIndex , 0 ) ;
EndIndex = FMath : : Min ( EndIndex + 1 , NumPoints ) ; // make it exclusive
if ( StartIndex < EndIndex )
{
auto TimeIt = Timeline . GetIteratorFromItem ( StartIndex ) ;
auto ValueIt = MaxTotalAllocatedMemoryTimeline . GetIteratorFromItem ( StartIndex ) ;
double PrevTime = * TimeIt ;
uint64 PrevValue = * ValueIt ;
+ + TimeIt ;
+ + ValueIt ;
for ( int32 Index = StartIndex + 1 ; Index < EndIndex ; + + Index , + + TimeIt , + + ValueIt )
{
const double Time = * TimeIt ;
Callback ( PrevTime , Time - PrevTime , PrevValue ) ;
PrevTime = * TimeIt ;
PrevValue = * ValueIt ;
}
if ( EndIndex < NumPoints )
{
const double Time = * TimeIt ;
Callback ( PrevTime , Time - PrevTime , PrevValue ) ;
}
else
{
Callback ( PrevTime , std : : numeric_limits < double > : : infinity ( ) , PrevValue ) ;
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FAllocationsProvider : : EnumerateMinLiveAllocationsTimeline ( int32 StartIndex , int32 EndIndex , TFunctionRef < void ( double Time , double Duration , uint32 Value ) > Callback ) const
{
const int32 NumPoints = Timeline . Num ( ) ;
StartIndex = FMath : : Max ( StartIndex , 0 ) ;
EndIndex = FMath : : Min ( EndIndex + 1 , NumPoints ) ; // make it exclusive
if ( StartIndex < EndIndex )
{
auto TimeIt = Timeline . GetIteratorFromItem ( StartIndex ) ;
auto ValueIt = MinLiveAllocationsTimeline . GetIteratorFromItem ( StartIndex ) ;
double PrevTime = * TimeIt ;
uint32 PrevValue = * ValueIt ;
+ + TimeIt ;
+ + ValueIt ;
for ( int32 Index = StartIndex + 1 ; Index < EndIndex ; + + Index , + + TimeIt , + + ValueIt )
{
const double Time = * TimeIt ;
Callback ( PrevTime , Time - PrevTime , PrevValue ) ;
PrevTime = * TimeIt ;
PrevValue = * ValueIt ;
}
if ( EndIndex < NumPoints )
{
const double Time = * TimeIt ;
Callback ( PrevTime , Time - PrevTime , PrevValue ) ;
}
else
{
Callback ( PrevTime , std : : numeric_limits < double > : : infinity ( ) , PrevValue ) ;
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FAllocationsProvider : : EnumerateMaxLiveAllocationsTimeline ( int32 StartIndex , int32 EndIndex , TFunctionRef < void ( double Time , double Duration , uint32 Value ) > Callback ) const
{
const int32 NumPoints = Timeline . Num ( ) ;
StartIndex = FMath : : Max ( StartIndex , 0 ) ;
EndIndex = FMath : : Min ( EndIndex + 1 , NumPoints ) ; // make it exclusive
if ( StartIndex < EndIndex )
{
auto TimeIt = Timeline . GetIteratorFromItem ( StartIndex ) ;
auto ValueIt = MaxLiveAllocationsTimeline . GetIteratorFromItem ( StartIndex ) ;
double PrevTime = * TimeIt ;
uint32 PrevValue = * ValueIt ;
+ + TimeIt ;
+ + ValueIt ;
for ( int32 Index = StartIndex + 1 ; Index < EndIndex ; + + Index , + + TimeIt , + + ValueIt )
{
const double Time = * TimeIt ;
Callback ( PrevTime , Time - PrevTime , PrevValue ) ;
PrevTime = * TimeIt ;
PrevValue = * ValueIt ;
}
if ( EndIndex < NumPoints )
{
const double Time = * TimeIt ;
Callback ( PrevTime , Time - PrevTime , PrevValue ) ;
}
else
{
Callback ( PrevTime , std : : numeric_limits < double > : : infinity ( ) , PrevValue ) ;
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FAllocationsProvider : : EnumerateAllocEventsTimeline ( int32 StartIndex , int32 EndIndex , TFunctionRef < void ( double Time , double Duration , uint32 Value ) > Callback ) const
{
const int32 NumPoints = Timeline . Num ( ) ;
StartIndex = FMath : : Max ( StartIndex , 0 ) ;
EndIndex = FMath : : Min ( EndIndex + 1 , NumPoints ) ; // make it exclusive
if ( StartIndex < EndIndex )
{
auto TimeIt = Timeline . GetIteratorFromItem ( StartIndex ) ;
auto ValueIt = AllocEventsTimeline . GetIteratorFromItem ( StartIndex ) ;
double PrevTime = * TimeIt ;
uint32 PrevValue = * ValueIt ;
+ + TimeIt ;
+ + ValueIt ;
for ( int32 Index = StartIndex + 1 ; Index < EndIndex ; + + Index , + + TimeIt , + + ValueIt )
{
const double Time = * TimeIt ;
Callback ( PrevTime , Time - PrevTime , PrevValue ) ;
PrevTime = * TimeIt ;
PrevValue = * ValueIt ;
}
if ( EndIndex < NumPoints )
{
const double Time = * TimeIt ;
Callback ( PrevTime , Time - PrevTime , PrevValue ) ;
}
else
{
Callback ( PrevTime , std : : numeric_limits < double > : : infinity ( ) , PrevValue ) ;
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FAllocationsProvider : : EnumerateFreeEventsTimeline ( int32 StartIndex , int32 EndIndex , TFunctionRef < void ( double Time , double Duration , uint32 Value ) > Callback ) const
{
const int32 NumPoints = Timeline . Num ( ) ;
StartIndex = FMath : : Max ( StartIndex , 0 ) ;
EndIndex = FMath : : Min ( EndIndex + 1 , NumPoints ) ; // make it exclusive
if ( StartIndex < EndIndex )
{
auto TimeIt = Timeline . GetIteratorFromItem ( StartIndex ) ;
auto ValueIt = FreeEventsTimeline . GetIteratorFromItem ( StartIndex ) ;
double PrevTime = * TimeIt ;
uint32 PrevValue = * ValueIt ;
+ + TimeIt ;
+ + ValueIt ;
for ( int32 Index = StartIndex + 1 ; Index < EndIndex ; + + Index , + + TimeIt , + + ValueIt )
{
const double Time = * TimeIt ;
Callback ( PrevTime , Time - PrevTime , PrevValue ) ;
PrevTime = * TimeIt ;
PrevValue = * ValueIt ;
}
if ( EndIndex < NumPoints )
{
const double Time = * TimeIt ;
Callback ( PrevTime , Time - PrevTime , PrevValue ) ;
}
else
{
Callback ( PrevTime , std : : numeric_limits < double > : : infinity ( ) , PrevValue ) ;
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
2022-03-21 08:09:19 -04:00
void FAllocationsProvider : : EnumerateTags ( TFunctionRef < void ( const TCHAR * , const TCHAR * , TagIdType , TagIdType ) > Callback ) const
{
TagTracker . EnumerateTags ( Callback ) ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
2020-11-25 12:48:47 -04:00
void FAllocationsProvider : : DebugPrint ( ) const
{
2022-05-05 06:14:08 -04:00
for ( const FSbTree * Tree : SbTree )
2021-09-22 12:25:29 -04:00
{
if ( Tree )
{
Tree - > DebugPrint ( ) ;
}
}
2020-11-25 12:48:47 -04:00
}
////////////////////////////////////////////////////////////////////////////////////////////////////
IAllocationsProvider : : FQueryHandle FAllocationsProvider : : StartQuery ( const IAllocationsProvider : : FQueryParams & Params ) const
{
2021-01-06 05:44:12 -04:00
const FCallstacksProvider * CallstacksProvider = Session . ReadProvider < FCallstacksProvider > ( FName ( " CallstacksProvider " ) ) ;
auto * Inner = new FAllocationsQuery ( * this , * CallstacksProvider , Params ) ;
2020-11-25 12:48:47 -04:00
return IAllocationsProvider : : FQueryHandle ( Inner ) ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FAllocationsProvider : : CancelQuery ( FQueryHandle Query ) const
{
auto * Inner = ( FAllocationsQuery * ) Query ;
2020-09-24 00:43:27 -04:00
return Inner - > Cancel ( ) ;
}
2020-11-25 12:48:47 -04:00
////////////////////////////////////////////////////////////////////////////////////////////////////
const IAllocationsProvider : : FQueryStatus FAllocationsProvider : : PollQuery ( FQueryHandle Query ) const
2020-09-24 00:43:27 -04:00
{
2020-11-25 12:48:47 -04:00
auto * Inner = ( FAllocationsQuery * ) Query ;
2020-09-24 00:43:27 -04:00
return Inner - > Poll ( ) ;
}
2020-11-25 12:48:47 -04:00
////////////////////////////////////////////////////////////////////////////////////////////////////
2022-05-05 06:14:08 -04:00
2021-09-22 12:25:29 -04:00
void FAllocationsProvider : : EnumerateLiveAllocs ( TFunctionRef < void ( const FAllocationItem & Alloc ) > Callback ) const
{
ReadAccessCheck ( ) ;
for ( const FLiveAllocCollection * Allocs : LiveAllocs )
{
if ( Allocs )
{
Allocs - > Enumerate ( Callback ) ;
}
}
}
2020-11-13 05:29:37 -04:00
2021-09-22 12:25:29 -04:00
////////////////////////////////////////////////////////////////////////////////////////////////////
[Insights]
- TraceServices: Changed ReadNetProfilerProvider, ReadMemoryProvider, ReadDiagnosticsProvider to return a pointer to the respective provider (instead of a reference). Can return nullptr. The UI should not assume the provider exists.
- TraceServices: Added GetNetProfilerProviderName, GetMemoryProviderName, GetDiagnosticsProviderName, GetAllocationsProviderName to return name of respective provider.
- TraceServices: Added ReadModuleProvider + GetModuleProviderName, ReadCallstacksProvider + GetCallstacksProviderName to access respective providers.
- TraceServices: Added a default empty implementation to IModule for GenerateReports, GetLoggers and GetCommandLineArgument.
- TraceServices: Changed FAnalysisService::StartAnalysis to not create default providers for Memory (LLM Stats), NetProfiler and Diagnostics, but to allow the respective modules (FMemoryModule, FNetProfilerModule, FDiagnosticsModule) to create the providers.
- TraceInsights: Fixed UI code to check if the Memory, NetProfiler and Diagnostics provider are available.
#rb Catalin.Dragoiu, Johan.Berg
#ROBOMERGE-SOURCE: CL 16967698 in //UE5/Main/...
#ROBOMERGE-BOT: STARSHIP (Main -> Release-Engine-Test) (v838-16927207)
[CL 16967704 by ionut matasaru in ue5-release-engine-test branch]
2021-07-27 08:19:49 -04:00
2021-09-22 12:25:29 -04:00
uint32 FAllocationsProvider : : GetNumLiveAllocs ( ) const
{
ReadAccessCheck ( ) ;
return TotalLiveAllocations ;
}
[Insights]
- TraceServices: Changed ReadNetProfilerProvider, ReadMemoryProvider, ReadDiagnosticsProvider to return a pointer to the respective provider (instead of a reference). Can return nullptr. The UI should not assume the provider exists.
- TraceServices: Added GetNetProfilerProviderName, GetMemoryProviderName, GetDiagnosticsProviderName, GetAllocationsProviderName to return name of respective provider.
- TraceServices: Added ReadModuleProvider + GetModuleProviderName, ReadCallstacksProvider + GetCallstacksProviderName to access respective providers.
- TraceServices: Added a default empty implementation to IModule for GenerateReports, GetLoggers and GetCommandLineArgument.
- TraceServices: Changed FAnalysisService::StartAnalysis to not create default providers for Memory (LLM Stats), NetProfiler and Diagnostics, but to allow the respective modules (FMemoryModule, FNetProfilerModule, FDiagnosticsModule) to create the providers.
- TraceInsights: Fixed UI code to check if the Memory, NetProfiler and Diagnostics provider are available.
#rb Catalin.Dragoiu, Johan.Berg
#ROBOMERGE-SOURCE: CL 16967698 in //UE5/Main/...
#ROBOMERGE-BOT: STARSHIP (Main -> Release-Engine-Test) (v838-16927207)
[CL 16967704 by ionut matasaru in ue5-release-engine-test branch]
2021-07-27 08:19:49 -04:00
////////////////////////////////////////////////////////////////////////////////////////////////////
2022-05-05 06:14:08 -04:00
FName GetAllocationsProviderName ( )
{
static FName Name ( TEXT ( " AllocationsProvider " ) ) ;
return Name ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
2020-11-25 12:48:47 -04:00
const IAllocationsProvider * ReadAllocationsProvider ( const IAnalysisSession & Session )
{
[Insights]
- TraceServices: Changed ReadNetProfilerProvider, ReadMemoryProvider, ReadDiagnosticsProvider to return a pointer to the respective provider (instead of a reference). Can return nullptr. The UI should not assume the provider exists.
- TraceServices: Added GetNetProfilerProviderName, GetMemoryProviderName, GetDiagnosticsProviderName, GetAllocationsProviderName to return name of respective provider.
- TraceServices: Added ReadModuleProvider + GetModuleProviderName, ReadCallstacksProvider + GetCallstacksProviderName to access respective providers.
- TraceServices: Added a default empty implementation to IModule for GenerateReports, GetLoggers and GetCommandLineArgument.
- TraceServices: Changed FAnalysisService::StartAnalysis to not create default providers for Memory (LLM Stats), NetProfiler and Diagnostics, but to allow the respective modules (FMemoryModule, FNetProfilerModule, FDiagnosticsModule) to create the providers.
- TraceInsights: Fixed UI code to check if the Memory, NetProfiler and Diagnostics provider are available.
#rb Catalin.Dragoiu, Johan.Berg
#ROBOMERGE-SOURCE: CL 16967698 in //UE5/Main/...
#ROBOMERGE-BOT: STARSHIP (Main -> Release-Engine-Test) (v838-16927207)
[CL 16967704 by ionut matasaru in ue5-release-engine-test branch]
2021-07-27 08:19:49 -04:00
return Session . ReadProvider < IAllocationsProvider > ( GetAllocationsProviderName ( ) ) ;
2020-11-25 12:48:47 -04:00
}
////////////////////////////////////////////////////////////////////////////////////////////////////
} // namespace TraceServices
2021-03-18 08:11:50 -04:00
# undef INSIGHTS_SLOW_CHECK
# undef INSIGHTS_DEBUG_WATCH
2022-02-07 11:28:45 -05:00
# undef INSIGHTS_DEBUG_WATCH_FOUND
2022-02-22 04:14:31 -05:00
# undef INSIGHTS_LLA_RESERVE
2021-03-18 08:11:50 -04:00
# undef INSIGHTS_USE_SHORT_LIVING_ALLOCS
2022-02-22 04:14:31 -05:00
# undef INSIGHTS_SLA_USE_ADDRESS_MAP
2021-03-18 08:11:50 -04:00
# undef INSIGHTS_USE_LAST_ALLOC
# undef INSIGHTS_VALIDATE_ALLOC_EVENTS
2022-05-05 06:14:08 -04:00
# undef INSIGHTS_DEBUG_METADATA