audit(gen): which post-hoc ops are tunnel-floors in disguise -- and the X+2A budget is unsound
The owner's framing for the night: "if it sees performance opportunity by unifying
some process that should be, or like the tunnels, have it be native more than patching
it after generation". This is the audit. No generator behaviour changed; the only code
here is request/generation timing instrumentation in VoxelWorld.
STRUCTURAL-POST AUDIT -- verdict per operator
FBoundarySealOp 0.000011 us/sample KEEP. A boundary condition, not a workaround.
FXYEdgeSealOp 0.000054 us/sample KEEP. Domain constraint; identity today with
WorldRadiusVoxels=0.
FOriginSpineOp 0.000588 us/sample PARTLY family, but origin anchoring and
ordering are special.
FPassageCarveOp 0.019977 us/sample Could share the volume/floor representation,
but its boundary-crossing order and
current-density carve are load-bearing.
floor protection 0.061298 us/sample ⭐ THIS IS STILL THE REAL PATCH.
TunnelAuthoredFloorProtectionClamps fired 29,634 / 29,634 -- every authored floor
sample -- while the named support/room fallbacks fired ZERO. So the backstop is not
a rare safety net; it is doing the work, and the tunnel floor is not yet native.
⭐ AND IT NAMED THE PATH OUT, which I had not seen: the floor is authored at build time
but LATER WRITERS can still refill or erase the clearance, so a clamp re-asserts it.
Native means either composing the floor AFTER all writers, or making every later
writer floor-aware with a proof it cannot violate the invariant. Removing the clamp
today would be unsafe. It did not remove it.
PRIMITIVE FAMILY -- valid, but my proposal was too crude
Algebraically sound: solid + floor via SmoothMax + bounded relief + smooth union.
Rooms, swept tunnels, landing rooms and some passages can share a cached
walkable-volume DESCRIPTOR (shape/profile, baked floor, relief params, mouth/room
ownership, capability metadata).
⛔ But they should NOT become one undifferentiated operator: tunnels are swept
multi-segment chains, passages cross structural boundaries, origin landings have
special finite geometry, seals are domain conditions. Flattening those would WEAKEN
interval proofs and operation ordering -- the opposite of what I hoped unification
would buy. Renaming the passage carve would not help either; it Lerps against
incoming density, so its global bound stays unbounded regardless.
X + 2A CLEARANCE BUDGET -- SETTLED, AND IT IS UNSOUND AS SPECIFIED
A surface-displacement budget needs BOTH an upper bound on field perturbation AND a
lower bound on the gradient near the zero surface. The second fails at flat or
degenerate crossings, and the current-density Lerp/Min operators make a global bound
unavailable. Perlin derivative bounds alone do not fix it.
⇒ Usable only inside separately proven primitive regions; elsewhere the validator and
backstop must stay. The owner and I both assumed interval propagation already gave
us this. It does not, and now we know why rather than just that.
ITEM ZERO -- the suspected in-game regression: NARROWED, NOT CONFIRMED
Queue wait is real, but meshed latency is primarily GENERATION time, not queue. One
EMPTY LOD0 generation took 551.7 ms, so it is not pure queue saturation either.
RoomGraphSource measures 0.278939 us/sample, which cannot explain a 400-1000 ms mesh.
Codex declined to call it a confirmed code regression on this data. Still open, and
it now points at the known-unsolved LOD0 mixed-classifier fallback rather than at the
floor work.
REFERENCE ARCHETYPE -- costs, and a correction to my arithmetic
CorridorRadius 12.5 voxels is a 6.25 m DIAMETER (I said 3.1 m), and validation caps
it at 16 voxels. The 15-20 m reference hall needs a separate gallery archetype or a
larger cell-size budget; raising the value violates current lattice/wall assumptions.
FCaveTerraceMod is a true no-op disabled (0.000531 us/sample); enabled it adds two
cached SDF probes, estimated lower bound ~0.56 us for a qualifying sample -- estimated,
not measured. Columns belong to slab generation; TunnelNetwork needs a baked column
op. Water is presentation, not rock density, and null-RHI cannot price it.
Build 0 errors. No RMC files, links, historical checkouts or logs touched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012aheo2crrZmHuYtPpdY2Cb
This commit is contained in:
1 parent
8e42d6d807
commit
5156084cac
2 files changed
+36
-3
No files matched your search
@@ -1306,15 +1306,36 @@ bool AVoxelWorld::ApplyTileResult(FChunkResult& Result)
|
||||
// dequeued. This makes request-to-ready include component setup, stream/buffer submission,
|
||||
// and collision configuration—the point at which the chunk is actually visible/collidable.
|
||||
const bool bResultEmpty = Result.bEmpty || !Result.Streams;
|
||||
const uint64 ApplyStartCycles = GVoxelForgeProfileTileGeneration != 0
|
||||
? FPlatformTime::Cycles64() : 0;
|
||||
const auto LogTileReady = [&]()
|
||||
{
|
||||
if (GVoxelForgeProfileTileGeneration != 0 && Result.RequestStartCycles != 0)
|
||||
{
|
||||
const uint64 ReadyCycles = FPlatformTime::Cycles64();
|
||||
const bool bHaveWorkerTiming = Result.GenerationStartCycles != 0
|
||||
&& Result.GenerationEndCycles >= Result.GenerationStartCycles;
|
||||
const double RequestToReady = FPlatformTime::ToSeconds64(
|
||||
ReadyCycles - Result.RequestStartCycles);
|
||||
const double ApplySeconds = ApplyStartCycles != 0
|
||||
? FPlatformTime::ToSeconds64(ReadyCycles - ApplyStartCycles) : 0.0;
|
||||
const double GenerationSeconds = bHaveWorkerTiming
|
||||
? FPlatformTime::ToSeconds64(
|
||||
Result.GenerationEndCycles - Result.GenerationStartCycles) : 0.0;
|
||||
const double WorkerQueueSeconds = bHaveWorkerTiming
|
||||
? FPlatformTime::ToSeconds64(
|
||||
Result.GenerationStartCycles - Result.RequestStartCycles) : 0.0;
|
||||
const double ResultQueueSeconds = bHaveWorkerTiming
|
||||
? FMath::Max(0.0, RequestToReady - WorkerQueueSeconds
|
||||
- GenerationSeconds - ApplySeconds) : 0.0;
|
||||
UE_LOG(LogTemp, Display,
|
||||
TEXT("[VoxelForgeTileReady] level=%d empty=%d request_to_ready=%.6f"),
|
||||
TEXT("[VoxelForgeTileReady] tile=(%d,%d,%d) level=%d empty=%d "
|
||||
"request_to_ready=%.6f worker_queue=%.6f generation=%.6f "
|
||||
"result_queue=%.6f apply=%.6f"),
|
||||
Result.Tile.Coord.X, Result.Tile.Coord.Y, Result.Tile.Coord.Z,
|
||||
Result.Tile.Level, bResultEmpty ? 1 : 0,
|
||||
FPlatformTime::ToSeconds64(
|
||||
FPlatformTime::Cycles64() - Result.RequestStartCycles));
|
||||
RequestToReady, WorkerQueueSeconds, GenerationSeconds,
|
||||
ResultQueueSeconds, ApplySeconds);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1405,10 +1426,13 @@ void AVoxelWorld::SyncRemeshTile(const FVoxelTileKey& Tile)
|
||||
Result.RequestStartCycles = bProfileModification
|
||||
? FPlatformTime::Cycles64() : 0;
|
||||
const uint64 GenerateStartCycles = bProfileModification ? FPlatformTime::Cycles64() : 0;
|
||||
Result.GenerationStartCycles = GenerateStartCycles;
|
||||
GenerateTileResult(Tile, OriginVoxels, Step, Cells, GenerationEpoch, /*bWantCapture*/ false,
|
||||
BandVoxLo, BandVoxHi, BandChunkLo, BandChunkHi,
|
||||
/*bSheetTile*/ false, /*SheetChunkZ*/ 0,
|
||||
/*Hole*/ 0, 0, 0, 0, Result); // hole unused (not a sheet tile)
|
||||
Result.GenerationEndCycles = GenerateStartCycles != 0
|
||||
? FPlatformTime::Cycles64() : 0;
|
||||
|
||||
const double GenerateSeconds = bProfileModification
|
||||
? FPlatformTime::ToSeconds64(FPlatformTime::Cycles64() - GenerateStartCycles)
|
||||
@@ -2290,9 +2314,14 @@ void AVoxelWorld::LoadTile(const FVoxelTileKey& Tile, bool bHighPriority)
|
||||
if (ShouldAbortWork()) return;
|
||||
|
||||
FChunkResult Result;
|
||||
const uint64 GenerationStartCycles = GVoxelForgeProfileTileGeneration != 0
|
||||
? FPlatformTime::Cycles64() : 0;
|
||||
Result.GenerationStartCycles = GenerationStartCycles;
|
||||
GenerateTileResult(Tile, OriginVoxels, Step, Cells, TaskEpoch, bWantCapture,
|
||||
BandVoxLo, BandVoxHi, BandChunkLo, BandChunkHi,
|
||||
bSheetTile, SheetChunkZ, HoleMinX, HoleMinY, HoleMaxX, HoleMaxY, Result);
|
||||
Result.GenerationEndCycles = GenerationStartCycles != 0
|
||||
? FPlatformTime::Cycles64() : 0;
|
||||
Result.RequestStartCycles = RequestStartCycles;
|
||||
|
||||
if (!ShouldAbortWork())
|
||||
|
||||
@@ -87,6 +87,10 @@ struct FChunkResult
|
||||
// Monotonic request timestamp used only for streaming telemetry. It is carried through the
|
||||
// worker queue so the profile can report request-to-ready, not just worker generation time.
|
||||
uint64 RequestStartCycles = 0;
|
||||
// Worker timing boundaries for separating scheduler wait from generation and result/apply wait.
|
||||
// These are telemetry-only and remain zero when tile profiling is disabled.
|
||||
uint64 GenerationStartCycles = 0;
|
||||
uint64 GenerationEndCycles = 0;
|
||||
bool bAborted = false; // Worker observed shutdown; never mark this tile loaded
|
||||
bool bEmpty = true; // true ⇒ all-air tile (Streams null); still marked loaded so we don't re-submit
|
||||
// F17 — the mesher classifies every triangle semantically (sky-cap = down-facing near the
|
||||
|
||||
Reference in new issue
Block a user