wip(assembler): round S13 -- tile cost counted per LOD (diagnostics only, no output change)
Exclusive per-stage tile timers and probes. Findings: LOD0 is MC-exclusive (10.4 of 14 ms p95, 243 ns/sample); LOD4's 3x cost is column-cache misses (8,224 vs ~1,600-1,900 at LOD3/5), cap refine secondary; per-tile feature lists cost ~0.001 ms; cross-worker column repeats common (277k at LOD0). Global octave drop and stride-2 interpolation probes fail the 2 cm gate. Worker cap 1 kept (cap 0 worse 40 m/s tick tail). Report: Standalone/Research/WorldAssemblerM3/Round17. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
This commit is contained in:
1 parent
212814a75c
commit
87b0e5d8cd
9 files changed
+763
-76
No files matched your search
@@ -6976,7 +6976,7 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
const FVector& CameraPositionVoxels,int32 WorkerCount,int32 MaxLevel,
|
||||
VoxelForgeCore::DetailVariant DetailVariant,const VoxelForgeCore::JobScheduler& Scheduler,
|
||||
bool bHashDensity,bool bSkipUvAndColors,bool bSkipMaterialGroups,bool bSkipUV,bool bSkipColors,
|
||||
std::chrono::steady_clock::time_point ColdStart,bool bProfileFarColumnOverlap,
|
||||
std::chrono::steady_clock::time_point ColdStart,bool bProfileColumnOverlap,
|
||||
int32 FarHorizonLOD8InteriorStepVoxels)
|
||||
{
|
||||
using Clock=std::chrono::steady_clock;
|
||||
@@ -7045,7 +7045,7 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
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,bProfileFarColumnOverlap,
|
||||
bSkipUvAndColors,bSkipMaterialGroups,bSkipUV,bSkipColors,&Shape,bProfileColumnOverlap,
|
||||
FarHorizonLOD8InteriorStepVoxels);
|
||||
const auto StreamStart=Clock::now();
|
||||
const FStandaloneStreamingUpdate Update=Streamer.StartWithDesired(Desired);
|
||||
@@ -7078,19 +7078,23 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
FVoxelTileKey Tile;
|
||||
std::uint64_t WorkerHash=0;
|
||||
};
|
||||
std::unordered_map<FColumnXY,FFirstColumnUse,FColumnXYHash> LOD8ColumnFirstUse;
|
||||
std::uint64_t LOD8ColumnDuplicateEvents=0,LOD8NeighbourDuplicateEvents=0;
|
||||
std::uint64_t LOD8CrossWorkerNeighbourDuplicateEvents=0;
|
||||
std::size_t LOD8ColumnCaptureTiles=0;
|
||||
bool bLOD8ColumnCaptureComplete=true;
|
||||
std::array<std::unordered_map<FColumnXY,std::vector<FFirstColumnUse>,FColumnXYHash>,9> ColumnUsesByLOD;
|
||||
std::array<std::uint64_t,9> ColumnDuplicateEventsByLOD{},NeighbourDuplicateEventsByLOD{};
|
||||
std::array<std::uint64_t,9> CrossWorkerNeighbourDuplicateEventsByLOD{};
|
||||
std::array<std::uint64_t,9> ColumnCaptureTilesByLOD{},ExpectedTilesByLOD{};
|
||||
std::array<bool,9> ColumnCaptureCompleteByLOD{};
|
||||
ColumnCaptureCompleteByLOD.fill(true);
|
||||
std::array<double,9> WorkerSecondsByLOD{};
|
||||
std::array<double,9> ColumnEvalMsByLOD{},MarchingExclusiveMsByLOD{};
|
||||
std::array<double,9> GroundRefineExclusiveMsByLOD{},CapRefineExclusiveMsByLOD{};
|
||||
std::array<double,9> MeshAssemblyMsByLOD{};
|
||||
std::array<std::uint64_t,9> TileCountByLOD{};
|
||||
const auto AreLOD8Neighbours=[](const FVoxelTileKey& A,const FVoxelTileKey& B)
|
||||
for(const FVoxelTileKey& Tile:Desired.Tiles)
|
||||
if(Tile.Level>=0&&Tile.Level<static_cast<int32>(ExpectedTilesByLOD.size()))
|
||||
++ExpectedTilesByLOD[static_cast<std::size_t>(Tile.Level)];
|
||||
const auto AreSameLODNeighbours=[](const FVoxelTileKey& A,const FVoxelTileKey& B)
|
||||
{
|
||||
if(A.Level!=8||B.Level!=8)return false;
|
||||
if(A.Level!=B.Level)return false;
|
||||
const std::int64_t DX=std::abs(static_cast<std::int64_t>(A.Coord.X)-B.Coord.X);
|
||||
const std::int64_t DY=std::abs(static_cast<std::int64_t>(A.Coord.Y)-B.Coord.Y);
|
||||
const std::int64_t DZ=std::abs(static_cast<std::int64_t>(A.Coord.Z)-B.Coord.Z);
|
||||
@@ -7122,10 +7126,12 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
CapRefineExclusiveMsByLOD[LOD]+=Tile.CoreDiagnostics.capRefinementExclusiveMilliseconds;
|
||||
MeshAssemblyMsByLOD[LOD]+=Tile.CoreDiagnostics.meshAssemblyMilliseconds;
|
||||
}
|
||||
if(bProfileFarColumnOverlap&&Tile.Key.Level==8)
|
||||
if(bProfileColumnOverlap&&Tile.Key.Level>=0
|
||||
&&Tile.Key.Level<static_cast<int32>(ColumnCaptureTilesByLOD.size()))
|
||||
{
|
||||
++LOD8ColumnCaptureTiles;
|
||||
bLOD8ColumnCaptureComplete=bLOD8ColumnCaptureComplete
|
||||
const std::size_t LOD=static_cast<std::size_t>(Tile.Key.Level);
|
||||
++ColumnCaptureTilesByLOD[LOD];
|
||||
ColumnCaptureCompleteByLOD[LOD]=ColumnCaptureCompleteByLOD[LOD]
|
||||
&&Tile.CoreDiagnostics.columnCoordinateCaptureComplete;
|
||||
std::vector<std::array<std::int64_t,2>> Coordinates=
|
||||
Tile.CoreDiagnostics.evaluatedColumnCoordinates;
|
||||
@@ -7134,16 +7140,26 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
for(const auto& Coordinate:Coordinates)
|
||||
{
|
||||
const FColumnXY XY{Coordinate[0],Coordinate[1]};
|
||||
const auto [First,Inserted]=LOD8ColumnFirstUse.try_emplace(XY,
|
||||
FFirstColumnUse{Tile.Key,Tile.CoreDiagnostics.columnEvaluationWorkerHash});
|
||||
if(Inserted)continue;
|
||||
++LOD8ColumnDuplicateEvents;
|
||||
if(AreLOD8Neighbours(First->second.Tile,Tile.Key))
|
||||
auto [Uses,Inserted]=ColumnUsesByLOD[LOD].try_emplace(XY);
|
||||
std::vector<FFirstColumnUse>& PriorUses=Uses->second;
|
||||
if(Inserted)
|
||||
{
|
||||
++LOD8NeighbourDuplicateEvents;
|
||||
if(First->second.WorkerHash!=Tile.CoreDiagnostics.columnEvaluationWorkerHash)
|
||||
++LOD8CrossWorkerNeighbourDuplicateEvents;
|
||||
PriorUses.push_back({Tile.Key,Tile.CoreDiagnostics.columnEvaluationWorkerHash});
|
||||
continue;
|
||||
}
|
||||
++ColumnDuplicateEventsByLOD[LOD];
|
||||
bool bHasNeighbourDuplicate=false,bHasCrossWorkerNeighbourDuplicate=false;
|
||||
for(const FFirstColumnUse& Prior:PriorUses)
|
||||
{
|
||||
if(!AreSameLODNeighbours(Prior.Tile,Tile.Key))continue;
|
||||
bHasNeighbourDuplicate=true;
|
||||
bHasCrossWorkerNeighbourDuplicate=bHasCrossWorkerNeighbourDuplicate
|
||||
||Prior.WorkerHash!=Tile.CoreDiagnostics.columnEvaluationWorkerHash;
|
||||
}
|
||||
if(bHasNeighbourDuplicate)++NeighbourDuplicateEventsByLOD[LOD];
|
||||
if(bHasCrossWorkerNeighbourDuplicate)
|
||||
++CrossWorkerNeighbourDuplicateEventsByLOD[LOD];
|
||||
PriorUses.push_back({Tile.Key,Tile.CoreDiagnostics.columnEvaluationWorkerHash});
|
||||
}
|
||||
}
|
||||
WholeViewReady=std::max(WholeViewReady,Tile.CompletedAt);
|
||||
@@ -7191,14 +7207,23 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
}
|
||||
}
|
||||
Streamer.Stop();
|
||||
if(bProfileFarColumnOverlap)
|
||||
bool bColumnOverlapCapturePassing=true;
|
||||
if(bProfileColumnOverlap)
|
||||
{
|
||||
std::printf("[WorldAssemblerLOD8ColumnOverlap] tiles=%zu unique_xy_columns=%zu repeated_tile_evaluations=%llu neighbouring_duplicate_evaluations=%llu cross_worker_neighbouring_duplicates=%llu capture_complete=%d\n",
|
||||
LOD8ColumnCaptureTiles,LOD8ColumnFirstUse.size(),
|
||||
static_cast<unsigned long long>(LOD8ColumnDuplicateEvents),
|
||||
static_cast<unsigned long long>(LOD8NeighbourDuplicateEvents),
|
||||
static_cast<unsigned long long>(LOD8CrossWorkerNeighbourDuplicateEvents),
|
||||
bLOD8ColumnCaptureComplete?1:0);
|
||||
for(std::size_t LOD=0;LOD<ColumnCaptureTilesByLOD.size();++LOD)
|
||||
{
|
||||
const bool bLODComplete=ColumnCaptureCompleteByLOD[LOD]
|
||||
&&ColumnCaptureTilesByLOD[LOD]==ExpectedTilesByLOD[LOD];
|
||||
bColumnOverlapCapturePassing=bColumnOverlapCapturePassing&&bLODComplete;
|
||||
std::printf("[WorldAssemblerLODColumnOverlap] lod=%zu tiles=%llu expected_tiles=%llu unique_xy_columns=%zu repeated_tile_evaluations=%llu neighbouring_duplicate_evaluations=%llu cross_worker_neighbouring_duplicates=%llu capture_complete=%d\n",
|
||||
LOD,static_cast<unsigned long long>(ColumnCaptureTilesByLOD[LOD]),
|
||||
static_cast<unsigned long long>(ExpectedTilesByLOD[LOD]),
|
||||
ColumnUsesByLOD[LOD].size(),
|
||||
static_cast<unsigned long long>(ColumnDuplicateEventsByLOD[LOD]),
|
||||
static_cast<unsigned long long>(NeighbourDuplicateEventsByLOD[LOD]),
|
||||
static_cast<unsigned long long>(CrossWorkerNeighbourDuplicateEventsByLOD[LOD]),
|
||||
bLODComplete?1:0);
|
||||
}
|
||||
}
|
||||
for(std::size_t LOD=0;LOD<TileCountByLOD.size();++LOD)
|
||||
{
|
||||
@@ -7253,7 +7278,7 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
}
|
||||
return NeighborhoodFinished==static_cast<int32>(Neighborhood.size())
|
||||
&&FullDetailFinished==FullDetailExpected&&Finished==Update.DesiredTiles&&bHashesPassing
|
||||
&&(!bProfileFarColumnOverlap||(bLOD8ColumnCaptureComplete&&LOD8ColumnCaptureTiles>0))?0:6;
|
||||
&&(!bProfileColumnOverlap||bColumnOverlapCapturePassing)?0:6;
|
||||
}
|
||||
int RunStreamingBenchmark(FStandaloneOwnerWorld& World,VoxelForgeCore::World* CoreWorld,
|
||||
const FVector& CameraPositionVoxels,
|
||||
@@ -9601,7 +9626,7 @@ int main(int Argc,char** Argv)
|
||||
std::string WorldAssemblyManifestOutputPath;
|
||||
bool bStreamBenchmark=false;
|
||||
bool bStreamPipeline=false;
|
||||
bool bProfileFarColumnOverlap=false;
|
||||
bool bProfileColumnOverlap=false;
|
||||
bool bCoarseFirstStreamOrder=false;
|
||||
bool bProfileDetailBand=false;
|
||||
bool bPassageDetailAuditOnly=false;
|
||||
@@ -9739,8 +9764,8 @@ int main(int Argc,char** Argv)
|
||||
else if(Arg=="--coarse-first-stream-order")bCoarseFirstStreamOrder=true;
|
||||
else if(Arg=="--stream-pipeline")
|
||||
{bStreamPipeline=true;bStreamBenchmark=true;App.bShapeWorld=true;App.bForceGenerate=true;}
|
||||
else if(Arg=="--profile-far-column-overlap")
|
||||
{bProfileFarColumnOverlap=true;bStreamPipeline=true;bStreamBenchmark=true;App.bShapeWorld=true;App.bForceGenerate=true;}
|
||||
else if(Arg=="--profile-column-overlap"||Arg=="--profile-far-column-overlap")
|
||||
{bProfileColumnOverlap=true;bStreamPipeline=true;bStreamBenchmark=true;App.bShapeWorld=true;App.bForceGenerate=true;}
|
||||
else if(Arg=="--edit-benchmark")
|
||||
{bEditBenchmark=true;bStreamBenchmark=true;App.bShapeWorld=true;}
|
||||
else if(Arg=="--stream-hash")bStreamHash=true;
|
||||
@@ -9957,7 +9982,7 @@ int main(int Argc,char** Argv)
|
||||
FVector(App.Position.X*4.0,App.Position.Y*4.0,App.Position.Z*4.0),
|
||||
App.WorkerCount,StreamBenchmarkMaxLevel,App.ShapeDetailVariant,App.CoreScheduler,
|
||||
bStreamHash||!BakeMeshCachePath.empty(),bSkipUvAndColors,bSkipMaterialGroups,
|
||||
bSkipUV,bSkipColors,ColdProcessStart,bProfileFarColumnOverlap,
|
||||
bSkipUV,bSkipColors,ColdProcessStart,bProfileColumnOverlap,
|
||||
App.FarHorizonLOD8InteriorStepVoxels);
|
||||
if(bEditBenchmark)
|
||||
return RunEditTransactionBenchmark(*App.World,*App.ShapeWorld,
|
||||
|
||||
@@ -424,13 +424,13 @@ public:
|
||||
bool bInSkipUV=false,
|
||||
bool bInSkipColors=false,
|
||||
VoxelForgeCore::World* InCoreWorld=nullptr,
|
||||
bool bInCaptureFarColumnCoordinates=false,
|
||||
bool bInCaptureColumnCoordinates=false,
|
||||
int32 InLod8HorizonInteriorStepVoxels=0)
|
||||
:World(&InWorld),WorkerCount(FMath::Clamp(InWorkerCount,1,16)),bHashDensity(bInHashDensity),
|
||||
MeshCache(InMeshCache),MaxLevelFilter(InMaxLevelFilter),
|
||||
CoreWorld(InCoreWorld),bSkipUvAndColors(bInSkipUvAndColors),bSkipMaterialGroups(bInSkipMaterialGroups),
|
||||
bSkipUV(bInSkipUV),bSkipColors(bInSkipColors),
|
||||
bCaptureFarColumnCoordinates(bInCaptureFarColumnCoordinates),
|
||||
bCaptureColumnCoordinates(bInCaptureColumnCoordinates),
|
||||
Lod8HorizonInteriorStepVoxels(std::max(0,InLod8HorizonInteriorStepVoxels))
|
||||
{
|
||||
VoxelGenLOD::InitializeConsoleSwitches();
|
||||
@@ -799,7 +799,7 @@ private:
|
||||
Options.bandMinZVoxel=Job.BandZMin;Options.bandMaxZVoxel=Job.BandZMax;
|
||||
Options.hashDensity=bHashDensity;Options.skipUvAndColors=bSkipUvAndColors;
|
||||
Options.skipMaterialGroups=bSkipMaterialGroups;Options.skipUv=bSkipUV;Options.skipColors=bSkipColors;
|
||||
Options.captureColumnCoordinates=bCaptureFarColumnCoordinates&&Level==8;
|
||||
Options.captureColumnCoordinates=bCaptureColumnCoordinates;
|
||||
Options.lod8HorizonInteriorStepVoxels=Lod8HorizonInteriorStepVoxels;
|
||||
std::string Error;
|
||||
auto Result=CoreWorld->generateTile(
|
||||
@@ -971,7 +971,7 @@ private:
|
||||
bool bSkipMaterialGroups=false;
|
||||
bool bSkipUV=false;
|
||||
bool bSkipColors=false;
|
||||
bool bCaptureFarColumnCoordinates=false;
|
||||
bool bCaptureColumnCoordinates=false;
|
||||
int32 Lod8HorizonInteriorStepVoxels=0;
|
||||
std::atomic<uint64> CacheHitCount{0};
|
||||
mutable std::mutex Mutex;
|
||||
|
||||
Reference in new issue
Block a user