perf(core): tile-drain instrumentation; parallel FI sign-edge repair, FI first tile 1.28 -> 0.85 s (L55); R24

Opt-in --instrument-tile-drain records per-tile queue/dispatch/finish timelines, stage spans and counters
(proof skips, X8 lanes, GradAt/midpoint memo, skirts, FI cache stats); <2% when off. Measured: SW 13.3 and
FI 50.2 worker-s across LOD0-8, tails are work-saturated. FI sign-edge repair now computes in parallel and
publishes in sorted serial order (exact output): sign-edge 535 -> 47 ms, FI first tile 1.28 -> 0.85 s, near
ring 1.46 -> 1.04 s, whole view 6.09 -> 5.65 s. Proof block size, lane batching, SW midpoint memo and helper
cap 12 measured and left off. fast/medium/full PASS, Clang and GCC. Research R24: slab + motif generator.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-25 06:16:07 +01:00
1 parent e35a77f676
commit aee1487410
13 files changed
+882 -74

No files matched your search

+145 -1
View File
@@ -2246,7 +2246,8 @@ public:
const std::vector<VoxelForgeCore::DetailBandTileRegion>& InGpuVisualDetailTiles={},
const std::vector<VoxelForgeCore::DetailBandTileRegion>& InCpuVisualDetailTiles={},
const VoxelForgeCore::WorldAssemblyManifest* InWorldAssembly=nullptr,
const VoxelForgeCore::ResolvedLayoutSnapshotV3* InResolvedLayout=nullptr)
const VoxelForgeCore::ResolvedLayoutSnapshotV3* InResolvedLayout=nullptr,
bool bInParallelSignEdgeRepair=false)
{
using Clock=std::chrono::steady_clock;
const auto TotalStart=Clock::now();
@@ -2257,6 +2258,7 @@ public:
BindResolvedStratumFields();
bAnalyticOnly=false;
bProfileDetailBand=bInProfileDetailBand;
bParallelSignEdgeRepair=bInParallelSignEdgeRepair;
for(int32 A=0;A<3;++A)
{
Min[A]=(&MinVoxels.X)[A]-2;
@@ -9084,6 +9086,8 @@ private:
uint64 CompleteSignEdgeDistances()
{
if(bParallelSignEdgeRepair&&Scheduler)
return CompleteSignEdgeDistancesParallel();
uint64 AddedTotal=0,SignCorrections=0;
const size_t Columns=static_cast<size_t>(Size[0])*Size[1];
for(int32 Pass=0;Pass<4;++Pass)
@@ -9183,6 +9187,145 @@ private:
return AddedTotal;
}
uint64 CompleteSignEdgeDistancesParallel()
{
uint64 AddedTotal=0,SignCorrections=0;
const size_t Columns=static_cast<size_t>(Size[0])*Size[1];
for(int32 Pass=0;Pass<4;++Pass)
{
std::vector<size_t> MissingNodes;
const auto AddMissing=[&](int32 X,int32 Y,int32 Z)
{
if(X<Min[0]||X>Max[0]||Y<Min[1]||Y>Max[1]||Z<Min[2]||Z>Max[2])return;
const size_t Column=static_cast<size_t>(Y-Min[1])*Size[0]
+static_cast<size_t>(X-Min[0]);
const size_t Zi=static_cast<size_t>(Z-Min[2]);
const size_t Word=Column*WordsPerZ+(Zi>>6);
const uint64 Mask=uint64{1}<<(Zi&63u);
if((CandidateWords[Word]&Mask)==0)
MissingNodes.push_back((Zi*static_cast<size_t>(Size[1])
+static_cast<size_t>(Y-Min[1]))*Size[0]
+static_cast<size_t>(X-Min[0]));
};
// Discover against a stable pass snapshot. Density work is then independent per
// lattice node; packed candidates and occupancy corrections publish in node order.
for(size_t Line=0;Line<Columns;++Line)
{
const int32 X=Min[0]+static_cast<int32>(Line%Size[0]);
const int32 Y=Min[1]+static_cast<int32>(Line/Size[0]);
const size_t Base=Line*WordsPerZ;
for(size_t W=0;W<WordsPerZ;++W)
{
const size_t Word=Base+W;
const uint64 Rock=RockWords[Word],Candidates=CandidateWords[Word];
const uint64 PreviousRock=W?RockWords[Word-1]>>63:0;
const uint64 PreviousCandidates=W?CandidateWords[Word-1]>>63:0;
uint64 Valid=(Size[2]-W*64)>=64?~uint64{0}
:((uint64{1}<<(Size[2]-W*64))-1);
if(W==0)Valid&=~uint64{1};
const uint64 ShiftedRock=(Rock<<1)|PreviousRock;
const uint64 ShiftedCandidates=(Candidates<<1)|PreviousCandidates;
uint64 Missing=((Rock^ShiftedRock)&Valid)
&~(Candidates&ShiftedCandidates);
while(Missing)
{
const uint32 Bit=std::countr_zero(Missing);Missing&=Missing-1;
const int32 Z=Min[2]+static_cast<int32>(W*64+Bit);
AddMissing(X,Y,Z);AddMissing(X,Y,Z-1);
}
if(X<Max[0])
{
const size_t Other=Word+WordsPerZ;
Missing=(Rock^RockWords[Other])&Valid
&~(Candidates&CandidateWords[Other]);
while(Missing)
{
const uint32 Bit=std::countr_zero(Missing);Missing&=Missing-1;
AddMissing(X,Y,Min[2]+static_cast<int32>(W*64+Bit));
AddMissing(X+1,Y,Min[2]+static_cast<int32>(W*64+Bit));
}
}
if(Y<Max[1])
{
const size_t Other=Word+static_cast<size_t>(Size[0])*WordsPerZ;
Missing=(Rock^RockWords[Other])&Valid
&~(Candidates&CandidateWords[Other]);
while(Missing)
{
const uint32 Bit=std::countr_zero(Missing);Missing&=Missing-1;
AddMissing(X,Y,Min[2]+static_cast<int32>(W*64+Bit));
AddMissing(X,Y+1,Min[2]+static_cast<int32>(W*64+Bit));
}
}
}
}
std::sort(MissingNodes.begin(),MissingNodes.end());
MissingNodes.erase(std::unique(MissingNodes.begin(),MissingNodes.end()),
MissingNodes.end());
std::vector<float> Densities(MissingNodes.size());
struct FParallelContext
{
FStandaloneShapeWorld* Shape;
const std::vector<size_t>* Nodes;
std::vector<float>* Values;
int32 Minimum[3];
int32 Extent[3];
} Context{this,&MissingNodes,&Densities,{Min[0],Min[1],Min[2]},
{Size[0],Size[1],Size[2]}};
const auto EvaluateNode=[](void* Raw,size_t Index,size_t)
{
auto& C=*static_cast<FParallelContext*>(Raw);
const size_t Node=(*C.Nodes)[Index];
const int32 X=static_cast<int32>(Node%static_cast<size_t>(C.Extent[0]));
const size_t YZ=Node/static_cast<size_t>(C.Extent[0]);
const int32 Y=static_cast<int32>(YZ%static_cast<size_t>(C.Extent[1]));
const int32 Z=static_cast<int32>(YZ/static_cast<size_t>(C.Extent[1]));
(*C.Values)[Index]=C.Shape->AnalyticDensityAt(
static_cast<float>(C.Minimum[0]+X),static_cast<float>(C.Minimum[1]+Y),
static_cast<float>(C.Minimum[2]+Z));
};
Scheduler->parallel_for(MissingNodes.size(),64,
static_cast<size_t>(std::max(1,WorkerCount)),&Context,EvaluateNode,nullptr,0);
uint64 AddedThisPass=0;
bool bSignChanged=false;
for(size_t Index=0;Index<MissingNodes.size();++Index)
{
const size_t Node=MissingNodes[Index];
const int32 X=Min[0]+static_cast<int32>(Node%static_cast<size_t>(Size[0]));
const size_t YZ=Node/static_cast<size_t>(Size[0]);
const int32 Y=Min[1]+static_cast<int32>(YZ%static_cast<size_t>(Size[1]));
const int32 Z=Min[2]+static_cast<int32>(YZ/static_cast<size_t>(Size[1]));
const size_t Column=static_cast<size_t>(Y-Min[1])*Size[0]
+static_cast<size_t>(X-Min[0]);
const size_t Zi=static_cast<size_t>(Z-Min[2]);
const size_t Word=Column*WordsPerZ+(Zi>>6);
const uint64 Mask=uint64{1}<<(Zi&63u);
if(CandidateWords[Word]&Mask)continue;
const float Density=Densities[Index];
StoreSurfaceDistance(Node,Density);
CandidateWords[Word]|=Mask;
++AddedThisPass;
const bool bExactRock=Density<0.0f;
const bool bPackedRock=(RockWords[Word]&Mask)!=0;
if(bExactRock!=bPackedRock)
{
if(bExactRock)RockWords[Word]|=Mask;
else RockWords[Word]&=~Mask;
++SignCorrections;
bSignChanged=true;
}
}
AddedTotal+=AddedThisPass;
if(!bSignChanged)break;
}
std::printf("[GridStairDistanceRepair] exact_endpoint_proxies=%llu occupancy_corrections=%llu mode=parallel_deterministic\n",
static_cast<unsigned long long>(AddedTotal),
static_cast<unsigned long long>(SignCorrections));
return AddedTotal;
}
void StoreSurfaceDistance(size_t Node,float Density)
{
int32 Q=static_cast<int32>(std::lround(Density*256.0f));
@@ -10191,6 +10334,7 @@ private:
const VoxelForgeCore::JobScheduler* Scheduler=nullptr;
bool RoundTunnelsEnabled=false;
bool bProfileDetailBand=false;
bool bParallelSignEdgeRepair=false;
int32 Min[3]{},Max[3]{},ClipMin[3]{},ClipMax[3]{},Size[3]{};
FIntVector EditBoundsMin=FIntVector(MAX_int32,MAX_int32,MAX_int32);
FIntVector EditBoundsMax=FIntVector(MIN_int32,MIN_int32,MIN_int32);