Files
VoxelForge/Standalone/Research/WorldAssemblerM3/Linux95/REPORT.md
T
Fr0zkaandClaude Opus 5.5 5389abed2e unreal: deeper ready queue keeps the 8 tile workers fed (L95); SW near set 2.37 -> 1.31 s
Unreal per-tile timeline: per-tile Core work is not slower than headless (FI 11.2 vs 16.2 ms
per shared key); the gap was tick-paced admission with a small queue (FI ~5.2 of 8 slots busy).
voxel.StreamingReadyQueueDepth default 16 -> 64 (effective 32 with 8 slots, total cap 40);
result backlog cap 256 unchanged. First admission -> LOD0-2 settled: FI 2.72 -> 2.10 s,
SW 2.37 -> 1.31 s (3 of 4 runs; one 6.9 s outlier re-admitting 3 LOD0 keys, cause open).
apply_ms max 4.2 ms (14 ms budget). Frame-interval max 118-145 ms both before and after (open).
World unchanged. Fast tier PASS; Linux UE host builds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
2026-10-28 08:51:25 +01:00

5.6 KiB
Raw Blame History

Linux L95: Unreal near-tile streaming

Timeline and cause

The Unreal traces cover the initial LOD0–2 desired set. The lifecycle CSV records each tile's common desired-set time, admission (request), worker start/end, approximate result enqueue (worker end is recorded immediately before enqueue), mesh application, and collision-ready or empty classification. Per-frame admission/apply counts and per-worker near-task intervals are also exported under Saved/Linux/l95/timelines/.

Per-key demand time is not emitted by Unreal, so the desired-set timestamp is a shared cohort origin. The tile event is after game-thread mesh submission to RMC, not GPU completion. settled_by_lod counts loaded or collision-not-required tiles; the first full sample is sampled at roughly 0.25 s intervals and does not mean every collision cook is finished. FI had 77 LOD0 collision-ready tiles by that sample; SW had 13–14 in normal runs. The 9-tile player support collision gate is measured separately.

Admission dominated the critical path. Before, FI admissions spanned 2.45–2.51 s and SW 2.10–2.28 s. After, FI spanned 1.95–1.99 s and normal SW runs 1.21–1.27 s. The last result was applied 18–22 ms after admission in the after runs (1–20 ms before); the full-settled sample followed shortly after. The trace has at most one scheduler pass per engine frame. Nonzero admission frames fell from 109 to 84 for FI and from 97–101 to 46–49 for normal SW runs. LOD0, then LOD1, then LOD2 became resident, so near-first ordering was already working. Per-worker “idle” means no recorded LOD0–2 task; the thread may have done far-level or other engine work.

Worker service

Headless runs imported the exact Unreal Core snapshots (world hash 1ecc162755ab83ac, layout 0589300eb07dfe06) and used 12 workers without --profile-lod-work. Service compares the exact shared LOD0–2 keys; Unreal has 22 additional SW keys, excluded from that comparison.

Stratum Shared keys Unreal before Unreal after Headless W12
FI 1,216 11.50 ms/tile 11.24 ms/tile 16.18 ms/tile
SW 1,408 1.00 ms/tile 0.75 ms/tile 1.13 ms/tile

These are summed worker-task intervals per shared key, not exclusive CPU cycles. They show no evidence that Unreal tile work is slower; this comparison does not isolate compiler or allocator differences between the host builds. Unreal had 8 effective TaskGraph tile workers versus headless's 12. Service-derived average occupied near slots rose from 5.2 to 6.5 of 8 for FI; for normal SW it was 0.6 to 0.8 of 8, versus 2.5 of 12 headless. This, plus tick-paced admission, explains the remaining wall-time gap better than per-tile adapter work. Unreal's worker time was nearly all Core generation; mesh copy plus RMC stream build totaled about 0.07 s across the FI cohort.

The fix raises StreamingReadyQueueDepth's default from 16 to 64. With 8 worker slots the existing clamp makes the effective depth 32 and total outstanding cap 40. The L94 before traces explicitly used depth 8/cap 16; the L95 after traces used 32/cap 40. The result backlog cap remains 256 and stayed below 102 in ordinary after runs (one SW outlier reached 250). Scheduler policy 3, dynamic near reserve, the 24-mesh/14 ms startup apply boost, and collision settings are unchanged. The movement portion exercised the walking case at 140 cm/s with policy 3 and the walkable gate ready; the fast-speed policy code is unchanged.

Before and after

Times are first scheduler admission to first full LOD0–2 settled sample. Frame values are the trace's interval between apply-drain entries, so they include work outside the apply drain.

Arrival Unreal before Unreal after frame_ms p95 before → after max before → after
FI 2.715 s (2.619–2.750, n=3) 2.104 s (2.068–2.114, n=3) 19.7–21.2 → 20.8–21.3 ms 137–158 → 118–122 ms
SW 2.372 s (2.333–2.373, n=3) 1.312 s (1.299–6.897, n=4) 20.7–23.4 → 24.7–27.6 ms 137–146 → 118–145 ms

Three SW after runs settled in 1.299–1.317 s; the fourth is a valid 6.897 s outlier. apply_ms stayed below the 14 ms budget in every run: 8.28 ms maximum before and 4.23 ms after. The SW tick-interval p95 is modestly higher after; it is not an isolated game-thread apply measurement.

Fast tier passed in 296.8 s. Worker-count hash checks were stable, and no generation or passage-composer code changed. Linux builds completed before timing: headless Clang 19, FP contraction off, 4 jobs; Unreal Linux Development with -NoUBA -MaxParallelActions=4. Timed Unreal runs had no --as; headless runs used prlimit --as=6442450944; runs were pinned to CPUs 0–11. No builds ran during timing.

Files and failed runs

Changed source: Source/VoxelForge/Private/VoxelWorld.cpp (queue default and opt-in snapshot export), Standalone/Source/StreamBenchmarkHeadless.cpp (exact snapshot input). Timeline outputs: unreal-tile-lifecycle.csv, unreal-per-frame.csv, unreal-worker-occupancy.csv, headless-tile-lifecycle.csv, and matched-worker-seconds.csv in Saved/Linux/l95/timelines/.

No L95 timed run failed. The SW outlier repeatedly re-admitted three LOD0 keys and nearly filled the result backlog; its cause is undetermined, and it is included above. L94 SW repeat 3 did not reach arrival and was excluded from the before sample; repeats 1, 2, and 4 were used. Fast tier's two negative-control cases printed expected FAIL results, their rejection checks passed, and the tier finished PASS. Diagnostic snapshot-export and exploratory probe runs are excluded from timing samples.