streaming: fast-travel near readiness in Unreal (L108)
Policy 3 movement traces (12 s move + 5 s dwell, 3 runs each). Unreal 30 m/s: near LOD0-2 ready while moving 31.6 -> 44.2% (LOD0 15.4 -> 34.7%), world tick p99/max 23.1/28.3 -> 11.3/13.6 ms, dwell completion 3.55 -> 3.22 s; far holes 2.5 -> 4.3%. Walking unchanged (~99%). Stale work is small (1.9% of moving LOD0 tiles finish out of range); the remaining limit is sustained generation throughput (8 task slots, p95 worker 105 ms). Near:far stays 4:1. World unchanged (pinned hashes pass). Fast tier PASS; Linux UE builds. 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
7c12b96ed1
commit
2ef0ca72b2
9 files changed
+816
-38
No files matched your search
@@ -5631,6 +5631,7 @@ namespace StandaloneStreamBenchmark
|
||||
return 9;
|
||||
}
|
||||
std::size_t NearDesired=0,NearResident=0,FarDesired=0,FarResident=0,FarCovered=0;
|
||||
std::size_t WalkableRingResident=0;
|
||||
double FarStaleAgeSum=0.0,FarStaleAgeMax=0.0;
|
||||
const auto FloorDiv=[](int32 Value,int32 Divisor)
|
||||
{
|
||||
@@ -5672,6 +5673,19 @@ namespace StandaloneStreamBenchmark
|
||||
}
|
||||
}
|
||||
}
|
||||
for(int32 Dy=-1;Dy<=1;++Dy)
|
||||
for(int32 Dx=-1;Dx<=1;++Dx)
|
||||
{
|
||||
const FVoxelTileKey WalkableKey(
|
||||
FIntVector(CurrentDesired.CenterChunk.X+Dx,
|
||||
CurrentDesired.CenterChunk.Y+Dy,
|
||||
CurrentDesired.CenterChunk.Z),0);
|
||||
const bool bWalkableKeyDesired=std::find(
|
||||
CurrentDesired.Tiles.begin(),CurrentDesired.Tiles.end(),WalkableKey)
|
||||
!=CurrentDesired.Tiles.end();
|
||||
if(bWalkableKeyDesired&&Resident.contains(WalkableKey))
|
||||
++WalkableRingResident;
|
||||
}
|
||||
FarMissingSince.swap(CurrentFarMissing);
|
||||
const double NearReadyPercent=100.0*static_cast<double>(NearResident)
|
||||
/static_cast<double>(std::max<std::size_t>(1,NearDesired));
|
||||
@@ -5681,12 +5695,15 @@ namespace StandaloneStreamBenchmark
|
||||
/static_cast<double>(std::max<std::size_t>(1,FarDesired));
|
||||
const double FarStaleAgeMean=FarDesired>FarResident
|
||||
?FarStaleAgeSum/static_cast<double>(FarDesired-FarResident):0.0;
|
||||
const double WalkableRingReadyPercent=100.0
|
||||
*static_cast<double>(WalkableRingResident)/9.0;
|
||||
if(FarDesired>0&&FarDesired==FarResident&&FirstAllFarReadySeconds<0.0)
|
||||
FirstAllFarReadySeconds=ElapsedSeconds;
|
||||
const char* Phase=ElapsedSeconds<MovingCameraDurationSeconds?"move":"dwell";
|
||||
std::printf("[L79MovingSample] policy=%d speed_mps=%.3f t_s=%.3f phase=%s x_m=%.3f near=%zu/%zu near_ready_pct=%.3f far=%zu/%zu far_missing_pct=%.3f far_covered=%zu/%zu far_hole_pct=%.3f far_stale_mean_s=%.3f far_stale_max_s=%.3f queued_jobs=%d queue_update_ms=%.3f generation_failures=%d\n",
|
||||
std::printf("[L79MovingSample] policy=%d speed_mps=%.3f t_s=%.3f phase=%s x_m=%.3f near=%zu/%zu near_ready_pct=%.3f walkable_ring=%zu/9 walkable_ring_ready_pct=%.3f far=%zu/%zu far_missing_pct=%.3f far_covered=%zu/%zu far_hole_pct=%.3f far_stale_mean_s=%.3f far_stale_max_s=%.3f queued_jobs=%d queue_update_ms=%.3f generation_failures=%d\n",
|
||||
SchedulerPolicy,MovingCameraSpeedMetersPerSecond,ElapsedSeconds,Phase,
|
||||
Camera.X*VoxelMetres,NearResident,NearDesired,NearReadyPercent,
|
||||
WalkableRingResident,WalkableRingReadyPercent,
|
||||
FarResident,FarDesired,FarMissingPercent,FarCovered,FarDesired,
|
||||
FarHolePercent,FarStaleAgeMean,FarStaleAgeMax,
|
||||
MovingUpdate.NewJobs,UpdateMilliseconds,GenerationFailures);
|
||||
|
||||
@@ -996,6 +996,7 @@ private:
|
||||
else if(Key.Level<=2)NearTiles.push_back(Key);
|
||||
else FarTiles.push_back(Key);
|
||||
}
|
||||
const int32 SpeedAwareMode=SpeedAwareSchedulerMode.load(std::memory_order_relaxed);
|
||||
std::unordered_map<FVoxelTileKey,std::size_t,FStandaloneTileKeyHash>
|
||||
PassageScores;
|
||||
if(!PassagePrioritySegments.empty())
|
||||
@@ -1026,6 +1027,40 @@ private:
|
||||
const std::size_t ScoreB=PassageScores.at(B);
|
||||
if(ScoreA!=ScoreB)return ScoreA>ScoreB;
|
||||
}
|
||||
if(SpeedAwareMode==2&&bNearFirst
|
||||
&&TravelDirection.X*TravelDirection.X
|
||||
+TravelDirection.Y*TravelDirection.Y>1.0e-12f)
|
||||
{
|
||||
const double TileScale=static_cast<double>(1<<A.Level);
|
||||
const double AlongA=
|
||||
((static_cast<double>(A.Coord.X)+0.5)*TileScale
|
||||
-NewDesired.CenterChunk.X)*TravelDirection.X
|
||||
+((static_cast<double>(A.Coord.Y)+0.5)*TileScale
|
||||
-NewDesired.CenterChunk.Y)*TravelDirection.Y;
|
||||
const double AlongB=
|
||||
((static_cast<double>(B.Coord.X)+0.5)*TileScale
|
||||
-NewDesired.CenterChunk.X)*TravelDirection.X
|
||||
+((static_cast<double>(B.Coord.Y)+0.5)*TileScale
|
||||
-NewDesired.CenterChunk.Y)*TravelDirection.Y;
|
||||
const auto LeadRank=[TileScale](double Projection)
|
||||
{
|
||||
if(Projection>=TileScale&&Projection<=TileScale*2.0)return 0;
|
||||
if(Projection>0.0&&Projection<TileScale)return 1;
|
||||
if(Projection>TileScale*2.0)return 2;
|
||||
return 3;
|
||||
};
|
||||
const int LeadRankA=LeadRank(AlongA),LeadRankB=LeadRank(AlongB);
|
||||
if(LeadRankA!=LeadRankB)return LeadRankA<LeadRankB;
|
||||
if(LeadRankA==0)
|
||||
{
|
||||
const double TargetLead=TileScale*1.5;
|
||||
const double ErrorA=std::abs(AlongA-TargetLead);
|
||||
const double ErrorB=std::abs(AlongB-TargetLead);
|
||||
if(ErrorA!=ErrorB)return ErrorA<ErrorB;
|
||||
}
|
||||
else if(LeadRankA==1&&AlongA!=AlongB)return AlongA>AlongB;
|
||||
else if(LeadRankA==2&&AlongA!=AlongB)return AlongA<AlongB;
|
||||
}
|
||||
const bool bAheadA=IsAhead(A),bAheadB=IsAhead(B);
|
||||
if(bAheadA!=bAheadB)return bAheadA;
|
||||
const double DA=StandaloneWorldMesher::TileDistanceSquaredChunks(A,NewDesired.CenterChunk);
|
||||
@@ -1042,12 +1077,19 @@ private:
|
||||
SpeedAwareOrder.insert(SpeedAwareOrder.end(),WalkableRing.begin(),WalkableRing.end());
|
||||
const double SpeedMetersPerSecond=SchedulerMotionSpeedMetersPerSecond.load(
|
||||
std::memory_order_relaxed);
|
||||
const int32 SpeedAwareMode=SpeedAwareSchedulerMode.load(std::memory_order_relaxed);
|
||||
if(SpeedAwareMode==2)
|
||||
{
|
||||
// Fast travel keeps parent coverage ahead of detail work.
|
||||
SpeedAwareOrder.insert(SpeedAwareOrder.end(),FarTiles.begin(),FarTiles.end());
|
||||
SpeedAwareOrder.insert(SpeedAwareOrder.end(),NearTiles.begin(),NearTiles.end());
|
||||
// Fast travel keeps a near-heavy admission ratio and a bounded horizon lane.
|
||||
size_t NearIndex=0,FarIndex=0;
|
||||
while(NearIndex<NearTiles.size())
|
||||
{
|
||||
const size_t NearEnd=std::min(NearTiles.size(),NearIndex+4);
|
||||
SpeedAwareOrder.insert(SpeedAwareOrder.end(),
|
||||
NearTiles.begin()+NearIndex,NearTiles.begin()+NearEnd);
|
||||
NearIndex=NearEnd;
|
||||
if(FarIndex<FarTiles.size())SpeedAwareOrder.push_back(FarTiles[FarIndex++]);
|
||||
}
|
||||
SpeedAwareOrder.insert(SpeedAwareOrder.end(),FarTiles.begin()+FarIndex,FarTiles.end());
|
||||
}
|
||||
else if(SpeedAwareMode==1)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user