profile: per-LOD whole-view breakdown for the four-strate owner world (L73, no world change)
FI/TN/VS (legacy compiled-analytic) skip ZERO tiles at every LOD and evaluate ~44k density points per LOD0/1 tile; SW skips 359/512 at LOD0. The whole-tile skip requires a native tile with a uniform verdict, and the legacy paths return Mixed/unknown (R39 notes attached). Opt-in stage timers, sampled field timer, per-LOD classification and composer counters. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
This commit is contained in:
1 parent
d970d75be8
commit
bd1b2a8f1d
10 files changed
+702
-5
No files matched your search
@@ -3,6 +3,7 @@
|
||||
#include "VoxelForgeCore/CpuCycleCounter.h"
|
||||
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
@@ -26,9 +27,12 @@ namespace VoxelForgeCore::floating_island_detail
|
||||
static constexpr std::uint64_t SampleMask=255;
|
||||
std::array<std::uint64_t,static_cast<std::size_t>(EIslandFieldCaller::Count)> sampledFieldCalls{};
|
||||
std::array<std::uint64_t,static_cast<std::size_t>(EIslandFieldCaller::Count)> fieldCycles{};
|
||||
std::array<std::uint64_t,static_cast<std::size_t>(EIslandFieldCaller::Count)> fieldNanoseconds{};
|
||||
std::array<std::uint64_t,static_cast<std::size_t>(EIslandFieldCaller::Count)> sampledNativeCalls{};
|
||||
std::array<std::uint64_t,static_cast<std::size_t>(EIslandFieldCaller::Count)> nativeCycles{};
|
||||
std::array<std::uint64_t,static_cast<std::size_t>(EIslandFieldCaller::Count)> nativeNanoseconds{};
|
||||
std::array<std::uint64_t,static_cast<std::size_t>(EIslandAttributionBucket::Count)> exclusiveCycles{};
|
||||
std::array<std::uint64_t,static_cast<std::size_t>(EIslandAttributionBucket::Count)> exclusiveNanoseconds{};
|
||||
std::array<std::uint64_t,static_cast<std::size_t>(EIslandAttributionBucket::Count)> scopeSamples{};
|
||||
std::uint64_t traceSampledMisses=0,traceSeenBefore=0,traceEvictions=0,
|
||||
traceReusedEvictions=0;
|
||||
@@ -118,7 +122,11 @@ namespace VoxelForgeCore::floating_island_detail
|
||||
&FIslandFieldAttributionInstrumentation::SampleMask;
|
||||
sampled=(((calls+phase)&FIslandFieldAttributionInstrumentation::SampleMask)==0);
|
||||
}
|
||||
if(sampled)start=VoxelForgeCoreShared::ReadCpuCycles();
|
||||
if(sampled)
|
||||
{
|
||||
start=VoxelForgeCoreShared::ReadCpuCycles();
|
||||
wallStart=std::chrono::steady_clock::now();
|
||||
}
|
||||
}
|
||||
~FScopedIslandAttributionTimer(){Stop();}
|
||||
std::uint64_t Stop() noexcept
|
||||
@@ -128,12 +136,18 @@ namespace VoxelForgeCore::floating_island_detail
|
||||
const std::uint64_t raw=VoxelForgeCoreShared::ReadCpuCycles()-start;
|
||||
const std::uint64_t overhead=VoxelForgeCoreShared::CpuCycleReadPairOverhead();
|
||||
const std::uint64_t cycles=raw>overhead?raw-overhead:0;
|
||||
const auto elapsed=std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::steady_clock::now()-wallStart).count();
|
||||
metrics->exclusiveCycles[bucketIndex]+=cycles;
|
||||
metrics->exclusiveNanoseconds[bucketIndex]+=elapsed>0
|
||||
?static_cast<std::uint64_t>(elapsed):0;
|
||||
++metrics->scopeSamples[bucketIndex];
|
||||
if(bucketIndex==static_cast<std::size_t>(EIslandAttributionBucket::Field))
|
||||
{
|
||||
const std::size_t callerIndex=static_cast<std::size_t>(ActiveIslandFieldCaller());
|
||||
metrics->fieldCycles[callerIndex]+=cycles;
|
||||
metrics->fieldNanoseconds[callerIndex]+=elapsed>0
|
||||
?static_cast<std::uint64_t>(elapsed):0;
|
||||
++metrics->sampledFieldCalls[callerIndex];
|
||||
}
|
||||
return cycles;
|
||||
@@ -141,6 +155,7 @@ namespace VoxelForgeCore::floating_island_detail
|
||||
FIslandFieldAttributionInstrumentation* metrics=nullptr;
|
||||
std::size_t bucketIndex=0;
|
||||
std::uint64_t start=0;
|
||||
std::chrono::steady_clock::time_point wallStart{};
|
||||
bool sampled=false;
|
||||
};
|
||||
|
||||
@@ -160,6 +175,7 @@ namespace VoxelForgeCore::floating_island_detail
|
||||
sampledCaller=caller;
|
||||
sampled=true;
|
||||
start=VoxelForgeCoreShared::ReadCpuCycles();
|
||||
wallStart=std::chrono::steady_clock::now();
|
||||
++attribution->sampledNativeCalls[callerIndex];
|
||||
}
|
||||
~FScopedIslandAttributionSample()
|
||||
@@ -168,12 +184,17 @@ namespace VoxelForgeCore::floating_island_detail
|
||||
const std::uint64_t raw=VoxelForgeCoreShared::ReadCpuCycles()-start;
|
||||
const std::uint64_t overhead=VoxelForgeCoreShared::CpuCycleReadPairOverhead();
|
||||
const std::uint64_t duration=raw>overhead?raw-overhead:0;
|
||||
const auto elapsed=std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::steady_clock::now()-wallStart).count();
|
||||
const std::size_t callerIndex=static_cast<std::size_t>(sampledCaller);
|
||||
sampledAttribution->nativeCycles[callerIndex]+=duration;
|
||||
sampledAttribution->nativeNanoseconds[callerIndex]+=elapsed>0
|
||||
?static_cast<std::uint64_t>(elapsed):0;
|
||||
}
|
||||
FIslandFieldAttributionInstrumentation* sampledAttribution=nullptr;
|
||||
EIslandFieldCaller sampledCaller=EIslandFieldCaller::Other;
|
||||
std::uint64_t start=0;
|
||||
std::chrono::steady_clock::time_point wallStart{};
|
||||
bool sampled=false;
|
||||
};
|
||||
|
||||
|
||||
@@ -159,6 +159,13 @@ namespace VoxelForgeCore
|
||||
std::uint64_t floatFieldCalls = 0;
|
||||
std::uint64_t latticeFieldCalls = 0;
|
||||
std::uint64_t unclampedFieldCalls = 0;
|
||||
std::uint64_t densityPointCalls = 0;
|
||||
std::uint64_t densityFloatPointCalls = 0;
|
||||
std::uint64_t densityLatticePointCalls = 0;
|
||||
std::uint64_t densityUnclampedPointCalls = 0;
|
||||
std::uint64_t densityX8PointCalls = 0;
|
||||
std::uint64_t densityFieldEvalNanoseconds = 0;
|
||||
std::uint64_t densityFieldEvalSamplePoints = 0;
|
||||
std::uint64_t columnCacheHits = 0;
|
||||
std::uint64_t columnCacheMisses = 0;
|
||||
std::uint64_t columnCacheConflictMisses = 0;
|
||||
|
||||
@@ -2160,6 +2160,11 @@ public:
|
||||
{
|
||||
uint64 SolidBoxes=0,AirBoxes=0,MixedBoxes=0,UnknownBoxes=0;
|
||||
uint64 NativeFloatFieldCalls=0,NativeLatticeFieldCalls=0,NativeUnclampedFieldCalls=0;
|
||||
bool CaptureDensityQueryProfile=false;
|
||||
uint64 DensityPointCalls=0,DensityFloatPointCalls=0,DensityLatticePointCalls=0,
|
||||
DensityUnclampedPointCalls=0,DensityX8PointCalls=0;
|
||||
uint64 DensityFieldEvalNanoseconds=0,DensityFieldEvalSamplePoints=0;
|
||||
std::array<uint64,4> DensityFieldEvalNanosecondsByKind{},DensityFieldEvalSamplePointsByKind{};
|
||||
double Milliseconds=0.0;
|
||||
#if defined(VF_L30_ENABLE_COST_COUNTERS)
|
||||
uint64 BoundaryBandCalls=0,TransitionWindowChecks=0,TransitionWindowHits=0;
|
||||
@@ -2171,8 +2176,60 @@ public:
|
||||
#endif
|
||||
};
|
||||
static void ResetThreadClassificationStats() { ThreadClassificationStats()={}; }
|
||||
static void SetThreadDensityQueryProfileEnabled(bool Enabled)
|
||||
{ThreadClassificationStats().CaptureDensityQueryProfile=Enabled;}
|
||||
static FClassificationThreadStats GetThreadClassificationStats()
|
||||
{ return ThreadClassificationStats(); }
|
||||
enum class EDensityQueryKind : uint8 { Float=0,Lattice=1,Unclamped=2,X8=3 };
|
||||
static uint32& DensityQuerySuppressionDepth()
|
||||
{static thread_local uint32 Depth=0;return Depth;}
|
||||
static uint64& DensityQuerySampleSequence()
|
||||
{static thread_local uint64 Sequence=0;return Sequence;}
|
||||
struct FScopedDensityQueryProfile
|
||||
{
|
||||
FScopedDensityQueryProfile(EDensityQueryKind Kind,uint64 PointCount=1)
|
||||
:stats(&ThreadClassificationStats()),kindIndex(static_cast<std::size_t>(Kind)),
|
||||
pointCount(PointCount)
|
||||
{
|
||||
if(!stats->CaptureDensityQueryProfile||DensityQuerySuppressionDepth()!=0)
|
||||
{stats=nullptr;return;}
|
||||
stats->DensityPointCalls+=pointCount;
|
||||
switch(Kind)
|
||||
{
|
||||
case EDensityQueryKind::Float:stats->DensityFloatPointCalls+=pointCount;break;
|
||||
case EDensityQueryKind::Lattice:stats->DensityLatticePointCalls+=pointCount;break;
|
||||
case EDensityQueryKind::Unclamped:stats->DensityUnclampedPointCalls+=pointCount;break;
|
||||
case EDensityQueryKind::X8:stats->DensityX8PointCalls+=pointCount;break;
|
||||
}
|
||||
const uint64 Sequence=++DensityQuerySampleSequence();
|
||||
if((Sequence&255u)!=0)return;
|
||||
sampled=true;start=std::chrono::steady_clock::now();
|
||||
}
|
||||
~FScopedDensityQueryProfile()
|
||||
{
|
||||
if(!sampled)return;
|
||||
const uint64 nanoseconds=static_cast<uint64>(std::max<std::int64_t>(0,
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::steady_clock::now()-start).count()));
|
||||
stats->DensityFieldEvalNanoseconds+=nanoseconds;
|
||||
stats->DensityFieldEvalSamplePoints+=pointCount;
|
||||
stats->DensityFieldEvalNanosecondsByKind[kindIndex]+=nanoseconds;
|
||||
stats->DensityFieldEvalSamplePointsByKind[kindIndex]+=pointCount;
|
||||
}
|
||||
bool IsActive()const noexcept{return stats!=nullptr;}
|
||||
FClassificationThreadStats* stats=nullptr;
|
||||
std::size_t kindIndex=0;
|
||||
uint64 pointCount=0;
|
||||
std::chrono::steady_clock::time_point start{};
|
||||
bool sampled=false;
|
||||
};
|
||||
struct FScopedDensityQueryBatch
|
||||
{
|
||||
explicit FScopedDensityQueryBatch(bool Enabled):enabled(Enabled)
|
||||
{if(enabled)++DensityQuerySuppressionDepth();}
|
||||
~FScopedDensityQueryBatch(){if(enabled)--DensityQuerySuppressionDepth();}
|
||||
bool enabled=false;
|
||||
};
|
||||
struct FFarConnectorSegment
|
||||
{
|
||||
FVector Start=FVector::ZeroVector;
|
||||
@@ -3157,6 +3214,7 @@ public:
|
||||
float DensityAt(float X,float Y,float Z) const
|
||||
{
|
||||
if(SharedDensitySource)return SharedDensitySource->DensityAt(X,Y,Z);
|
||||
FScopedDensityQueryProfile queryProfile(EDensityQueryKind::Float);
|
||||
if(bNativeOnly)
|
||||
{
|
||||
if(!NativeOnlyContains(X,Y,Z))
|
||||
@@ -3232,6 +3290,7 @@ public:
|
||||
float DensityAtLattice(int32 X,int32 Y,int32 Z) const
|
||||
{
|
||||
if(SharedDensitySource)return SharedDensitySource->DensityAtLattice(X,Y,Z);
|
||||
FScopedDensityQueryProfile queryProfile(EDensityQueryKind::Lattice);
|
||||
if(bNativeOnly)
|
||||
{
|
||||
if(!NativeOnlyContains(static_cast<float>(X),static_cast<float>(Y),
|
||||
@@ -3272,6 +3331,7 @@ public:
|
||||
float DensityAtUnclamped(float X,float Y,float Z) const
|
||||
{
|
||||
if(SharedDensitySource)return SharedDensitySource->DensityAtUnclamped(X,Y,Z);
|
||||
FScopedDensityQueryProfile queryProfile(EDensityQueryKind::Unclamped);
|
||||
if(bNativeOnly)
|
||||
{
|
||||
if(!NativeOnlyContains(X,Y,Z))
|
||||
@@ -3326,6 +3386,9 @@ public:
|
||||
}
|
||||
Count=std::clamp(Count,0,8);
|
||||
if(Count==0)return;
|
||||
FScopedDensityQueryProfile queryProfile(EDensityQueryKind::X8,
|
||||
static_cast<uint64>(Count));
|
||||
FScopedDensityQueryBatch queryBatch(queryProfile.IsActive());
|
||||
if(bNativeOnly)
|
||||
{
|
||||
for(int32 Lane=0;Lane<Count;++Lane)
|
||||
|
||||
@@ -2162,6 +2162,17 @@ namespace VoxelForgeCore
|
||||
TileMesh out;out.key=key;
|
||||
const auto CopyIslandCacheMetrics=[&]()
|
||||
{
|
||||
if(options.instrumentTileDrain)
|
||||
{
|
||||
const auto& QueryCounts=FStandaloneShapeWorld::GetThreadClassificationStats();
|
||||
out.diagnostics.densityPointCalls=QueryCounts.DensityPointCalls;
|
||||
out.diagnostics.densityFloatPointCalls=QueryCounts.DensityFloatPointCalls;
|
||||
out.diagnostics.densityLatticePointCalls=QueryCounts.DensityLatticePointCalls;
|
||||
out.diagnostics.densityUnclampedPointCalls=QueryCounts.DensityUnclampedPointCalls;
|
||||
out.diagnostics.densityX8PointCalls=QueryCounts.DensityX8PointCalls;
|
||||
out.diagnostics.densityFieldEvalNanoseconds=QueryCounts.DensityFieldEvalNanoseconds;
|
||||
out.diagnostics.densityFieldEvalSamplePoints=QueryCounts.DensityFieldEvalSamplePoints;
|
||||
}
|
||||
if(!options.instrumentTileDrain)return;
|
||||
islandCacheInstrumentation.tileCycles=VoxelForgeCoreShared::ReadCpuCycles()
|
||||
-islandCacheInstrumentation.tileStartCycles;
|
||||
@@ -2200,16 +2211,25 @@ namespace VoxelForgeCore
|
||||
line<<" native_"<<CallerNames[i]<<"="<<a.sampledNativeCalls[i]*256<<"/"
|
||||
<<a.sampledNativeCalls[i]<<"/"
|
||||
<<Estimate(a.nativeCycles[i],a.sampledNativeCalls[i]*256,
|
||||
a.sampledNativeCalls[i])
|
||||
<<" native_"<<CallerNames[i]<<"_ns_est="
|
||||
<<Estimate(a.nativeNanoseconds[i],a.sampledNativeCalls[i]*256,
|
||||
a.sampledNativeCalls[i]);
|
||||
line<<" field_"<<CallerNames[i]<<"="<<a.sampledFieldCalls[i]*256<<"/"
|
||||
<<a.sampledFieldCalls[i]<<"/"
|
||||
<<Estimate(a.fieldCycles[i],a.sampledFieldCalls[i]*256,
|
||||
a.sampledFieldCalls[i])
|
||||
<<" field_"<<CallerNames[i]<<"_ns_est="
|
||||
<<Estimate(a.fieldNanoseconds[i],a.sampledFieldCalls[i]*256,
|
||||
a.sampledFieldCalls[i]);
|
||||
}
|
||||
for(std::size_t i=0;i<BucketNames.size();++i)
|
||||
line<<" comp_"<<BucketNames[i]<<"="
|
||||
<<Estimate(a.exclusiveCycles[i],a.scopeSamples[i]*256,
|
||||
a.scopeSamples[i])
|
||||
<<" comp_"<<BucketNames[i]<<"_ns_est="
|
||||
<<Estimate(a.exclusiveNanoseconds[i],a.scopeSamples[i]*256,
|
||||
a.scopeSamples[i])
|
||||
<<"/"<<a.scopeSamples[i]<<"/"<<a.scopeSamples[i]*256;
|
||||
const auto& shared=islandCacheInstrumentation.shared;
|
||||
line<<" local_probe_calls="<<(islandCacheInstrumentation.localHits
|
||||
@@ -2323,6 +2343,7 @@ namespace VoxelForgeCore
|
||||
&&bHasNativeSurfaceHorizonPlan&&!bHasIslandPlanInTile;
|
||||
const bool bSkipFarShellRepair=key.lod>=7&&bUseNativeSurfaceHorizon;
|
||||
FStandaloneShapeWorld::ResetThreadClassificationStats();
|
||||
FStandaloneShapeWorld::SetThreadDensityQueryProfileEnabled(options.instrumentTileDrain);
|
||||
VoxelForgeCore::Heightfield2D::resetThreadColumnCacheStats(
|
||||
options.captureColumnCoordinates);
|
||||
if(options.captureColumnCoordinates)
|
||||
|
||||
Reference in new issue
Block a user