p.SerializeSQs

p.SerializeSQs

#Overview

name: p.SerializeSQs

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

It is referenced in 13 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of p.SerializeSQs is to enable the creation of scene query (SQ) captures for scene queries that take longer than a specified duration in microseconds. This variable is primarily used for debugging and performance analysis in the Unreal Engine’s collision and physics systems.

This setting variable is mainly used in the collision and physics subsystems of Unreal Engine, specifically in the scene query low-level functionality. It’s part of the Engine module, as evidenced by its location in the Engine/Source/Runtime/Engine/Private/Collision/ directory.

The value of this variable is set through the console variable system, as shown by the FAutoConsoleVariableRef declaration. It can be changed at runtime using console commands.

Several other variables interact with p.SerializeSQs:

  1. SerializeSQSamples: Determines the number of samples to take when measuring query duration.
  2. ReplaySQs: Enables rerunning the scene query against Chaos physics engine.
  3. SerializeBadSQs: Enables creating SQ captures when Chaos and PhysX results diverge.
  4. EnableRaycastSQCapture, EnableOverlapSQCapture, EnableSweepSQCapture: Control which types of queries are considered for serialization.

Developers should be aware that:

  1. This feature is only available in non-shipping builds (#if !UE_BUILD_SHIPPING).
  2. Enabling this can be very expensive as it saves out the entire scene.
  3. It’s primarily used for debugging performance issues with scene queries.

Best practices when using this variable:

  1. Use it only when necessary for debugging, as it can significantly impact performance.
  2. Adjust the threshold (microseconds) to capture only the queries you’re interested in.
  3. Use in conjunction with the other related variables to fine-tune the capture process.

Regarding the associated variable SerializeSQs: The purpose of SerializeSQs is the same as p.SerializeSQs. It’s the actual integer variable that stores the value set by the console variable system. It’s used throughout the code to check if serialization should occur and what the duration threshold is.

SerializeSQs is set in the same file and is used in various functions related to scene queries (sweeps, raycasts, overlaps). It’s checked in these functions to determine if a capture should be created based on the query duration.

The same considerations and best practices apply to SerializeSQs as to p.SerializeSQs, as they are essentially the same variable, with p.SerializeSQs being the console-accessible name and SerializeSQs being the actual variable used in the code.

#References in C++ code

#Callsites

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

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Collision/SceneQueryLowLevel.cpp:23

Scope: file

Source code excerpt:

int32 EnableSweepSQCapture = 1;

FAutoConsoleVariableRef CVarSerializeSQs(TEXT("p.SerializeSQs"), SerializeSQs, TEXT("If enabled, we create a sq capture per sq that takes more than provided value in microseconds. This can be very expensive as the entire scene is saved out"));
FAutoConsoleVariableRef CVarSerializeSQSamples(TEXT("p.SerializeSQSampleCount"), SerializeSQSamples, TEXT("If Query exceeds duration threshold, we will re-measure SQ this many times before serializing. Larger values cause hitching."));
FAutoConsoleVariableRef CVarReplaySweeps(TEXT("p.ReplaySQs"), ReplaySQs, TEXT("If enabled, we rerun the sq against chaos"));
FAutoConsoleVariableRef CVarSerializeBadSweeps(TEXT("p.SerializeBadSQs"), SerializeBadSQs, TEXT("If enabled, we create a sq capture whenever chaos and physx diverge"));
FAutoConsoleVariableRef CVarSerializeSQsRaycastEnabled(TEXT("p.SerializeSQsRaycastEnabled"), EnableRaycastSQCapture, TEXT("If disabled, p.SerializeSQs will not consider raycasts"));
FAutoConsoleVariableRef CVarSerializeSQsOverlapEnabled(TEXT("p.SerializeSQsOverlapEnabled"), EnableOverlapSQCapture, TEXT("If disabled, p.SerializeSQs will not consider overlaps"));
FAutoConsoleVariableRef CVarSerializeSQsSweepEnabled(TEXT("p.SerializeSQsSweepEnabled"), EnableSweepSQCapture, TEXT("If disabled, p.SerializeSQs will not consider sweeps"));

#Associated Variable and Callsites

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

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Collision/SceneQueryLowLevel.cpp:15

Scope: file

Source code excerpt:


#if !UE_BUILD_SHIPPING
int32 SerializeSQs = 0;
int32 SerializeSQSamples = 100;
int32 SerializeBadSQs = 0;
int32 ReplaySQs = 0;
int32 EnableRaycastSQCapture = 1;
int32 EnableOverlapSQCapture = 1;
int32 EnableSweepSQCapture = 1;

FAutoConsoleVariableRef CVarSerializeSQs(TEXT("p.SerializeSQs"), SerializeSQs, TEXT("If enabled, we create a sq capture per sq that takes more than provided value in microseconds. This can be very expensive as the entire scene is saved out"));
FAutoConsoleVariableRef CVarSerializeSQSamples(TEXT("p.SerializeSQSampleCount"), SerializeSQSamples, TEXT("If Query exceeds duration threshold, we will re-measure SQ this many times before serializing. Larger values cause hitching."));
FAutoConsoleVariableRef CVarReplaySweeps(TEXT("p.ReplaySQs"), ReplaySQs, TEXT("If enabled, we rerun the sq against chaos"));
FAutoConsoleVariableRef CVarSerializeBadSweeps(TEXT("p.SerializeBadSQs"), SerializeBadSQs, TEXT("If enabled, we create a sq capture whenever chaos and physx diverge"));
FAutoConsoleVariableRef CVarSerializeSQsRaycastEnabled(TEXT("p.SerializeSQsRaycastEnabled"), EnableRaycastSQCapture, TEXT("If disabled, p.SerializeSQs will not consider raycasts"));
FAutoConsoleVariableRef CVarSerializeSQsOverlapEnabled(TEXT("p.SerializeSQsOverlapEnabled"), EnableOverlapSQCapture, TEXT("If disabled, p.SerializeSQs will not consider overlaps"));
FAutoConsoleVariableRef CVarSerializeSQsSweepEnabled(TEXT("p.SerializeSQsSweepEnabled"), EnableSweepSQCapture, TEXT("If disabled, p.SerializeSQs will not consider sweeps"));
#else
constexpr int32 SerializeSQs = 0;
constexpr int32 ReplaySQs = 0;
constexpr int32 SerializeSQSamples = 0;
constexpr int32 EnableRaycastSQCapture = 0;
constexpr int32 EnableOverlapSQCapture = 0;
constexpr int32 EnableSweepSQCapture = 0;
#endif

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Collision/SceneQueryLowLevel.cpp:44

Scope (from outer to inner):

file
namespace    anonymous
function     void FinalizeCapture

Source code excerpt:

	{
#if !UE_BUILD_SHIPPING
		if (SerializeSQs)
		{
			Serializer.Serialize(TEXT("SQCapture"));
		}
#if 0
		if (ReplaySQs)
		{

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Collision/SceneQueryLowLevel.cpp:55

Scope (from outer to inner):

file
namespace    anonymous
function     void FinalizeCapture

Source code excerpt:

			{
				UE_LOG(LogPhysicsCore, Warning, TEXT("Chaos SQ does not match physx"));
				if (SerializeBadSQs && !SerializeSQs)
				{
					Serializer.Serialize(TEXT("BadSQCapture"));
				}
			}
		}
#endif

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Collision/SceneQueryLowLevel.cpp:116

Scope (from outer to inner):

file
namespace    anonymous
function     void SweepSQCaptureHelper

Source code excerpt:

#if !UE_BUILD_SHIPPING
		float QueryDurationMicro = QueryDurationSeconds * 1000.0 * 1000.0;
		if (((SerializeSQs && QueryDurationMicro > SerializeSQs)) && IsInGameThread())
		{
			// Measure average time of query over multiple samples to reduce fluke from context switches or that kind of thing.
			uint32 Cycles = 0.0;
			const uint32 SampleCount = SerializeSQSamples;
			for (uint32 Samples = 0; Samples < SampleCount; ++Samples)
			{

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Collision/SceneQueryLowLevel.cpp:134

Scope (from outer to inner):

file
namespace    anonymous
function     void SweepSQCaptureHelper

Source code excerpt:

			float AvgMicroseconds = (Milliseconds * 1000) / SampleCount;

			if (AvgMicroseconds > SerializeSQs)
			{
				FPhysTestSerializer Serializer;
				Serializer.SetPhysicsData(*Scene.GetSolver()->GetEvolution());
				FSQCapture& SweepCapture = Serializer.CaptureSQ();
				SweepCapture.StartCaptureChaosSweep(*Scene.GetSolver()->GetEvolution(), QueryGeom, StartTM, Dir, DeltaMag, OutputFlags, QueryFilterData, Filter, *QueryCallback);
				SweepCapture.EndCaptureChaosSweep(HitBuffer);

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Collision/SceneQueryLowLevel.cpp:153

Scope (from outer to inner):

file
namespace    anonymous
function     void RaycastSQCaptureHelper

Source code excerpt:

#if !UE_BUILD_SHIPPING
		float QueryDurationMicro = QueryDurationSeconds * 1000.0 * 1000.0;
		if (((!!SerializeSQs && QueryDurationMicro > SerializeSQs)) && IsInGameThread())
		{
			// Measure average time of query over multiple samples to reduce fluke from context switches or that kind of thing.
			uint32 Cycles = 0.0;
			const uint32 SampleCount = SerializeSQSamples;
			for (uint32 Samples = 0; Samples < SampleCount; ++Samples)
			{

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Collision/SceneQueryLowLevel.cpp:171

Scope (from outer to inner):

file
namespace    anonymous
function     void RaycastSQCaptureHelper

Source code excerpt:

			float AvgMicroseconds = (Milliseconds * 1000) / SampleCount;

			if (AvgMicroseconds > SerializeSQs)
			{
				FPhysTestSerializer Serializer;
				Serializer.SetPhysicsData(*Scene.GetSolver()->GetEvolution());
				FSQCapture& RaycastCapture = Serializer.CaptureSQ();
				RaycastCapture.StartCaptureChaosRaycast(*Scene.GetSolver()->GetEvolution(), Start, Dir, DeltaMag, OutputFlags, QueryFilterData, Filter, *QueryCallback);
				RaycastCapture.EndCaptureChaosRaycast(HitBuffer);

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Collision/SceneQueryLowLevel.cpp:190

Scope (from outer to inner):

file
namespace    anonymous
function     void OverlapSQCaptureHelper

Source code excerpt:

#if !UE_BUILD_SHIPPING
		float QueryDurationMicro = QueryDurationSeconds * 1000.0 * 1000.0;
		if (((!!SerializeSQs && QueryDurationMicro > SerializeSQs)) && IsInGameThread())
		{
			// Measure average time of query over multiple samples to reduce fluke from context switches or that kind of thing.
			uint32 Cycles = 0.0;
			const uint32 SampleCount = SerializeSQSamples;
			for (uint32 Samples = 0; Samples < SampleCount; ++Samples)
			{

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Collision/SceneQueryLowLevel.cpp:208

Scope (from outer to inner):

file
namespace    anonymous
function     void OverlapSQCaptureHelper

Source code excerpt:

			float AvgMicroseconds = (Milliseconds * 1000) / SampleCount;

			if (AvgMicroseconds > SerializeSQs)
			{
				FPhysTestSerializer Serializer;
				Serializer.SetPhysicsData(*Scene.GetSolver()->GetEvolution());
				FSQCapture& OverlapCapture = Serializer.CaptureSQ();
				OverlapCapture.StartCaptureChaosOverlap(*Scene.GetSolver()->GetEvolution(), QueryGeom, GeomPose, QueryFilterData, Filter, *QueryCallback);
				OverlapCapture.EndCaptureChaosOverlap(HitBuffer);

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Collision/SceneQueryLowLevel.cpp:274

Scope (from outer to inner):

file
function     void LowLevelRaycast

Source code excerpt:

		if constexpr (bGTData && TTraits::IsPhysScene())
		{
			if (!!SerializeSQs && !!EnableRaycastSQCapture)
			{
				RaycastSQCaptureHelper(Time, SQAccelerator, Container, Start, Dir, DeltaMag, HitBuffer, OutputFlags, QueryFlags, Filter, QueryFilterData, QueryCallback, DebugParams);
			}
		}
	}
}

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Collision/SceneQueryLowLevel.cpp:308

Scope (from outer to inner):

file
function     void LowLevelSweep

Source code excerpt:

			if constexpr (bGTData && FAccelerationContainerTraits<TAccelContainer, bGTData>::IsPhysScene())
			{
				if(!!SerializeSQs && !!EnableSweepSQCapture)
				{
					SweepSQCaptureHelper(Time, SQAccelerator, Container, QueryGeom, StartTM, Dir, DeltaMag, HitBuffer, OutputFlags, QueryFlags, Filter, QueryFilterData, QueryCallback, DebugParams);
				}
			}
		}
	}

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Collision/SceneQueryLowLevel.cpp:342

Scope (from outer to inner):

file
function     void LowLevelOverlap

Source code excerpt:

		if constexpr(bGTData && FAccelerationContainerTraits<TAccelContainer, bGTData>::IsPhysScene())
		{
			if(!!SerializeSQs && !!EnableOverlapSQCapture)
			{
				OverlapSQCaptureHelper(Time, SQAccelerator, Container, QueryGeom, GeomPose, HitBuffer, QueryFlags, Filter, QueryFilterData, QueryCallback, DebugParams);
			}
		}
	}
}