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
@@ -1479,12 +1479,18 @@ namespace VoxelForgeCore
|
||||
const bool bSkipFarShellRepair=key.lod>=7&&bUseNativeSurfaceHorizon;
|
||||
FStandaloneShapeWorld::ResetThreadClassificationStats();
|
||||
VoxelForgeCore::Heightfield2D::resetThreadColumnCacheStats(
|
||||
options.captureColumnCoordinates&&key.lod==8);
|
||||
options.captureColumnCoordinates);
|
||||
bool bNativeSurfaceTile=false;
|
||||
bool bNativeSurfaceBandSafe=false;
|
||||
double classificationColumnComputeMilliseconds=0.0;
|
||||
if(bHasWorldAssembly)
|
||||
{
|
||||
const double columnMillisecondsBeforeClassification=
|
||||
VoxelForgeCore::Heightfield2D::threadColumnCacheStats().columnComputeMilliseconds;
|
||||
const auto Classification=tileShape.ClassifyBoxDetailed(origin,step,cells);
|
||||
classificationColumnComputeMilliseconds=std::max(0.0,
|
||||
VoxelForgeCore::Heightfield2D::threadColumnCacheStats().columnComputeMilliseconds
|
||||
-columnMillisecondsBeforeClassification);
|
||||
bNativeSurfaceTile=Classification.bNativeSurface;
|
||||
// NativeSurfaceDensityAt consumes only the bounded manifest heightfield and its
|
||||
// bounded type-2/type-4 features. Unknown tile occupancy does not make that Z support
|
||||
@@ -1518,7 +1524,16 @@ namespace VoxelForgeCore
|
||||
out.diagnostics.columnCacheHits=Columns.columnHits;
|
||||
out.diagnostics.columnCacheMisses=Columns.columnMisses;
|
||||
out.diagnostics.classificationMilliseconds=Counts.Milliseconds;
|
||||
out.diagnostics.classificationExclusiveMilliseconds=std::max(0.0,
|
||||
Counts.Milliseconds-classificationColumnComputeMilliseconds);
|
||||
out.diagnostics.columnComputeMilliseconds=Columns.columnComputeMilliseconds;
|
||||
if(options.captureColumnCoordinates)
|
||||
{
|
||||
out.diagnostics.columnEvaluationWorkerHash=static_cast<std::uint64_t>(
|
||||
std::hash<std::thread::id>{}(std::this_thread::get_id()))+1u;
|
||||
out.diagnostics.columnCoordinateCaptureComplete=Columns.coordinateCaptureComplete;
|
||||
out.diagnostics.evaluatedColumnCoordinates=Columns.evaluatedCoordinates;
|
||||
}
|
||||
out.densitySampleCount=0;
|
||||
return out;
|
||||
}
|
||||
@@ -1662,6 +1677,8 @@ namespace VoxelForgeCore
|
||||
VoxelForgeCore::Heightfield2D::threadColumnCacheStats().columnComputeMilliseconds;
|
||||
out.diagnostics.marchingCubesExclusiveMilliseconds=std::max(0.0,
|
||||
MarchingCubesWallMilliseconds-(ColumnMillisecondsAfterMeshing-ColumnMillisecondsBeforeMeshing));
|
||||
out.diagnostics.marchingCubesColumnComputeMilliseconds=std::max(0.0,
|
||||
ColumnMillisecondsAfterMeshing-ColumnMillisecondsBeforeMeshing);
|
||||
const double MeshingMilliseconds=std::chrono::duration<double,std::milli>(
|
||||
std::chrono::steady_clock::now()-MeshingStart).count();
|
||||
out.diagnostics.farHorizonVersion=key.lod>=4?options.farHorizonVersion:0;
|
||||
@@ -1712,6 +1729,8 @@ namespace VoxelForgeCore
|
||||
VoxelForgeCore::Heightfield2D::threadColumnCacheStats().columnComputeMilliseconds;
|
||||
out.diagnostics.groundRefinementExclusiveMilliseconds=std::max(0.0,
|
||||
GroundWallMilliseconds-(ColumnMillisecondsAfterGround-ColumnMillisecondsBeforeGround));
|
||||
out.diagnostics.groundRefinementColumnComputeMilliseconds=std::max(0.0,
|
||||
ColumnMillisecondsAfterGround-ColumnMillisecondsBeforeGround);
|
||||
const double ColumnMillisecondsBeforeCap=
|
||||
VoxelForgeCore::Heightfield2D::threadColumnCacheStats().columnComputeMilliseconds;
|
||||
const auto CapStart=std::chrono::steady_clock::now();
|
||||
@@ -1723,6 +1742,8 @@ namespace VoxelForgeCore
|
||||
VoxelForgeCore::Heightfield2D::threadColumnCacheStats().columnComputeMilliseconds;
|
||||
out.diagnostics.capRefinementExclusiveMilliseconds=std::max(0.0,
|
||||
CapWallMilliseconds-(ColumnMillisecondsAfterCap-ColumnMillisecondsBeforeCap));
|
||||
out.diagnostics.capRefinementColumnComputeMilliseconds=std::max(0.0,
|
||||
ColumnMillisecondsAfterCap-ColumnMillisecondsBeforeCap);
|
||||
out.diagnostics.farHorizonMilliseconds=std::chrono::duration<double,std::milli>(
|
||||
std::chrono::steady_clock::now()-HorizonStart).count();
|
||||
out.diagnostics.capRefined=CapStats.Refined;
|
||||
@@ -1747,7 +1768,9 @@ namespace VoxelForgeCore
|
||||
out.diagnostics.columnComputeMilliseconds=Columns.columnComputeMilliseconds;
|
||||
out.diagnostics.columnEvaluationExclusiveMilliseconds=Columns.columnComputeMilliseconds;
|
||||
out.diagnostics.classificationMilliseconds=Counts.Milliseconds;
|
||||
if(options.captureColumnCoordinates&&key.lod==8)
|
||||
out.diagnostics.classificationExclusiveMilliseconds=std::max(0.0,
|
||||
Counts.Milliseconds-classificationColumnComputeMilliseconds);
|
||||
if(options.captureColumnCoordinates)
|
||||
{
|
||||
out.diagnostics.columnEvaluationWorkerHash=static_cast<std::uint64_t>(
|
||||
std::hash<std::thread::id>{}(std::this_thread::get_id()))+1u;
|
||||
|
||||
@@ -1027,11 +1027,18 @@ namespace world_assembly_detail
|
||||
std::int64_t wavelengthSubvoxels)
|
||||
{ return FloorDiv(positionSubvoxels * Q16, wavelengthSubvoxels); }
|
||||
|
||||
// Audit-only override; normal tile generation resets this to zero before evaluating a recipe.
|
||||
// Surcharge reservee aux mesures; la generation remet zero avant d'evaluer une recette.
|
||||
inline thread_local std::uint32_t HeightfieldColumnOctaveDrop = 0;
|
||||
|
||||
inline std::int32_t FractalNoiseQ16(std::int64_t xQ16, std::int64_t yQ16,
|
||||
std::int64_t zQ16, std::uint32_t octaves, bool ridged = false)
|
||||
{
|
||||
std::int64_t total = 0, weightSum = 0, weight = Q16, ridgeWeight = Q16;
|
||||
for (std::uint32_t octave = 0; octave < octaves; ++octave)
|
||||
std::uint32_t effectiveOctaves=octaves;
|
||||
if(HeightfieldColumnOctaveDrop!=0&&octaves!=0)
|
||||
effectiveOctaves=std::max(1u,octaves-std::min(octaves-1,HeightfieldColumnOctaveDrop));
|
||||
for (std::uint32_t octave = 0; octave < effectiveOctaves; ++octave)
|
||||
{
|
||||
const std::int64_t scale = 1ll << octave;
|
||||
const std::int64_t noise = Perlin3DQ16(xQ16 * scale,yQ16 * scale,zQ16 * scale);
|
||||
@@ -1965,9 +1972,15 @@ HeightfieldPointSample Heightfield2D::point(std::int64_t x, std::int64_t y,
|
||||
return out;
|
||||
}
|
||||
|
||||
void Heightfield2D::resetThreadColumnCacheStats(bool captureCoordinates) noexcept
|
||||
void Heightfield2D::resetThreadColumnCacheStats(bool captureCoordinates, bool clearCache,
|
||||
std::uint32_t octaveDrop) noexcept
|
||||
{
|
||||
// Diagnostic probes may clear old tile entries before comparing isolated sample grids.
|
||||
// Les sondes de mesure peuvent vider les entrees d'une tuile avant de comparer deux grilles.
|
||||
if(clearCache)world_assembly_detail::HeightfieldColumnCache.fill(
|
||||
world_assembly_detail::HeightfieldColumnCacheEntry{});
|
||||
auto& Stats=world_assembly_detail::HeightfieldColumnStats;
|
||||
world_assembly_detail::HeightfieldColumnOctaveDrop=octaveDrop;
|
||||
Stats.pointCalls=0;
|
||||
Stats.columnHits=0;
|
||||
Stats.columnMisses=0;
|
||||
|
||||
Reference in new issue
Block a user