p.Chaos.MaxNumWorkers

p.Chaos.MaxNumWorkers

#Overview

name: p.Chaos.MaxNumWorkers

This variable is created as a Console Variable (cvar).

It is referenced in 9 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of p.Chaos.MaxNumWorkers is to set the maximum number of worker threads that can be used for parallel processing in the Chaos physics system of Unreal Engine 5. This variable is crucial for controlling the level of parallelism in physics simulations.

The Chaos physics subsystem, which is part of the Experimental module in Unreal Engine 5, relies on this setting variable. It’s used in various parts of the physics simulation, including parallel for loops and island group management.

The value of this variable is set through a console variable (CVar) named “p.Chaos.MaxNumWorkers”. It’s initialized with a default value of 100, as seen in the associated variable declaration.

Several other variables interact with MaxNumWorkers:

  1. InnerParallelForBatchSize
  2. MinRangeBatchSize
  3. SmallBatchSize
  4. LargeBatchSize

These variables work together to control the batching and parallelization of physics computations.

Developers must be aware that:

  1. This variable caps the number of worker threads, even if the system has more available.
  2. It affects performance and scalability of physics simulations.
  3. It interacts with other system settings like GSingleThreadedPhysics.

Best practices when using this variable include:

  1. Adjusting it based on the target hardware capabilities.
  2. Balancing it with other batch size settings for optimal performance.
  3. Testing different values to find the best performance for specific game scenarios.

Regarding the associated variable MaxNumWorkers:

#References in C++ code

#Callsites

This variable is referenced in the following C++ source code:

#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Chaos/Private/Chaos/Framework/Parallel.cpp:23

Scope (from outer to inner):

file
namespace    Chaos

Source code excerpt:

	FAutoConsoleVariableRef CVarInnerPhysicsBatchSize(TEXT("p.Chaos.InnerParallelForBatchSize"), InnerParallelForBatchSize, TEXT("Set the batch size threshold for inner parallel fors"));
	FAutoConsoleVariableRef CVarMinRangeBatchSize(TEXT("p.Chaos.MinRangeBatchSize"), MinRangeBatchSize, TEXT("Set the min range batch size for parallel for"));
	FAutoConsoleVariableRef CVarMaxRangeBatchWorkers(TEXT("p.Chaos.MaxNumWorkers"), MaxNumWorkers, TEXT("Set the max number of workers for physics"));
	FAutoConsoleVariableRef CVarSmallBatchSize(TEXT("p.Chaos.SmallBatchSize"), SmallBatchSize, TEXT("Small batch size for chaos parallel loops"));
	FAutoConsoleVariableRef CVarLargeBatchSize(TEXT("p.Chaos.LargeBatchSize"), LargeBatchSize, TEXT("Large batch size for chaos parallel loops"));
#endif
}

void Chaos::InnerPhysicsParallelFor(int32 Num, TFunctionRef<void(int32)> InCallable, bool bForceSingleThreaded)

#Associated Variable and Callsites

This variable is associated with another variable named MaxNumWorkers. They share the same value. See the following C++ source code.

#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Chaos/Private/Chaos/Framework/Parallel.cpp:9

Scope (from outer to inner):

file
namespace    Chaos

Source code excerpt:

	CHAOS_API int32 InnerParallelForBatchSize = 0;
	CHAOS_API int32 MinRangeBatchSize = 0;
	CHAOS_API int32 MaxNumWorkers = 100;
	CHAOS_API int32 SmallBatchSize = 10;
	CHAOS_API int32 LargeBatchSize = 100;
	
#if !UE_BUILD_SHIPPING
	CHAOS_API bool bDisablePhysicsParallelFor = false;
	CHAOS_API bool bDisableParticleParallelFor = false;

#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Chaos/Private/Chaos/Framework/Parallel.cpp:23

Scope (from outer to inner):

file
namespace    Chaos

Source code excerpt:

	FAutoConsoleVariableRef CVarInnerPhysicsBatchSize(TEXT("p.Chaos.InnerParallelForBatchSize"), InnerParallelForBatchSize, TEXT("Set the batch size threshold for inner parallel fors"));
	FAutoConsoleVariableRef CVarMinRangeBatchSize(TEXT("p.Chaos.MinRangeBatchSize"), MinRangeBatchSize, TEXT("Set the min range batch size for parallel for"));
	FAutoConsoleVariableRef CVarMaxRangeBatchWorkers(TEXT("p.Chaos.MaxNumWorkers"), MaxNumWorkers, TEXT("Set the max number of workers for physics"));
	FAutoConsoleVariableRef CVarSmallBatchSize(TEXT("p.Chaos.SmallBatchSize"), SmallBatchSize, TEXT("Small batch size for chaos parallel loops"));
	FAutoConsoleVariableRef CVarLargeBatchSize(TEXT("p.Chaos.LargeBatchSize"), LargeBatchSize, TEXT("Large batch size for chaos parallel loops"));
#endif
}

void Chaos::InnerPhysicsParallelFor(int32 Num, TFunctionRef<void(int32)> InCallable, bool bForceSingleThreaded)

#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Chaos/Private/Chaos/Framework/Parallel.cpp:76

Scope (from outer to inner):

