SoftGCStartNumerator

SoftGCStartNumerator

#Overview

name: SoftGCStartNumerator

The value of this variable can be defined or overridden in .ini config files. 1 .ini config file referencing this setting variable.

It is referenced in 11 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of SoftGCStartNumerator is to control the soft garbage collection (GC) mechanism in Unreal Engine’s cooking process. It is used in conjunction with SoftGCDenominator to determine the initial memory threshold for triggering a soft garbage collection.

This setting variable is primarily used by the Cook On The Fly Server subsystem, which is part of the UnrealEd module. It’s specifically utilized in the context of memory management during the cooking process for content preparation.

The value of this variable is set in the GEditorIni configuration file under the [CookSettings] section. It can be loaded using the GConfig->GetInt() function.

SoftGCStartNumerator interacts closely with SoftGCDenominator. Together, they form a fraction (SoftGCStartNumerator / SoftGCDenominator) that determines the initial percentage of total physical memory at which soft garbage collection should start.

Developers should be aware that:

  1. This variable is only relevant when bUseSoftGC is set to true.
  2. The actual value used is always at least 1, even if set lower in the configuration.
  3. It’s part of a dynamic memory management system that adjusts GC thresholds based on available memory.

Best practices when using this variable include:

  1. Ensure SoftGCStartNumerator is smaller than SoftGCDenominator to set a fractional threshold.
  2. Adjust these values carefully based on the target platform’s memory characteristics and the project’s memory usage patterns.
  3. Monitor cooking performance and memory usage when modifying these values to find the optimal balance between memory efficiency and cooking speed.
  4. Consider the relationship between this setting and other memory-related cook settings for a holistic approach to memory management during cooking.

#Setting Variables

#References In INI files

Location: <Workspace>/Engine/Config/BaseEditor.ini:376, section: [CookSettings]

#References in C++ code

#Callsites

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

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Classes/CookOnTheSide/CookOnTheFlyServer.h:342

Scope (from outer to inner):

file
class        class UCookOnTheFlyServer : public UObject, public FTickableEditorObject, public FExec, public UE::Cook::ICookInfo

