diff --git a/Standalone/Core/include/VoxelForgeCore/SharedColumnCache.h b/Standalone/Core/include/VoxelForgeCore/SharedColumnCache.h index cbb0885..3784247 100644 --- a/Standalone/Core/include/VoxelForgeCore/SharedColumnCache.h +++ b/Standalone/Core/include/VoxelForgeCore/SharedColumnCache.h @@ -2,6 +2,7 @@ #include "VoxelForgeCore/CpuCycleCounter.h" +#include #include #include #include @@ -24,12 +25,15 @@ namespace VoxelForgeCoreShared std::uint64_t lockWaitNanoseconds = 0; std::uint64_t sampledInitialReadCycles = 0; std::uint64_t sampledInitialReads = 0; + std::uint64_t sampledInitialReadNanoseconds = 0; std::uint64_t sampledLockedReadCycles = 0; std::uint64_t sampledLockedReads = 0; + std::uint64_t sampledLockedReadNanoseconds = 0; std::uint64_t sampledLockCycles = 0; std::uint64_t sampledLocks = 0; std::uint64_t sampledBuildCycles = 0; std::uint64_t sampledBuilds = 0; + bool captureNanoseconds = false; }; // Exact input identity for a pure XY column value. LOD is deliberately not part of this key: @@ -140,12 +144,19 @@ namespace VoxelForgeCoreShared static thread_local std::uint64_t timingSequence=0; const bool sampleCycles=metrics&&((++timingSequence&127u)==0); const std::uint64_t initialReadStart=sampleCycles?ReadCpuCycles():0; + const auto initialReadStartNs=sampleCycles&&metrics->captureNanoseconds + ?std::chrono::steady_clock::now():std::chrono::steady_clock::time_point{}; const bool initialHit=TryReadSet(set, keyWords, tag, value); if(sampleCycles) { metrics->sampledInitialReadCycles+=AdjustedCpuCycleDelta( initialReadStart,ReadCpuCycles()); ++metrics->sampledInitialReads; + if(metrics->captureNanoseconds) + metrics->sampledInitialReadNanoseconds+=static_cast( + std::max(0,std::chrono::duration_cast< + std::chrono::nanoseconds>(std::chrono::steady_clock::now() + -initialReadStartNs).count())); } if (initialHit) { @@ -156,12 +167,19 @@ namespace VoxelForgeCoreShared FSpinGuard lock(set.Writer, metrics,sampleCycles); const std::uint64_t lockedReadStart=sampleCycles?ReadCpuCycles():0; + const auto lockedReadStartNs=sampleCycles&&metrics->captureNanoseconds + ?std::chrono::steady_clock::now():std::chrono::steady_clock::time_point{}; const bool lockedHit=TryReadSet(set, keyWords, tag, value); if(sampleCycles) { metrics->sampledLockedReadCycles+=AdjustedCpuCycleDelta( lockedReadStart,ReadCpuCycles()); ++metrics->sampledLockedReads; + if(metrics->captureNanoseconds) + metrics->sampledLockedReadNanoseconds+=static_cast( + std::max(0,std::chrono::duration_cast< + std::chrono::nanoseconds>(std::chrono::steady_clock::now() + -lockedReadStartNs).count())); } if (lockedHit) { diff --git a/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h b/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h index ac27df1..ad6e8c2 100644 --- a/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h +++ b/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h @@ -147,6 +147,7 @@ namespace VoxelForgeCore // by the opt-in passage composer profile, except the mesh composition itself. std::uint64_t passageSweepRouteSegmentCandidates = 0; std::uint64_t passageSweepSegmentSamplePairs = 0; + std::uint64_t passageSweepBoundPrunedPairs = 0; std::uint64_t passageSweepOutsideInfluencePairs = 0; std::uint64_t passageSweepMinimumUpdates = 0; std::uint64_t passageSweepBaseInfluenceSamples = 0; @@ -158,6 +159,19 @@ namespace VoxelForgeCore std::uint64_t passageSweepBaseInfluenceHits = 0; std::uint64_t passageSweepOutOfInfluenceHits = 0; std::uint64_t passageSweepMissingSamples = 0; + double passageSweepPrepareMilliseconds = 0.0; + std::uint64_t passageSmoothMinCalls = 0; + std::uint64_t passageSmoothMinSampledNanoseconds = 0; + std::uint64_t passageSmoothMinSamples = 0; + std::uint64_t heightfieldPointSampledNanoseconds = 0; + std::uint64_t heightfieldPointSamples = 0; + std::uint64_t heightfieldCachedColumnSampledNanoseconds = 0; + std::uint64_t heightfieldCachedColumnSamples = 0; + std::uint64_t heightfieldSharedInitialReadSampledNanoseconds = 0; + std::uint64_t heightfieldSharedInitialReadSamples = 0; + std::uint64_t heightfieldSharedLockedReadSampledNanoseconds = 0; + std::uint64_t heightfieldSharedLockedReadSamples = 0; + bool l118FieldTagsCaptured = false; std::array passageSweepMissingLookupsByCaller{}; std::array passageSweepExactRouteFallbacksByCaller{}; std::array passageSweepFeatureBoundSkipsByCaller{}; @@ -1394,6 +1408,16 @@ namespace VoxelForgeCore std::uint64_t sharedColumnHits = 0; std::uint64_t columnEvaluations = 0; double columnComputeMilliseconds = 0.0; + // L118 opt-in, one-in-128 sampled timings. Nanoseconds are accumulated only for + // sampled calls; report estimates multiply by 128. + std::uint64_t sampledPointNanoseconds = 0; + std::uint64_t sampledPointCalls = 0; + std::uint64_t sampledCachedColumnNanoseconds = 0; + std::uint64_t sampledCachedColumnCalls = 0; + std::uint64_t sampledSharedInitialReadNanoseconds = 0; + std::uint64_t sampledSharedInitialReads = 0; + std::uint64_t sampledSharedLockedReadNanoseconds = 0; + std::uint64_t sampledSharedLockedReads = 0; bool captureCoordinates = false; bool coordinateCaptureComplete = true; std::vector evaluatedCoordinates; diff --git a/Standalone/Core/src/ShapeWorldInternal.h b/Standalone/Core/src/ShapeWorldInternal.h index c266bd8..4782980 100644 --- a/Standalone/Core/src/ShapeWorldInternal.h +++ b/Standalone/Core/src/ShapeWorldInternal.h @@ -72,6 +72,14 @@ static bool VF_IsL98PassagePrepareTraceEnabled() return bEnabled; } +static bool VF_IsL118TagTimingEnabled() +{ + static const bool bEnabled=VF_IsL88DiagnosticSwitchEnabled( + "VOXELFORGE_L118_TAG_TIMING"); + return bEnabled; +} +static thread_local std::uint64_t VF_L118SmoothMinTimingSequence=0; + static double VF_L93PassageCarveReachMetres() { // The generated world uses a fixed bounded tube influence. An explicit diagnostic @@ -289,6 +297,8 @@ public: std::vector passages; std::atomic lookups{0},cacheHits{0},baseInfluenceHits{0}, outOfInfluenceHits{0},missingSamples{0}; + std::atomic smoothMinCalls{0},smoothMinSampledNanoseconds{0}, + smoothMinSamples{0}; std::array,PassageDensityQueryCallerCount> missingLookupsByCaller{},exactRouteFallbacksByCaller{}, featureBoundSkipsByCaller{},tileFreeSkipsByCaller{}, @@ -376,6 +386,17 @@ public: const FPassageSweepSample* sweptSample(std::size_t passageIndex, double qx,double qy,double qz) const; bool hasSweptTubeBase() const noexcept{return passageSweepData_!=nullptr;} + void recordSmoothMinTiming(std::uint64_t nanoseconds,bool sampled) const noexcept + { + if(!profileStats_||!passageSweepData_)return; + passageSweepData_->smoothMinCalls.fetch_add(1,std::memory_order_relaxed); + if(sampled) + { + passageSweepData_->smoothMinSampledNanoseconds.fetch_add( + nanoseconds,std::memory_order_relaxed); + passageSweepData_->smoothMinSamples.fetch_add(1,std::memory_order_relaxed); + } + } void copySweptTubeRuntimeCounts() const noexcept { if(!ownsPassageSweepDiagnostics_||!profileStats_||!passageSweepData_)return; @@ -389,6 +410,13 @@ public: passageSweepData_->outOfInfluenceHits.load(std::memory_order_relaxed); profileStats_->passageSweepMissingSamples=passageSweepData_->missingSamples.load( std::memory_order_relaxed); + profileStats_->passageSmoothMinCalls=passageSweepData_->smoothMinCalls.load( + std::memory_order_relaxed); + profileStats_->passageSmoothMinSampledNanoseconds= + passageSweepData_->smoothMinSampledNanoseconds.load( + std::memory_order_relaxed); + profileStats_->passageSmoothMinSamples=passageSweepData_->smoothMinSamples.load( + std::memory_order_relaxed); for(std::size_t caller=0;callerpassageSweepMissingLookupsByCaller[caller]= @@ -1298,12 +1326,19 @@ public: const double ex=qx-cx,ey=qy-cy,ez=qz-cz; const double roundDistance=DeterministicSqrt( ex*ex+ey*ey+ez*ez)-radius; + const double floorCenterDistanceSq=ex*ex+ey*ey+ez*ez; + const bool floorWins=floorCenterDistanceSq1.0e-12 ?(((qx-segment.a[0])*segment.delta[0] +(qy-segment.a[1])*segment.delta[1]) /segment.horizontalLengthSq):t; const double floorTClamped=std::clamp(floorT,0.0,1.0); - const double floorCenterDistanceSq=ex*ex+ey*ey+ez*ez; const double floorRadius=segment.radiusA +floorTClamped*segment.radiusDelta; const double floorDepth=PassageFlatFloorDepthSubvoxels( @@ -1311,13 +1346,9 @@ public: const double floorCenterZ=PassageFlatFloorCenterZSubvoxels( constants,segments,segmentIndex,floorT,segment, qx,qy,floorDepth,qPerMetre); - const double flatDistance=PassageFlatBottomDistance( - static_cast(roundDistance),floorCenterZ,qz,floorDepth,qPerMetre); // The profile uses the closest route projection's arc length. Tube // radius selects the bore shape only; it never selects floor height. - if(floorCenterDistanceSq(roundDistance),floorCenterZ,qz,floorDepth, + qPerMetre); bestDistance=roundDistance; nearest.signedDistance=flatDistance; nearest.roundSignedDistance=roundDistance; @@ -6929,12 +6961,31 @@ private: static float SmoothMinDistance(float A,float B,float Width) { FScopedLegacySmoothMinTimer SmoothMinTimer; + const auto* tagScope=VF_IsL118TagTimingEnabled() + ?ActivePassageTileQueries:nullptr; + const bool tag=tagScope&&tagScope->profileStats() + &&tagScope->hasSweptTubeBase(); + const bool sampled=tag&&((++VF_L118SmoothMinTimingSequence&127u)==0); + const auto tagStart=sampled?std::chrono::steady_clock::now() + :std::chrono::steady_clock::time_point{}; + const auto recordTag=[&]() + { + if(!tag)return; + const std::uint64_t elapsed=sampled?static_cast(std::max(0, + std::chrono::duration_cast( + std::chrono::steady_clock::now()-tagStart).count())):0; + tagScope->recordSmoothMinTiming(elapsed,sampled); + }; if(Width<=0.0f) { - return std::min(A,B); + const float result=std::min(A,B); + recordTag(); + return result; } const float H=std::max(Width-std::abs(A-B),0.0f)/Width; - return std::min(A,B)-(H*H*H)*(Width/6.0f); + const float result=std::min(A,B)-(H*H*H)*(Width/6.0f); + recordTag(); + return result; } static float SmoothMaxDistance(float A,float B,float Width) {return -SmoothMinDistance(-A,-B,Width);} @@ -11464,6 +11515,9 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa const double wallReliefShell=0.41*qPerMetre; const double floorDetailShell=1.0*qPerMetre; const bool profile=profileStats_!=nullptr; + const bool tagTiming=profile&&VF_IsL118TagTimingEnabled(); + const auto tagStart=tagTiming?std::chrono::steady_clock::now() + :std::chrono::steady_clock::time_point{}; if(profile) { profileStats_->passageSweepRouteSegmentCandidates=routeSegmentCandidateCount_; @@ -11527,6 +11581,31 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa ||qy>segment.sweepMaximumSubvoxels[1] ||qzsegment.sweepMaximumSubvoxels[2])continue; + const std::size_t sampleIndex=(static_cast(gz) + *static_cast(sweep->dimension)+static_cast(gy)) + *static_cast(sweep->dimension)+static_cast(gx); + auto& sample=passageSamples.samples[sampleIndex]; + const double boundDx=std::max({std::min(segment.a[0],segment.b[0])-qx, + 0.0,qx-std::max(segment.a[0],segment.b[0])}); + const double boundDy=std::max({std::min(segment.a[1],segment.b[1])-qy, + 0.0,qy-std::max(segment.a[1],segment.b[1])}); + const double boundDz=std::max({std::min(segment.a[2],segment.b[2])-qz, + 0.0,qz-std::max(segment.a[2],segment.b[2])}); + const double centerDistanceLowerBoundSq=boundDx*boundDx + +boundDy*boundDy+boundDz*boundDz; + const double roundDistanceLowerBound=FStandaloneShapeWorld::DeterministicSqrt( + centerDistanceLowerBoundSq)-std::max(segment.radiusA,segment.radiusB); + const bool couldImproveRound=!sample.valid + ||roundDistanceLowerBound<=sample.roundSignedDistance; + const bool couldImproveFloor=centerDistanceLowerBoundSq + <=sample.floorCenterDistanceSq; + const bool couldContributeShell=roundDistanceLowerBound<=shellThickness; + if(!couldImproveRound&&!couldImproveFloor&&!couldContributeShell) + { + if(profile)++profileStats_->passageSweepBoundPrunedPairs; + continue; + } + if(profile)++profileStats_->passageSweepSegmentSamplePairs; const double projectionXY=(qx-segment.a[0])*segment.delta[0] +(qy-segment.a[1])*segment.delta[1]; const double t=std::clamp((projectionXY @@ -11552,15 +11631,10 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa qx,qy,floorDepth,qPerMetre); const double flatDistance=FStandaloneShapeWorld::PassageFlatBottomDistance( static_cast(signedDistance),floorCenterZ,qz,floorDepth,qPerMetre); - if(profile)++profileStats_->passageSweepSegmentSamplePairs; if(signedDistance>sweep->influenceSubvoxels) { if(profile)++profileStats_->passageSweepOutsideInfluencePairs; } - const std::size_t sampleIndex=(static_cast(gz) - *static_cast(sweep->dimension)+static_cast(gy)) - *static_cast(sweep->dimension)+static_cast(gx); - auto& sample=passageSamples.samples[sampleIndex]; if(floorCenterDistanceSq(std::count(anyPassageInfluence.begin(), anyPassageInfluence.end(),static_cast(0))); } + if(tagTiming) + profileStats_->passageSweepPrepareMilliseconds= + std::chrono::duration( + std::chrono::steady_clock::now()-tagStart).count(); passageSweepData_=std::move(sweep); } diff --git a/Standalone/Core/src/VoxelForgeCore.cpp b/Standalone/Core/src/VoxelForgeCore.cpp index b139ec4..a25049d 100644 --- a/Standalone/Core/src/VoxelForgeCore.cpp +++ b/Standalone/Core/src/VoxelForgeCore.cpp @@ -2444,6 +2444,28 @@ namespace VoxelForgeCore FStandaloneShapeWorld::SetThreadDensityQueryProfileEnabled(options.instrumentTileDrain); VoxelForgeCore::Heightfield2D::resetThreadColumnCacheStats( options.captureColumnCoordinates); + const auto copyL118FieldTags=[&]() + { + if(!options.profilePassageComposer + ||!world_assembly_detail::L118FieldTagTimingEnabled())return; + const auto& Columns=VoxelForgeCore::Heightfield2D::threadColumnCacheStats(); + out.diagnostics.l118FieldTagsCaptured=true; + out.diagnostics.heightfieldPointSampledNanoseconds= + Columns.sampledPointNanoseconds; + out.diagnostics.heightfieldPointSamples=Columns.sampledPointCalls; + out.diagnostics.heightfieldCachedColumnSampledNanoseconds= + Columns.sampledCachedColumnNanoseconds; + out.diagnostics.heightfieldCachedColumnSamples= + Columns.sampledCachedColumnCalls; + out.diagnostics.heightfieldSharedInitialReadSampledNanoseconds= + Columns.sampledSharedInitialReadNanoseconds; + out.diagnostics.heightfieldSharedInitialReadSamples= + Columns.sampledSharedInitialReads; + out.diagnostics.heightfieldSharedLockedReadSampledNanoseconds= + Columns.sampledSharedLockedReadNanoseconds; + out.diagnostics.heightfieldSharedLockedReadSamples= + Columns.sampledSharedLockedReads; + }; if(options.captureColumnCoordinates) { constexpr std::int64_t SubvoxelsPerVoxel=WorldAssemblySubvoxelsPerVoxel; @@ -2530,6 +2552,7 @@ namespace VoxelForgeCore out.diagnostics.classificationExclusiveMilliseconds=std::max(0.0, Counts.Milliseconds-classificationColumnComputeMilliseconds); out.diagnostics.columnComputeMilliseconds=Columns.columnComputeMilliseconds; + copyL118FieldTags(); #if defined(VF_L30_ENABLE_COST_COUNTERS) PrintL30CostCounters(Counts); #endif @@ -3128,6 +3151,7 @@ namespace VoxelForgeCore out.diagnostics.columnEvaluations=Columns.columnEvaluations; out.diagnostics.columnComputeMilliseconds=Columns.columnComputeMilliseconds; out.diagnostics.columnEvaluationExclusiveMilliseconds=Columns.columnComputeMilliseconds; + copyL118FieldTags(); out.diagnostics.classificationMilliseconds=Counts.Milliseconds; out.diagnostics.classificationExclusiveMilliseconds=std::max(0.0, Counts.Milliseconds-classificationColumnComputeMilliseconds); diff --git a/Standalone/Core/src/WorldAssemblerInternal.h b/Standalone/Core/src/WorldAssemblerInternal.h index 07b3c9b..dd7c1d6 100644 --- a/Standalone/Core/src/WorldAssemblerInternal.h +++ b/Standalone/Core/src/WorldAssemblerInternal.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -1798,11 +1799,49 @@ namespace world_assembly_detail inline thread_local VoxelForgeCoreThreadLocal::FLazy< std::array> HeightfieldColumnCacheNextWay; inline thread_local HeightfieldColumnCacheStats HeightfieldColumnStats{}; + inline thread_local VoxelForgeCoreShared::FColumnCacheMetrics + HeightfieldSharedColumnCacheMetrics{}; + inline thread_local std::uint64_t HeightfieldPointTimingSequence=0; + inline thread_local std::uint64_t HeightfieldCachedColumnTimingSequence=0; inline thread_local bool HeightfieldColumnCacheLegacyDirectMapped=false; inline thread_local std::array HeightfieldColumnCaptureBounds{}; inline thread_local bool HeightfieldColumnCaptureBoundsValid=false; inline std::atomic HeightfieldColumnCaptureSequence{0}; + inline bool L118FieldTagTimingEnabled() noexcept + { + static const bool enabled=[] + { + const char* value=std::getenv("VOXELFORGE_L118_TAG_TIMING"); + return value&&value[0]=='1'&&value[1]=='\0'; + }(); + return enabled; + } + + struct FScopedHeightfieldSampledTimer + { + FScopedHeightfieldSampledTimer(std::uint64_t& nanoseconds, + std::uint64_t& samples,std::uint64_t& sequence) noexcept + :Nanoseconds(nanoseconds),Samples(samples) + { + if(!L118FieldTagTimingEnabled()||((++sequence&127u)!=0))return; + Start=std::chrono::steady_clock::now(); + bTimed=true; + } + ~FScopedHeightfieldSampledTimer() + { + if(!bTimed)return; + Nanoseconds+=static_cast(std::max(0, + std::chrono::duration_cast( + std::chrono::steady_clock::now()-Start).count())); + ++Samples; + } + std::uint64_t& Nanoseconds; + std::uint64_t& Samples; + std::chrono::steady_clock::time_point Start{}; + bool bTimed=false; + }; + inline std::size_t HeightfieldColumnCacheSet(const WorldAssemblyRecipeV1& recipe, const WorldAssemblyStratumPlanV1& plan,std::int64_t x,std::int64_t y) noexcept { @@ -1989,6 +2028,10 @@ namespace world_assembly_detail inline HeightfieldPointSample CachedColumn(const WorldAssemblyRecipeV1& recipe, const WorldAssemblyStratumPlanV1& plan,std::int64_t x,std::int64_t y) { + FScopedHeightfieldSampledTimer CachedColumnTimer( + HeightfieldColumnStats.sampledCachedColumnNanoseconds, + HeightfieldColumnStats.sampledCachedColumnCalls, + HeightfieldCachedColumnTimingSequence); const std::int64_t InterpolationStride=HeightfieldColumnInterpolationStrideSubvoxels; if(InterpolationStride>0) { @@ -2105,7 +2148,10 @@ namespace world_assembly_detail static_cast(reinterpret_cast(&plan)), plan.contentHash,x,y}; bool computed=false; - column=shared->getOrCompute(key,compute,computed); + auto* metrics=L118FieldTagTimingEnabled() + ?&HeightfieldSharedColumnCacheMetrics:nullptr; + if(metrics)metrics->captureNanoseconds=true; + column=shared->getOrCompute(key,compute,computed,metrics); if(!computed)++HeightfieldColumnStats.sharedColumnHits; } else column=compute(); @@ -2576,6 +2622,10 @@ WorldAssemblyFeatureTileListV1 Heightfield2D::buildFeatureTileList( HeightfieldPointSample Heightfield2D::point(std::int64_t x, std::int64_t y, std::int64_t z) const noexcept { + world_assembly_detail::FScopedHeightfieldSampledTimer PointTimer( + world_assembly_detail::HeightfieldColumnStats.sampledPointNanoseconds, + world_assembly_detail::HeightfieldColumnStats.sampledPointCalls, + world_assembly_detail::HeightfieldPointTimingSequence); HeightfieldPointSample out; if (!isValid() || world_assembly_detail::OutsideRange(x) || world_assembly_detail::OutsideRange(y) @@ -2635,6 +2685,17 @@ void Heightfield2D::resetThreadColumnCacheStats(bool captureCoordinates, bool cl Stats.sharedColumnHits=0; Stats.columnEvaluations=0; Stats.columnComputeMilliseconds=0.0; + Stats.sampledPointNanoseconds=0; + Stats.sampledPointCalls=0; + Stats.sampledCachedColumnNanoseconds=0; + Stats.sampledCachedColumnCalls=0; + Stats.sampledSharedInitialReadNanoseconds=0; + Stats.sampledSharedInitialReads=0; + Stats.sampledSharedLockedReadNanoseconds=0; + Stats.sampledSharedLockedReads=0; + world_assembly_detail::HeightfieldSharedColumnCacheMetrics={}; + world_assembly_detail::HeightfieldPointTimingSequence=0; + world_assembly_detail::HeightfieldCachedColumnTimingSequence=0; Stats.captureCoordinates=captureCoordinates; Stats.coordinateCaptureComplete=true; Stats.evaluatedCoordinates.clear(); @@ -2670,7 +2731,15 @@ std::int64_t Heightfield2D::threadColumnInterpolationStrideSubvoxels() noexcept const HeightfieldColumnCacheStats& Heightfield2D::threadColumnCacheStats() noexcept -{ return world_assembly_detail::HeightfieldColumnStats; } +{ + auto& Stats=world_assembly_detail::HeightfieldColumnStats; + const auto& Shared=world_assembly_detail::HeightfieldSharedColumnCacheMetrics; + Stats.sampledSharedInitialReadNanoseconds=Shared.sampledInitialReadNanoseconds; + Stats.sampledSharedInitialReads=Shared.sampledInitialReads; + Stats.sampledSharedLockedReadNanoseconds=Shared.sampledLockedReadNanoseconds; + Stats.sampledSharedLockedReads=Shared.sampledLockedReads; + return Stats; +} HeightfieldBoxClass Heightfield2D::classifyLatticeBox(std::int64_t minimumX, std::int64_t minimumY,std::int64_t minimumZ,std::int64_t maximumX, diff --git a/Standalone/Source/StreamingWorld.h b/Standalone/Source/StreamingWorld.h index 2964e86..231362b 100644 --- a/Standalone/Source/StreamingWorld.h +++ b/Standalone/Source/StreamingWorld.h @@ -1580,7 +1580,7 @@ private: static_cast(D.islandSharedCacheConflictReplacements), static_cast(D.islandSharedCacheLockWaitNanoseconds)/1000.0); if(D.passageComposerProfiled) - std::printf("[PassageComposerTile] key=(%d,%d,%d,lod%d) worker_ms=%.3f samples=%llu native_field_calls=%llu features=%llu route_candidates=%llu boundary_band_queries=%llu queries=%llu passage_iterations=%llu carve_segment_visits=%llu relief_field_calls=%llu sweep_segments=%llu sweep_pairs=%llu sweep_outside_pairs=%llu sweep_min_updates=%llu sweep_base_samples=%llu sweep_detail_samples=%llu sweep_grid_samples=%llu sweep_no_influence_samples=%llu sweep_lookups=%llu sweep_cache_hits=%llu sweep_base_hits=%llu sweep_outside_hits=%llu sweep_missing=%llu\n", + std::printf("[PassageComposerTile] key=(%d,%d,%d,lod%d) worker_ms=%.3f samples=%llu native_field_calls=%llu features=%llu route_candidates=%llu boundary_band_queries=%llu queries=%llu passage_iterations=%llu carve_segment_visits=%llu relief_field_calls=%llu sweep_segments=%llu sweep_pairs=%llu sweep_bound_pruned=%llu sweep_outside_pairs=%llu sweep_min_updates=%llu sweep_base_samples=%llu sweep_detail_samples=%llu sweep_grid_samples=%llu sweep_no_influence_samples=%llu sweep_lookups=%llu sweep_cache_hits=%llu sweep_base_hits=%llu sweep_outside_hits=%llu sweep_missing=%llu\n", Event.Key.Coord.X,Event.Key.Coord.Y,Event.Key.Coord.Z,Event.Key.Level, Event.WorkerMilliseconds,static_cast(Event.DensitySamples), static_cast(D.fieldCalls), @@ -1593,6 +1593,7 @@ private: static_cast(D.passageReliefFieldCalls), static_cast(D.passageSweepRouteSegmentCandidates), static_cast(D.passageSweepSegmentSamplePairs), + static_cast(D.passageSweepBoundPrunedPairs), static_cast(D.passageSweepOutsideInfluencePairs), static_cast(D.passageSweepMinimumUpdates), static_cast(D.passageSweepBaseInfluenceSamples), @@ -1604,6 +1605,24 @@ private: static_cast(D.passageSweepBaseInfluenceHits), static_cast(D.passageSweepOutOfInfluenceHits), static_cast(D.passageSweepMissingSamples)); + if(D.l118FieldTagsCaptured) + std::printf("[L118FieldTags] key=(%d,%d,%d,lod%d) sweep_prepare_ms=%.3f smoothmin_calls=%llu smoothmin_samples=%llu smoothmin_ms_est=%.3f point_samples=%llu point_ms_est=%.3f cached_column_samples=%llu cached_column_ms_est=%.3f shared_initial_read_samples=%llu shared_initial_read_ms_est=%.3f shared_locked_read_samples=%llu shared_locked_read_ms_est=%.3f sample_period=128 overlap=(point_contains_cached_column,cached_column_contains_shared_reads)\n", + Event.Key.Coord.X,Event.Key.Coord.Y,Event.Key.Coord.Z,Event.Key.Level, + D.passageSweepPrepareMilliseconds, + static_cast(D.passageSmoothMinCalls), + static_cast(D.passageSmoothMinSamples), + D.passageSmoothMinSamples + ?static_cast(D.passageSmoothMinSampledNanoseconds)*128.0/1.0e6:0.0, + static_cast(D.heightfieldPointSamples), + static_cast(D.heightfieldPointSampledNanoseconds)*128.0/1.0e6, + static_cast(D.heightfieldCachedColumnSamples), + static_cast(D.heightfieldCachedColumnSampledNanoseconds)*128.0/1.0e6, + static_cast(D.heightfieldSharedInitialReadSamples), + static_cast(D.heightfieldSharedInitialReadSampledNanoseconds) + *128.0/1.0e6, + static_cast(D.heightfieldSharedLockedReadSamples), + static_cast(D.heightfieldSharedLockedReadSampledNanoseconds) + *128.0/1.0e6); } void RecordTimelineEvent(FStandaloneCpuTileTimelineEvent::EType Type, const FVoxelTileKey& Key,int32 WorkerId,size_t QueueDepth,size_t ActiveWorkers,