void FMalloc::UpdateStats()
{
#if	STATS
	GetCurrentFrameCalls().Update();

	SET_DWORD_STAT( STAT_MallocCalls, GetCurrentFrameCalls().MallocCalls );
	SET_DWORD_STAT( STAT_ReallocCalls, GetCurrentFrameCalls().ReallocCalls );
	SET_DWORD_STAT( STAT_FreeCalls, GetCurrentFrameCalls().FreeCalls );
	SET_DWORD_STAT( STAT_TotalAllocatorCalls, GetCurrentFrameCalls().AllocatorCalls );
#endif
}
	/**
	 * The real thread entry point. It waits for work events to be queued. Once
	 * an event is queued, it executes it and goes back to waiting.
	 */
	virtual uint32 Run() override
	{
		while (!TimeToDie)
		{
			// This will force sending the stats packet from the previous frame.
			SET_DWORD_STAT( STAT_ThreadPoolDummyCounter, 0 );
			// We need to wait for shorter amount of time
			bool bContinueWaiting = true;
			while( bContinueWaiting )
			{				
				DECLARE_SCOPE_CYCLE_COUNTER( TEXT( "FQueuedThread::Run.WaitForWork" ), STAT_FQueuedThread_Run_WaitForWork, STATGROUP_ThreadPoolAsyncTasks );
				// Wait for some work to do
				bContinueWaiting = !DoWorkEvent->Wait( 10 );
			}

			IQueuedWork* LocalQueuedWork = QueuedWork;
			QueuedWork = nullptr;
			FPlatformMisc::MemoryBarrier();
			check(LocalQueuedWork || TimeToDie); // well you woke me up, where is the job or termination request?
			while (LocalQueuedWork)
			{
				// Tell the object to do the work
				LocalQueuedWork->DoThreadedWork();
				// Let the object cleanup before we remove our ref to it
				LocalQueuedWork = OwningThreadPool->ReturnToPoolOrGetNextJob(this);
			} 
		}
		return 0;
	}
