unreal: tile generation at BackgroundLow priority (L97); FI arrival world-tick max 93 -> 21 ms

The 50-90 ms UWorld::Tick spikes were the TG_EndPhysics barrier waiting for physics-scene
completion while all 8 TaskGraph workers ran BackgroundHigh tile tasks. Near and horizon tile
generation now run at ETaskPriority::BackgroundLow (helper lanes background); queue depth and
the 8 workers are kept. FI: near set 2.11 s (10 runs), max UWorld::Tick 21 ms, max
EndPhysics->PostPhysics gap 16 ms; SW: 1.32 s, 11 ms. A hard 7-task cap removed spikes but
doubled settle time. World unchanged. Fast tier PASS; Linux UE host builds.
R44 notes (exact passage restructuring: only a full-composer z-column SIMD kernel could
plausibly reach 3x; smaller exact pieces ~1.1-1.2x each) attached.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-28 12:03:52 +01:00
1 parent 94f9aa6790
commit 9d9504ae4e
4 files changed
+600 -14

No files matched your search

+107 -14
View File
@@ -82,6 +82,22 @@
#include <atomic>
#include <unordered_set>
static int32 GVoxelForgeCoreParallelForBackgroundPriority = 1;
static FAutoConsoleVariableRef CVarVoxelForgeCoreParallelForBackgroundPriority(
TEXT("voxel.CoreParallelForBackgroundPriority"),
GVoxelForgeCoreParallelForBackgroundPriority,
TEXT("Run Core tile helper lanes at background priority so their work yields to frame tasks; 0 restores inherited ParallelFor priority."));
static int32 GVoxelForgeStreamingTileBackgroundLow = 1;
static FAutoConsoleVariableRef CVarVoxelForgeStreamingTileBackgroundLow(
TEXT("voxel.StreamingTileBackgroundLow"),
GVoxelForgeStreamingTileBackgroundLow,
TEXT("Run near and horizon tile generation at BackgroundLow so higher-priority engine work is scheduled first."));
static int32 GVoxelForgeStreamingTileBackgroundNormal = 0;
static FAutoConsoleVariableRef CVarVoxelForgeStreamingTileBackgroundNormal(
TEXT("voxel.StreamingTileBackgroundNormal"),
GVoxelForgeStreamingTileBackgroundNormal,
TEXT("Run near and horizon tile generation at BackgroundNormal; BackgroundLow takes precedence."));
static FORCEINLINE int32 VF_ClipLevelScale(int32 Level)
{
const uint32 SafeLevel = static_cast<uint32>(FMath::Clamp(Level, 0, 8));
@@ -119,6 +135,10 @@ public:
// Each ParallelFor lane is a stable Core worker index. Unreal owns the actual threads;
// callbacks keep claiming fixed-size batches until every input index has run once.
const EParallelForFlags ParallelFlags =
GVoxelForgeCoreParallelForBackgroundPriority != 0
? EParallelForFlags::BackgroundPriority
: EParallelForFlags::None;
ParallelFor(static_cast<int32>(WorkerCount), [&](int32 Lane)
{
const double Started = FPlatformTime::Seconds();
@@ -134,7 +154,7 @@ public:
}
ActiveSeconds[static_cast<std::size_t>(Lane)] =
FPlatformTime::Seconds() - Started;
});
}, ParallelFlags);
double TotalSeconds = 0.0;
for (std::size_t Lane = 0; Lane < WorkerCount; ++Lane)
@@ -260,6 +280,12 @@ namespace
GVoxelForgeStreamingBackgroundWorkerCap,
TEXT("Size tile admission slots to the TaskGraph background workers used by tile tasks; 0 restores the logical-core cap."));
int32 GVoxelForgeStreamingBackgroundWorkerReserve = 0;
FAutoConsoleVariableRef CVarVoxelForgeStreamingBackgroundWorkerReserve(
TEXT("voxel.StreamingBackgroundWorkerReserve"),
GVoxelForgeStreamingBackgroundWorkerReserve,
TEXT("Keep this many TaskGraph background workers outside tile admission when background worker capping is enabled."));
int32 GVoxelForgeCoreColumnCacheDirectMapped = 0;
FAutoConsoleVariableRef CVarVoxelForgeCoreColumnCacheDirectMapped(
TEXT("voxel.CoreColumnCacheDirectMapped"),
@@ -2121,6 +2147,13 @@ void AVoxelWorld::BeginPlay()
int32 CommandLineStreamingResultBacklogCap = GVoxelForgeStreamingResultBacklogCap;
int32 CommandLineStreamingReadyQueueDepth = GVoxelForgeStreamingReadyQueueDepth;
int32 CommandLineStreamingBackgroundWorkerCap = GVoxelForgeStreamingBackgroundWorkerCap;
int32 CommandLineStreamingBackgroundWorkerReserve =
GVoxelForgeStreamingBackgroundWorkerReserve;
int32 CommandLineCoreParallelForBackgroundPriority =
GVoxelForgeCoreParallelForBackgroundPriority;
int32 CommandLineStreamingTileBackgroundLow = GVoxelForgeStreamingTileBackgroundLow;
int32 CommandLineStreamingTileBackgroundNormal = GVoxelForgeStreamingTileBackgroundNormal;
int32 CommandLineTestLogTickFunctions = 0;
int32 CommandLineCoreColumnCacheDirectMapped = GVoxelForgeCoreColumnCacheDirectMapped;
int32 CommandLineCoreMCGradientMemoization = GVoxelForgeCoreMCGradientMemoization;
int32 CommandLineStep1GenerationCap = GVoxelForgeStep1GenerationCap;
@@ -2229,6 +2262,44 @@ void AVoxelWorld::BeginPlay()
GVoxelForgeStreamingBackgroundWorkerCap =
CommandLineStreamingBackgroundWorkerCap != 0 ? 1 : 0;
}
if (FParse::Value(FCommandLine::Get(), TEXT("voxel.StreamingBackgroundWorkerReserve="),
CommandLineStreamingBackgroundWorkerReserve))
{
GVoxelForgeStreamingBackgroundWorkerReserve =
FMath::Max(0, CommandLineStreamingBackgroundWorkerReserve);
}
if (FParse::Value(FCommandLine::Get(), TEXT("voxel.CoreParallelForBackgroundPriority="),
CommandLineCoreParallelForBackgroundPriority))
{
GVoxelForgeCoreParallelForBackgroundPriority =
CommandLineCoreParallelForBackgroundPriority != 0 ? 1 : 0;
}
if (FParse::Value(FCommandLine::Get(), TEXT("voxel.StreamingTileBackgroundLow="),
CommandLineStreamingTileBackgroundLow))
{
GVoxelForgeStreamingTileBackgroundLow =
CommandLineStreamingTileBackgroundLow != 0 ? 1 : 0;
}
if (FParse::Value(FCommandLine::Get(), TEXT("voxel.StreamingTileBackgroundNormal="),
CommandLineStreamingTileBackgroundNormal))
{
GVoxelForgeStreamingTileBackgroundNormal =
CommandLineStreamingTileBackgroundNormal != 0 ? 1 : 0;
}
if (FParse::Value(FCommandLine::Get(), TEXT("voxel.TestLogTickFunctions="),
CommandLineTestLogTickFunctions)
&& CommandLineTestLogTickFunctions != 0)
{
if (IConsoleVariable* LogTicks = IConsoleManager::Get().FindConsoleVariable(TEXT("tick.LogTicks")))
{
LogTicks->Set(1, ECVF_SetByCode);
}
if (IConsoleVariable* ShowPrerequisites =
IConsoleManager::Get().FindConsoleVariable(TEXT("tick.ShowPrerequistes")))
{
ShowPrerequisites->Set(0, ECVF_SetByCode);
}
}
if (FParse::Value(FCommandLine::Get(), TEXT("voxel.CoreColumnCacheDirectMapped="),
CommandLineCoreColumnCacheDirectMapped))
{
@@ -2659,13 +2730,15 @@ void AVoxelWorld::BeginPlay()
"\"taskgraph_background_threads\":%d,\"global_queued_thread_pool_threads\":%d,"
"\"step1_cook_pool_threads\":%d,\"ready_queue_depth_cvar\":%d,"
"\"ready_queue_depth\":%d,"
"\"near_priority\":\"BackgroundHigh\","
"\"horizon_priority\":\"BackgroundNormal\","
"\"near_priority\":\"%s\","
"\"horizon_priority\":\"%s\","
"\"streaming_coarse_first\":%d,\"streaming_dynamic_near_reserve\":%d,"
"\"streaming_legacy_pending_result_cap\":%d,"
"\"streaming_collision_lookahead\":%d,\"core_region_concurrent_admission\":%d,"
"\"collision_gate\":%d,"
"\"streaming_result_backlog_cap\":%d,\"streaming_startup_apply_boost\":%d,"
"\"streaming_background_worker_reserve\":%d,\"core_parallel_for_background_priority\":%d,"
"\"streaming_tile_background_low\":%d,\"streaming_tile_background_normal\":%d,"
"\"core_column_cache_direct_mapped\":%d,"
"\"core_mc_gradient_memoization\":%d"),
FPlatformMisc::NumberOfCoresIncludingHyperthreads(), GetMaxConcurrentStreamingTasks(),
@@ -2676,17 +2749,26 @@ void AVoxelWorld::BeginPlay()
TaskGraph.GetNumBackgroundThreads(), GThreadPool ? GThreadPool->GetNumThreads() : 0,
GVoxelForgeStep1CoreCookPool.Pool ? GVoxelForgeStep1CoreCookPool.Pool->GetNumThreads() : 0,
GVoxelForgeStreamingReadyQueueDepth, QueueDepth,
GVoxelForgeStreamingTileBackgroundLow ? TEXT("BackgroundLow")
: (GVoxelForgeStreamingTileBackgroundNormal ? TEXT("BackgroundNormal")
: TEXT("BackgroundHigh")),
GVoxelForgeStreamingTileBackgroundLow ? TEXT("BackgroundLow") : TEXT("BackgroundNormal"),
GVoxelForgeStreamingCoarseFirst, GVoxelForgeStreamingDynamicNearReserve,
GVoxelForgeStreamingLegacyPendingResultCap,
GVoxelForgeStreamingCollisionLookahead, GVoxelForgeCoreRegionConcurrentAdmission,
GVoxelForgeCollisionGate,
GVoxelForgeStreamingResultBacklogCap, GVoxelForgeStreamingStartupApplyBoost,
GVoxelForgeStreamingBackgroundWorkerReserve,
GVoxelForgeCoreParallelForBackgroundPriority,
GVoxelForgeStreamingTileBackgroundLow,
GVoxelForgeStreamingTileBackgroundNormal,
GVoxelForgeCoreColumnCacheDirectMapped,
GVoxelForgeCoreMCGradientMemoization));
VoxelForgeStartupTrace::RecordEvent(TEXT("streaming_worker_cap_readback"), FString::Printf(
TEXT("\"streaming_background_worker_cap\":%d,\"background_worker_threads\":%d,"
"\"effective_tile_slots\":%d"),
TEXT("\"streaming_background_worker_cap\":%d,\"background_worker_reserve\":%d,"
"\"background_worker_threads\":%d,\"effective_tile_slots\":%d"),
GVoxelForgeStreamingBackgroundWorkerCap,
GVoxelForgeStreamingBackgroundWorkerReserve,
TaskGraph.GetNumBackgroundThreads(), GetMaxConcurrentStreamingTasks()));
}
@@ -7626,6 +7708,7 @@ void AVoxelWorld::Tick(float DeltaTime)
"\"collision_probe_ms\":%s,\"visibility_reconcile_ms\":%s,"
"\"visible_apply_probe_ms\":%s,\"lod0_ready_ms\":%s,"
"\"modification_ms\":%s,\"lifecycle_audit_ms\":%s,"
"\"active_generation_workers\":%d,\"active_tile_tasks\":%d,"
"\"trace_json_ms\":%s,\"trace_archive_serialize_ms\":%s"),
static_cast<unsigned long long>(GFrameCounter),
*FString::SanitizeFloat(FPlatformTime::ToSeconds64(
@@ -7642,6 +7725,8 @@ void AVoxelWorld::Tick(float DeltaTime)
*FString::SanitizeFloat(FPlatformTime::ToSeconds64(LOD0ReadyCycles) * 1000.0),
*FString::SanitizeFloat(FPlatformTime::ToSeconds64(ModificationCycles) * 1000.0),
*FString::SanitizeFloat(FPlatformTime::ToSeconds64(LifecycleAuditCycles) * 1000.0),
ActiveGenerationWorkerCount.load(std::memory_order_relaxed),
ActiveTileTaskCount.load(std::memory_order_relaxed),
*FString::SanitizeFloat(TraceWriteMetrics.JsonWriteMilliseconds),
*FString::SanitizeFloat(TraceWriteMetrics.ArchiveSerializeMilliseconds)));
}
@@ -11974,7 +12059,11 @@ int32 AVoxelWorld::GetMaxConcurrentStreamingTasks() const
return TaskCap;
}
const int32 BackgroundWorkers = FTaskGraphInterface::Get().GetNumBackgroundThreads();
return BackgroundWorkers > 0 ? FMath::Min(TaskCap, BackgroundWorkers) : TaskCap;
if (BackgroundWorkers <= 0) return TaskCap;
const int32 Reserve = FMath::Clamp(
GVoxelForgeStreamingBackgroundWorkerReserve, 0, FMath::Max(0, BackgroundWorkers - 1));
const int32 AvailableWorkers = FMath::Max(1, BackgroundWorkers - Reserve);
return FMath::Min(TaskCap, AvailableWorkers);
}
int32 AVoxelWorld::GetActiveGenerationTaskCount() const
@@ -13673,11 +13762,13 @@ void AVoxelWorld::LoadTile(const FVoxelTileKey& Tile, EVoxelTileWorkPriority Wor
ActiveTaskCount.fetch_add(1, std::memory_order_relaxed);
ActiveTileTaskCount.fetch_add(1, std::memory_order_relaxed);
// BackgroundNormal yields to foreground work; near tasks stay ahead at BackgroundHigh.
// BackgroundNormal cede la priorite au premier plan ; les tuiles proches restent prioritaires en BackgroundHigh.
const UE::Tasks::ETaskPriority TaskPriority = bNearPriority
? UE::Tasks::ETaskPriority::BackgroundHigh
: UE::Tasks::ETaskPriority::BackgroundNormal;
// The VR setting puts every tile task at BackgroundLow; 0 keeps near/horizon priorities.
// Le reglage VR place chaque tuile en BackgroundLow ; 0 conserve les priorites proches/horizon.
const UE::Tasks::ETaskPriority TaskPriority = GVoxelForgeStreamingTileBackgroundLow
? UE::Tasks::ETaskPriority::BackgroundLow
: (GVoxelForgeStreamingTileBackgroundNormal || !bNearPriority
? UE::Tasks::ETaskPriority::BackgroundNormal
: UE::Tasks::ETaskPriority::BackgroundHigh);
UE::Tasks::Launch(TEXT("ChunkGen"), [this, Tile, OriginVoxels, Step, Cells, TaskEpoch,
bWantCapture, bWantPreEditDensityGrid, bWantSurfaceWitnesses,
BandVoxLo, BandVoxHi, BandChunkLo, BandChunkHi,
@@ -13918,9 +14009,11 @@ void AVoxelWorld::LoadCoreTile(const FVoxelTileKey& Tile, EVoxelTileWorkPriority
const bool bCaptureHashes = bCaptureVoxelForgeCoreHashesForValidation;
const bool bLegacyDirectMappedColumnCache=GVoxelForgeCoreColumnCacheDirectMapped!=0;
const bool bMemoizeCoreMCGradients=GVoxelForgeCoreMCGradientMemoization!=0;
const UE::Tasks::ETaskPriority TaskPriority = bNearPriority
? UE::Tasks::ETaskPriority::BackgroundHigh
: UE::Tasks::ETaskPriority::BackgroundNormal;
const UE::Tasks::ETaskPriority TaskPriority = GVoxelForgeStreamingTileBackgroundLow
? UE::Tasks::ETaskPriority::BackgroundLow
: (GVoxelForgeStreamingTileBackgroundNormal || !bNearPriority
? UE::Tasks::ETaskPriority::BackgroundNormal
: UE::Tasks::ETaskPriority::BackgroundHigh);
UE::Tasks::Launch(TEXT("VoxelForgeCoreTile"),
[this, State, Cancellation, Tile, WorkPriority, TaskEpoch, TaskDesiredEpoch,
TaskModificationEpoch, RequestStartCycles, RequestOrdinal, bResidentAtRequest,