void FStatsMallocProfilerProxy::TrackAlloc( void* Ptr, int64 Size, int32 SequenceTag )
{
	if( bEnabled )
	{
		FThreadStats* ThreadStats = FThreadStats::GetThreadStats();

#ifdef DEBUG_MALLOC_PROXY
		if (GThreadStatsToDumpMemory == ThreadStats && ThreadStats->MemoryMessageScope == 0)
		{
			ThreadStats->MemoryMessageScope++;
			UE_LOG( LogStats, Warning, TEXT( "TrackAlloc, %llu, %lli, %i, %i" ), (uint64)(UPTRINT)Ptr, Size, SequenceTag, ThreadStats->MemoryMessageScope );
			ThreadStats->MemoryMessageScope--;
		}
#endif // DEBUG_MALLOC_PROXY

		if (ThreadStats->MemoryMessageScope == 0)
		{
#if	UE_BUILD_DEBUG
			if (ThreadStats->Packet.StatMessages.Num() > 0 && ThreadStats->Packet.StatMessages.Num() % 32767 == 0)
			{
				ThreadStats->MemoryMessageScope++;
				const double InvMB = 1.0f / 1024.0f / 1024.0f;
				UE_LOG( LogStats, Verbose, TEXT( "ThreadID: %i, Current: %.1f" ), FPlatformTLS::GetCurrentThreadId(), InvMB*(int64)ThreadStats->Packet.StatMessages.Num()*sizeof( FStatMessage ) );
				ThreadStats->MemoryMessageScope--;
			}
#endif // UE_BUILD_DEBUG

			// 48 bytes per allocation.
			ThreadStats->AddMemoryMessage( GET_STATFNAME( STAT_Memory_AllocPtr ), (uint64)(UPTRINT)Ptr | (uint64)EMemoryOperation::Alloc );
			ThreadStats->AddMemoryMessage( GET_STATFNAME( STAT_Memory_AllocSize ), Size );
			ThreadStats->AddMemoryMessage( GET_STATFNAME( STAT_Memory_OperationSequenceTag ), (int64)SequenceTag );
			AllocPtrCalls.Increment();
		}
	}
}
void FStatsMallocProfilerProxy::TrackFree( void* Ptr, int32 SequenceTag )
{
	if( bEnabled )
	{
		if( Ptr != nullptr )
		{
			FThreadStats* ThreadStats = FThreadStats::GetThreadStats();

#ifdef DEBUG_MALLOC_PROXY
			if( GThreadStatsToDumpMemory == ThreadStats && ThreadStats->MemoryMessageScope == 0 )
			{
				ThreadStats->MemoryMessageScope++;
				UE_LOG(LogStats, Warning, TEXT("TrackFree, %llu, 0, %i, %i"), (uint64)(UPTRINT)Ptr, SequenceTag, ThreadStats->MemoryMessageScope);
				ThreadStats->MemoryMessageScope--;
			}
#endif // DEBUG_MALLOC_PROXY

			if( ThreadStats->MemoryMessageScope == 0 )
			{
				// 32 bytes per free.
				ThreadStats->AddMemoryMessage( GET_STATFNAME(STAT_Memory_FreePtr), (uint64)(UPTRINT)Ptr | (uint64)EMemoryOperation::Free );	// 16 bytes total				
				ThreadStats->AddMemoryMessage( GET_STATFNAME(STAT_Memory_OperationSequenceTag), (int64)SequenceTag );	
				FreePtrCalls.Increment();
			}
		}	
	}
}
void FStatsMallocProfilerProxy::TrackRealloc( void* OldPtr, void* NewPtr, int64 NewSize, int32 SequenceTag )
{
	if (bEnabled)
	{
		if (OldPtr != nullptr && NewSize > 0)
		{
			FThreadStats* ThreadStats = FThreadStats::GetThreadStats();
			if (ThreadStats->MemoryMessageScope == 0)
			{
				// 64 bytes per reallocation. 80 for Free/Alloc
				ThreadStats->AddMemoryMessage( GET_STATFNAME( STAT_Memory_FreePtr ), (uint64)(UPTRINT)OldPtr | (uint64)EMemoryOperation::Realloc );
				ThreadStats->AddMemoryMessage( GET_STATFNAME( STAT_Memory_AllocPtr ), (uint64)(UPTRINT)NewPtr | (uint64)EMemoryOperation::Realloc );
				ThreadStats->AddMemoryMessage( GET_STATFNAME( STAT_Memory_AllocSize ), NewSize );
				ThreadStats->AddMemoryMessage( GET_STATFNAME( STAT_Memory_OperationSequenceTag ), (int64)SequenceTag );
				ReallocPtrCalls.Increment();
			}
		}
		else if (OldPtr == nullptr)
		{
#if !PLATFORM_XBOXONE
			TrackAlloc( NewPtr, NewSize, SequenceTag );
#endif
		}
		else
		{
			TrackFree( OldPtr, SequenceTag );
		}
	}
}
void FMalloc::InitializeStatsMetadata()
{
	// Initialize stats metadata here instead of UpdateStats.
	// Mostly to avoid dead-lock when stats malloc profiler is enabled.
	GET_STATFNAME(STAT_MallocCalls);
	GET_STATFNAME(STAT_ReallocCalls);
	GET_STATFNAME(STAT_FreeCalls);
	GET_STATFNAME(STAT_TotalAllocatorCalls);
}
void FStatsMallocProfilerProxy::InitializeStatsMetadata()
{
	UsedMalloc->InitializeStatsMetadata();

	// Initialize the memory messages metadata.
	// Malloc profiler proxy needs to be disabled otherwise it will hit infinite recursion in DoSetup.
	// Needs to be changed if we want to support boot time memory profiling.
	const FName NameAllocPtr = GET_STATFNAME(STAT_Memory_AllocPtr);
	const FName NameReallocPtr = GET_STATFNAME(STAT_Memory_ReallocPtr);
	const FName NameFreePtr = GET_STATFNAME(STAT_Memory_FreePtr);
	const FName NameAllocSize = GET_STATFNAME(STAT_Memory_AllocSize);
	const FName NameOperationSequenceTag = GET_STATFNAME(STAT_Memory_OperationSequenceTag);

	GET_STATFNAME(STAT_Memory_AllocPtr_Calls);
	GET_STATFNAME(STAT_Memory_ReallocPtr_Calls);
	GET_STATFNAME(STAT_Memory_FreePtr_Calls);

	GET_STATFNAME(STAT_Memory_AllocPtr_Mem);
	GET_STATFNAME(STAT_Memory_FreePtr_Mem);
}