file
function     void Chaos::PhysicsParallelFor

Source code excerpt:

	const bool bSingleThreaded = !!GSingleThreadedPhysics || bDisablePhysicsParallelFor || bForceSingleThreaded;
	const EParallelForFlags Flags = (bSingleThreaded ? EParallelForFlags::ForceSingleThread : EParallelForFlags::None);
	const int32 MinBatchSize = ((MaxNumWorkers > 0) && (InNum > MaxNumWorkers)) ? FMath::DivideAndRoundUp(InNum, MaxNumWorkers) : 1;

	ParallelFor(TEXT("PhysicsParallelFor"), InNum, MinBatchSize, PassThrough, Flags);
	//::ParallelFor(InNum, PassThrough, !!GSingleThreadedPhysics || bDisablePhysicsParallelFor || bForceSingleThreaded);
}

void Chaos::PhysicsParallelForRange(int32 InNum, TFunctionRef<void(int32, int32)> InCallable, const int32 InMinBatchSize, bool bForceSingleThreaded)

#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Chaos/Private/Chaos/Framework/Parallel.cpp:103

Scope (from outer to inner):

file
function     void Chaos::PhysicsParallelForRange

Source code excerpt:

	}
	NumWorkers = FMath::Min(NumWorkers, InNum);
	NumWorkers = FMath::Min(NumWorkers, MaxNumWorkers);
	check(NumWorkers > 0);
	int32 BatchSize = FMath::DivideAndRoundUp<int32>(InNum, NumWorkers);
	int32 MinBatchSize = FMath::Max(InMinBatchSize, MinRangeBatchSize);
	// @todo(mlentine): Find a better batch size in this case
	if (InNum < MinBatchSize)
	{

#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Chaos/Private/Chaos/Framework/Parallel.cpp:173

Scope (from outer to inner):

file
function     void Chaos::PhysicsParallelForWithContext

Source code excerpt:

	const bool bSingleThreaded = !!GSingleThreadedPhysics || bDisablePhysicsParallelFor || bForceSingleThreaded;
	const EParallelForFlags Flags = bSingleThreaded ? (EParallelForFlags::ForceSingleThread) : (EParallelForFlags::None);
	const int32 MinBatchSize = ((MaxNumWorkers > 0) && (InNum > MaxNumWorkers)) ? FMath::DivideAndRoundUp(InNum, MaxNumWorkers) : 1;

	// Unfortunately ParallelForWithTaskContext takes an array of context objects - we don't use it and in our case
	// it ends up being an array where array[index] = index.
	// The reason we don't need it is that our ContextCreator returns the context index we want to use on a given
	// worker thread, and this is passed to the user function. The user function can just captures its array of
	// contexts and use the context indeex to get its context from it.

#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Chaos/Private/Chaos/Island/IslandGroupManager.cpp:66

Scope (from outer to inner):

file
namespace    Chaos
namespace    Private
function     FPBDIslandGroupManager::FPBDIslandGroupManager

Source code excerpt:

			// Check for use of the "-onethread" command line arg, and physics threading disabled (GetNumWorkerThreads() is not affected by these)
			// @todo(chaos): is the number of worker threads a good indicator of how many threads we get in the solver loop? (Currently uses ParallelFor)
			NumWorkerThreads = (FApp::ShouldUseThreadingForPerformance() && !GSingleThreadedPhysics) ? FMath::Min(FTaskGraphInterface::Get().GetNumWorkerThreads(), Chaos::MaxNumWorkers) : 0;
			const int32 MaxIslandGroups = (CVars::GIslandGroupsMaxWorkers > 0) ? CVars::GIslandGroupsMaxWorkers : TNumericLimits<int32>::Max();
			const int32 NumIslandGroups = FMath::Clamp(FMath::CeilToInt32(FReal(NumWorkerThreads) * CVars::GIslandGroupsWorkerMultiplier), 1, MaxIslandGroups);

			IslandGroups.Reserve(NumIslandGroups);
			for (int32 GroupIndex = 0; GroupIndex < NumIslandGroups; ++GroupIndex)
			{

#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Chaos/Private/Chaos/PBDRigidsEvolutionGBF.cpp:207

Scope (from outer to inner):

file
namespace    Chaos
function     int32 CalculateNumCollisionsPerBlock

Source code excerpt:

		else
		{
			const int32 NumWorkers = FMath::Min(FTaskGraphInterface::Get().GetNumWorkerThreads(), Chaos::MaxNumWorkers);
			const int32 NumTasks = FMath::Max(NumWorkers, 1);
			return FMath::Max(NumCollisionsPerBlock / NumTasks, MinCollisionsPerBlock);
		}
	}

#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Chaos/Public/Chaos/Framework/Parallel.h:14

Scope (from outer to inner):

file
namespace    Chaos

Source code excerpt:



	CHAOS_API extern int32 MaxNumWorkers;
	CHAOS_API extern int32 SmallBatchSize;
	CHAOS_API extern int32 LargeBatchSize;
#if UE_BUILD_SHIPPING
	const bool bDisablePhysicsParallelFor = false;
	const bool bDisableParticleParallelFor = false;
	const bool bDisableCollisionParallelFor = false;