perf(streaming): item 3 bought nothing, item 5 removed dead weight -- both worth knowing
Two WORK-NEXT items, one null result and one confirmed removal. Item 4 untouched.
ITEM 3 -- CANCEL OBSOLETE WORK AND PRIORITISE THE FLOOR: NULL RESULT
Clean -nullrhi, diagnostics off, 800 cm/s, 200 m of travel:
before after
request->ready p95 0.369117 s 0.367612 s
queue wait p95 0.066949 s 0.064483 s
generation p95 0.287926 s 0.283642 s
p95 travel distance 2.952938 m 2.940894 m
obsolete aborts 0 12
Flat. Aborting obsolete tiles, sorting from the true pawn position and prioritising the
occupied/next tile changed request-to-ready by 0.4%.
⭐ AND THE NULL RESULT IS ITSELF THE FINDING. Look at the split: queue wait is 65 ms of a
368 ms p95; generation is 284 ms. **The queue was never the problem, so reordering it
cannot help.** Only 12 tiles in a 200 m run were obsolete enough to abort. The floor is
late because generation is slow, not because work is badly ordered -- item 3 establishes
that by exclusion, which is worth more than the 0.4%.
The machinery is kept: it is correct, it costs nothing, and it will matter once
generation is fast enough for ordering to be the binding constraint.
ITEM 5 -- VERDICT CACHE REMOVED. It was pure overhead.
Clean moving-session audit:
outer calls/probes/hits 2,109 / 2,109 / 0
nested calls/probes/hits 19,904 / 19,904 / 0
enclosing hits 0
stores 15,877, evictions 15,365
⇒ It stored 15,877 proofs, evicted 15,365 of them, and hit ZERO times. A moving player
visits unique regions; the cache was filling and thrashing a 512-entry table under a
global lock for no benefit. Same-binary A/B: request p95 0.367645 vs 0.365978,
generation p95 0.285559 vs 0.285992 -- neutral within noise, so its cost was the lock and
the linear scans rather than time we can see.
Removed: the global cache, its lock, the entry table, the invalidation path, the
cache-only profiler fields and the synthetic probe. The proof classifier stays.
⚠️ I asked for this cache two days ago on the strength of a commandlet measurement that
re-visited the same region repeatedly. That access pattern is nothing like a moving
player, and I should have said so when specifying it.
VERIFIED BY ME: build 0 errors; export 0.563 / 0.565 / 0.566 s (35de59b was 0.545-0.563,
flat as expected); geometry SHA-256 b3e5f4c3..9b377 UNCHANGED; capability 20,830 /
10,909, connected.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012aheo2crrZmHuYtPpdY2Cb
This commit is contained in:
1 parent
35de59bac5
commit
cf0319d480
12 files changed
+660
-514
No files matched your search
@@ -22,7 +22,6 @@
|
||||
#include "HAL/PlatformTime.h"
|
||||
#include "HAL/IConsoleManager.h"
|
||||
#include "Misc/CommandLine.h"
|
||||
#include "Misc/ScopeLock.h"
|
||||
|
||||
#if WITH_EDITOR
|
||||
#include "VoxelStrateComposer.h"
|
||||
@@ -56,6 +55,7 @@ namespace
|
||||
GVoxelForgeUseFusedEvaluator = CommandLineValue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
@@ -1532,169 +1532,6 @@ UVoxelGenerator::UVoxelGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
void UVoxelGenerator::InvalidateTileVerdictCache() const
|
||||
{
|
||||
FScopeLock Lock(&TileVerdictCacheLock);
|
||||
TileVerdictCache.Reset();
|
||||
TileVerdictCacheClock = 0;
|
||||
}
|
||||
|
||||
bool UVoxelGenerator::FindTileVerdict(
|
||||
const FIntVector& OriginVoxels, int32 Step, int32 CellsPerAxis,
|
||||
int32 ManagerWorldSeed, uint32 LayoutVersion, uint32 DiffVersion,
|
||||
uint64 ParamsFingerprint, uint8 PassageSupportFloorWrites,
|
||||
EVoxelTileClass& OutVerdict, bool& bOutRegionHit) const
|
||||
{
|
||||
bOutRegionHit = false;
|
||||
FScopeLock Lock(&TileVerdictCacheLock);
|
||||
++TileVerdictCacheClock;
|
||||
|
||||
const int64 RequestMaxX = static_cast<int64>(OriginVoxels.X)
|
||||
+ static_cast<int64>(CellsPerAxis) * Step;
|
||||
const int64 RequestMaxY = static_cast<int64>(OriginVoxels.Y)
|
||||
+ static_cast<int64>(CellsPerAxis) * Step;
|
||||
const int64 RequestMaxZ = static_cast<int64>(OriginVoxels.Z)
|
||||
+ static_cast<int64>(CellsPerAxis) * Step;
|
||||
|
||||
int32 BestIndex = INDEX_NONE;
|
||||
bool bBestExact = false;
|
||||
for (int32 Index = 0; Index < TileVerdictCache.Num(); ++Index)
|
||||
{
|
||||
FTileVerdictCacheEntry& Entry = TileVerdictCache[Index];
|
||||
if (Entry.GeneratorSeed != Seed
|
||||
|| Entry.ManagerWorldSeed != ManagerWorldSeed
|
||||
|| Entry.OriginSpineRadius != OriginSpineRadius
|
||||
|| Entry.WorldRadiusVoxels != WorldRadiusVoxels
|
||||
|| Entry.EdgeSealThickness != EdgeSealThickness
|
||||
|| Entry.ManagerLifetimeId != (StrateManager ? StrateManager->GetCacheLifetimeId() : 0)
|
||||
|| Entry.LayoutVersion != LayoutVersion
|
||||
|| Entry.DiffVersion != DiffVersion
|
||||
|| Entry.ParamsFingerprint != ParamsFingerprint
|
||||
|| Entry.PassageSupportFloorWrites != PassageSupportFloorWrites
|
||||
|| Entry.Step != Step
|
||||
|| Entry.CellsPerAxis < CellsPerAxis)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const int64 EntryMaxX = static_cast<int64>(Entry.Origin.X)
|
||||
+ static_cast<int64>(Entry.CellsPerAxis) * Step;
|
||||
const int64 EntryMaxY = static_cast<int64>(Entry.Origin.Y)
|
||||
+ static_cast<int64>(Entry.CellsPerAxis) * Step;
|
||||
const int64 EntryMaxZ = static_cast<int64>(Entry.Origin.Z)
|
||||
+ static_cast<int64>(Entry.CellsPerAxis) * Step;
|
||||
const int64 DeltaX = static_cast<int64>(OriginVoxels.X) - Entry.Origin.X;
|
||||
const int64 DeltaY = static_cast<int64>(OriginVoxels.Y) - Entry.Origin.Y;
|
||||
const int64 DeltaZ = static_cast<int64>(OriginVoxels.Z) - Entry.Origin.Z;
|
||||
if (DeltaX < 0 || DeltaY < 0 || DeltaZ < 0
|
||||
|| (DeltaX % Step) != 0 || (DeltaY % Step) != 0 || (DeltaZ % Step) != 0
|
||||
|| RequestMaxX > EntryMaxX || RequestMaxY > EntryMaxY || RequestMaxZ > EntryMaxZ)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool bExact = Entry.Origin == OriginVoxels
|
||||
&& Entry.CellsPerAxis == CellsPerAxis;
|
||||
if (BestIndex == INDEX_NONE || (bExact && !bBestExact)
|
||||
|| (bExact == bBestExact
|
||||
&& Entry.CellsPerAxis < TileVerdictCache[BestIndex].CellsPerAxis))
|
||||
{
|
||||
BestIndex = Index;
|
||||
bBestExact = bExact;
|
||||
}
|
||||
}
|
||||
|
||||
if (BestIndex == INDEX_NONE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FTileVerdictCacheEntry& Entry = TileVerdictCache[BestIndex];
|
||||
Entry.LastUse = TileVerdictCacheClock;
|
||||
OutVerdict = Entry.Verdict;
|
||||
bOutRegionHit = !(Entry.Origin == OriginVoxels
|
||||
&& Entry.CellsPerAxis == CellsPerAxis);
|
||||
return OutVerdict != EVoxelTileClass::Mixed;
|
||||
}
|
||||
|
||||
void UVoxelGenerator::StoreTileVerdict(
|
||||
const FIntVector& OriginVoxels, int32 Step, int32 CellsPerAxis,
|
||||
int32 ManagerWorldSeed, uint32 LayoutVersion, uint32 DiffVersion,
|
||||
uint64 ParamsFingerprint, uint8 PassageSupportFloorWrites,
|
||||
EVoxelTileClass Verdict) const
|
||||
{
|
||||
if (Verdict == EVoxelTileClass::Mixed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FScopeLock Lock(&TileVerdictCacheLock);
|
||||
++TileVerdictCacheClock;
|
||||
|
||||
int32 SlotIndex = INDEX_NONE;
|
||||
int32 VictimIndex = INDEX_NONE;
|
||||
uint32 OldestUse = MAX_uint32;
|
||||
for (int32 Index = 0; Index < TileVerdictCache.Num(); ++Index)
|
||||
{
|
||||
FTileVerdictCacheEntry& Entry = TileVerdictCache[Index];
|
||||
if (Entry.GeneratorSeed == Seed
|
||||
&& Entry.ManagerWorldSeed == ManagerWorldSeed
|
||||
&& Entry.OriginSpineRadius == OriginSpineRadius
|
||||
&& Entry.WorldRadiusVoxels == WorldRadiusVoxels
|
||||
&& Entry.EdgeSealThickness == EdgeSealThickness
|
||||
&& Entry.ManagerLifetimeId == (StrateManager ? StrateManager->GetCacheLifetimeId() : 0)
|
||||
&& Entry.LayoutVersion == LayoutVersion
|
||||
&& Entry.DiffVersion == DiffVersion
|
||||
&& Entry.ParamsFingerprint == ParamsFingerprint
|
||||
&& Entry.PassageSupportFloorWrites == PassageSupportFloorWrites
|
||||
&& Entry.Origin == OriginVoxels
|
||||
&& Entry.Step == Step
|
||||
&& Entry.CellsPerAxis == CellsPerAxis)
|
||||
{
|
||||
SlotIndex = Index;
|
||||
break;
|
||||
}
|
||||
if (Entry.LastUse < OldestUse)
|
||||
{
|
||||
OldestUse = Entry.LastUse;
|
||||
VictimIndex = Index;
|
||||
}
|
||||
}
|
||||
|
||||
if (SlotIndex == INDEX_NONE)
|
||||
{
|
||||
if (TileVerdictCache.Num() < TileVerdictCacheCapacity)
|
||||
{
|
||||
SlotIndex = TileVerdictCache.AddDefaulted();
|
||||
}
|
||||
else if (VictimIndex != INDEX_NONE)
|
||||
{
|
||||
SlotIndex = VictimIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
FTileVerdictCacheEntry& Entry = TileVerdictCache[SlotIndex];
|
||||
Entry.Origin = OriginVoxels;
|
||||
Entry.Step = Step;
|
||||
Entry.CellsPerAxis = CellsPerAxis;
|
||||
Entry.GeneratorSeed = Seed;
|
||||
Entry.ManagerWorldSeed = ManagerWorldSeed;
|
||||
Entry.OriginSpineRadius = OriginSpineRadius;
|
||||
Entry.WorldRadiusVoxels = WorldRadiusVoxels;
|
||||
Entry.EdgeSealThickness = EdgeSealThickness;
|
||||
Entry.ManagerLifetimeId = StrateManager ? StrateManager->GetCacheLifetimeId() : 0;
|
||||
Entry.LayoutVersion = LayoutVersion;
|
||||
Entry.DiffVersion = DiffVersion;
|
||||
Entry.ParamsFingerprint = ParamsFingerprint;
|
||||
Entry.PassageSupportFloorWrites = PassageSupportFloorWrites;
|
||||
Entry.Verdict = Verdict;
|
||||
Entry.LastUse = TileVerdictCacheClock;
|
||||
}
|
||||
|
||||
void UVoxelGenerator::InitializeSettings(const UVoxelSettings* Settings)
|
||||
{
|
||||
// Les paramètres globaux sont copiés ici une seule fois : le chemin voxel ne doit pas
|
||||
@@ -1703,7 +1540,6 @@ void UVoxelGenerator::InitializeSettings(const UVoxelSettings* Settings)
|
||||
OriginSpineRadius = Settings ? Settings->GetEffectiveOriginSpineRadius() : 14.0f;
|
||||
WorldRadiusVoxels = Settings ? Settings->GetEffectiveWorldRadiusVoxels() : 0.0f;
|
||||
EdgeSealThickness = Settings ? Settings->EdgeSealThickness : 64.0f;
|
||||
InvalidateTileVerdictCache();
|
||||
}
|
||||
|
||||
void UVoxelGenerator::BeginDensityBlock(FIntVector OriginVoxels, int32 Step,
|
||||
@@ -5115,48 +4951,6 @@ EVoxelTileClass UVoxelGenerator::ClassifyTile(const FIntVector& OriginVoxels, in
|
||||
VoxelDensityProfile::AddCounter(
|
||||
VoxelDensityProfile::ECounter::TileClassifyCalls);
|
||||
|
||||
const uint64 ParamsFingerprint = StrateManager
|
||||
? StrateManager->GetGenerationParamsFingerprint() : 0;
|
||||
const bool bCacheable = ParamsFingerprint != 0;
|
||||
const uint32 LayoutVersion = StrateManager ? StrateManager->GetLayoutVersion() : 0;
|
||||
const uint32 DiffVersion = DiffLayer ? DiffLayer->GetModsVersion() : 0;
|
||||
const int32 ManagerWorldSeed = StrateManager ? StrateManager->GetWorldSeed() : 0;
|
||||
const uint8 PassageSupportFloorWrites = StrateManager
|
||||
&& StrateManager->ArePassageSupportFloorWritesEnabledForDiagnostics() ? 1u : 0u;
|
||||
|
||||
EVoxelTileClass CachedVerdict = EVoxelTileClass::Mixed;
|
||||
bool bRegionHit = false;
|
||||
if (bCacheable
|
||||
&& FindTileVerdict(
|
||||
OriginVoxels, NormalizedStep, NormalizedCellsPerAxis,
|
||||
ManagerWorldSeed, LayoutVersion, DiffVersion, ParamsFingerprint,
|
||||
PassageSupportFloorWrites, CachedVerdict, bRegionHit))
|
||||
{
|
||||
VoxelDensityProfile::AddCounter(
|
||||
VoxelDensityProfile::ECounter::TileVerdictCacheHits);
|
||||
if (bRegionHit)
|
||||
{
|
||||
VoxelDensityProfile::AddCounter(
|
||||
VoxelDensityProfile::ECounter::TileVerdictRegionHits);
|
||||
}
|
||||
if (CachedVerdict == EVoxelTileClass::AllSolid)
|
||||
{
|
||||
VoxelDensityProfile::AddCounter(
|
||||
VoxelDensityProfile::ECounter::TileClassifyAllSolid);
|
||||
}
|
||||
else if (CachedVerdict == EVoxelTileClass::AllAir)
|
||||
{
|
||||
VoxelDensityProfile::AddCounter(
|
||||
VoxelDensityProfile::ECounter::TileClassifyAllAir);
|
||||
}
|
||||
else
|
||||
{
|
||||
VoxelDensityProfile::AddCounter(
|
||||
VoxelDensityProfile::ECounter::TileClassifyMixed);
|
||||
}
|
||||
return CachedVerdict;
|
||||
}
|
||||
|
||||
const EVoxelTileClass Verdict = ClassifyTileUncached(
|
||||
OriginVoxels, NormalizedStep, NormalizedCellsPerAxis, OutStats);
|
||||
if (Verdict == EVoxelTileClass::AllSolid)
|
||||
@@ -5175,15 +4969,6 @@ EVoxelTileClass UVoxelGenerator::ClassifyTile(const FIntVector& OriginVoxels, in
|
||||
VoxelDensityProfile::ECounter::TileClassifyMixed);
|
||||
}
|
||||
|
||||
if (bCacheable && Verdict != EVoxelTileClass::Mixed)
|
||||
{
|
||||
StoreTileVerdict(
|
||||
OriginVoxels, NormalizedStep, NormalizedCellsPerAxis,
|
||||
ManagerWorldSeed, LayoutVersion, DiffVersion, ParamsFingerprint,
|
||||
PassageSupportFloorWrites, Verdict);
|
||||
VoxelDensityProfile::AddCounter(
|
||||
VoxelDensityProfile::ECounter::TileVerdictCacheStores);
|
||||
}
|
||||
return Verdict;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user