wip(assembler): round L11 -- fix 24 m+ crossing crash; near ring ready 2x sooner at spawn
Crash: crossing tiles were coalesced into one huge rectangle, and BuildSpatialBins tried to resize to ~4.3e17 bytes (std::bad_alloc; the L7 32 m failure had the same cause). Analytic regions now skip unread dense bins and compile in world-aligned 128-voxel pages, published together; out-of-range keys error before allocation. 24 m, 32 m and 1 km crossings pass (1 km: 72 pages, peak RSS 700 MiB). Spawn: World::isTileShapeFree proves LOD0 SurfaceWorld tiles that never read the cave shape; those start before shape compile, and all others wait. Reviewer W12 no-hash: near ring 0.337 -> 0.159 s, whole view +2.1%. All SurfaceWorld/FloatingIslands hashes unchanged (W1/W8/W12, both compilers, forced-overlap run). Unreal VoxelWorld.cpp adapter changed but NOT built here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CSFYgsdW8ejZSyiMf4qRSX
This commit is contained in:
1 parent
b370908174
commit
b1cfaf53b8
8 files changed
+808
-59
No files matched your search
@@ -9,6 +9,7 @@
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
@@ -41,6 +42,9 @@ namespace
|
||||
bool ScreenSpaceGate=false;
|
||||
bool AuditUniformBlockProofs=false;
|
||||
bool ProfileLodWork=false;
|
||||
bool RegionCrossing=false;
|
||||
bool AuditTileShapeReadiness=false;
|
||||
int DiagnosticSlowShapeCompileMs=0;
|
||||
bool HasSeedOverride=false;
|
||||
int SeedOverride=0;
|
||||
bool HasRenderDistanceOverride=false;
|
||||
@@ -106,6 +110,7 @@ namespace
|
||||
" --workers=N --clip-radius=N --max-clip-level=N --max-level=N\n"
|
||||
" --camera=X,Y,Z,YAW,PITCH (position in metres) --stream-hash\n"
|
||||
" --camera-step=X,Y,Z (optional second view step in metres)\n"
|
||||
" --region-crossing (compile entering Core regions at the camera step)\n"
|
||||
" --column-cache=shared|thread-local (default: shared)\n"
|
||||
" --mesh-export=FILE (write the exact generated tile meshes for offline rendering)\n"
|
||||
" --profile-column-overlap --far-horizon-lod8-step=N --force-generate\n"
|
||||
@@ -115,6 +120,8 @@ namespace
|
||||
" --screen-space-gate (measure display error and historical negative controls)\n"
|
||||
" --audit-uniform-block-proofs (fill and check every interval-certified block)\n"
|
||||
" --profile-lod-work (report per-LOD density sample counts)\n"
|
||||
" --audit-tile-shape-readiness (run a deliberately mis-marked tile against the native-only guard)\n"
|
||||
" --diagnostic-slow-shape-compile-ms=N (diagnostic overlap control; default 0)\n"
|
||||
" --render-distance-chunks=N (0 disables the extra far ring)\n"
|
||||
" --tls-probe=N (Linux worker TLS/stack measurement; N=0..12)\n"
|
||||
" --tls-probe-touch=none|surface-world|floating-islands (first-use probe)\n"
|
||||
@@ -132,6 +139,8 @@ namespace
|
||||
else if(arg=="--screen-space-gate")options.ScreenSpaceGate=true;
|
||||
else if(arg=="--audit-uniform-block-proofs")options.AuditUniformBlockProofs=true;
|
||||
else if(arg=="--profile-lod-work")options.ProfileLodWork=true;
|
||||
else if(arg=="--region-crossing")options.RegionCrossing=true;
|
||||
else if(arg=="--audit-tile-shape-readiness")options.AuditTileShapeReadiness=true;
|
||||
else if(arg=="--auto-surface-camera")options.AutoSurfaceCamera=true;
|
||||
else if(arg.starts_with("--recipe="))
|
||||
{
|
||||
@@ -199,6 +208,8 @@ namespace
|
||||
{if(!readInt("--max-level=",options.MaxLevel))return false;}
|
||||
else if(arg.starts_with("--far-horizon-lod8-step="))
|
||||
{if(!readInt("--far-horizon-lod8-step=",options.FarHorizonLOD8InteriorStepVoxels))return false;}
|
||||
else if(arg.starts_with("--diagnostic-slow-shape-compile-ms="))
|
||||
{if(!readInt("--diagnostic-slow-shape-compile-ms=",options.DiagnosticSlowShapeCompileMs))return false;}
|
||||
else if(arg.starts_with("--process-affinity=")||arg.starts_with("--process-priority=")
|
||||
||arg.starts_with("--frame-limit="))
|
||||
{
|
||||
@@ -213,8 +224,11 @@ namespace
|
||||
options.ClipRadius=std::clamp(options.ClipRadius,1,64);
|
||||
options.MaxClipLevel=std::clamp(options.MaxClipLevel,0,8);
|
||||
options.FarHorizonLOD8InteriorStepVoxels=std::max(0,options.FarHorizonLOD8InteriorStepVoxels);
|
||||
options.DiagnosticSlowShapeCompileMs=std::clamp(options.DiagnosticSlowShapeCompileMs,0,30000);
|
||||
if(!options.TlsProbeRequested&&options.TlsProbeTouch!="none")
|
||||
{std::fprintf(stderr,"--tls-probe-touch requires --tls-probe=N\n");return false;}
|
||||
if(options.RegionCrossing&&!options.HasCameraStep)
|
||||
{std::fprintf(stderr,"--region-crossing requires --camera-step=X,Y,Z\n");return false;}
|
||||
if(options.TlsProbeRequested)return true;
|
||||
if(!options.WorldAssemblerPrototype||!options.StreamBenchmark||!options.StreamPipeline)
|
||||
{
|
||||
@@ -354,5 +368,7 @@ int main(int argc,char** argv)
|
||||
options.ProfileColumnOverlap,options.FarHorizonLOD8InteriorStepVoxels,
|
||||
options.MeshCoverage,options.MeshExportPath,options.CameraYawDegrees,
|
||||
options.CameraPitchDegrees,options.ScreenSpaceGate,options.UseSharedColumnCache,
|
||||
cameraStepVoxels,options.AuditUniformBlockProofs,options.ProfileLodWork);
|
||||
cameraStepVoxels,options.AuditUniformBlockProofs,options.ProfileLodWork,
|
||||
options.RegionCrossing,options.AuditTileShapeReadiness,
|
||||
options.DiagnosticSlowShapeCompileMs);
|
||||
}
|
||||
@@ -9,10 +9,13 @@
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
#include <cstdio>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <future>
|
||||
#include <limits>
|
||||
#include <numeric>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
@@ -139,7 +142,9 @@ namespace StandaloneStreamBenchmark
|
||||
const std::filesystem::path& MeshExportPath={},float CameraYawDegrees=0.0f,
|
||||
float CameraPitchDegrees=0.0f,bool bScreenSpaceGate=false,
|
||||
bool bUseSharedColumnCache=true,FVector CameraStepVoxels=FVector::ZeroVector,
|
||||
bool bAuditUniformBlockProofs=false,bool bReportLodWorkProfile=false)
|
||||
bool bAuditUniformBlockProofs=false,bool bReportLodWorkProfile=false,
|
||||
bool bRegionCrossing=false,
|
||||
bool bAuditTileShapeReadiness=false,int DiagnosticSlowShapeCompileMs=0)
|
||||
{
|
||||
using Clock=std::chrono::steady_clock;
|
||||
FStandaloneOwnerWorld& World=*OwnerWorld;
|
||||
@@ -223,7 +228,7 @@ namespace StandaloneStreamBenchmark
|
||||
}
|
||||
};
|
||||
AccumulateBounds(Desired.Tiles);
|
||||
if(bHasCameraStep)AccumulateBounds(MovedDesired.Tiles);
|
||||
if(bHasCameraStep&&!bRegionCrossing)AccumulateBounds(MovedDesired.Tiles);
|
||||
if(FineMin.X==INT32_MAX||ClipMin.X==INT32_MAX)
|
||||
{std::fprintf(stderr,"[StreamPipeline] no desired detail or clipmap tiles.\n");return 7;}
|
||||
|
||||
@@ -237,6 +242,46 @@ namespace StandaloneStreamBenchmark
|
||||
if(Neighborhood.size()!=27)
|
||||
{std::fprintf(stderr,"[StreamPipeline] expected 27 player-neighborhood tiles, found %zu.\n",Neighborhood.size());return 7;}
|
||||
|
||||
FStandaloneDesiredTileSet ShapeFreeDesired=Desired;
|
||||
ShapeFreeDesired.Tiles.clear();
|
||||
std::vector<FVoxelTileKey> ShapeFreeTiles;
|
||||
ShapeFreeTiles.reserve(Neighborhood.size());
|
||||
int32 ShapeFreeNeighborhood=0;
|
||||
for(const FVoxelTileKey& Tile:Desired.Tiles)
|
||||
{
|
||||
if(!Neighborhood.contains(Tile))continue;
|
||||
const VoxelForgeCore::TileKey CoreKey{{Tile.Coord.X,Tile.Coord.Y,Tile.Coord.Z},Tile.Level};
|
||||
if(!Shape.isTileShapeFree(CoreKey))continue;
|
||||
ShapeFreeDesired.Tiles.push_back(Tile);
|
||||
ShapeFreeTiles.push_back(Tile);
|
||||
if(Neighborhood.contains(Tile))++ShapeFreeNeighborhood;
|
||||
}
|
||||
if(bAuditTileShapeReadiness)
|
||||
{
|
||||
FVoxelTileKey DeliberatelyWrong(FIntVector(0,0,31250),0);
|
||||
for(int32 Z=100000;Z<100100;++Z)
|
||||
{
|
||||
DeliberatelyWrong=FVoxelTileKey(FIntVector(0,0,Z),0);
|
||||
if(!Shape.isTileShapeFree({{0,0,Z},0}))break;
|
||||
}
|
||||
VoxelForgeCore::TileGenerationOptions NegativeControlOptions;
|
||||
NegativeControlOptions.diagnosticForceNativeOnly=true;
|
||||
std::string NegativeControlError;
|
||||
const auto MisMarked=Shape.generateTile(
|
||||
{{DeliberatelyWrong.Coord.X,DeliberatelyWrong.Coord.Y,DeliberatelyWrong.Coord.Z},0},
|
||||
NegativeControlOptions,NegativeControlError);
|
||||
const bool bGuardCaught=!MisMarked
|
||||
&&NegativeControlError.find("shape-free guard")!=std::string::npos;
|
||||
std::printf("[ShapeReadinessNegativeControl] deliberately_mismarked=(%d,%d,%d,lod0) result=%s guard_caught=%d error=%s\n",
|
||||
DeliberatelyWrong.Coord.X,DeliberatelyWrong.Coord.Y,DeliberatelyWrong.Coord.Z,
|
||||
MisMarked?"generated":"rejected",bGuardCaught?1:0,
|
||||
NegativeControlError.c_str());
|
||||
if(!bGuardCaught)
|
||||
{std::fprintf(stderr,"[StreamPipeline] shape-free guard did not reject the deliberately mis-marked tile.\n");return 9;}
|
||||
}
|
||||
std::printf("[ShapeReadiness] shape_free_desired=%zu/%zu near_ring=%d/27 proof=single_SurfaceWorld_plan_no_features_routes_passages_edits_or_owner_primitive_overlap\n",
|
||||
ShapeFreeTiles.size(),Desired.Tiles.size(),ShapeFreeNeighborhood);
|
||||
|
||||
// The initial desired set now owns all clipmap metadata needed by this Core-only run.
|
||||
// Release the separate compatibility-world generation graph before compiling Core.
|
||||
World.Generator.reset();
|
||||
@@ -245,10 +290,7 @@ namespace StandaloneStreamBenchmark
|
||||
World.BiomeStorage.clear();
|
||||
World.OperationStorage.clear();
|
||||
World.DensitySamples.clear();
|
||||
|
||||
std::string BuildError;
|
||||
const bool bIncludeFarWorld=MaxLevel<0||MaxLevel>=World.FullResClipLevels;
|
||||
const auto ShapeBuildStart=Clock::now();
|
||||
VoxelForgeCore::ShapeBuildRequest ShapeRequest;
|
||||
ShapeRequest.minVoxel={FineMin.X,FineMin.Y,FineMin.Z};
|
||||
ShapeRequest.maxVoxel={FineMax.X,FineMax.Y,FineMax.Z};
|
||||
@@ -258,21 +300,82 @@ namespace StandaloneStreamBenchmark
|
||||
ShapeRequest.detail=DetailVariant;ShapeRequest.includeFarWorld=bIncludeFarWorld;
|
||||
ShapeRequest.roundTunnels=bRoundTunnels;
|
||||
ShapeRequest.enhancedTunnelWalls=bEnhancedTunnelWalls;
|
||||
if(!Shape.compile(ShapeRequest,Scheduler,BuildError))
|
||||
{std::fprintf(stderr,"[StreamPipeline] full shape build failed: %s\n",BuildError.c_str());return 2;}
|
||||
const auto ShapeReady=Clock::now();
|
||||
const double ShapeSeconds=std::chrono::duration<double>(ShapeReady-ShapeBuildStart).count();
|
||||
FStandaloneStreamingGenerator Streamer(World,WorkerCount,bHashDensity,nullptr,MaxLevel,
|
||||
bSkipUvAndColors,bSkipMaterialGroups,bSkipUV,bSkipColors,&Shape,bProfileColumnOverlap,
|
||||
FarHorizonLOD8InteriorStepVoxels,bUseSharedColumnCache);
|
||||
Streamer.SetUniformBlockProofAuditEnabled(bAuditUniformBlockProofs);
|
||||
if(bScreenSpaceGate)Streamer.SetMesherStageProfilingEnabled(true);
|
||||
const auto StreamStart=Clock::now();
|
||||
const FStandaloneStreamingUpdate Update=Streamer.StartWithDesired(Desired);
|
||||
const FStandaloneStreamingUpdate EarlyUpdate=Streamer.StartWithDesired(ShapeFreeDesired);
|
||||
if(EarlyUpdate.DesiredTiles!=static_cast<int32>(ShapeFreeDesired.Tiles.size()))
|
||||
{
|
||||
Streamer.Stop();
|
||||
std::fprintf(stderr,"[StreamPipeline] expected %zu shape-free tiles but queued %d.\n",
|
||||
ShapeFreeDesired.Tiles.size(),EarlyUpdate.DesiredTiles);return 7;
|
||||
}
|
||||
const auto ShapeBuildStart=Clock::now();
|
||||
auto ShapeBuildFuture=std::async(std::launch::async,
|
||||
[&Shape,&Scheduler,ShapeRequest,DiagnosticSlowShapeCompileMs]() mutable
|
||||
{
|
||||
if(DiagnosticSlowShapeCompileMs>0)
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(DiagnosticSlowShapeCompileMs));
|
||||
std::string Error;
|
||||
const bool bCompiled=Shape.compile(ShapeRequest,Scheduler,Error);
|
||||
return std::pair<bool,std::string>{bCompiled,std::move(Error)};
|
||||
});
|
||||
const auto [bShapeCompiled,BuildError]=ShapeBuildFuture.get();
|
||||
if(!bShapeCompiled)
|
||||
{
|
||||
Streamer.Stop();
|
||||
std::fprintf(stderr,"[StreamPipeline] full shape build failed: %s\n",BuildError.c_str());return 2;
|
||||
}
|
||||
const auto ShapeReady=Clock::now();
|
||||
const double ShapeSeconds=std::chrono::duration<double>(ShapeReady-ShapeBuildStart).count();
|
||||
if(bAuditTileShapeReadiness)
|
||||
{
|
||||
VoxelForgeCore::TileGenerationOptions CompiledOptions;
|
||||
VoxelForgeCore::TileGenerationOptions NativeOnlyOptions;
|
||||
CompiledOptions.hashDensity=true;
|
||||
NativeOnlyOptions.hashDensity=true;
|
||||
NativeOnlyOptions.diagnosticForceNativeOnly=true;
|
||||
int32 Compared=0,Mismatched=0;
|
||||
for(const FVoxelTileKey& Tile:ShapeFreeTiles)
|
||||
{
|
||||
if(!Neighborhood.contains(Tile))continue;
|
||||
const VoxelForgeCore::TileKey CoreKey{{Tile.Coord.X,Tile.Coord.Y,Tile.Coord.Z},Tile.Level};
|
||||
std::string CompiledError,NativeOnlyError;
|
||||
const auto Compiled=Shape.generateTile(CoreKey,CompiledOptions,CompiledError);
|
||||
const auto NativeOnly=Shape.generateTile(CoreKey,NativeOnlyOptions,NativeOnlyError);
|
||||
++Compared;
|
||||
const bool bSame=Compiled&&NativeOnly
|
||||
&&Compiled->densityHash==NativeOnly->densityHash
|
||||
&&Compiled->meshHash==NativeOnly->meshHash
|
||||
&&Compiled->payloadHash==NativeOnly->payloadHash
|
||||
&&Compiled->topologyHash==NativeOnly->topologyHash;
|
||||
if(!bSame)
|
||||
{
|
||||
++Mismatched;
|
||||
std::printf("[ShapeReadinessEquivalence] key=(%d,%d,%d,lod%d) match=0 compiled=%s native_only=%s density=%s mesh=%s\n",
|
||||
Tile.Coord.X,Tile.Coord.Y,Tile.Coord.Z,Tile.Level,
|
||||
Compiled?"ok":CompiledError.c_str(),NativeOnly?"ok":NativeOnlyError.c_str(),
|
||||
Compiled&&NativeOnly&&Compiled->densityHash==NativeOnly->densityHash?"same":"different",
|
||||
Compiled&&NativeOnly&&Compiled->meshHash==NativeOnly->meshHash?"same":"different");
|
||||
}
|
||||
}
|
||||
std::printf("[ShapeReadinessEquivalence] compared_near_ring=%d mismatches=%d status=%s\n",
|
||||
Compared,Mismatched,Mismatched==0?"PASS":"FAIL");
|
||||
if(Mismatched!=0)
|
||||
{
|
||||
Streamer.Stop();
|
||||
std::fprintf(stderr,"[StreamPipeline] native-only tile generation differs from compiled generation.\n");
|
||||
return 9;
|
||||
}
|
||||
}
|
||||
const FStandaloneStreamingUpdate Update=Streamer.UpdateDesiredWithSet(Desired,{},0);
|
||||
if(Update.DesiredTiles!=static_cast<int32>(Desired.Tiles.size()))
|
||||
{
|
||||
Streamer.Stop();
|
||||
std::fprintf(stderr,"[StreamPipeline] expected %zu tiles but queued %d.\n",
|
||||
std::fprintf(stderr,"[StreamPipeline] expected %zu tiles after shape publication but queued %d.\n",
|
||||
Desired.Tiles.size(),Update.DesiredTiles);return 7;
|
||||
}
|
||||
FSceneExportWriter SceneExport;
|
||||
@@ -355,8 +458,8 @@ namespace StandaloneStreamBenchmark
|
||||
std::array<std::optional<FStandaloneCpuTile>,9> GateSampleTiles{};
|
||||
std::array<double,9> GateSampleDistances{};
|
||||
GateSampleDistances.fill(std::numeric_limits<double>::infinity());
|
||||
Clock::time_point NeighborhoodReady{},FullDetailReady{},WholeViewReady{};
|
||||
bool bNeighborhoodReported=false,bFullDetailReported=false;
|
||||
Clock::time_point FirstTileReady{},NeighborhoodReady{},FullDetailReady{},WholeViewReady{};
|
||||
bool bFirstTileReported=false,bNeighborhoodReported=false,bFullDetailReported=false;
|
||||
uint64 BlockProofBlocksChecked=0,BlockProofSamplesChecked=0;
|
||||
uint64 BlockProofFallbackBlocks=0,BlockProofUnknownBlocks=0,BlockProofViolations=0;
|
||||
while(Finished<Update.DesiredTiles)
|
||||
@@ -365,6 +468,12 @@ namespace StandaloneStreamBenchmark
|
||||
if(Ready.empty()){std::this_thread::sleep_for(std::chrono::milliseconds(1));continue;}
|
||||
for(const FStandaloneCpuTile& Tile:Ready)
|
||||
{
|
||||
if(Tile.bGenerationFailed)
|
||||
{
|
||||
Streamer.Stop();
|
||||
std::fprintf(stderr,"[StreamPipeline] a tile failed generation; refusing a partial result.\n");
|
||||
return 9;
|
||||
}
|
||||
if(bExportRequested)SceneExport.Add(Tile);
|
||||
++Finished;
|
||||
if(bReportMeshCoverage)
|
||||
@@ -426,6 +535,8 @@ namespace StandaloneStreamBenchmark
|
||||
}
|
||||
}
|
||||
WholeViewReady=std::max(WholeViewReady,Tile.CompletedAt);
|
||||
if(FirstTileReady.time_since_epoch().count()==0||Tile.CompletedAt<FirstTileReady)
|
||||
FirstTileReady=Tile.CompletedAt;
|
||||
if(Neighborhood.contains(Tile.Key))
|
||||
{
|
||||
++NeighborhoodFinished;
|
||||
@@ -455,6 +566,12 @@ namespace StandaloneStreamBenchmark
|
||||
if(Tile.bHasTopologyHash)TopologyRows.push_back({Tile.Key,Tile.TopologyHash});
|
||||
}
|
||||
}
|
||||
if(!bFirstTileReported&&FirstTileReady.time_since_epoch().count()!=0)
|
||||
{
|
||||
std::printf("[PipelineMilestone] first_tile_ready=%.3fs\n",
|
||||
std::chrono::duration<double>(FirstTileReady-ColdStart).count());
|
||||
bFirstTileReported=true;
|
||||
}
|
||||
if(!bNeighborhoodReported&&NeighborhoodFinished==static_cast<int32>(Neighborhood.size()))
|
||||
{
|
||||
std::printf("[PipelineMilestone] neighborhood_ready=%.3fs generated=%d/27\n",
|
||||
@@ -472,9 +589,55 @@ namespace StandaloneStreamBenchmark
|
||||
if(bHasCameraStep)
|
||||
{
|
||||
const auto MovingStart=Clock::now();
|
||||
double RegionCompileWallSeconds=0.0;
|
||||
double RegionCompileCpuSeconds=0.0;
|
||||
std::size_t RegionCompileRequested=0,RegionCompileCovered=0;
|
||||
VoxelForgeCore::TileRegionCompileStats RegionCompileStats;
|
||||
if(bRegionCrossing)
|
||||
{
|
||||
std::unordered_set<FVoxelTileKey,FStandaloneTileKeyHash> InitialKeys;
|
||||
InitialKeys.reserve(Desired.Tiles.size()*2+1);
|
||||
for(const FVoxelTileKey& Key:Desired.Tiles)InitialKeys.insert(Key);
|
||||
std::vector<VoxelForgeCore::TileKey> EnteringCoreTiles;
|
||||
EnteringCoreTiles.reserve(MovedDesired.Tiles.size());
|
||||
for(const FVoxelTileKey& Key:MovedDesired.Tiles)
|
||||
{
|
||||
if(InitialKeys.contains(Key))continue;
|
||||
EnteringCoreTiles.push_back({{Key.Coord.X,Key.Coord.Y,Key.Coord.Z},Key.Level});
|
||||
}
|
||||
RegionCompileRequested=EnteringCoreTiles.size();
|
||||
const auto RegionCompileStart=Clock::now();
|
||||
const std::clock_t RegionCompileCpuStart=std::clock();
|
||||
std::string RegionCompileError;
|
||||
if(!Shape.compileTileRegion(EnteringCoreTiles,
|
||||
static_cast<uint32>(std::clamp(WorkerCount,1,16)),Scheduler,
|
||||
RegionCompileError,&RegionCompileCovered,&RegionCompileStats,true))
|
||||
{
|
||||
Streamer.Stop();
|
||||
std::fprintf(stderr,"[MovingRegionCompile] failed: %s\n",RegionCompileError.c_str());
|
||||
return 2;
|
||||
}
|
||||
RegionCompileWallSeconds=std::chrono::duration<double>(
|
||||
Clock::now()-RegionCompileStart).count();
|
||||
RegionCompileCpuSeconds=static_cast<double>(std::clock()-RegionCompileCpuStart)
|
||||
/CLOCKS_PER_SEC;
|
||||
const std::size_t ParallelWorkers=RegionCompileStats.regionsBuilt>1
|
||||
?std::min<std::size_t>(8,RegionCompileStats.regionsBuilt):0;
|
||||
std::printf("[MovingRegionCompile] distance_m=%.3f entering_tiles=%zu covered_tiles=%zu regions=%zu lattice_nodes=%llu wall_s=%.6f cpu_s=%.6f worker_threads=%zu mode=analytic-shape-pages\n",
|
||||
std::sqrt(static_cast<double>(CameraStepVoxels.X)*CameraStepVoxels.X
|
||||
+static_cast<double>(CameraStepVoxels.Y)*CameraStepVoxels.Y
|
||||
+static_cast<double>(CameraStepVoxels.Z)*CameraStepVoxels.Z)
|
||||
*static_cast<double>(World.CoreVoxelSizeMicrons)/1000000.0,
|
||||
RegionCompileRequested,RegionCompileCovered,RegionCompileStats.regionsBuilt,
|
||||
static_cast<unsigned long long>(RegionCompileStats.latticeNodes),
|
||||
RegionCompileWallSeconds,RegionCompileCpuSeconds,ParallelWorkers);
|
||||
}
|
||||
const auto MovingTileStart=Clock::now();
|
||||
const auto MovingUpdate=Streamer.UpdateDesiredWithSet(MovedDesired,Desired.Tiles,1);
|
||||
std::array<std::uint64_t,9> MovingTilesByLOD{};
|
||||
std::array<double,9> MovingWorkerSecondsByLOD{};
|
||||
std::vector<FHashedTile> MovingDensityRows,MovingMeshRows,
|
||||
MovingPayloadRows,MovingTopologyRows;
|
||||
int32 MovingFinished=0;
|
||||
while(MovingFinished<MovingUpdate.NewJobs)
|
||||
{
|
||||
@@ -490,8 +653,17 @@ namespace StandaloneStreamBenchmark
|
||||
++MovingTilesByLOD[LOD];
|
||||
MovingWorkerSecondsByLOD[LOD]+=Tile.WorkerSeconds;
|
||||
}
|
||||
if(bHashDensity)
|
||||
{
|
||||
if(Tile.bHasDensityHash)MovingDensityRows.push_back({Tile.Key,Tile.DensityHash});
|
||||
if(Tile.bHasMeshHash)MovingMeshRows.push_back({Tile.Key,Tile.MeshHash});
|
||||
if(Tile.bHasPayloadHash)MovingPayloadRows.push_back({Tile.Key,Tile.PayloadHash});
|
||||
if(Tile.bHasTopologyHash)MovingTopologyRows.push_back({Tile.Key,Tile.TopologyHash});
|
||||
}
|
||||
}
|
||||
}
|
||||
const double MovingTileWallSeconds=std::chrono::duration<double>(
|
||||
Clock::now()-MovingTileStart).count();
|
||||
const double MovingWallSeconds=std::chrono::duration<double>(Clock::now()-MovingStart).count();
|
||||
const double StepDistanceMeters=std::sqrt(
|
||||
static_cast<double>(CameraStepVoxels.X)*CameraStepVoxels.X
|
||||
@@ -502,6 +674,23 @@ namespace StandaloneStreamBenchmark
|
||||
CameraStepVoxels.X,CameraStepVoxels.Y,CameraStepVoxels.Z,StepDistanceMeters,
|
||||
MovedDesired.Tiles.size(),MovingUpdate.NewJobs,MovingFinished,MovingWallSeconds,
|
||||
bUseSharedColumnCache?"on":"off");
|
||||
std::printf("[MovingTileWork] tiles=%d wall_s=%.6f worker_sum_s=%.6f region_compile_wall_s=%.6f crossing_total_s=%.6f\n",
|
||||
MovingFinished,MovingTileWallSeconds,
|
||||
std::accumulate(MovingWorkerSecondsByLOD.begin(),MovingWorkerSecondsByLOD.end(),0.0),
|
||||
RegionCompileWallSeconds,MovingWallSeconds);
|
||||
if(bHashDensity)
|
||||
std::printf("[MovingTileHash] tiles=%d rows=(%zu,%zu,%zu,%zu) density=0x%016llx mesh=0x%016llx payload=0x%016llx topology=0x%016llx status=%s\n",
|
||||
MovingFinished,MovingDensityRows.size(),MovingMeshRows.size(),
|
||||
MovingPayloadRows.size(),MovingTopologyRows.size(),
|
||||
static_cast<unsigned long long>(HashTileRows(MovingDensityRows)),
|
||||
static_cast<unsigned long long>(HashTileRows(MovingMeshRows)),
|
||||
static_cast<unsigned long long>(HashTileRows(MovingPayloadRows)),
|
||||
static_cast<unsigned long long>(HashTileRows(MovingTopologyRows)),
|
||||
MovingDensityRows.size()==static_cast<std::size_t>(MovingFinished)
|
||||
&&MovingMeshRows.size()==static_cast<std::size_t>(MovingFinished)
|
||||
&&MovingPayloadRows.size()==static_cast<std::size_t>(MovingFinished)
|
||||
&&MovingTopologyRows.size()==static_cast<std::size_t>(MovingFinished)
|
||||
?"PASS":"FAIL");
|
||||
for(std::size_t LOD=0;LOD<MovingTilesByLOD.size();++LOD)
|
||||
if(MovingTilesByLOD[LOD]!=0)
|
||||
std::printf("[MovingCameraStepLOD] lod=%zu tiles=%llu worker_sum_s=%.6f\n",
|
||||
@@ -623,12 +812,14 @@ namespace StandaloneStreamBenchmark
|
||||
}
|
||||
}
|
||||
const double NeighborhoodSeconds=std::chrono::duration<double>(NeighborhoodReady-ColdStart).count();
|
||||
const double NeighborhoodMeshSeconds=std::chrono::duration<double>(NeighborhoodReady-ShapeReady).count();
|
||||
const double NeighborhoodMeshSeconds=std::max(0.0,
|
||||
std::chrono::duration<double>(NeighborhoodReady-ShapeReady).count());
|
||||
const double FullDetailSeconds=std::chrono::duration<double>(FullDetailReady-ColdStart).count();
|
||||
const double WholeViewSeconds=std::chrono::duration<double>(WholeViewReady-ColdStart).count();
|
||||
const double StreamSeconds=std::chrono::duration<double>(WholeViewReady-StreamStart).count();
|
||||
std::printf("[StreamPipeline] workers=%d shape=%.3fs neighborhood_mesh=%.3fs neighborhood_ready=%.3fs full_detail_ready=%.3fs whole_view_ready=%.3fs neighborhood_tiles=%d/27 full_detail_tiles=%d/%d whole_tiles=%d/%zu stream_wall=%.3fs cache_hits=0 full_payload=1\n",
|
||||
WorkerCount,ShapeSeconds,NeighborhoodMeshSeconds,NeighborhoodSeconds,
|
||||
const double FirstTileSeconds=std::chrono::duration<double>(FirstTileReady-ColdStart).count();
|
||||
std::printf("[StreamPipeline] workers=%d shape=%.3fs first_tile_ready=%.3fs neighborhood_mesh=%.3fs neighborhood_ready=%.3fs full_detail_ready=%.3fs whole_view_ready=%.3fs neighborhood_tiles=%d/27 full_detail_tiles=%d/%d whole_tiles=%d/%zu stream_wall=%.3fs cache_hits=0 full_payload=1\n",
|
||||
WorkerCount,ShapeSeconds,FirstTileSeconds,NeighborhoodMeshSeconds,NeighborhoodSeconds,
|
||||
FullDetailSeconds,WholeViewSeconds,NeighborhoodFinished,
|
||||
FullDetailFinished,FullDetailExpected,Finished,Desired.Tiles.size(),StreamSeconds);
|
||||
if(bReportMeshCoverage)
|
||||
|
||||
@@ -60,6 +60,7 @@ struct FStandaloneCpuTile
|
||||
bool bHasPayloadHash=false;
|
||||
uint64 TopologyHash=14695981039346656037ull;
|
||||
bool bHasTopologyHash=false;
|
||||
bool bGenerationFailed=false;
|
||||
uint64 MeshPayloadAllocatedBytes=0;
|
||||
VoxelForgeCore::TileGenerationStats CoreDiagnostics{};
|
||||
std::array<uint64,VoxelDensityProfile::BucketCount> ProfileCycles{};
|
||||
@@ -834,6 +835,7 @@ private:
|
||||
if(!Result)
|
||||
{
|
||||
std::fprintf(stderr,"[VoxelForgeCore] tile generation failed: %s\n",Error.c_str());
|
||||
Out.bGenerationFailed=true;
|
||||
Out.WorkerSeconds=std::chrono::duration<double>(FClock::now()-StartTime).count();
|
||||
Out.CompletedAt=FClock::now();return Out;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user