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:
Fr0zkaandClaude Opus 5.5 committed 2026-10-29 00:09:26 +01:00
1 parent 7c12b96ed1
commit 2ef0ca72b2
9 files changed
+816 -38

No files matched your search

@@ -291,15 +291,16 @@ void RecordEvent(const TCHAR* Type, const FString& FieldsJson)
WriteEventLocked(*GState, Type, FieldsJson);
}
void RecordRequest(const FTileSample& Sample, uint32 Epoch)
void RecordRequest(const FTileSample& Sample, uint32 Epoch, uint32 DesiredEpoch)
{
FScopeLock Lock(&GTraceLock);
if (!GState.IsValid() || !GState->bActive) return;
WriteEventLocked(*GState, TEXT("request"), FString::Printf(
TEXT("\"tile\":[%d,%d,%d],\"level\":%d,\"priority\":%d,"
"\"request_ordinal\":%llu,\"epoch\":%u,\"resident_at_request\":%d"),
"\"request_ordinal\":%llu,\"epoch\":%u,\"desired_epoch\":%u,"
"\"resident_at_request\":%d"),
Sample.TileX, Sample.TileY, Sample.TileZ, Sample.Level, Sample.WorkPriority,
static_cast<unsigned long long>(Sample.RequestOrdinal), Epoch,
static_cast<unsigned long long>(Sample.RequestOrdinal), Epoch, DesiredEpoch,
Sample.bResidentAtRequest ? 1 : 0));
}
+237 -29
View File
@@ -10627,16 +10627,31 @@ void AVoxelWorld::QueuePendingUnload(const FVoxelTileKey& Tile)
void AVoxelWorld::HideOverlappingDesiredVisuals(const FVoxelTileKey& RetiredTile)
{
for (const TPair<FVoxelTileKey, URealtimeMeshComponent*>& Pair : TileComponents)
TArray<FVoxelTileKey, TInlineAllocator<32>> OverlappingDesired;
if (const TArray<FVoxelTileKey>* Descendants = DesiredTransitionDescendants.Find(RetiredTile))
{
if (Pair.Key == RetiredTile || !Pair.Value || !IsDesired(Pair.Key)
|| CollisionOnlyTiles.Contains(Pair.Key))
OverlappingDesired.Append(*Descendants);
}
for (int32 Level = RetiredTile.Level + 1; Level <= DesiredTransitionMaxLevel; ++Level)
{
TArray<FVoxelTileKey, TInlineAllocator<8>> Ancestors;
VF_AppendTouchingAncestors(RetiredTile, Level, Ancestors);
for (const FVoxelTileKey& Ancestor : Ancestors)
{
OverlappingDesired.Add(Ancestor);
}
}
for (const FVoxelTileKey& Candidate : OverlappingDesired)
{
if (Candidate == RetiredTile || !IsDesired(Candidate)
|| CollisionOnlyTiles.Contains(Candidate)
|| !VF_TileFootprintsOverlap(RetiredTile, Candidate))
{
continue;
}
if (VF_TileFootprintsOverlap(RetiredTile, Pair.Key))
if (URealtimeMeshComponent* Comp = TileComponents.FindRef(Candidate))
{
Pair.Value->SetVisibility(false);
Comp->SetVisibility(false);
}
}
}
@@ -11764,7 +11779,18 @@ void AVoxelWorld::CancelObsoleteTileWork()
if (TSharedPtr<FVoxelTileCancellationState, ESPMode::ThreadSafe>* Cancellation =
PendingTileCancellation.Find(Tile))
{
(*Cancellation)->bObsolete.store(true, std::memory_order_release);
const bool bWasObsolete = (*Cancellation)->bObsolete.exchange(
true, std::memory_order_acq_rel);
if (!bWasObsolete && VoxelForgeStartupTrace::IsActive())
{
VoxelForgeStartupTrace::RecordEvent(TEXT("tile_cancelled"), FString::Printf(
TEXT("\"tile\":[%d,%d,%d],\"level\":%d,\"priority\":%d,"
"\"request_ordinal\":%llu,\"request_epoch\":%u,\"desired_epoch\":%u"),
Tile.Coord.X, Tile.Coord.Y, Tile.Coord.Z, Tile.Level,
(*Cancellation)->WorkPriority,
static_cast<unsigned long long>((*Cancellation)->RequestOrdinal),
(*Cancellation)->RequestEpoch, DesiredEpoch));
}
}
}
}
@@ -12178,6 +12204,7 @@ void AVoxelWorld::UpdateChunksAroundPosition(const FVector& CenterPosition, APaw
const uint64 ResultBacklogCapStopsAtUpdateEntry =
StreamingResultBacklogCapStops.load(std::memory_order_relaxed);
double DesiredRebuildMilliseconds = 0.0;
double DesiredReconcileMilliseconds = 0.0;
double SubmitTilesMilliseconds = 0.0;
double SubmitLevelMilliseconds = 0.0;
double LevelCandidateScanMilliseconds = 0.0;
@@ -12391,10 +12418,15 @@ void AVoxelWorld::UpdateChunksAroundPosition(const FVector& CenterPosition, APaw
const int32 MaxTasks = GetMaxConcurrentStreamingTasks();
// Keep several bounded worker-sets ready so frame-paced admission can feed the
// background lane continuously without moving mesh application onto the game thread.
const int32 ReadyQueueDepth = FMath::Clamp(
const int32 ConfiguredReadyQueueDepth = FMath::Clamp(
GVoxelForgeStreamingReadyQueueDepth, 0, FMath::Min(64, FMath::Max(1, MaxTasks) * 4));
const bool bFastTravelAdmission = GVoxelForgeStreamingSchedulerPolicy == 3
&& bSpeedAwareFastMode;
const int32 ReadyQueueDepth = bFastTravelAdmission
? FMath::Max(ConfiguredReadyQueueDepth, 24) : ConfiguredReadyQueueDepth;
const int32 TotalAdmissionCap = MaxTasks + ReadyQueueDepth;
const int32 AuthoredNearTaskReserve = GetNearTaskReserve(MaxTasks);
const int32 FastTravelTotalCap = TotalAdmissionCap;
const FIntVector CenterChunk = GetTileCoordAtLocalCm(WorldToLocalCm(CenterPosition));
FVoxelTileKey WalkableSupportTile;
const FIntVector WalkableCenter = GetPlayerSupportTile(
@@ -12488,8 +12520,16 @@ void AVoxelWorld::UpdateChunksAroundPosition(const FVector& CenterPosition, APaw
? AuthoredNearTaskReserve
: ((bPawnMoving || !bWalkableRingReadyForReserve) ? QueueAwareNearTaskReserve : 0);
const int32 NearTaskReserve = EffectiveNearTaskReserve;
const int32 NearAdmissionCap = bPawnMoving ? MaxTasks : TotalAdmissionCap;
const int32 CoarseTaskCap = FMath::Max(1, MaxTasks - NearTaskReserve) + ReadyQueueDepth;
const bool bPolicy3FastTravel = SchedulerPolicy == 3 && bSpeedAwareFastMode;
// Fast travel keeps three quarters of the bounded ready queue for near detail and
// leaves the final quarter open for horizon coverage. The walkable ring is submitted first.
const int32 FastTravelNearCap = MaxTasks + (ReadyQueueDepth * 3) / 4;
const int32 NearAdmissionCap = bPawnMoving
? (bPolicy3FastTravel ? FastTravelNearCap : MaxTasks)
: TotalAdmissionCap;
const int32 CoarseTaskCap = bPolicy3FastTravel
? FastTravelTotalCap
: FMath::Max(1, MaxTasks - NearTaskReserve) + ReadyQueueDepth;
constexpr int32 FirstFarLevel = 3;
const int32 FirstCoarseLevel = FMath::Max(
2, Settings ? Settings->FullResClipLevels : 2);
@@ -12583,6 +12623,8 @@ void AVoxelWorld::UpdateChunksAroundPosition(const FVector& CenterPosition, APaw
//=========================================================================
const bool bDesiredRebuiltThisUpdate =
CenterChunk != LastUpdateCenter || bAnchorsMoved || bForceDesiredRebuild;
const double DesiredReconcileStartSeconds = bTraceStreamingScheduler
? FPlatformTime::Seconds() : 0.0;
if (bDesiredRebuiltThisUpdate)
{
LastUpdateCenter = CenterChunk;
@@ -12826,6 +12868,11 @@ void AVoxelWorld::UpdateChunksAroundPosition(const FVector& CenterPosition, APaw
// Teardown différé — ProcessUnloadQueue étale les destructions sur plusieurs frames.
}
}
if (bTraceStreamingScheduler)
{
DesiredReconcileMilliseconds = (FPlatformTime::Seconds()
- DesiredReconcileStartSeconds) * 1000.0;
}
//=========================================================================
if (bUseVoxelForgeCore && bCoreRegionCompilePending
@@ -12969,6 +13016,7 @@ void AVoxelWorld::UpdateChunksAroundPosition(const FVector& CenterPosition, APaw
}
const uint64 TraceLevelSortStartCycles = bTraceStreamingScheduler
? FPlatformTime::Cycles64() : 0;
const bool bUseFastNearLeadOrder = bPolicy3FastTravel && Level <= 2;
std::stable_sort(LevelTiles.GetData(),LevelTiles.GetData()+LevelTiles.Num(),
[&](const FVoxelTileKey& A,const FVoxelTileKey& B)
{
@@ -12982,6 +13030,36 @@ void AVoxelWorld::UpdateChunksAroundPosition(const FVector& CenterPosition, APaw
(static_cast<double>(B.Coord.Z) + 0.5) * TileSizeCm);
const FVector OffsetA = CenterA - PlayerLocalCm;
const FVector OffsetB = CenterB - PlayerLocalCm;
if (bUseFastNearLeadOrder && !Heading.IsNearlyZero())
{
const double ProjectionA = FVector::DotProduct(OffsetA, Heading);
const double ProjectionB = FVector::DotProduct(OffsetB, Heading);
const auto LeadRank = [TileSizeCm](double Projection)
{
if (Projection >= TileSizeCm && Projection <= TileSizeCm * 2.0) return 0;
if (Projection > 0.0 && Projection < TileSizeCm) return 1;
if (Projection > TileSizeCm * 2.0) return 2;
return 3;
};
const int32 LeadRankA = LeadRank(ProjectionA);
const int32 LeadRankB = LeadRank(ProjectionB);
if (LeadRankA != LeadRankB) return LeadRankA < LeadRankB;
if (LeadRankA == 0)
{
const double TargetLead = TileSizeCm * 1.5;
const double LeadErrorA = FMath::Abs(ProjectionA - TargetLead);
const double LeadErrorB = FMath::Abs(ProjectionB - TargetLead);
if (LeadErrorA != LeadErrorB) return LeadErrorA < LeadErrorB;
}
else if (LeadRankA == 1 && ProjectionA != ProjectionB)
{
return ProjectionA > ProjectionB;
}
else if (LeadRankA == 2 && ProjectionA != ProjectionB)
{
return ProjectionA < ProjectionB;
}
}
const bool bAheadA = !Heading.IsNearlyZero() && FVector::DotProduct(OffsetA, Heading) > 0.0;
const bool bAheadB = !Heading.IsNearlyZero() && FVector::DotProduct(OffsetB, Heading) > 0.0;
if (bAheadA != bAheadB) return bAheadA;
@@ -13104,19 +13182,43 @@ void AVoxelWorld::UpdateChunksAroundPosition(const FVector& CenterPosition, APaw
}
// Policy 0 reconstructs L77. Policy 3 enters that order only after sustained fast travel.
const bool bPolicy3FastTravel = SchedulerPolicy == 3 && bSpeedAwareFastMode;
if (SchedulerPolicy == 0 || bPolicy3FastTravel)
if (bPolicy3FastTravel)
{
const bool bPolicy3MayAdmit = !bPolicy3FastTravel
|| (bWalkableRingReadyForReserve && AreCriticalTilesReady());
const bool bCoarseFirstForPolicy = bPolicy3FastTravel
? bWalkableRingReadyForReserve : bUseCoarseFirstOrder;
if (bPolicy3MayAdmit && bCoarseFirstForPolicy)
if (bWalkableRingReadyForReserve && AreCriticalTilesReady())
{
const int32 ShareAdmissionCap = FastTravelTotalCap;
const int32 StartingAdmissions = GetGenerationAdmissionCount();
const int32 AvailableAdmissions = FMath::Max(
0, ShareAdmissionCap - StartingAdmissions);
const int32 NearShareAdmissions = (AvailableAdmissions * 4 + 4) / 5;
const int32 NearShareCap = StartingAdmissions + NearShareAdmissions;
const int32 LOD0ShareCap = StartingAdmissions + (NearShareAdmissions + 1) / 2;
const int32 LOD1ShareCap = StartingAdmissions
+ (NearShareAdmissions * 3 + 3) / 4;
if (MaxDesiredLevel >= 0)
{
SubmitLevel(0, EVoxelTileWorkPriority::LOD0, LOD0ShareCap, true);
}
if (MaxDesiredLevel >= 1)
SubmitLevel(1, EVoxelTileWorkPriority::Horizon, LOD1ShareCap, true);
if (MaxDesiredLevel >= 2)
SubmitLevel(2, EVoxelTileWorkPriority::Horizon, NearShareCap, true);
for (int32 Level = MaxDesiredLevel; Level >= FirstFarLevel; --Level)
{
SubmitLevel(Level, EVoxelTileWorkPriority::Horizon,
ShareAdmissionCap, true);
if (GetGenerationAdmissionCount() >= ShareAdmissionCap) break;
}
}
}
else if (SchedulerPolicy == 0)
{
if (bUseCoarseFirstOrder)
{
for (int32 Level = MaxDesiredLevel; Level >= FirstCoarseLevel; --Level)
{
SubmitLevel(Level, EVoxelTileWorkPriority::Horizon,
CoarseTaskCap, true);
CoarseTaskCap, false);
}
for (int32 Level = 0; Level < FirstCoarseLevel && Level <= MaxDesiredLevel; ++Level)
{
@@ -13124,10 +13226,10 @@ void AVoxelWorld::UpdateChunksAroundPosition(const FVector& CenterPosition, APaw
? EVoxelTileWorkPriority::LOD0 : EVoxelTileWorkPriority::Horizon;
SubmitLevel(Level, Priority,
Priority == EVoxelTileWorkPriority::LOD0 ? NearAdmissionCap : CoarseTaskCap,
true);
false);
}
}
else if (bPolicy3MayAdmit)
else
{
SubmitLevel(0, EVoxelTileWorkPriority::LOD0, NearAdmissionCap, false);
for (int32 Level = 1; Level <= MaxDesiredLevel; ++Level)
@@ -13362,6 +13464,7 @@ void AVoxelWorld::UpdateChunksAroundPosition(const FVector& CenterPosition, APaw
"\"desired_by_lod\":%s,\"resident_by_lod\":%s,\"settled_by_lod\":%s,"
"\"pending_by_lod\":%s,"
"\"covered_by_lod\":%s,"
"\"walkable_ready_tiles\":%d,\"walkable_required_tiles\":9,"
"\"active_generation\":%d,\"admission_occupancy\":%d,"
"\"task_cap\":%d,\"near_reserve\":%d,"
"\"coarse_first\":%d,\"dynamic_near_reserve\":%d,"
@@ -13373,6 +13476,7 @@ void AVoxelWorld::UpdateChunksAroundPosition(const FVector& CenterPosition, APaw
*FString::SanitizeFloat(PlayerHeading.Size()),
bWalkableRingReadyForReserve ? 1 : 0,
*DesiredCounts, *ResidentCounts, *SettledCounts, *PendingCounts, *CoveredCounts,
WalkableRingReadyCount,
GetActiveGenerationTaskCount(), GetGenerationAdmissionCount(), MaxTasks, NearTaskReserve,
GVoxelForgeStreamingCoarseFirst, GVoxelForgeStreamingDynamicNearReserve,
GVoxelForgeStreamingLegacyPendingResultCap,
@@ -13529,6 +13633,7 @@ void AVoxelWorld::UpdateChunksAroundPosition(const FVector& CenterPosition, APaw
"\"region_independent_submissions\":%llu,\"region_dependent_declines\":%llu,"
"\"worker_busy_s_interval\":%s,\"worker_busy_avg\":%s,"
"\"update_chunks_ms\":%s,\"desired_rebuild_ms\":%s,"
"\"desired_reconcile_ms\":%s,"
"\"submit_tiles_ms\":%s,\"submit_level_ms\":%s,"
"\"level_candidate_scan_ms\":%s,\"passage_score_ms\":%s,"
"\"level_sort_ms\":%s,\"level_admit_ms\":%s,"
@@ -13561,6 +13666,7 @@ void AVoxelWorld::UpdateChunksAroundPosition(const FVector& CenterPosition, APaw
*FString::SanitizeFloat(IntervalSeconds > 0.0 ? BusySeconds / IntervalSeconds : 0.0),
*FString::SanitizeFloat(SchedulerUpdateMilliseconds),
*FString::SanitizeFloat(DesiredRebuildMilliseconds),
*FString::SanitizeFloat(DesiredReconcileMilliseconds),
*FString::SanitizeFloat(SubmitTilesMilliseconds),
*FString::SanitizeFloat(SubmitLevelMilliseconds),
*FString::SanitizeFloat(LevelCandidateScanMilliseconds),
@@ -13608,16 +13714,26 @@ void AVoxelWorld::LoadTile(const FVoxelTileKey& Tile, EVoxelTileWorkPriority Wor
}
const int32 MaxTasks = GetMaxConcurrentStreamingTasks(); // Core and worker lane clamped. / Core et voie worker plafonnes.
const int32 ReadyQueueDepth = FMath::Clamp(
const int32 ConfiguredReadyQueueDepth = FMath::Clamp(
GVoxelForgeStreamingReadyQueueDepth, 0, FMath::Min(64, FMath::Max(1, MaxTasks) * 4));
const bool bFastTravelAdmission = GVoxelForgeStreamingSchedulerPolicy == 3
&& bSpeedAwareFastMode;
const int32 ReadyQueueDepth = bFastTravelAdmission
? FMath::Max(ConfiguredReadyQueueDepth, 24) : ConfiguredReadyQueueDepth;
const int32 TotalAdmissionCap = MaxTasks + ReadyQueueDepth;
const bool bNearPriority = WorkPriority != EVoxelTileWorkPriority::Horizon
|| Tile.Level <= 2;
const int32 NearReserve = EffectiveNearTaskReserve >= 0
? FMath::Clamp(EffectiveNearTaskReserve, 0, FMath::Max(0, MaxTasks - 1))
: GetNearTaskReserve(MaxTasks);
const int32 NearAdmissionCap = bStreamingPlayerMoving ? MaxTasks : TotalAdmissionCap;
const int32 CoarseTaskCap = FMath::Max(1, MaxTasks - NearReserve) + ReadyQueueDepth;
const int32 FastTravelTotalCap = TotalAdmissionCap;
const int32 FastTravelNearCap = MaxTasks + (ReadyQueueDepth * 3) / 4;
const int32 NearAdmissionCap = bStreamingPlayerMoving
? (bFastTravelAdmission ? FastTravelNearCap : MaxTasks)
: TotalAdmissionCap;
const int32 CoarseTaskCap = bFastTravelAdmission
? FastTravelTotalCap
: FMath::Max(1, MaxTasks - NearReserve) + ReadyQueueDepth;
const int32 AdmissionCap = WorkPriority == EVoxelTileWorkPriority::Horizon
&& Tile.Level > 2
? CoarseTaskCap
@@ -13650,7 +13766,7 @@ void AVoxelWorld::LoadTile(const FVoxelTileKey& Tile, EVoxelTileWorkPriority Wor
RequestSample.WorkPriority = static_cast<int32>(WorkPriority);
RequestSample.RequestOrdinal = RequestOrdinal;
RequestSample.bResidentAtRequest = bResidentAtRequest;
VoxelForgeStartupTrace::RecordRequest(RequestSample, GenerationEpoch);
VoxelForgeStartupTrace::RecordRequest(RequestSample, GenerationEpoch, DesiredEpoch);
}
if (bStartupCollisionGateTimingCaptured
&& StartupCollisionGateSupportTile.Coord == Tile.Coord
@@ -13758,6 +13874,9 @@ void AVoxelWorld::LoadTile(const FVoxelTileKey& Tile, EVoxelTileWorkPriority Wor
const TSharedPtr<FVoxelTileCancellationState, ESPMode::ThreadSafe> Cancellation =
MakeShared<FVoxelTileCancellationState, ESPMode::ThreadSafe>();
Cancellation->RequestOrdinal = RequestOrdinal;
Cancellation->RequestEpoch = GenerationEpoch;
Cancellation->WorkPriority = static_cast<int32>(WorkPriority);
PendingTileCancellation.Add(Tile, Cancellation);
ActiveTaskCount.fetch_add(1, std::memory_order_relaxed);
ActiveTileTaskCount.fetch_add(1, std::memory_order_relaxed);
@@ -13820,6 +13939,25 @@ void AVoxelWorld::LoadTile(const FVoxelTileKey& Tile, EVoxelTileWorkPriority Wor
{
return;
}
if (VoxelForgeStartupTrace::IsActive())
{
const uint64 WorkerEndCycles = FPlatformTime::Cycles64();
VoxelForgeStartupTrace::RecordEvent(TEXT("tile_worker_end"), FString::Printf(
TEXT("\"tile\":[%d,%d,%d],\"level\":%d,\"priority\":%d,"
"\"request_ordinal\":%llu,\"generation_ordinal\":%llu,"
"\"epoch\":%u,\"generated\":%d,\"aborted\":%d,\"obsolete\":1,"
"\"worker_task_s\":%s"),
Tile.Coord.X, Tile.Coord.Y, Tile.Coord.Z, Tile.Level,
static_cast<int32>(WorkPriority),
static_cast<unsigned long long>(RequestOrdinal),
static_cast<unsigned long long>(Result.GenerationOrdinal), TaskEpoch,
Result.GenerationEndCycles != 0 && !Result.bAborted ? 1 : 0,
Result.bAborted ? 1 : 0,
*FString::SanitizeFloat(WorkerTaskStartCycles != 0
&& WorkerEndCycles >= WorkerTaskStartCycles
? FPlatformTime::ToSeconds64(WorkerEndCycles - WorkerTaskStartCycles)
: 0.0)));
}
FChunkResult Canceled;
Canceled.Tile = Tile;
Canceled.Epoch = TaskEpoch;
@@ -13901,6 +14039,25 @@ void AVoxelWorld::LoadTile(const FVoxelTileKey& Tile, EVoxelTileWorkPriority Wor
if (!ShouldAbortWork())
{
Result.WorkerTaskEndCycles = FPlatformTime::Cycles64();
if (VoxelForgeStartupTrace::IsActive())
{
VoxelForgeStartupTrace::RecordEvent(TEXT("tile_worker_end"), FString::Printf(
TEXT("\"tile\":[%d,%d,%d],\"level\":%d,\"priority\":%d,"
"\"request_ordinal\":%llu,\"generation_ordinal\":%llu,"
"\"epoch\":%u,\"generated\":%d,\"aborted\":%d,\"obsolete\":0,"
"\"worker_task_s\":%s"),
Tile.Coord.X, Tile.Coord.Y, Tile.Coord.Z, Tile.Level,
static_cast<int32>(WorkPriority),
static_cast<unsigned long long>(RequestOrdinal),
static_cast<unsigned long long>(Result.GenerationOrdinal), TaskEpoch,
Result.GenerationEndCycles != 0 && !Result.bAborted ? 1 : 0,
Result.bAborted ? 1 : 0,
*FString::SanitizeFloat(WorkerTaskStartCycles != 0
&& Result.WorkerTaskEndCycles >= WorkerTaskStartCycles
? FPlatformTime::ToSeconds64(
Result.WorkerTaskEndCycles - WorkerTaskStartCycles)
: 0.0)));
}
EnqueueStreamingResult(MoveTemp(Result)); // move: don't copy the geometry payload
}
}, TaskPriority);
@@ -13959,16 +14116,26 @@ void AVoxelWorld::LoadCoreTile(const FVoxelTileKey& Tile, EVoxelTileWorkPriority
}
const int32 MaxTasks = GetMaxConcurrentStreamingTasks();
const int32 ReadyQueueDepth = FMath::Clamp(
const int32 ConfiguredReadyQueueDepth = FMath::Clamp(
GVoxelForgeStreamingReadyQueueDepth, 0, FMath::Min(64, FMath::Max(1, MaxTasks) * 4));
const bool bFastTravelAdmission = GVoxelForgeStreamingSchedulerPolicy == 3
&& bSpeedAwareFastMode;
const int32 ReadyQueueDepth = bFastTravelAdmission
? FMath::Max(ConfiguredReadyQueueDepth, 24) : ConfiguredReadyQueueDepth;
const int32 TotalAdmissionCap = MaxTasks + ReadyQueueDepth;
const bool bNearPriority = WorkPriority != EVoxelTileWorkPriority::Horizon
|| Tile.Level <= 2;
const int32 NearReserve = EffectiveNearTaskReserve >= 0
? FMath::Clamp(EffectiveNearTaskReserve, 0, FMath::Max(0, MaxTasks - 1))
: GetNearTaskReserve(MaxTasks);
const int32 NearAdmissionCap = bStreamingPlayerMoving ? MaxTasks : TotalAdmissionCap;
const int32 CoarseTaskCap = FMath::Max(1, MaxTasks - NearReserve) + ReadyQueueDepth;
const int32 FastTravelTotalCap = TotalAdmissionCap;
const int32 FastTravelNearCap = MaxTasks + (ReadyQueueDepth * 3) / 4;
const int32 NearAdmissionCap = bStreamingPlayerMoving
? (bFastTravelAdmission ? FastTravelNearCap : MaxTasks)
: TotalAdmissionCap;
const int32 CoarseTaskCap = bFastTravelAdmission
? FastTravelTotalCap
: FMath::Max(1, MaxTasks - NearReserve) + ReadyQueueDepth;
const int32 AdmissionCap = WorkPriority == EVoxelTileWorkPriority::Horizon
&& Tile.Level > 2
? CoarseTaskCap
@@ -13993,6 +14160,9 @@ void AVoxelWorld::LoadCoreTile(const FVoxelTileKey& Tile, EVoxelTileWorkPriority
const uint32 TaskModificationEpoch = ModificationEpoch;
const uint64 RequestStartCycles = FPlatformTime::Cycles64();
const uint64 RequestOrdinal = ++NextStreamingRequestOrdinal;
Cancellation->RequestOrdinal = RequestOrdinal;
Cancellation->RequestEpoch = TaskEpoch;
Cancellation->WorkPriority = static_cast<int32>(WorkPriority);
const bool bResidentAtRequest = LoadedTiles.Contains(Tile);
if (VoxelForgeStartupTrace::IsActive())
{
@@ -14004,7 +14174,7 @@ void AVoxelWorld::LoadCoreTile(const FVoxelTileKey& Tile, EVoxelTileWorkPriority
RequestSample.WorkPriority = static_cast<int32>(WorkPriority);
RequestSample.RequestOrdinal = RequestOrdinal;
RequestSample.bResidentAtRequest = bResidentAtRequest;
VoxelForgeStartupTrace::RecordRequest(RequestSample, TaskEpoch);
VoxelForgeStartupTrace::RecordRequest(RequestSample, TaskEpoch, TaskDesiredEpoch);
}
const bool bCaptureHashes = bCaptureVoxelForgeCoreHashesForValidation;
const bool bLegacyDirectMappedColumnCache=GVoxelForgeCoreColumnCacheDirectMapped!=0;
@@ -14048,10 +14218,30 @@ void AVoxelWorld::LoadCoreTile(const FVoxelTileKey& Tile, EVoxelTileWorkPriority
}
} WorkerGuard{ActiveGenerationWorkerCount, TotalGenerationWorkerTaskCycles, WorkerTaskStartCycles};
auto Enqueue = [this, WorkPriority](FChunkResult&& Result)
auto Enqueue = [this, WorkPriority, Cancellation](FChunkResult&& Result)
{
Result.WorkPriority = WorkPriority;
Result.WorkerTaskEndCycles = FPlatformTime::Cycles64();
if (VoxelForgeStartupTrace::IsActive() && !Result.bObsolete)
{
VoxelForgeStartupTrace::RecordEvent(TEXT("tile_worker_end"), FString::Printf(
TEXT("\"tile\":[%d,%d,%d],\"level\":%d,\"priority\":%d,"
"\"request_ordinal\":%llu,\"generation_ordinal\":%llu,"
"\"epoch\":%u,\"generated\":%d,\"aborted\":%d,\"obsolete\":%d,"
"\"worker_task_s\":%s"),
Result.Tile.Coord.X, Result.Tile.Coord.Y, Result.Tile.Coord.Z,
Result.Tile.Level, static_cast<int32>(WorkPriority),
static_cast<unsigned long long>(Result.RequestOrdinal),
static_cast<unsigned long long>(Result.GenerationOrdinal), Result.Epoch,
Result.GenerationEndCycles != 0 && !Result.bAborted ? 1 : 0,
Result.bAborted ? 1 : 0,
Cancellation->bObsolete.load(std::memory_order_acquire) ? 1 : 0,
*FString::SanitizeFloat(Result.WorkerTaskStartCycles != 0
&& Result.WorkerTaskEndCycles >= Result.WorkerTaskStartCycles
? FPlatformTime::ToSeconds64(
Result.WorkerTaskEndCycles - Result.WorkerTaskStartCycles)
: 0.0)));
}
EnqueueStreamingResult(MoveTemp(Result));
};
@@ -14094,10 +14284,28 @@ void AVoxelWorld::LoadCoreTile(const FVoxelTileKey& Tile, EVoxelTileWorkPriority
Canceled.WorkerThreadId = Result.WorkerThreadId;
Canceled.bResidentAtRequest = bResidentAtRequest;
Canceled.GenerationStartCycles = Result.GenerationStartCycles;
Canceled.GenerationEndCycles = FPlatformTime::Cycles64();
Canceled.GenerationEndCycles = Result.GenerationEndCycles;
Canceled.WorkPriority = WorkPriority;
Canceled.bAborted = true;
Canceled.bObsolete = true;
if (VoxelForgeStartupTrace::IsActive())
{
const uint64 WorkerEndCycles = FPlatformTime::Cycles64();
VoxelForgeStartupTrace::RecordEvent(TEXT("tile_worker_end"), FString::Printf(
TEXT("\"tile\":[%d,%d,%d],\"level\":%d,\"priority\":%d,"
"\"request_ordinal\":%llu,\"generation_ordinal\":%llu,"
"\"epoch\":%u,\"generated\":%d,\"aborted\":1,\"obsolete\":1,"
"\"worker_task_s\":%s"),
Tile.Coord.X, Tile.Coord.Y, Tile.Coord.Z, Tile.Level,
static_cast<int32>(WorkPriority),
static_cast<unsigned long long>(RequestOrdinal),
static_cast<unsigned long long>(Result.GenerationOrdinal), TaskEpoch,
Result.GenerationEndCycles != 0 && !Result.bAborted ? 1 : 0,
*FString::SanitizeFloat(WorkerTaskStartCycles != 0
&& WorkerEndCycles >= WorkerTaskStartCycles
? FPlatformTime::ToSeconds64(WorkerEndCycles - WorkerTaskStartCycles)
: 0.0)));
}
if (!bShuttingDown.load(std::memory_order_acquire)
&& !State->bShuttingDown.load(std::memory_order_acquire))
{
+2 -1
View File
@@ -86,7 +86,8 @@ namespace VoxelForgeStartupTrace
/** FieldsJson is the contents after the type/timestamp object prefix, without braces. */
VOXELFORGE_API void RecordEvent(const TCHAR* Type, const FString& FieldsJson = FString());
VOXELFORGE_API void RecordRequest(const FTileSample& Sample, uint32 Epoch);
VOXELFORGE_API void RecordRequest(const FTileSample& Sample, uint32 Epoch,
uint32 DesiredEpoch = 0);
VOXELFORGE_API void StageBegin(const TCHAR* Name);
VOXELFORGE_API void StageEnd(const TCHAR* Name);
+3
View File
@@ -52,6 +52,9 @@ struct FVoxelForgeCoreTileHashRecord
struct FVoxelTileCancellationState
{
std::atomic<bool> bObsolete{false};
uint64 RequestOrdinal = 0;
uint32 RequestEpoch = 0;
int32 WorkPriority = 0;
};
/**