The L70 "2x SurfaceWorld GenerateTile in Unreal" was the instrument: the trace enabled bCaptureVoxelForgeCoreHashesForValidation, which disables the native heightfield-band shortcut and whole-tile skips (W1 same keys: 9.00 s hash-off vs 28.46 s hash-on). With hashing off, Unreal and headless match at W8 within 1.2-2.5% (Core 14.42 s vs 14.26 s) on identical tile keys. LOD0 p95 tail = real cost of non-empty passage tiles near the spawn mouth (p50/p95 18.8/105 ms); most LOD0 tiles are empty. verify.py reads its baselines from Standalone/Tools/verify/baselines/ instead of untracked Saved/Linux. The 11 .vfmesh control meshes (~78 MB) are not committed yet (to be stored compressed). Fast tier green. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
3.4 KiB
Linux71 — SurfaceWorld generation timing
Like-for-like result
All runs used the same host and CPU affinity. Unreal and headless resolved plan hash bcc0d0d33ea39435 and the exact same 2,850 tile keys at LOD0–8. The live asset trace still prints clip 6/max 6; the captured tile keys are identical to headless radius 3/max 8.
| Run | Tile workers | Hashing | Sum of Core/worker time |
|---|---|---|---|
| L70 Unreal median | 8 slots | on | Core 42.69s; worker 42.91s |
| L70 headless | 12 | off | worker 20.06s |
| L71 Unreal median | 8 slots | off | Core 14.42s; worker 14.62s |
| L71 headless | 8 | off | worker 14.26s |
At matched W8 the Core sum differs by 1.2% from headless end-to-end worker time; Unreal worker time differs by 2.5%. The same-worker L71 per-LOD comparison is within about ±11%. Unreal’s initial-set-ready milestone is 4.71–4.83s; the 53s commandlet lifetime includes the trace’s UntilEndPlay sampling after all tiles finished. Headless whole-view readiness was 2.16s.
Cause and tail
The L70 timing trace enabled bCaptureVoxelForgeCoreHashesForValidation, which set TileGenerationOptions.hashDensity. That diagnostic disables the native heightfield-band shortcut and whole-tile early skips. A direct W1 headless A/B on the same keys went from 9.00s/hash-off to 28.46s/hash-on: field calls rose from 5.46M to 33.82M and 654 whole-tile skips fell to zero. Turning hashing off in the Unreal trace reduced its Core sum 66%, from 42.69s to 14.42s. The no-hash profile shows LOD0 marching-cubes density-grid work as the largest near-field cost; LOD8 also spends time in MC, ground refinement and caps.
The L71 Core p50/p95/max is 1.78/17.56/130.52ms; worker p50/p95 is 1.80/17.97ms. LOD0 p50 is 0.50ms and p95 34.8–39.1ms; LOD1 is 0.60–0.64ms and 10.3–10.7ms. Most LOD0/1 tiles are empty (441/512 and 372/448); the nonempty passage tiles have p50/p95 of 18.8/105.1ms at LOD0 and 8.6/65.0ms at LOD1. The slow keys cluster around the spawn mouth and first passage bend. This is real per-tile generation variance. Queue p95 is separately 129.45ms, so it increases arrival latency but is not counted in core_generate_s.
Changes and verification
The stream-trace commandlet now leaves hash capture off; dedicated hash/parity tests still enable it. This changes no world data or hashes. No shared Core or build-setting change was warranted by the matched result. No Windows build-flag change is indicated by this Linux run. The only Source/ change is Source/VoxelForgeEditor/Private/VoxelForgeExploreCommandlet.cpp; Linux VFHostEditor Development UBT succeeded with -MaxParallelActions=4 (log: Saved/Linux/l71/ubt-source-change.log). No Unreal build ran during timing.
Historical fixtures and controls used directly or indirectly by verify tiers now live under Standalone/Tools/verify/baselines/; verify.py and its helper scripts point there. Gate thresholds and outcomes are unchanged. The Clang fast tier passed in 267.2s (log: Saved/Linux/l71/verify-fast-tier.log).
perf and stack-sampling tools were unavailable, so stage counters and per-tile traces supplied the profile. Initial UE launches used an output path outside the host plugin’s Saved tree and stopped before measurement; corrected launches all passed. The first UBT attempt could not open its default user log; retrying with an explicit -Log succeeded. The first fast invocation lacked its output binary; after the Clang build, the rerun passed. No commit, push or stash was made.