Source code excerpt:

	double LastSoftGCTime = 0.;
	int64 SoftGCNextAvailablePhysicalTarget = -1;
	int32 SoftGCStartNumerator = 5;
	int32 SoftGCDenominator = 10;
	bool bUseSoftGC = false;
	bool bWarnedExceededMaxMemoryWithinGCCooldown = false;
	bool bGarbageCollectTypeSoft = false;

	/**

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/CookOnTheFlyServer.cpp:5051

Scope (from outer to inner):

file
function     bool UCookOnTheFlyServer::PumpHasExceededMaxMemory

Source code excerpt:

		if (SoftGCNextAvailablePhysicalTarget == -1) // Uninitialized
		{
			int32 StartNumerator = FMath::Max(SoftGCStartNumerator, 1);
			int32 Denominator = FMath::Max(SoftGCDenominator, 1);
			// e.g. Start the target at 5/10, and decrease it by 1/10 each time the target is reached
			SoftGCNextAvailablePhysicalTarget = (static_cast<int64>(MemStats.TotalPhysical)*StartNumerator)
				/Denominator;
		}

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/CookOnTheFlyServer.cpp:5581

Scope (from outer to inner):

file
function     void UCookOnTheFlyServer::EvaluateGarbageCollectionResults

Source code excerpt:

	{
		LastSoftGCTime = LastGCTime;
		int32 StartNumerator = FMath::Max(SoftGCStartNumerator, 1);
		int32 Denominator = FMath::Max(SoftGCDenominator, 1);
		// Calculate the new SoftGCNextAvailablePhysicalTarget. Use the floor of NewAvailableMemory/Denominator,
		// unless we are already 50% of the way through that level, in which case use the next value below that
		int64 PhysicalMemoryQuantum = static_cast<int64>(MemStatsAfterGC.TotalPhysical) / Denominator;
		int32 NextTarget =
			static_cast<int64>(MemStatsAfterGC.AvailablePhysical - PhysicalMemoryQuantum/2) / PhysicalMemoryQuantum;

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/CookOnTheFlyServer.cpp:6902

Scope (from outer to inner):

file
namespace    UE::Cook
function     void FInitializeConfigSettings::LoadLocal

Source code excerpt:

	MemoryMinFreePhysical = 0;
	bUseSoftGC = false;
	SoftGCStartNumerator = 5;
	SoftGCDenominator = 10;

	ReadMemorySetting(TEXT("MemoryMaxUsedVirtual"), MemoryMaxUsedVirtual);
	ReadMemorySetting(TEXT("MemoryMaxUsedPhysical"), MemoryMaxUsedPhysical);
	ReadMemorySetting(TEXT("MemoryMinFreeVirtual"), MemoryMinFreeVirtual);
	ReadMemorySetting(TEXT("MemoryMinFreePhysical"), MemoryMinFreePhysical);

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/CookOnTheFlyServer.cpp:6917

Scope (from outer to inner):

file
namespace    UE::Cook
function     void FInitializeConfigSettings::LoadLocal

Source code excerpt:

	}
	GConfig->GetBool(TEXT("CookSettings"), TEXT("bUseSoftGC"), bUseSoftGC, GEditorIni);
	GConfig->GetInt(TEXT("CookSettings"), TEXT("SoftGCStartNumerator"), SoftGCStartNumerator, GEditorIni);
	GConfig->GetInt(TEXT("CookSettings"), TEXT("SoftGCDenominator"), SoftGCDenominator, GEditorIni);

	MemoryExpectedFreedToSpreadRatio = 0.10f;
	GConfig->GetFloat(TEXT("CookSettings"), TEXT("MemoryExpectedFreedToSpreadRatio"),
		MemoryExpectedFreedToSpreadRatio, GEditorIni);

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/CookOnTheFlyServer.cpp:6943

Scope (from outer to inner):

file
namespace    UE::Cook
function     void FInitializeConfigSettings::LoadLocal

Source code excerpt:

		*LexToString(MemoryTriggerGCAtPressureLevel),
		bUseSoftGC ? TEXT("true") : TEXT("false"),
		bUseSoftGC ? *FString::Printf(TEXT(" (%d/%d)"), SoftGCStartNumerator, SoftGCDenominator) : TEXT(""));

	const FConfigSection* CacheSettings = GConfig->GetSection(TEXT("CookPlatformDataCacheSettings"), false, GEditorIni);
	if (CacheSettings)
	{
		for (const auto& CacheSetting : *CacheSettings)
		{

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Cooker/CookDirector.cpp:1081

Scope (from outer to inner):

file
namespace    UE::Cook
function     void FCookDirector::ActivateMachineResourceReduction

Source code excerpt:

		*LexToString(COTFS.MemoryTriggerGCAtPressureLevel),
		COTFS.bUseSoftGC ? TEXT("true") : TEXT("false"),
		COTFS.bUseSoftGC ? *FString::Printf(TEXT(" (%d/%d)"), COTFS.SoftGCStartNumerator, COTFS.SoftGCDenominator) : TEXT("")
	);

	// Set CoreLimit for updating workerthreads in this process and passing to the commandline for workers
	int32 NumProcesses = RequestedCookWorkerCount + 1;
	int32 NumberOfCores = FPlatformMisc::NumberOfCores();
	int32 HyperThreadCount = FPlatformMisc::NumberOfCoresIncludingHyperthreads();

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Cooker/CookTypes.cpp:627

Scope (from outer to inner):

file
function     FCbWriter& operator<<

Source code excerpt:

	Writer << "MemoryTriggerGCAtPressureLevel" << static_cast<uint8>(Value.MemoryTriggerGCAtPressureLevel);
	Writer << "bUseSoftGC" << Value.bUseSoftGC;
	Writer << "SoftGCStartNumerator" << Value.SoftGCStartNumerator;
	Writer << "SoftGCDenominator" << Value.SoftGCDenominator;
	Writer << "MinFreeUObjectIndicesBeforeGC" << Value.MinFreeUObjectIndicesBeforeGC;
	Writer << "MaxNumPackagesBeforePartialGC" << Value.MaxNumPackagesBeforePartialGC;
	Writer << "ConfigSettingDenyList" << Value.ConfigSettingDenyList;
	Writer << "MaxAsyncCacheForType" << Value.MaxAsyncCacheForType;
	// Make sure new values are added to LoadFromCompactBinary and MoveOrCopy

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Cooker/CookTypes.cpp:662

Scope (from outer to inner):

file
function     bool LoadFromCompactBinary

Source code excerpt:

	}
	bOk = LoadFromCompactBinary(Field["bUseSoftGC"], OutValue.bUseSoftGC) & bOk;
	bOk = LoadFromCompactBinary(Field["SoftGCStartNumerator"], OutValue.SoftGCStartNumerator) & bOk;
	bOk = LoadFromCompactBinary(Field["SoftGCDenominator"], OutValue.SoftGCDenominator) & bOk;
	bOk = LoadFromCompactBinary(Field["MinFreeUObjectIndicesBeforeGC"], OutValue.MinFreeUObjectIndicesBeforeGC) & bOk;
	bOk = LoadFromCompactBinary(Field["MaxNumPackagesBeforePartialGC"], OutValue.MaxNumPackagesBeforePartialGC) & bOk;
	bOk = LoadFromCompactBinary(Field["ConfigSettingDenyList"], OutValue.ConfigSettingDenyList) & bOk;
	bOk = LoadFromCompactBinary(Field["MaxAsyncCacheForType"], OutValue.MaxAsyncCacheForType) & bOk;
	// Make sure new values are added to MoveOrCopy and operator<<

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Cooker/CookTypes.cpp:690

Scope (from outer to inner):

file
namespace    UE::Cook
function     void FInitializeConfigSettings::MoveOrCopy

Source code excerpt:

	Target.MemoryTriggerGCAtPressureLevel = Source.MemoryTriggerGCAtPressureLevel;
	Target.bUseSoftGC = Source.bUseSoftGC;
	Target.SoftGCStartNumerator = Source.SoftGCStartNumerator;
	Target.SoftGCDenominator = Source.SoftGCDenominator;
	Target.MinFreeUObjectIndicesBeforeGC = Source.MinFreeUObjectIndicesBeforeGC;
	Target.MaxNumPackagesBeforePartialGC = Source.MaxNumPackagesBeforePartialGC;
	Target.ConfigSettingDenyList = MoveTempIfPossible(Source.ConfigSettingDenyList);
	Target.MaxAsyncCacheForType = MoveTempIfPossible(Source.MaxAsyncCacheForType);
	// Make sure new values are added to operator<< and LoadFromCompactBinary

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Cooker/CookTypes.h:323

Scope (from outer to inner):

file
namespace    UE::Cook

Source code excerpt:

		int32 MinFreeUObjectIndicesBeforeGC;
		int32 MaxNumPackagesBeforePartialGC;
		int32 SoftGCStartNumerator;
		int32 SoftGCDenominator;
		TArray<FString> ConfigSettingDenyList;
		TMap<FName, int32> MaxAsyncCacheForType; // max number of objects of a specific type which are allowed to async cache at once
		bool bUseSoftGC = false;

		friend FCbWriter& ::operator<<(FCbWriter& Writer, const UE::Cook::FInitializeConfigSettings& Value);