void FStatsMallocProfilerProxy::UpdateStats()
{
	UsedMalloc->UpdateStats();

	if( bEnabled )
	{
		const int32 NumAllocPtrCalls = AllocPtrCalls.GetValue();
		const int32 NumFreePtrCalls = FreePtrCalls.GetValue();

		SET_DWORD_STAT( STAT_Memory_AllocPtr_Calls, NumAllocPtrCalls );
		SET_DWORD_STAT( STAT_Memory_FreePtr_Calls, NumFreePtrCalls );

		// AllocPtr, AllocSize
		SET_MEMORY_STAT( STAT_Memory_AllocPtr_Mem, NumAllocPtrCalls*(sizeof(FStatMessage)*2) );
		// FreePtr
		SET_MEMORY_STAT( STAT_Memory_FreePtr_Mem, NumFreePtrCalls*(sizeof(FStatMessage)*1) );

		AllocPtrCalls.Reset();
		FreePtrCalls.Reset();
	}
}
void FSlateRHIRenderingPolicy::UpdateVertexAndIndexBuffers(FRHICommandListImmediate& RHICmdList, FSlateBatchData& InBatchData)
{
	SCOPE_CYCLE_COUNTER( STAT_SlateUpdateBufferRTTime );

	// Should only be called by the rendering thread
	check(IsInRenderingThread());

	const int32 NumVertices = InBatchData.GetNumBatchedVertices();
	const int32 NumIndices = InBatchData.GetNumBatchedIndices();

	if( InBatchData.GetRenderBatches().Num() > 0  && NumVertices > 0 && NumIndices > 0)
	{
		TSlateElementVertexBuffer<FSlateVertex>& VertexBuffer = VertexBuffers[CurrentBufferIndex];
		FSlateElementIndexBuffer& IndexBuffer = IndexBuffers[CurrentBufferIndex];

		bool bShouldShrinkResources = false;

		VertexBuffer.PreFillBuffer(NumVertices, bShouldShrinkResources);
		IndexBuffer.PreFillBuffer(NumIndices, bShouldShrinkResources);

		if(!GRHIThread || RHICmdList.Bypass())
		{
			uint8* VertexBufferData = (uint8*)VertexBuffer.LockBuffer_RenderThread(NumVertices);
			uint8* IndexBufferData =  (uint8*)IndexBuffer.LockBuffer_RenderThread(NumIndices);

			InBatchData.FillVertexAndIndexBuffer( VertexBufferData, IndexBufferData );
	
			VertexBuffer.UnlockBuffer_RenderThread();
			IndexBuffer.UnlockBuffer_RenderThread();
		}
		else
		{
			new (RHICmdList.AllocCommand<FSlateUpdateVertexAndIndexBuffers>()) FSlateUpdateVertexAndIndexBuffers(VertexBuffer, IndexBuffer, InBatchData);
		}
	}

	SET_DWORD_STAT( STAT_SlateNumLayers, InBatchData.GetNumLayers() );
	SET_DWORD_STAT( STAT_SlateNumBatches, InBatchData.GetRenderBatches().Num() );
	SET_DWORD_STAT( STAT_SlateVertexCount, InBatchData.GetNumBatchedVertices() );
}
void UBehaviorTreeManager::FinishDestroy()
{
	SET_DWORD_STAT(STAT_AI_BehaviorTree_NumTemplates, 0);

	for (int32 Idx = 0; Idx < ActiveComponents.Num(); Idx++)
	{
		if (ActiveComponents[Idx] && !ActiveComponents[Idx]->HasAnyFlags(RF_BeginDestroyed))
		{
			ActiveComponents[Idx]->Cleanup();
		}
	}

	ActiveComponents.Reset();
	Super::FinishDestroy();
}
Beispiel #6
0
void GatherPhysXStats(PxScene* PScene, uint32 SceneType)
{
	/** Gather PhysX stats */
	if (SceneType == 0)
	{
		if (PScene)
		{
			SCOPED_SCENE_READ_LOCK(PScene);
			PxSimulationStatistics SimStats;
			PScene->getSimulationStatistics(SimStats);

			SET_DWORD_STAT(STAT_NumActiveConstraints, SimStats.nbActiveConstraints);
			SET_DWORD_STAT(STAT_NumActiveSimulatedBodies, SimStats.nbActiveDynamicBodies);
			SET_DWORD_STAT(STAT_NumActiveKinematicBodies, SimStats.nbActiveKinematicBodies);
			SET_DWORD_STAT(STAT_NumStaticBodies, SimStats.nbStaticBodies);
			SET_DWORD_STAT(STAT_NumMobileBodies, SimStats.nbDynamicBodies);
			
			SET_DWORD_STAT(STAT_NumBroadphaseAdds, SimStats.getNbBroadPhaseAdds(PxSimulationStatistics::VolumeType::eRIGID_BODY));
			SET_DWORD_STAT(STAT_NumBroadphaseRemoves, SimStats.getNbBroadPhaseRemoves(PxSimulationStatistics::VolumeType::eRIGID_BODY));

			uint32 NumShapes = 0;
			for (int32 GeomType = 0; GeomType < PxGeometryType::eGEOMETRY_COUNT; ++GeomType)
			{
				NumShapes += SimStats.nbShapes[GeomType];
			}

			SET_DWORD_STAT(STAT_NumShapes, NumShapes);

		}

	}

#if 0	//this is not reliable right now
	else if (SceneType == 1 & UPhysicsSettings::Get()->bEnableAsyncScene)
	{
		//Having to duplicate because of macros. In theory we can fix this but need to get this quickly
		PxSimulationStatistics SimStats;
		PScene->getSimulationStatistics(SimStats);

		SET_DWORD_STAT(STAT_NumActiveConstraintsAsync, SimStats.nbActiveConstraints);
		SET_DWORD_STAT(STAT_NumActiveSimulatedBodiesAsync, SimStats.nbActiveDynamicBodies);
		SET_DWORD_STAT(STAT_NumActiveKinematicBodiesAsync, SimStats.nbActiveKinematicBodies);
		SET_DWORD_STAT(STAT_NumStaticBodiesAsync, SimStats.nbStaticBodies);
		SET_DWORD_STAT(STAT_NumMobileBodiesAsync, SimStats.nbDynamicBodies);

		SET_DWORD_STAT(STAT_NumBroadphaseAddsAsync, SimStats.getNbBroadPhaseAdds(PxSimulationStatistics::VolumeType::eRIGID_BODY));
		SET_DWORD_STAT(STAT_NumBroadphaseRemovesAsync, SimStats.getNbBroadPhaseRemoves(PxSimulationStatistics::VolumeType::eRIGID_BODY));

		uint32 NumShapes = 0;
		for (int32 GeomType = 0; GeomType < PxGeometryType::eGEOMETRY_COUNT; ++GeomType)
		{
			NumShapes += SimStats.nbShapes[GeomType];
		}

		SET_DWORD_STAT(STAT_NumShapesAsync, NumShapes);
	}
#endif
}
uint32 FOnlineAsyncTaskManager::Run(void)
{
	InvocationCount++;
	// This should not be set yet
	check(OnlineThreadId == 0);
	FPlatformAtomics::InterlockedExchange((volatile int32*)&OnlineThreadId, FPlatformTLS::GetCurrentThreadId());

	do 
	{
		int32 InitialQueueSize = 0;
		int32 CurrentQueueSize = 0;
		FOnlineAsyncTask* Task = NULL;

		// Wait for a trigger event to start work
		WorkEvent->Wait(PollingInterval);
		if (!bRequestingExit)
		{
			SCOPE_CYCLE_COUNTER(STAT_Online_Async);
			{
				FScopeLock LockInQueue(&InQueueLock);
				InitialQueueSize = InQueue.Num();
				SET_DWORD_STAT(STAT_Online_AsyncTasks, InitialQueueSize);
			}
			
			double TimeElapsed = 0;

			// Chance for services to do work
			OnlineTick();

			TArray<FOnlineAsyncTask*> CopyParallelTasks;

			// Grab a copy of the parallel list
			{
				FScopeLock LockParallelTasks(&ParallelTasksLock);

				CopyParallelTasks = ParallelTasks;
			}

			// Tick all the parallel tasks
			for ( auto it = CopyParallelTasks.CreateIterator(); it; ++it )
			{
				Task = *it;

				Task->Tick();

				if (Task->IsDone())
				{
					UE_LOG(LogOnline, Log, TEXT("Async task '%s' completed in %f seconds with %d (Parallel)"),
						*Task->ToString(),
						Task->GetElapsedTime(),
						Task->WasSuccessful());

					// Task is done, remove from the incoming queue and add to the outgoing queue
					RemoveFromParallelTasks( Task );

					AddToOutQueue( Task );
				}
			}

			// Now process the serial "In" queue
			do
			{	
				Task = NULL;

				// Grab the current task from the queue
				{
					FScopeLock LockInQueue(&InQueueLock);
					CurrentQueueSize = InQueue.Num();
					if (CurrentQueueSize > 0)
					{
						Task = InQueue[0];
					}
				}

				if (Task)
				{
					Task->Tick();
	
					if (Task->IsDone())
					{
						if (Task->WasSuccessful())
						{
							UE_LOG(LogOnline, Log, TEXT("Async task '%s' completed in %f seconds with %d"),
								*Task->ToString(),
								Task->GetElapsedTime(),
								Task->WasSuccessful());
						}
						else
						{
							UE_LOG(LogOnline, Warning, TEXT("Async task '%s' completed in %f seconds with %d"),
								*Task->ToString(),
								Task->GetElapsedTime(),
								Task->WasSuccessful());
						}
						
						// Task is done, remove from the incoming queue and add to the outgoing queue
						PopFromInQueue();
						AddToOutQueue(Task);
					}
					else
					{
						Task = NULL;
					}
				}
			}
			while (Task != NULL);
		}
	} 
	while (!bRequestingExit);

	return 0;
}
void FAnimNode_AnimDynamics::EvaluateBoneTransforms(USkeletalMeshComponent* SkelComp, FCSPose<FCompactPose>& MeshBases, TArray<FBoneTransform>& OutBoneTransforms)
{
	SCOPE_CYCLE_COUNTER(STAT_AnimDynamicsOverall);

	int32 RestrictToLOD = CVarRestrictLod.GetValueOnAnyThread();
	bool bEnabledForLod = RestrictToLOD >= 0 ? SkelComp->PredictedLODLevel == RestrictToLOD : true;

	if (CVarEnableDynamics.GetValueOnAnyThread() == 1 && bEnabledForLod)
	{
		// Pretty nasty - but there isn't really a good way to get clean bone transforms (without the modification from
		// previous runs) so we have to initialize here, checking often so we can restart a simulation in the editor.
		if (bRequiresInit)
		{
			InitPhysics(SkelComp, MeshBases);
			bRequiresInit = false;
		}

		if (bDoUpdate && NextTimeStep > 0.0f)
		{
			// Wind / Force update
			if(CVarEnableWind.GetValueOnAnyThread() == 1 && bEnableWind)
			{
				SCOPE_CYCLE_COUNTER(STAT_AnimDynamicsWindData);

				for(FAnimPhysRigidBody* Body : BaseBodyPtrs)
				{
					if(SkelComp && SkelComp->GetWorld())
					{
						Body->bWindEnabled = bEnableWind;

						if(Body->bWindEnabled)
						{
							UWorld* World = SkelComp->GetWorld();
							FSceneInterface* Scene = World->Scene;

							// Unused by our simulation but needed for the call to GetWindParameters below
							float WindMinGust;
							float WindMaxGust;

							// Setup wind data
							Body->bWindEnabled = true;
							Scene->GetWindParameters(SkelComp->ComponentToWorld.TransformPosition(Body->Pose.Position), Body->WindData.WindDirection, Body->WindData.WindSpeed, WindMinGust, WindMaxGust);

							Body->WindData.WindDirection = SkelComp->ComponentToWorld.Inverse().TransformVector(Body->WindData.WindDirection);
							Body->WindData.WindAdaption = FMath::FRandRange(0.0f, 2.0f);
							Body->WindData.BodyWindScale = WindScale;
						}
					}
				}
			}
			else
			{
				SCOPE_CYCLE_COUNTER(STAT_AnimDynamicsWindData);
				// Disable wind.
				for(FAnimPhysRigidBody* Body : BaseBodyPtrs)
				{
					Body->bWindEnabled = false;
				}
			}

			if (CVarEnableAdaptiveSubstep.GetValueOnAnyThread() == 1)
			{
				float FixedTimeStep = MaxSubstepDeltaTime * CurrentTimeDilation;

				// Clamp the fixed timestep down to max physics tick time.
				// at high speeds the simulation will not converge as the delta time is too high, this will
				// help to keep constraints together at a cost of physical accuracy
				FixedTimeStep = FMath::Clamp(FixedTimeStep, 0.0f, MaxPhysicsDeltaTime);

				// Calculate number of substeps we should do.
				int32 NumIters = FMath::TruncToInt((NextTimeStep + (TimeDebt * CurrentTimeDilation)) / FixedTimeStep);
				NumIters = FMath::Clamp(NumIters, 0, MaxSubsteps);

				SET_DWORD_STAT(STAT_AnimDynamicsSubSteps, NumIters);

				// Store the remaining time as debt for later frames
				TimeDebt = (NextTimeStep + TimeDebt) - (NumIters * FixedTimeStep);
				TimeDebt = FMath::Clamp(TimeDebt, 0.0f, MaxTimeDebt);

				NextTimeStep = FixedTimeStep;

				for (int32 Iter = 0; Iter < NumIters; ++Iter)
				{
					UpdateLimits(SkelComp, MeshBases);
					FAnimPhys::PhysicsUpdate(FixedTimeStep, BaseBodyPtrs, LinearLimits, AngularLimits, Springs, NumSolverIterationsPreUpdate, NumSolverIterationsPostUpdate);
				}
			}
			else
			{
				// Do variable frame-time update
				const float MaxDeltaTime = MaxPhysicsDeltaTime;

				NextTimeStep = FMath::Min(NextTimeStep, MaxDeltaTime);

				UpdateLimits(SkelComp, MeshBases);
				FAnimPhys::PhysicsUpdate(NextTimeStep, BaseBodyPtrs, LinearLimits, AngularLimits, Springs, NumSolverIterationsPreUpdate, NumSolverIterationsPostUpdate);
			}
		}

		if (bDoEval)
		{
			SCOPE_CYCLE_COUNTER(STAT_AnimDynamicsBoneEval);

			const FBoneContainer& BoneContainer = MeshBases.GetPose().GetBoneContainer();

			for (int32 Idx = 0; Idx < BoundBoneReferences.Num(); ++Idx)
			{
				FBoneReference& CurrentChainBone = BoundBoneReferences[Idx];
				FAnimPhysRigidBody& CurrentBody = Bodies[Idx].RigidBody.PhysBody;

				// Skip invalid bones
				if(!CurrentChainBone.IsValid(BoneContainer))
				{
					continue;
				}

				FCompactPoseBoneIndex BoneIndex = CurrentChainBone.GetCompactPoseIndex(BoneContainer);

				FTransform NewBoneTransform(CurrentBody.Pose.Orientation, CurrentBody.Pose.Position + CurrentBody.Pose.Orientation.RotateVector(JointOffsets[Idx]));
				OutBoneTransforms.Add(FBoneTransform(BoneIndex, NewBoneTransform));
			}
		}
	}
}
void UEnvQueryManager::Tick(float DeltaTime)
{
	SCOPE_CYCLE_COUNTER(STAT_AI_EQS_Tick);
	SET_DWORD_STAT(STAT_AI_EQS_NumInstances, RunningQueries.Num());
	// @TODO: threads?

	const double ExecutionTimeWarningSeconds = 0.25;
	const double MaxAllowedSeconds = 0.010;
	double TimeLeft = MaxAllowedSeconds;
	int32 FinishedQueriesCount = 0;
		
	TArray<TSharedPtr<FEnvQueryInstance> > RunningQueriesCopy = RunningQueries;

	{
		SCOPE_CYCLE_COUNTER(STAT_AI_EQS_TickWork);
		while (TimeLeft > 0.0 && RunningQueriesCopy.Num() > 0)
		{
			bool LoggedExecutionTimeWarning = false;

			for (int32 Index = 0; Index < RunningQueriesCopy.Num() && TimeLeft > 0.0; Index++)
			{
				const double StartTime = FPlatformTime::Seconds();

				TSharedPtr<FEnvQueryInstance>& QueryInstance = RunningQueriesCopy[Index];

				QueryInstance->ExecuteOneStep(TimeLeft);

				if (QueryInstance->IsFinished())
				{
					// Always log that we executed total execution time at the end of the query.
					if (QueryInstance->GetTotalExecutionTime() > ExecutionTimeWarningSeconds)
					{
						UE_LOG(LogEQS, Warning, TEXT("Finished query %s over execution time warning. %s"), *QueryInstance->QueryName, *QueryInstance->GetExecutionTimeDescription());
					}

					RunningQueriesCopy.RemoveAt(Index, 1, /*bAllowShrinking=*/false);
					Index--;
					++FinishedQueriesCount;
					LoggedExecutionTimeWarning = false;
				}

				if (!QueryInstance->HasLoggedTimeLimitWarning() && (QueryInstance->GetTotalExecutionTime() > ExecutionTimeWarningSeconds))
				{
					UE_LOG(LogEQS, Warning, TEXT("Query %s over execution time warning. %s"), *QueryInstance->QueryName, *QueryInstance->GetExecutionTimeDescription());
					QueryInstance->SetHasLoggedTimeLimitWarning();
				}

				TimeLeft -= (FPlatformTime::Seconds() - StartTime);
			}
		}
	}

	{
		SCOPE_CYCLE_COUNTER(STAT_AI_EQS_TickNotifies);
		for (int32 Index = RunningQueries.Num() - 1; Index >= 0 && FinishedQueriesCount > 0; --Index)
		{
			TSharedPtr<FEnvQueryInstance>& QueryInstance = RunningQueries[Index];

			if (QueryInstance->IsFinished())
			{
				UE_VLOG_EQS(*QueryInstance.Get(), LogEQS, All);

#if USE_EQS_DEBUGGER
				EQSDebugger.StoreQuery(GetWorld(), QueryInstance);
#endif // USE_EQS_DEBUGGER

				QueryInstance->FinishDelegate.ExecuteIfBound(QueryInstance);
				RunningQueries.RemoveAtSwap(Index, 1, /*bAllowShrinking=*/false);

				--FinishedQueriesCount;
			}
		}
	}
}