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,
@@ -0,0 +1,35 @@
## Ranked findings
**[INFERENCE] No measured result establishes an exact 3× speed-up. The plausible route is a z-column evaluator that combines prepared segment data, full-reach candidate dispatch, and bit-preserving SIMD across lanes.** Current code offers exact work to reuse within a column, but the 3× target requires accelerating most of the composition work. Falsifier for this route: an implementation either differs on any per-sample output bit or fails to reach 3× with its build and fallback costs included.
**[MEASURED]** At W12, L88 reports passage-on versus passage-off readiness of 2.273−0.812 = **1.461 s for FI**, and 2.253−0.851 = **1.402 s for TN**. A 3× cut would put the passage work at about 0.487/0.467 s and imply roughly 1.299/1.318 s total readiness, before added setup cost. The ablation intentionally fails route walkability, so those totals are projections, not valid finished-world targets. [Linux88 report:10](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux88/REPORT.md:10) [Linux88 report:14](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux88/REPORT.md:14). Falsifier: a replay using the same W12 protocol produces different medians or ablation behavior.
1. **[INFERENCE] Exact z-column SIMD across the complete composer — highest potential; large effort; 3× is possible in principle, unmeasured.** In the carve callback, fixed segment data costs 9 of the 34 basic floating-point operations: 3 subtractions, 3 multiplies, 2 adds for `lengthSq`, and one radius-delta subtraction. For a fixed XY column, the projection’s XY numerator costs another 5 operations per segment; sharing it across an eight-sample run saves 35 operations over those eight lanes. That is **13.4/34, or 39% of the basic operation count per lane on average**. The 34 count excludes branches, loads, optional Catmull–Rom work, and the separate player-capsule path. The code computes clamped `t` independently at each Z, then updates the center, radius, distance, and stable `(scanPhase,index)` tie-break; four scan phases feed that callback. [Carve callback and tie-break](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/ShapeWorldInternal.h:1800) [Projection and clamp](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/ShapeWorldInternal.h:1815) [Distance and tie-break](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/ShapeWorldInternal.h:1865) [Four search phases](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/ShapeWorldInternal.h:1880).
**[CODE]** The XY numerator can be reused exactly if it keeps the original operation grouping. The clamped projection, winning segment, reach check, and final composition cannot be reused as a column-wide value: each lane’s Z and evolving `composed` value matter. The current z-run path batches base-field work in groups of up to eight, while composition still appears at scalar call sites. [Z-run batching](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/ShapeWorldInternal.h:12834) [Scalar composition call](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/ShapeWorldInternal.h:7223). Falsifier: changing the operation grouping, lane casts, division, square root, or tie resolution changes any lane’s output bits.
**[MEASURED → INFERENCE]** L83’s PC attribution puts carve distance at 41.5% FI / 39.2% TN of passage-plus-support samples, support at 18.2% / 17.5%, and relief at 21.3% / 23.7%. A 4× kernel needs to cover at least 88.9% of total work to achieve 3× by itself; the profiler shares are sample attribution, not wall-time timers. The counted carve arithmetic alone does not cover that share, so this approach needs to speed up candidate traversal, relief, and support as well. [L83 FI attribution](/home/jahni/VoxelM/Plugins/VoxelForge/Saved/Linux/l83/census/analysis.json:219) [L83 TN attribution](/home/jahni/VoxelM/Plugins/VoxelForge/Saved/Linux/l83/census/analysis.json:316). Falsifier: end-to-end profiling shows the accelerated kernel covers too little time, or the cold W12 result misses 3×.
2. **[INFERENCE] Full-reach prepared lists with flat, ordered evaluation — theoretical ceiling about 1.35× from traversal removal alone; large effort; possible regression.** L83 assigns the recursive nearest-node and potential-within symbols 9,097 of 33,687 FI passage-plus-support ticks (27.0%) and 8,456 of 32,728 TN ticks (25.8%). Erasing all that attributed time with zero replacement cost gives optimistic ceilings of **1.37× FI / 1.35× TN**; a flat loop still evaluates candidates, so actual gain would be lower. [L83 FI symbols](/home/jahni/VoxelM/Plugins/VoxelForge/Saved/Linux/l83/census/analysis.json:239) [L83 TN symbols](/home/jahni/VoxelM/Plugins/VoxelForge/Saved/Linux/l83/census/analysis.json:337). Falsifier: an implementation’s measured traversal time is too small to support that ceiling, or candidate evaluation costs exceed the removed traversal cost.
**[MEASURED]** L90’s 10 m census has active carve p90 13, tread p90 4, and clearance p90 2; weighted fallback is 18.28%, all from the reach limit. It emitted 54,324 bricks and about 12.1 MiB of references, but it is census instrumentation, not a production evaluator, and no full-reach list counts exist. [L90 distributions](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux90/REPORT.md:7) [L90 fallback](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux90/REPORT.md:14) [L90 status](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux90/REPORT.md:31). Falsifier: a full-reach census shows low candidate counts and negligible fallback cost—or, in the other direction, shows list inflation erases traversal savings.
**[CODE/INFERENCE]** Full reach matters: at 0.25 m per voxel, the source-aware rule `−source·Q + 0.24 m` reaches **32.24 m** for a −128-voxel input. A fixed candidate superset could also evaluate segments the current dynamic-best BVH prunes. The current node bounds use endpoint AABBs, while the callback can replace the chord center with a Catmull–Rom value; preserving output therefore requires proving extra candidates harmless or retaining equivalent per-lane pruning behavior. [Reach rule](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/ShapeWorldInternal.h:1316) [Endpoint bounds](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/ShapeWorldInternal.h:5313) [Catmull–Rom callback](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/ShapeWorldInternal.h:1839). Falsifier: a bitwise comparison shows that the flat list changes a winner or any later composed density.
3. **[INFERENCE] Prepared segment constants and per-column XY terms — likely modest, roughly 1.18–1.20× under a generous linear-time model; low-to-medium effort.** The 9 static and 5 shared operations above are 39% of the counted carve operations. Applying that proportion directly to L83’s carve attribution yields an optimistic total-work estimate of about 1.20× FI / 1.18× TN. This assumes operation-count savings translate proportionally into time; the logs do not establish that. Current passage constants cover passage-level metadata, not these segment values. [Carve operation order](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/ShapeWorldInternal.h:1807) [Passage constants](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/ShapeWorldInternal.h:5521). Falsifier: exact replay shows bit changes, or timings show no gain after build cost. Keep the existing division and expression order; reciprocal substitution or algebraic rewrites can round differently.
4. **[INFERENCE] Share relief interpolation within same-cell z-runs — likely around 1.10× at best under a generous model; medium effort.** Each noise octave performs seven lerps, so wall relief performs 21. In an eight-lane run whose three octave cells stay fixed, broad and mid relief can share six and four intermediate lerps respectively for lanes 2–8: 70 of 168 lerps saved, or 41.7%. The existing cache already reuses lattice corners, but still does per-sample coordinate, hash/key, fade, and interpolation work. [Cached-noise behavior](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/VoxelForgeFieldShared.h:257) [Three wall-relief octaves](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/VoxelForgeFieldShared.h:394). L83 assigns 21.3% FI / 23.7% TN to remaining relief; even the 41.7% lerp reduction maps to only about 1.10× / 1.11× if time scales linearly, and actual gain should be smaller because not all relief work is those lerps. Falsifier: same-cell lanes differ bitwise, or profiling shows cell/hash work dominates and the shared interpolation barely changes time.
5. **[INFERENCE] Reuse support, tread, clearance, and mouth XY work per column — small standalone gain, medium effort.** The support projection and horizontal capsule projection can be shared for fixed XY and a fixed segment, but support ownership can change with Z; vertical capsule distance, density gates, and deferred support still vary per lane. [Support projection](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/ShapeWorldInternal.h:2210) [Support and clearance ordering](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/ShapeWorldInternal.h:2524). L83 attributes 18.2% FI / 17.5% TN of passage-plus-support samples to the support phase, an absolute upper bound of 1.22× / 1.21× if that whole phase vanished; XY reuse covers only part of it. L88 records about 0.97 / 0.99 support visits per passage iteration, while L90’s active tread and clearance p90s are 4 and 2. [Support-phase shares](/home/jahni/VoxelM/Plugins/VoxelForge/Saved/Linux/l83/census/analysis.json:208) [L88 support counters](/home/jahni/VoxelM/Plugins/VoxelForge/Saved/Linux/l88/ceiling-split/profile-summary.json:20) [L90 semantic counts](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux90/REPORT.md:9). Falsifier: exact per-lane support/capsule comparisons fail at helix overlaps, mouths, or bridges, or the reused XY work is too small to move total time.
6. **[INFERENCE] Per-brick mouth/support memoization and true-composed identity proofs — useful as an add-on; no defensible speed estimate yet.** Reuse XY terms and candidate dispatch, not final decisions that depend on Z or evolving `composed`. Existing code already has tile feature flags and density-aware reach checks; a stronger brick proof must cover every lane and prior passage update. [Tile and column guards](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/ShapeWorldInternal.h:1651) [Sequential support restoration](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/ShapeWorldInternal.h:2583). L83’s direct `PassageMayAffectDensity` symbol is only 1.09% FI / 0.76% TN of passage samples, while the logs provide no count of whole bricks that a new composed-bound proof could skip. [L83 FI proof symbol](/home/jahni/VoxelM/Plugins/VoxelForge/Saved/Linux/l83/census/analysis.json:275) [L83 TN proof symbol](/home/jahni/VoxelM/Plugins/VoxelForge/Saved/Linux/l83/census/analysis.json:372). Falsifier: counters show few proven skips or the proof misses a lane whose output changes.
## Builder brief for the top route
- **[INFERENCE] Goal:** Build a full-composer z-column kernel using prepared segment data, per-run candidate unions, and SIMD lanes; include carve, relief, support, tread, mouth, and clearance costs. Include build and fallback time in the cold result. Falsifier: the kernel accelerates carve alone while total cold passage time remains below a 3× improvement.
- **[CODE] Invariants:** Preserve each lane’s sample-coordinate casts, clamped `t`, divide/square-root behavior, Catmull expression, four scan phases, `(scanPhase,index)` tie-break, passage order, source-dependent reach, `std::lerp` and min/max ordering, support deferral, and mouth restoration. Do not cap lists; retain exact fallback for any lane outside the proven set. [Carve and tie rules](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/ShapeWorldInternal.h:1815) [Final carve blend](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/ShapeWorldInternal.h:2163) [Deferred support](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/ShapeWorldInternal.h:2575). Falsifier: any per-sample density bit differs from the current scalar path.
- **[INFERENCE] Evidence bar:** Compare every sampled density bit and the density/mesh/payload/topology hashes on FI/TN LOD0–2. On the same cold W12 protocol, show at least 3× lower passage time with setup and fallback included; report candidate distributions, fallback time, and per-phase wall time. Falsifier: any parity mismatch, or a speed ratio below 3×.
**[MEASURED]** The 4-voxel trilinear cache regressed readiness in L88, L91 reports source floors changed samples and meshes, and L93’s R=4 m reach changed normals by up to 53.193°. Those remain outside the exact-restructuring ranking. [L88 cache result](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux88/REPORT.md:27) [L91 floor result](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux91/REPORT.md:9) [L93 reach result](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux93/REPORT.md:20). Falsifier: a remeasurement shows those reported output changes or regressions were recorded incorrectly.
**[CODE]** This was read-only research; I ran no project code, builds, tests, or benchmarks.
@@ -0,0 +1,35 @@
# Linux L97 — arrival tick stalls
## Stall
**Measured:** FI control runs had 54.1 ms and 93.4 ms `UWorld::Tick` spikes while `AVoxelWorld::Tick` took 1.7 ms and 1.3 ms. Eight tile workers were active. Text `tick.LogTicks` output put 52 ms and 92 ms between releasing `TG_EndPhysics` and `TG_PostPhysics`; the group 3 log names `FEndPhysicsTickFunction`.
**Engine source:** `LevelTick.cpp` blocks on `TG_EndPhysics`. `FEndPhysicsTickFunction` in `PhysLevel.cpp` holds its completion event on `PhysScene->GetCompletionEvents()` and then runs `FinishPhysicsSim`. Thus the measured wait is the EndPhysics barrier waiting for physics-scene completion. **Inferred cause:** near tile tasks at `BackgroundHigh`, plus their helper lanes, delay that completion work when the shared worker pool is full. Lowering helper priority alone did not remove the spikes. The exact Chaos completion task was not available: L96's `.utrace` export failed to start Insights on SDL/UDEV, so L97 used Unreal's text tick logger instead.
## Fix and measurements
Set near and horizon tile generation to `UE::Tasks::ETaskPriority::BackgroundLow`; keep Core `ParallelFor` helper lanes background-prioritized. Keep the existing refill queue (CVar 64, effective depth 32) and all 8 background workers. This changes scheduling only; generation inputs and output are unchanged.
| Configuration | FI: median near-set / max `UWorld::Tick` | SW: median near-set / max `UWorld::Tick` |
|---|---:|---:|
| Existing near-high priorities, 5 runs each | 2.338 s / 93.4 ms | 1.298 s / 11.2 ms |
| Helper lanes background only, 5 each | 2.318 s / 71.9 ms | 1.547 s / 11.1 ms |
| Hard cap 7 tasks, refill queue 0, 5 each | 4.169 s / 7.2 ms | 4.422 s / 10.8 ms |
| All tile tasks `BackgroundNormal`, 5 each | 2.337 s / 240.0 ms | 1.301 s / 13.3 ms |
| **Selected: all tile tasks `BackgroundLow`, 10 FI / 5 SW** | **2.109 s / 21.0 ms** | **1.316 s / 11.0 ms** |
The selected FI near-set range was 2.075–2.611 s (three of ten runs exceeded 2.3 s); SW was 1.285–1.323 s. In the selected runs, the largest EndPhysics-to-PostPhysics gap was 16 ms FI and 7 ms SW. A one-worker reserve with CVar depth 64 (effective depth 28) still ran 8 workers and reached 107.9 ms FI; setting the queue to zero enforced a true 7-task cap but caused 4.2–4.4 s settle times. The selected configuration's enclosing harness interval peaked at 37.0 ms, with 16.0 ms outside `UWorld::Tick`; the largest `UWorld::Tick` was 21.0 ms.
Fast tier: **PASS**, 269 passing checks and 5 diagnostic-only baseline comparisons. Final Linux UE build passed with `-NoUBA -MaxParallelActions=4`. Logs and per-run summaries are under `Saved/Linux/l97/`.
## Files
- `Source/VoxelForge/Private/VoxelWorld.cpp`
- `Standalone/Research/WorldAssemblerM3/Linux97/RunL97UnrealArrival.py`
- Engine references only (not modified): `Engine/Source/Runtime/Engine/Private/LevelTick.cpp`, `Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysLevel.cpp`, `Engine/Source/Runtime/Engine/Private/TickTaskManager.cpp`.
## Failed attempts
- One early repeat requested reserve 0/helper priority off, but CVar startup readback used defaults; excluded. A `--phase diagnostic` invocation was invalid and rerun with `probe`.
- The first fast-tier attempt used the stale default `l42` executable. Rebuilt an L97 Clang headless binary and reran successfully.
- No L97 `.utrace` decode; Insights export had the SDL/UDEV startup failure recorded in L96. No installs, commits, pushes, or stashes.
@@ -0,0 +1,423 @@
#!/usr/bin/env python3
"""Run one pinned null-RHI SW/FI arrival for Linux 97."""
from __future__ import annotations
import argparse
from collections import Counter
import json
import re
import subprocess
import time
from pathlib import Path
ROOT = Path(__file__).resolve().parents[4]
HOST = Path("/home/jahni/VFHost")
HOST_PLUGIN_SAVED = HOST / "Plugins/VoxelForge/Saved/Linux/l97"
HOST_SAVED = HOST / "Saved/Linux/l97"
EDITOR = Path("/home/jahni/UnrealEngine/Engine/Binaries/Linux/UnrealEditor-Cmd")
OUT = ROOT / "Saved/Linux/l97/unreal-arrival"
SPAWNS_M = {
"FI": (25.8369140625, 3.19921875, -737.0),
"SW": (25.8369140625, 3.19921875, -200.0),
}
MOVE_START_S = 20.0
MOVE_DURATION_S = 12.0
EXIT_S = MOVE_START_S + MOVE_DURATION_S + 5.0
def read_events(path: Path) -> list[dict]:
events = []
if path.is_file():
for line in path.read_text(encoding="utf-8", errors="replace").splitlines():
if line.startswith("{"):
try:
events.append(json.loads(line))
except json.JSONDecodeError:
pass
return events
def percentile(values: list[float], fraction: float) -> float | None:
if not values:
return None
ordered = sorted(values)
return ordered[min(len(ordered) - 1, int(round((len(ordered) - 1) * fraction)))]
def run(stratum: str, repeat: int, phase: str, ready_depth: int,
background_cap: int, worker_reserve: int, helper_background: int,
tile_background_low: int, tile_background_normal: int, startup_boost: int,
tick_logs: bool, insights: bool) -> dict:
label = (f"{phase}-{stratum.lower()}-rd{ready_depth}-bg{background_cap}"
f"-reserve{worker_reserve}-helperbg{helper_background}"
f"-tilelow{tile_background_low}-tilenormal{tile_background_normal}"
f"-ticklog{int(tick_logs)}"
f"-boost{startup_boost}-{repeat}")
trace = OUT / f"{label}.trace.jsonl"
utrace = OUT / f"{label}.utrace"
abslog = OUT / f"{label}.log"
stdout = OUT / f"{label}.stdout.log"
output = HOST_PLUGIN_SAVED / "output" / label
userdir = HOST_SAVED / "user" / label
zendata = HOST_SAVED / "zen" / label
ddc = HOST_SAVED / "DDC"
for directory in (OUT, output, userdir, zendata, ddc):
directory.mkdir(parents=True, exist_ok=True)
trace.unlink(missing_ok=True)
utrace.unlink(missing_ok=True)
spawn_cm = ",".join(f"{value * 100.0:.3f}" for value in SPAWNS_M[stratum])
command = [
str(EDITOR), str(HOST / "VFHost.uproject"), "-nullrhi", "-unattended",
"-nop4", "-nosplash", "-NoSound", "-corelimit=12", "-NoZenAutoLaunch",
"-notraceserver", "-nocrashreports", "-DisablePlugins=AndroidFileServer",
"-ddc=NoZenLocalFallback", f"-userdir={userdir}", f"-ZenDataPath={zendata}",
f"-LocalDataCachePath={ddc}", "-run=VoxelForgeExplore", "-seed=0",
"-archetype=TunnelNetwork", f"-slot={1 if stratum == 'FI' else 0}",
"-modes=export", "-gameconfig=1", "-coreworldtest=1",
"-ownerfourstrateplan=1", "-corevoxelsizecm=25", "-coreislandtest=0",
"-corefallbacktest=0", "-coreofftest=0", "-coreplantest=0",
"-settingsref=/Game/VoxelForge/DA_Settings.DA_Settings", "-corehybridmesher=0",
f"-out={output}", "-voxel.StreamingCoarseFirst=1",
"-voxel.StreamingDynamicNearReserve=1",
"-voxel.StreamingLegacyPendingResultCap=0",
"-voxel.CoreRegionConcurrentAdmission=1",
"-voxel.StreamingResultBacklogCap=256",
f"-voxel.StreamingReadyQueueDepth={ready_depth}",
f"-voxel.StreamingBackgroundWorkerCap={background_cap}",
f"-voxel.StreamingBackgroundWorkerReserve={worker_reserve}",
f"-voxel.CoreParallelForBackgroundPriority={helper_background}",
f"-voxel.StreamingTileBackgroundLow={tile_background_low}",
f"-voxel.StreamingTileBackgroundNormal={tile_background_normal}",
f"-voxel.TestLogTickFunctions={int(tick_logs)}",
"-voxel.CoreColumnCacheDirectMapped=0", "-voxel.CoreMCGradientMemoization=1",
"-voxel.StreamingCollisionLookahead=1",
f"-voxel.StreamingStartupApplyBoost={startup_boost}",
"-voxel.TestMove=1", "-voxel.TestMoveSpeedCmPerSecond=140.0",
f"-voxel.TestMoveStartSeconds={MOVE_START_S:.1f}",
f"-voxel.TestMoveDurationSeconds={MOVE_DURATION_S:.1f}",
f"-voxel.TestExitSeconds={EXIT_S:.1f}", "-voxel.TestMoveDirection=1,0,0",
"-voxel.StreamingSchedulerPolicy=3", "-voxel.TestExitOnSteady=0",
"-coreworldstreamtrace=1", f"-voxel.StartupTraceSpawnCm={spawn_cm}",
"-voxel.StartupTraceUntilEndPlay=1", "-voxel.StartupTraceThroughCrossing=1",
"-voxel.StartupTraceMaxTiles=16384", f"-voxel.StartupTraceFile={trace}",
f"-abslog={abslog}",
]
if insights:
command += ["-trace=cpu,task,frame", "-statnamedevents",
f"-tracefile={utrace}", "-tracefiletrunc"]
wrapped = ["taskset", "-c", "0-11", "timeout", "1740s", *command]
started = time.monotonic()
with stdout.open("w", encoding="utf-8") as stream:
result = subprocess.run(wrapped, cwd=ROOT, stdout=stream,
stderr=subprocess.STDOUT, check=False, timeout=1740)
events = read_events(trace)
worker_backend_config = next(
(e for e in events if e.get("type") == "worker_backend_config"), {})
worker_cap_readback = next(
(e for e in events if e.get("type") == "streaming_worker_cap_readback"), {})
samples = [e for e in events if e.get("type") == "streaming_sample"]
arrival = [e for e in samples if float(e.get("t_s", 0.0)) < MOVE_START_S]
full = next((e for e in arrival
if sum(e.get("desired_by_lod", [0] * 9)[:3]) > 0
and sum(e.get("settled_by_lod", [0] * 9)[:3])
>= sum(e.get("desired_by_lod", [0] * 9)[:3])), None)
first_admission = next((e for e in events if e.get("type") == "scheduler_admission"
and e.get("desired_rebuilt") == 1), None)
request_events = [e for e in events if e.get("type") == "request"]
initial_request_events = [e for e in request_events if e.get("epoch") == 0]
tile_by_ordinal = {e.get("request_ordinal"): e for e in events
if e.get("type") == "tile"}
collision_count = sum(1 for e in events if e.get("type") == "collision_ready"
and e.get("level", 9) <= 2
and full and e.get("t_s", 1e30) <= full["t_s"])
initial_tiles = [tile_by_ordinal[r.get("request_ordinal")] for r in initial_request_events
if full and r.get("t_s", 1e30) <= full["t_s"]
and r.get("request_ordinal") in tile_by_ordinal
and tile_by_ordinal[r["request_ordinal"]].get("level", 9) <= 2]
burst_start_s = float(first_admission["t_s"]) if first_admission else -1.0
burst_end_s = float(full["t_s"]) if full else -1.0
work_by_frame = {int(e.get("frame", -1)): e for e in events
if e.get("type") == "game_thread_work_frame"}
work_values = [e for e in work_by_frame.values()
if burst_start_s <= float(e.get("t_s", -1.0)) <= burst_end_s]
arrival_frame_ids = {int(e.get("frame", -1)) for e in work_values}
scheduler_by_frame = {int(e.get("frame", -1)): e for e in events
if e.get("type") == "scheduler_admission"}
scheduler_values = [e for e in events if e.get("type") == "scheduler_admission"
and burst_start_s <= float(e.get("t_s", -1.0)) <= burst_end_s]
apply_by_frame = {int(e.get("frame", -1)): e for e in events
if e.get("type") == "apply_frame"}
commandlet_tick_by_frame = {int(e.get("frame", -1)): e for e in events
if e.get("type") == "commandlet_world_tick_frame"}
garbage_collect_by_frame = {int(e.get("frame", -1)): e for e in events
if e.get("type") == "garbage_collect"}
# apply_frame N+1 records the interval containing AVoxelWorld::Tick N. Its apply_ms
# belongs to Tick N+1, so use apply_by_frame[N] for the same-tick apply breakdown.
near_intervals = [apply_by_frame[frame + 1] for frame in arrival_frame_ids
if frame + 1 in apply_by_frame]
rmc_by_frame: dict[int, dict[str, float]] = {}
for event in events:
frame = int(event.get("frame", -1))
if event.get("type") != "rmc_submit" or frame not in arrival_frame_ids:
continue
values = rmc_by_frame.setdefault(frame, {
"component_acquire_ms": 0.0,
"create_section_group_ms": 0.0,
"create_sections_ms": 0.0,
"collision_handoff_ms": 0.0,
})
for key in values:
values[key] += float(event.get(key, 0.0))
collision_completion_by_frame: dict[int, float] = {}
for event in events:
frame = int(event.get("frame", -1))
if event.get("type") == "collision_completion" and frame in arrival_frame_ids:
collision_completion_by_frame[frame] = collision_completion_by_frame.get(frame, 0.0) \
+ float(event.get("handler_ms", 0.0))
near_requests = [r for r in request_events if full and r.get("t_s", 1e30) <= full["t_s"]
and r.get("level", 9) <= 2]
initial_lod0_counts = Counter(
tuple(r.get("tile", ())) for r in near_requests if r.get("level") == 0)
repeated_lod0_keys = [
{"tile": list(tile), "requests": count}
for tile, count in sorted(initial_lod0_counts.items()) if count > 1]
initial_scheduler_frames = [e for e in events
if e.get("type") == "scheduler_admission" and full
and e.get("t_s", 1e30) <= full["t_s"]]
worst_interval = max(near_intervals, key=lambda e: float(e.get("frame_ms", 0.0)), default=None)
worst_interval_frame_id = int(worst_interval.get("frame", -1)) if worst_interval else -1
worst_work_frame_id = worst_interval_frame_id - 1
worst_work = work_by_frame.get(worst_work_frame_id, {})
worst_apply = apply_by_frame.get(worst_work_frame_id, {})
worst_scheduler = scheduler_by_frame.get(worst_work_frame_id, {})
worst_rmc = rmc_by_frame.get(worst_work_frame_id, {})
worst_collision_completion_ms = collision_completion_by_frame.get(worst_work_frame_id, 0.0)
rmc_values = [rmc_by_frame.get(frame, {}) for frame in arrival_frame_ids]
apply_values = [apply_by_frame[frame] for frame in arrival_frame_ids
if frame in apply_by_frame]
commandlet_tick_values = [commandlet_tick_by_frame[frame] for frame in arrival_frame_ids
if frame in commandlet_tick_by_frame]
garbage_collect_values = [garbage_collect_by_frame[frame] for frame in arrival_frame_ids
if frame in garbage_collect_by_frame]
def work_stat(name: str, fraction: float | None = None) -> float | None:
values = [float(e.get(name, 0.0)) for e in work_values]
return percentile(values, fraction) if fraction is not None else max(values, default=0.0)
def scheduler_stat(name: str, fraction: float | None = None) -> float | None:
values = [float(e.get(name, 0.0)) for e in scheduler_values]
return percentile(values, fraction) if fraction is not None else max(values, default=0.0)
def rmc_stat(name: str, fraction: float | None = None) -> float | None:
values = [float(e.get(name, 0.0)) for e in rmc_values]
return percentile(values, fraction) if fraction is not None else max(values, default=0.0)
def commandlet_stat(name: str, fraction: float | None = None) -> float | None:
values = [float(e.get(name, 0.0)) for e in commandlet_tick_values]
return percentile(values, fraction) if fraction is not None else max(values, default=0.0)
row = {
"label": label, "stratum": stratum, "repeat": repeat, "phase": phase,
"ready_queue_depth": ready_depth,
"requested_background_worker_cap": background_cap,
"background_worker_cap": worker_cap_readback.get(
"streaming_background_worker_cap", background_cap),
"requested_background_worker_reserve": worker_reserve,
"background_worker_reserve": worker_backend_config.get(
"streaming_background_worker_reserve", worker_cap_readback.get(
"background_worker_reserve", worker_reserve)),
"requested_core_parallel_for_background_priority": helper_background,
"core_parallel_for_background_priority": worker_backend_config.get(
"core_parallel_for_background_priority", helper_background),
"requested_streaming_tile_background_low": tile_background_low,
"streaming_tile_background_low": worker_backend_config.get(
"streaming_tile_background_low", tile_background_low),
"requested_streaming_tile_background_normal": tile_background_normal,
"streaming_tile_background_normal": worker_backend_config.get(
"streaming_tile_background_normal", tile_background_normal),
"effective_tile_slots": worker_backend_config.get("effective_tile_slots"),
"background_worker_threads": worker_backend_config.get("taskgraph_background_threads"),
"startup_apply_boost": startup_boost, "insights": insights,
"engine_tick_logs": tick_logs,
"exit_code": result.returncode,
"wall_s": round(time.monotonic() - started, 3),
"desired_t_s": next((e.get("t_s") for e in events if e.get("type") == "desired_set"), None),
"first_admission_t_s": first_admission.get("t_s") if first_admission else None,
"lod02_full_settled_t_s": full.get("t_s") if full else None,
"near_settle_from_first_admission_s": round(
float(full["t_s"]) - float(first_admission["t_s"]), 4)
if full and first_admission else None,
"desired_by_lod": full.get("desired_by_lod", [])[:3] if full else None,
"settled_by_lod": full.get("settled_by_lod", [])[:3] if full else None,
"near_admitted_tiles": len(near_requests),
"initial_lod0_admissions": sum(initial_lod0_counts.values()),
"repeated_lod0_request_keys_before_settle": repeated_lod0_keys,
"peak_result_backlog_before_settle": max(
(int(e.get("result_backlog", 0)) for e in initial_scheduler_frames), default=0),
"last_admission_t_s": max((e.get("t_s", 0.0) for e in near_requests), default=None),
"near_tile_events": len(initial_tiles),
"near_worker_seconds": round(sum(e.get("worker_task_s", 0.0) for e in initial_tiles), 4),
"near_core_seconds": round(sum(e.get("core_generate_s", 0.0) for e in initial_tiles), 4),
"collision_ready_by_settle": collision_count,
"burst_frame_count": len(near_intervals),
"burst_frame_ms_p95": round(sorted(e.get("frame_ms", 0.0) for e in near_intervals)[
min(len(near_intervals) - 1, int(.95 * (len(near_intervals) - 1)))], 3)
if near_intervals else None,
"burst_frame_ms_max": round(max((e.get("frame_ms", 0.0) for e in near_intervals), default=0.0), 3),
"burst_full_world_tick_ms_p99": round(commandlet_stat("world_tick_ms", .99) or 0.0, 3),
"burst_full_world_tick_ms_max": round(commandlet_stat("world_tick_ms") or 0.0, 3),
"burst_world_pre_actor_ms_p99": round(commandlet_stat("world_pre_actor_ms", .99) or 0.0, 3),
"burst_world_pre_actor_ms_max": round(commandlet_stat("world_pre_actor_ms") or 0.0, 3),
"burst_world_actor_phase_ms_p99": round(commandlet_stat("world_actor_phase_ms", .99) or 0.0, 3),
"burst_world_actor_phase_ms_max": round(commandlet_stat("world_actor_phase_ms") or 0.0, 3),
"burst_world_post_actor_ms_p99": round(commandlet_stat("world_post_actor_ms", .99) or 0.0, 3),
"burst_world_post_actor_ms_max": round(commandlet_stat("world_post_actor_ms") or 0.0, 3),
"burst_commandlet_readiness_check_ms_max": round(
commandlet_stat("readiness_check_ms") or 0.0, 3),
"burst_commandlet_sleep_ms_p99": round(commandlet_stat("sleep_ms", .99) or 0.0, 3),
"burst_commandlet_sleep_ms_max": round(commandlet_stat("sleep_ms") or 0.0, 3),
"burst_commandlet_loop_ms_max": round(commandlet_stat("loop_ms") or 0.0, 3),
"burst_gc_count": len(garbage_collect_values),
"burst_gc_duration_ms_max": round(max(
(float(e.get("duration_ms", 0.0)) for e in garbage_collect_values), default=0.0), 3),
"burst_max_meshes_per_frame": max((e.get("meshes_applied", 0) for e in apply_values), default=0),
"burst_max_apply_ms": round(max((e.get("apply_ms", 0.0) for e in apply_values), default=0.0), 3),
"burst_max_admit_per_frame": max((sum(e.get("submitted_by_lod", [0] * 9)[:3])
for e in scheduler_values), default=0),
"burst_frame_timing_count": len(work_values),
"burst_active_generation_workers_p95": round(work_stat("active_generation_workers", .95) or 0.0, 3),
"burst_active_generation_workers_max": round(work_stat("active_generation_workers") or 0.0, 3),
"burst_active_tile_tasks_max": round(work_stat("active_tile_tasks") or 0.0, 3),
"burst_world_tick_ms_p99": round(work_stat("tick_ms", .99) or 0.0, 3),
"burst_world_tick_ms_max": round(work_stat("tick_ms") or 0.0, 3),
"burst_update_chunks_ms_p99": round(work_stat("update_chunks_ms", .99) or 0.0, 3),
"burst_update_chunks_ms_max": round(work_stat("update_chunks_ms") or 0.0, 3),
"burst_pending_drain_ms_p99": round(work_stat("pending_drain_ms", .99) or 0.0, 3),
"burst_pending_drain_ms_max": round(work_stat("pending_drain_ms") or 0.0, 3),
"burst_post_apply_callbacks_ms_p99": round(work_stat("post_apply_callbacks_ms", .99) or 0.0, 3),
"burst_post_apply_callbacks_ms_max": round(work_stat("post_apply_callbacks_ms") or 0.0, 3),
"burst_visibility_reconcile_ms_p99": round(work_stat("visibility_reconcile_ms", .99) or 0.0, 3),
"burst_visibility_reconcile_ms_max": round(work_stat("visibility_reconcile_ms") or 0.0, 3),
"burst_collision_probe_ms_max": round(work_stat("collision_probe_ms") or 0.0, 3),
"burst_visible_apply_probe_ms_max": round(work_stat("visible_apply_probe_ms") or 0.0, 3),
"burst_lod0_ready_ms_max": round(work_stat("lod0_ready_ms") or 0.0, 3),
"burst_steady_trace_ms_max": round(work_stat("steady_trace_ms") or 0.0, 3),
"burst_modification_ms_max": round(work_stat("modification_ms") or 0.0, 3),
"burst_lifecycle_audit_ms_p99": round(work_stat("lifecycle_audit_ms", .99) or 0.0, 3),
"burst_lifecycle_audit_ms_max": round(work_stat("lifecycle_audit_ms") or 0.0, 3),
"burst_collision_gate_ms_p99": round(work_stat("collision_gate_ms", .99) or 0.0, 3),
"burst_collision_gate_ms_max": round(work_stat("collision_gate_ms") or 0.0, 3),
"burst_unload_ms_p99": round(work_stat("unload_ms", .99) or 0.0, 3),
"burst_unload_ms_max": round(work_stat("unload_ms") or 0.0, 3),
"burst_trace_json_ms_p99": round(work_stat("trace_json_ms", .99) or 0.0, 3),
"burst_trace_json_ms_max": round(work_stat("trace_json_ms") or 0.0, 3),
"burst_desired_rebuild_ms_max": round(scheduler_stat("desired_rebuild_ms") or 0.0, 3),
"burst_rmc_create_group_ms_p99": round(rmc_stat("create_section_group_ms", .99) or 0.0, 3),
"burst_rmc_create_group_ms_max": round(rmc_stat("create_section_group_ms") or 0.0, 3),
"burst_rmc_collision_handoff_ms_max": round(rmc_stat("collision_handoff_ms") or 0.0, 3),
"burst_collision_completion_ms_max": round(max(
collision_completion_by_frame.values(), default=0.0), 3),
"worst_frame_breakdown": {
"frame": worst_work_frame_id,
"world_tick_frame": worst_work_frame_id,
"frame_interval_end_frame": worst_interval_frame_id,
"frame_interval_ms": round(float(worst_interval.get("frame_ms", 0.0)), 3)
if worst_interval else None,
"apply_ms": round(float(worst_apply.get("apply_ms", 0.0)), 3)
if worst_apply else None,
"result_drain_ms": round(float(worst_apply.get("drain_ms", 0.0)), 3)
if worst_apply else None,
"outside_world_tick_ms": round(max(0.0, float(worst_interval.get("frame_ms", 0.0))
- float(worst_work.get("tick_ms", 0.0))), 3)
if worst_interval else None,
"outside_full_world_tick_ms": round(max(0.0, float(worst_interval.get("frame_ms", 0.0))
- float(commandlet_tick_by_frame.get(worst_work_frame_id, {}).get("world_tick_ms", 0.0))), 3)
if worst_interval else None,
"full_world_tick_ms": round(float(commandlet_tick_by_frame.get(
worst_work_frame_id, {}).get("world_tick_ms", 0.0)), 3),
"world_pre_actor_ms": round(float(commandlet_tick_by_frame.get(
worst_work_frame_id, {}).get("world_pre_actor_ms", 0.0)), 3),
"world_actor_phase_ms": round(float(commandlet_tick_by_frame.get(
worst_work_frame_id, {}).get("world_actor_phase_ms", 0.0)), 3),
"world_post_actor_ms": round(float(commandlet_tick_by_frame.get(
worst_work_frame_id, {}).get("world_post_actor_ms", 0.0)), 3),
"commandlet_readiness_check_ms": round(float(commandlet_tick_by_frame.get(
worst_work_frame_id, {}).get("readiness_check_ms", 0.0)), 3),
"commandlet_sleep_ms": round(float(commandlet_tick_by_frame.get(
worst_work_frame_id, {}).get("sleep_ms", 0.0)), 3),
"commandlet_loop_ms": round(float(commandlet_tick_by_frame.get(
worst_work_frame_id, {}).get("loop_ms", 0.0)), 3),
"gc_duration_ms": round(float(garbage_collect_by_frame.get(
worst_work_frame_id, {}).get("duration_ms", 0.0)), 3),
"world_tick_ms": round(float(worst_work.get("tick_ms", 0.0)), 3),
"active_generation_workers": int(worst_work.get("active_generation_workers", 0)),
"active_tile_tasks": int(worst_work.get("active_tile_tasks", 0)),
"collision_gate_ms": round(float(worst_work.get("collision_gate_ms", 0.0)), 3),
"update_chunks_ms": round(float(worst_work.get("update_chunks_ms", 0.0)), 3),
"desired_rebuild_ms": round(float(worst_scheduler.get("desired_rebuild_ms", 0.0)), 3),
"pending_drain_ms": round(float(worst_work.get("pending_drain_ms", 0.0)), 3),
"post_apply_callbacks_ms": round(float(worst_work.get("post_apply_callbacks_ms", 0.0)), 3),
"collision_probe_ms": round(float(worst_work.get("collision_probe_ms", 0.0)), 3),
"visibility_reconcile_ms": round(float(worst_work.get("visibility_reconcile_ms", 0.0)), 3),
"visible_apply_probe_ms": round(float(worst_work.get("visible_apply_probe_ms", 0.0)), 3),
"lod0_ready_ms": round(float(worst_work.get("lod0_ready_ms", 0.0)), 3),
"unload_ms": round(float(worst_work.get("unload_ms", 0.0)), 3),
"steady_trace_ms": round(float(worst_work.get("steady_trace_ms", 0.0)), 3),
"modification_ms": round(float(worst_work.get("modification_ms", 0.0)), 3),
"lifecycle_audit_ms": round(float(worst_work.get("lifecycle_audit_ms", 0.0)), 3),
"trace_json_ms": round(float(worst_work.get("trace_json_ms", 0.0)), 3),
"trace_archive_serialize_ms": round(float(
worst_work.get("trace_archive_serialize_ms", 0.0)), 3),
"collision_completion_ms": round(worst_collision_completion_ms, 3),
**{key: round(float(worst_rmc.get(key, 0.0)), 3)
for key in ("component_acquire_ms", "create_section_group_ms",
"create_sections_ms", "collision_handoff_ms")},
},
"trace": str(trace.relative_to(ROOT)), "utrace": str(utrace.relative_to(ROOT)),
"abslog": str(abslog.relative_to(ROOT)), "stdout": str(stdout.relative_to(ROOT)),
}
stdout_text = stdout.read_text(encoding="utf-8", errors="replace")
failure = re.search(r"\[VoxelForgeCoreWorldTest\] failed: ([^\r\n]+)", stdout_text)
if failure:
row["world_test_failure"] = failure.group(1)
with (OUT / "runs.jsonl").open("a", encoding="utf-8") as stream:
stream.write(json.dumps(row, sort_keys=True) + "\n")
(OUT / f"{label}.summary.json").write_text(json.dumps(row, indent=2) + "\n",
encoding="utf-8")
print("[L97UnrealArrival] " + json.dumps(row, sort_keys=True), flush=True)
if result.returncode:
raise SystemExit(f"Unreal commandlet failed: {stdout}; exit={result.returncode}")
if not full or len(arrival) < 8:
raise SystemExit(f"Unreal arrival trace incomplete: {stdout}; exit={result.returncode}")
if insights and (not utrace.is_file() or utrace.stat().st_size < 1024):
raise SystemExit(f"Unreal Insights trace missing or empty: {utrace}")
return row
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--stratum", choices=("FI", "SW"), required=True)
parser.add_argument("--repeat", type=int, default=1)
parser.add_argument("--phase", choices=("probe", "before", "after", "snapshot"), default="probe")
parser.add_argument("--ready-depth", type=int, default=64)
parser.add_argument("--background-cap", type=int, choices=(0, 1), default=1)
parser.add_argument("--worker-reserve", type=int, choices=(0, 1, 2, 3), default=0)
parser.add_argument("--helper-background", type=int, choices=(0, 1), default=1)
parser.add_argument("--tile-background-low", type=int, choices=(0, 1), default=1)
parser.add_argument("--tile-background-normal", type=int, choices=(0, 1), default=0)
parser.add_argument("--startup-boost", type=int, choices=(0, 1), default=1)
parser.add_argument("--tick-logs", action="store_true")
parser.add_argument("--insights", action="store_true")
args = parser.parse_args()
if not EDITOR.is_file():
raise SystemExit(f"missing Unreal commandlet executable: {EDITOR}")
run(args.stratum, args.repeat, args.phase, args.ready_depth,
args.background_cap, args.worker_reserve, args.helper_background,
args.tile_background_low, args.tile_background_normal, args.startup_boost,
args.tick_logs, args.insights)
return 0
if __name__ == "__main__":
raise SystemExit(main())