Headless Linux benchmark/hash tool (Clang 19 / GCC 14) sharing the viewer's plan builder and streaming pipeline (moved verbatim into StreamBenchmarkPipeline.h / WorldAssemblyPrototype.h). Owner Round17 view: density/mesh/payload/topology hashes equal the Windows S13 reference at W1/W8/W12 (Clang, 3 runs each) and W8 (GCC), with -ffp-contract=off. No output change. Baseline (i9-12900H, CPUs 0-11, powersave/balance_performance): whole view W8 3.562 s median, W12 3.512 s, W1 16.555 s; peak RSS < 605 MiB. Review: the default-stack crash is 17.3 MiB of static TLS per thread (glibc puts it in the thread stack; HeightfieldColumnCache 6.8 MB), not recursion -- open, after S14. MSVC compile of the viewer refactor not verified (no MSVC here). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
369 lines
22 KiB
C++
369 lines
22 KiB
C++
#pragma once
|
|
|
|
#include "OwnerWorldLoader.h"
|
|
#include "StreamingWorld.h"
|
|
|
|
#include <algorithm>
|
|
#include <array>
|
|
#include <chrono>
|
|
#include <cmath>
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <limits>
|
|
#include <thread>
|
|
#include <unordered_map>
|
|
#include <unordered_set>
|
|
#include <vector>
|
|
|
|
namespace StandaloneStreamBenchmark
|
|
{
|
|
inline void HashWord(uint64& Hash,uint64 Word,int32 Bytes=8)
|
|
{
|
|
for(int32 I=0;I<Bytes;++I)
|
|
{
|
|
Hash^=static_cast<uint8>(Word>>(I*8));
|
|
Hash*=1099511628211ull;
|
|
}
|
|
}
|
|
|
|
struct FHashedTile
|
|
{
|
|
FVoxelTileKey Key;
|
|
uint64 Hash=14695981039346656037ull;
|
|
};
|
|
|
|
inline bool TileKeyLessForHash(const FVoxelTileKey& A,const FVoxelTileKey& B)
|
|
{
|
|
if(A.Level!=B.Level)return A.Level<B.Level;
|
|
if(A.Coord.Z!=B.Coord.Z)return A.Coord.Z<B.Coord.Z;
|
|
if(A.Coord.Y!=B.Coord.Y)return A.Coord.Y<B.Coord.Y;
|
|
return A.Coord.X<B.Coord.X;
|
|
}
|
|
|
|
inline uint64 HashTileRows(std::vector<FHashedTile>& Rows)
|
|
{
|
|
std::sort(Rows.begin(),Rows.end(),[](const FHashedTile& A,const FHashedTile& B)
|
|
{return TileKeyLessForHash(A.Key,B.Key);});
|
|
uint64 Hash=14695981039346656037ull;
|
|
for(const FHashedTile& Row:Rows)
|
|
{
|
|
HashWord(Hash,static_cast<uint32>(Row.Key.Level),4);
|
|
HashWord(Hash,static_cast<uint32>(Row.Key.Coord.X),4);
|
|
HashWord(Hash,static_cast<uint32>(Row.Key.Coord.Y),4);
|
|
HashWord(Hash,static_cast<uint32>(Row.Key.Coord.Z),4);
|
|
HashWord(Hash,Row.Hash);
|
|
}
|
|
return Hash;
|
|
}
|
|
|
|
inline int RunPipelinedStreamingBenchmark(std::shared_ptr<FStandaloneOwnerWorld> OwnerWorld,
|
|
const VoxelForgeCore::ResolvedWorldSnapshot& CoreSnapshot,
|
|
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 bProfileColumnOverlap,
|
|
int32 FarHorizonLOD8InteriorStepVoxels)
|
|
{
|
|
using Clock=std::chrono::steady_clock;
|
|
FStandaloneOwnerWorld& World=*OwnerWorld;
|
|
const bool bRoundTunnels=World.Generator->bStandaloneResearchRoundTunnels;
|
|
const bool bEnhancedTunnelWalls=World.Generator->bStandaloneResearchEnhancedWalls;
|
|
VoxelForgeCore::World Shape(CoreSnapshot);
|
|
FStandaloneDesiredTileSet Desired=StandaloneWorldMesher::BuildDesiredSet(World,CameraPositionVoxels);
|
|
const auto CoreTiles=Shape.desiredTiles(
|
|
{CameraPositionVoxels.X,CameraPositionVoxels.Y,CameraPositionVoxels.Z});
|
|
Desired.Tiles.clear();Desired.Tiles.reserve(CoreTiles.size());
|
|
for(const auto& Key:CoreTiles)
|
|
Desired.Tiles.emplace_back(FIntVector(Key.coordinate.x,Key.coordinate.y,Key.coordinate.z),Key.lod);
|
|
if(MaxLevel>=0)
|
|
Desired.Tiles.erase(std::remove_if(Desired.Tiles.begin(),Desired.Tiles.end(),
|
|
[&](const FVoxelTileKey& Tile){return Tile.Level>MaxLevel;}),Desired.Tiles.end());
|
|
FIntVector FineMin(INT32_MAX,INT32_MAX,INT32_MAX),FineMax(INT32_MIN,INT32_MIN,INT32_MIN);
|
|
FIntVector ClipMin(INT32_MAX,INT32_MAX,INT32_MAX),ClipMax(INT32_MIN,INT32_MIN,INT32_MIN);
|
|
for(const FVoxelTileKey& Tile:Desired.Tiles)
|
|
{
|
|
const FIntVector Origin=Tile.OriginVoxels();const int32 Extent=Tile.ExtentVoxels();
|
|
ClipMin.X=std::min(ClipMin.X,Origin.X);ClipMin.Y=std::min(ClipMin.Y,Origin.Y);ClipMin.Z=std::min(ClipMin.Z,Origin.Z);
|
|
ClipMax.X=std::max(ClipMax.X,Origin.X+Extent);ClipMax.Y=std::max(ClipMax.Y,Origin.Y+Extent);ClipMax.Z=std::max(ClipMax.Z,Origin.Z+Extent);
|
|
if(Tile.Level<World.FullResClipLevels)
|
|
{
|
|
FineMin.X=std::min(FineMin.X,Origin.X);FineMin.Y=std::min(FineMin.Y,Origin.Y);FineMin.Z=std::min(FineMin.Z,Origin.Z);
|
|
FineMax.X=std::max(FineMax.X,Origin.X+Extent);FineMax.Y=std::max(FineMax.Y,Origin.Y+Extent);FineMax.Z=std::max(FineMax.Z,Origin.Z+Extent);
|
|
}
|
|
}
|
|
if(FineMin.X==INT32_MAX||ClipMin.X==INT32_MAX)
|
|
{std::fprintf(stderr,"[StreamPipeline] no desired detail or clipmap tiles.\n");return 7;}
|
|
|
|
const FIntVector CenterChunk=Desired.CenterChunk;
|
|
std::unordered_set<FVoxelTileKey,FStandaloneTileKeyHash> Neighborhood;
|
|
Neighborhood.reserve(32);
|
|
for(const FVoxelTileKey& Tile:Desired.Tiles)
|
|
if(Tile.Level==0&&std::abs(Tile.Coord.X-CenterChunk.X)<=1
|
|
&&std::abs(Tile.Coord.Y-CenterChunk.Y)<=1&&std::abs(Tile.Coord.Z-CenterChunk.Z)<=1)
|
|
Neighborhood.insert(Tile);
|
|
if(Neighborhood.size()!=27)
|
|
{std::fprintf(stderr,"[StreamPipeline] expected 27 player-neighborhood tiles, found %zu.\n",Neighborhood.size());return 7;}
|
|
|
|
// 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();
|
|
World.Manager.reset();
|
|
World.DefinitionStorage.clear();
|
|
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};
|
|
ShapeRequest.clipMinVoxel={ClipMin.X,ClipMin.Y,ClipMin.Z};
|
|
ShapeRequest.clipMaxVoxel={ClipMax.X,ClipMax.Y,ClipMax.Z};
|
|
ShapeRequest.workerLimit=static_cast<uint32>(std::clamp(WorkerCount,1,16));
|
|
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);
|
|
const auto StreamStart=Clock::now();
|
|
const FStandaloneStreamingUpdate Update=Streamer.StartWithDesired(Desired);
|
|
if(Update.DesiredTiles!=static_cast<int32>(Desired.Tiles.size()))
|
|
{
|
|
Streamer.Stop();
|
|
std::fprintf(stderr,"[StreamPipeline] expected %zu tiles but queued %d.\n",
|
|
Desired.Tiles.size(),Update.DesiredTiles);return 7;
|
|
}
|
|
|
|
std::vector<FHashedTile> DensityRows,MeshRows,PayloadRows,TopologyRows;
|
|
int32 Finished=0,NeighborhoodFinished=0,FullDetailFinished=0;
|
|
int32 FullDetailExpected=0;
|
|
struct FColumnXY
|
|
{
|
|
std::int64_t X=0,Y=0;
|
|
bool operator==(const FColumnXY&)const=default;
|
|
};
|
|
struct FColumnXYHash
|
|
{
|
|
std::size_t operator()(const FColumnXY& Value)const noexcept
|
|
{
|
|
const std::size_t X=std::hash<std::int64_t>{}(Value.X);
|
|
const std::size_t Y=std::hash<std::int64_t>{}(Value.Y);
|
|
return X^(Y+static_cast<std::size_t>(0x9E3779B9u)+(X<<6)+(X>>2));
|
|
}
|
|
};
|
|
struct FFirstColumnUse
|
|
{
|
|
FVoxelTileKey Tile;
|
|
std::uint64_t WorkerHash=0;
|
|
};
|
|
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{};
|
|
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!=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);
|
|
return std::max({DX,DY,DZ})<=1&&(DX+DY+DZ)>0;
|
|
};
|
|
uint64 NativeSolidBoxes=0,NativeAirBoxes=0,NativeMixedBoxes=0,NativeUnknownBoxes=0;
|
|
uint64 NativeFieldCalls=0,NativeColumnHits=0,NativeColumnMisses=0,NativeMeshingSkips=0;
|
|
double NativeClassificationMilliseconds=0.0,NativeColumnComputeMilliseconds=0.0;
|
|
double NativeMeshingMilliseconds=0.0;
|
|
for(const FVoxelTileKey& Tile:Desired.Tiles)
|
|
if(Tile.Level<World.FullResClipLevels)++FullDetailExpected;
|
|
Clock::time_point NeighborhoodReady{},FullDetailReady{},WholeViewReady{};
|
|
bool bNeighborhoodReported=false,bFullDetailReported=false;
|
|
while(Finished<Update.DesiredTiles)
|
|
{
|
|
std::vector<FStandaloneCpuTile> Ready=Streamer.TakeReady();
|
|
if(Ready.empty()){std::this_thread::sleep_for(std::chrono::milliseconds(1));continue;}
|
|
for(const FStandaloneCpuTile& Tile:Ready)
|
|
{
|
|
++Finished;
|
|
if(Tile.Key.Level>=0&&Tile.Key.Level<static_cast<int32>(TileCountByLOD.size()))
|
|
{
|
|
const std::size_t LOD=static_cast<std::size_t>(Tile.Key.Level);
|
|
++TileCountByLOD[LOD];
|
|
WorkerSecondsByLOD[LOD]+=Tile.WorkerSeconds;
|
|
ColumnEvalMsByLOD[LOD]+=Tile.CoreDiagnostics.columnEvaluationExclusiveMilliseconds;
|
|
MarchingExclusiveMsByLOD[LOD]+=Tile.CoreDiagnostics.marchingCubesExclusiveMilliseconds;
|
|
GroundRefineExclusiveMsByLOD[LOD]+=Tile.CoreDiagnostics.groundRefinementExclusiveMilliseconds;
|
|
CapRefineExclusiveMsByLOD[LOD]+=Tile.CoreDiagnostics.capRefinementExclusiveMilliseconds;
|
|
MeshAssemblyMsByLOD[LOD]+=Tile.CoreDiagnostics.meshAssemblyMilliseconds;
|
|
}
|
|
if(bProfileColumnOverlap&&Tile.Key.Level>=0
|
|
&&Tile.Key.Level<static_cast<int32>(ColumnCaptureTilesByLOD.size()))
|
|
{
|
|
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;
|
|
std::sort(Coordinates.begin(),Coordinates.end());
|
|
Coordinates.erase(std::unique(Coordinates.begin(),Coordinates.end()),Coordinates.end());
|
|
for(const auto& Coordinate:Coordinates)
|
|
{
|
|
const FColumnXY XY{Coordinate[0],Coordinate[1]};
|
|
auto [Uses,Inserted]=ColumnUsesByLOD[LOD].try_emplace(XY);
|
|
std::vector<FFirstColumnUse>& PriorUses=Uses->second;
|
|
if(Inserted)
|
|
{
|
|
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);
|
|
if(Neighborhood.contains(Tile.Key))
|
|
{
|
|
++NeighborhoodFinished;
|
|
NeighborhoodReady=std::max(NeighborhoodReady,Tile.CompletedAt);
|
|
}
|
|
if(Tile.Key.Level<World.FullResClipLevels)
|
|
{
|
|
++FullDetailFinished;
|
|
FullDetailReady=std::max(FullDetailReady,Tile.CompletedAt);
|
|
NativeSolidBoxes+=Tile.CoreDiagnostics.solidBoxes;
|
|
NativeAirBoxes+=Tile.CoreDiagnostics.airBoxes;
|
|
NativeMixedBoxes+=Tile.CoreDiagnostics.mixedBoxes;
|
|
NativeUnknownBoxes+=Tile.CoreDiagnostics.unknownBoxes;
|
|
NativeFieldCalls+=Tile.CoreDiagnostics.fieldCalls;
|
|
NativeColumnHits+=Tile.CoreDiagnostics.columnCacheHits;
|
|
NativeColumnMisses+=Tile.CoreDiagnostics.columnCacheMisses;
|
|
NativeMeshingSkips+=Tile.CoreDiagnostics.meshingSkipped?1u:0u;
|
|
NativeClassificationMilliseconds+=Tile.CoreDiagnostics.classificationMilliseconds;
|
|
NativeColumnComputeMilliseconds+=Tile.CoreDiagnostics.columnComputeMilliseconds;
|
|
NativeMeshingMilliseconds+=Tile.CoreDiagnostics.meshingMilliseconds;
|
|
}
|
|
if(bHashDensity)
|
|
{
|
|
if(Tile.bHasDensityHash)DensityRows.push_back({Tile.Key,Tile.DensityHash});
|
|
if(Tile.bHasMeshHash)MeshRows.push_back({Tile.Key,Tile.MeshHash});
|
|
if(Tile.bHasPayloadHash)PayloadRows.push_back({Tile.Key,Tile.PayloadHash});
|
|
if(Tile.bHasTopologyHash)TopologyRows.push_back({Tile.Key,Tile.TopologyHash});
|
|
}
|
|
}
|
|
if(!bNeighborhoodReported&&NeighborhoodFinished==static_cast<int32>(Neighborhood.size()))
|
|
{
|
|
std::printf("[PipelineMilestone] neighborhood_ready=%.3fs generated=%d/27\n",
|
|
std::chrono::duration<double>(NeighborhoodReady-ColdStart).count(),NeighborhoodFinished);
|
|
bNeighborhoodReported=true;
|
|
}
|
|
if(!bFullDetailReported&&FullDetailFinished==FullDetailExpected)
|
|
{
|
|
std::printf("[PipelineMilestone] full_detail_ready=%.3fs generated=%d/%d\n",
|
|
std::chrono::duration<double>(FullDetailReady-ColdStart).count(),
|
|
FullDetailFinished,FullDetailExpected);
|
|
bFullDetailReported=true;
|
|
}
|
|
}
|
|
Streamer.Stop();
|
|
bool bColumnOverlapCapturePassing=true;
|
|
if(bProfileColumnOverlap)
|
|
{
|
|
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)
|
|
{
|
|
std::printf("[WorldAssemblerLODWorker] lod=%zu tiles=%llu worker_sum_s=%.6f column_eval_exclusive_ms=%.3f mc_exclusive_ms=%.3f ground_refine_exclusive_ms=%.3f cap_refine_exclusive_ms=%.3f mesh_assembly_ms=%.3f\n",
|
|
LOD,static_cast<unsigned long long>(TileCountByLOD[LOD]),WorkerSecondsByLOD[LOD],
|
|
ColumnEvalMsByLOD[LOD],MarchingExclusiveMsByLOD[LOD],
|
|
GroundRefineExclusiveMsByLOD[LOD],CapRefineExclusiveMsByLOD[LOD],MeshAssemblyMsByLOD[LOD]);
|
|
}
|
|
const double NeighborhoodSeconds=std::chrono::duration<double>(NeighborhoodReady-ColdStart).count();
|
|
const double NeighborhoodMeshSeconds=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,
|
|
FullDetailSeconds,WholeViewSeconds,NeighborhoodFinished,
|
|
FullDetailFinished,FullDetailExpected,Finished,Desired.Tiles.size(),StreamSeconds);
|
|
std::printf("[WorldAssemblerTilePipeline] full_detail_tiles=%d solid_boxes=%llu air_boxes=%llu mixed_boxes=%llu unknown_boxes=%llu whole_tile_skips=%llu field_calls=%llu column_cache_hits=%llu column_cache_misses=%llu column_compute_worker_ms=%.3f classification_worker_ms=%.3f meshing_worker_ms=%.3f\n",
|
|
FullDetailExpected,static_cast<unsigned long long>(NativeSolidBoxes),
|
|
static_cast<unsigned long long>(NativeAirBoxes),
|
|
static_cast<unsigned long long>(NativeMixedBoxes),
|
|
static_cast<unsigned long long>(NativeUnknownBoxes),
|
|
static_cast<unsigned long long>(NativeMeshingSkips),
|
|
static_cast<unsigned long long>(NativeFieldCalls),
|
|
static_cast<unsigned long long>(NativeColumnHits),
|
|
static_cast<unsigned long long>(NativeColumnMisses),
|
|
NativeColumnComputeMilliseconds,NativeClassificationMilliseconds,
|
|
NativeMeshingMilliseconds);
|
|
|
|
bool bHashesPassing=true;
|
|
if(bHashDensity)
|
|
{
|
|
bHashesPassing=DensityRows.size()==Desired.Tiles.size()
|
|
&&MeshRows.size()==Desired.Tiles.size()
|
|
&&PayloadRows.size()==Desired.Tiles.size()
|
|
&&TopologyRows.size()==Desired.Tiles.size();
|
|
std::vector<FHashedTile> FullDensity,FullMesh,FullPayload,FullTopology;
|
|
for(const FHashedTile& Row:DensityRows)if(Row.Key.Level<World.FullResClipLevels)FullDensity.push_back(Row);
|
|
for(const FHashedTile& Row:MeshRows)if(Row.Key.Level<World.FullResClipLevels)FullMesh.push_back(Row);
|
|
for(const FHashedTile& Row:PayloadRows)if(Row.Key.Level<World.FullResClipLevels)FullPayload.push_back(Row);
|
|
for(const FHashedTile& Row:TopologyRows)if(Row.Key.Level<World.FullResClipLevels)FullTopology.push_back(Row);
|
|
std::printf("[PipelineFullDetailHash] tiles=%d density=0x%016llx mesh=0x%016llx payload=0x%016llx topology=0x%016llx\n",
|
|
FullDetailExpected,static_cast<unsigned long long>(HashTileRows(FullDensity)),
|
|
static_cast<unsigned long long>(HashTileRows(FullMesh)),
|
|
static_cast<unsigned long long>(HashTileRows(FullPayload)),
|
|
static_cast<unsigned long long>(HashTileRows(FullTopology)));
|
|
std::printf("[PipelineWholeViewHash] tiles=%zu density=0x%016llx mesh=0x%016llx payload=0x%016llx topology=0x%016llx\n",
|
|
Desired.Tiles.size(),static_cast<unsigned long long>(HashTileRows(DensityRows)),
|
|
static_cast<unsigned long long>(HashTileRows(MeshRows)),
|
|
static_cast<unsigned long long>(HashTileRows(PayloadRows)),
|
|
static_cast<unsigned long long>(HashTileRows(TopologyRows)));
|
|
}
|
|
return NeighborhoodFinished==static_cast<int32>(Neighborhood.size())
|
|
&&FullDetailFinished==FullDetailExpected&&Finished==Update.DesiredTiles&&bHashesPassing
|
|
&&(!bProfileColumnOverlap||bColumnOverlapCapturePassing)?0:6;
|
|
}
|
|
} // namespace StandaloneStreamBenchmark
|