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(); }
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; } } } }