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
@@ -268,7 +268,6 @@ struct FExploreArguments
|
||||
bool bProfileDensityFull = false;
|
||||
bool bProfileLod = false;
|
||||
bool bOpBounds = false;
|
||||
bool bProfileTileVerdictCache = false;
|
||||
bool bFailureFocusRender = false;
|
||||
FString OutDirectory;
|
||||
|
||||
@@ -361,8 +360,6 @@ bool ParseArguments(const FString& Params, FExploreArguments& OutArguments, FStr
|
||||
OutArguments.bProfileDensity |= OutArguments.bProfileDensityFull;
|
||||
OutArguments.bProfileLod = FParse::Param(*Params, TEXT("profilelod"));
|
||||
OutArguments.bOpBounds = FParse::Param(*Params, TEXT("opbounds"));
|
||||
OutArguments.bProfileTileVerdictCache = FParse::Param(
|
||||
*Params, TEXT("profiletileverdictcache"));
|
||||
FParse::Value(*Params, TEXT("out="), OutText);
|
||||
FParse::Value(*Params, TEXT("renderwidth="), OutArguments.RenderWidth);
|
||||
FParse::Value(*Params, TEXT("renderheight="), OutArguments.RenderHeight);
|
||||
@@ -4352,8 +4349,6 @@ FString BuildExploreJson(
|
||||
Writer->WriteValue(TEXT("profile_density"), Arguments.bProfileDensity);
|
||||
Writer->WriteValue(TEXT("profile_density_full"), Arguments.bProfileDensityFull);
|
||||
Writer->WriteValue(TEXT("profile_lod"), Arguments.bProfileLod);
|
||||
Writer->WriteValue(TEXT("profile_tile_verdict_cache"),
|
||||
Arguments.bProfileTileVerdictCache);
|
||||
Writer->WriteValue(TEXT("op_bounds"), Arguments.bOpBounds);
|
||||
Writer->WriteValue(TEXT("budget_minutes"), static_cast<double>(Arguments.BudgetMinutes));
|
||||
Writer->WriteValue(TEXT("out_directory"), Arguments.OutDirectory);
|
||||
@@ -5410,66 +5405,6 @@ bool RunOpBounds(
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RunTileVerdictCacheProbe(
|
||||
const FExploreArguments& Arguments,
|
||||
FExploreWorld& World,
|
||||
FString& OutError)
|
||||
{
|
||||
if (!World.Generator)
|
||||
{
|
||||
OutError = TEXT("tile-verdict cache probe has no generator.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Deliberately use a region well above the synthetic layout. The first 32-cell proof is a
|
||||
// genuine enclosing-region certificate; the 8-cell requests below are aligned subregions of
|
||||
// that same lattice. No generated cave data is involved in this probe.
|
||||
const FIntVector RegionOrigin(-32, -32, World.TargetTopWorldZ + 1024);
|
||||
const EVoxelTileClass RegionVerdict = World.Generator->ClassifyTile(
|
||||
RegionOrigin, 1, 32);
|
||||
if (RegionVerdict != EVoxelTileClass::AllAir)
|
||||
{
|
||||
OutError = FString::Printf(
|
||||
TEXT("tile-verdict cache probe expected an all-air enclosing region, got %d."),
|
||||
static_cast<int32>(RegionVerdict));
|
||||
return false;
|
||||
}
|
||||
|
||||
auto ClassifyChildren = [&World, &RegionOrigin]()
|
||||
{
|
||||
for (int32 Z = 0; Z < 32; Z += 8)
|
||||
for (int32 Y = 0; Y < 32; Y += 8)
|
||||
for (int32 X = 0; X < 32; X += 8)
|
||||
{
|
||||
World.Generator->ClassifyTile(
|
||||
RegionOrigin + FIntVector(X, Y, Z), 1, 8);
|
||||
}
|
||||
};
|
||||
|
||||
ClassifyChildren();
|
||||
World.Generator->ClassifyTile(RegionOrigin, 1, 32);
|
||||
ClassifyChildren();
|
||||
|
||||
const VoxelDensityProfile::FSnapshot Snapshot = VoxelDensityProfile::Snapshot();
|
||||
const int32 CallsIndex = static_cast<int32>(
|
||||
VoxelDensityProfile::ECounter::TileClassifyCalls);
|
||||
const int32 HitsIndex = static_cast<int32>(
|
||||
VoxelDensityProfile::ECounter::TileVerdictCacheHits);
|
||||
const int32 RegionHitsIndex = static_cast<int32>(
|
||||
VoxelDensityProfile::ECounter::TileVerdictRegionHits);
|
||||
const int32 StoresIndex = static_cast<int32>(
|
||||
VoxelDensityProfile::ECounter::TileVerdictCacheStores);
|
||||
UE_LOG(LogTemp, Display,
|
||||
TEXT("[VoxelForgeTileVerdictCache] probe region=(%d,%d,%d) cells=32 verdict=AllAir "
|
||||
"calls=%llu hits=%llu region_hits=%llu stores=%llu"),
|
||||
RegionOrigin.X, RegionOrigin.Y, RegionOrigin.Z,
|
||||
static_cast<unsigned long long>(Snapshot.Counters[CallsIndex]),
|
||||
static_cast<unsigned long long>(Snapshot.Counters[HitsIndex]),
|
||||
static_cast<unsigned long long>(Snapshot.Counters[RegionHitsIndex]),
|
||||
static_cast<unsigned long long>(Snapshot.Counters[StoresIndex]));
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
UVoxelForgeExploreCommandlet::UVoxelForgeExploreCommandlet()
|
||||
@@ -5526,16 +5461,6 @@ int32 RunExploreCase(const FString& Params, FString* OutJson)
|
||||
}
|
||||
const double SetupSeconds = FPlatformTime::Seconds() - SetupStartSeconds;
|
||||
|
||||
if (Arguments.bProfileTileVerdictCache)
|
||||
{
|
||||
if (!RunTileVerdictCacheProbe(Arguments, World, Error))
|
||||
{
|
||||
UE_LOG(LogTemp, Error,
|
||||
TEXT("[VoxelForgeExplore] tile-verdict cache probe failed: %s"), *Error);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool bRequestedModeFailed = false;
|
||||
if (Arguments.bOpBounds)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user