wip(standalone): GPU step 24 -- warmup policy off the critical path; first launch = CPU
Luna: warmup policy (marker read, hashes, adapter query) now resolves on a
background thread; startup fflush(stdout) removed (a redirected flush measured
136 ms). Device-init -> generation-setup gap 0.056 ms on the miss route.
Deferred-batch replay runner reproduces 85-86% of the viewer's GPU time
(240 vs 279 ms); the old "10x" compared one LOD2 tile to a mixed LOD0-8 mean.
Remaining sequence-dependent spikes (11-29 ms on tiles that take ~0.1 ms alone)
are unexplained. Open: a marker-miss survival audit once stalled after
[CpuReadyFrameBeforeGpu].
My runs outside the sandbox (Step24.exe, marker removed first, interleaved, -Timeline):
CPU 1.350 / 1.281 / 1.266 s
GPU marker miss 1.336 s (all-CPU fallback, generation setup at 88 ms)
GPU cached 1.167 / 1.166 / 1.168 s (GPU timestamps 220 / 255 / 205 ms,
max dispatch 5.6 / 22.0 / 1.0 ms; 1,134-1,236 GPU tiles)
Steadier than step 23 (1.07-1.17) but not faster; <=1.0 s not reached.
Audits: hashes w1/w8, walk 5,642/5,642, near 960 / far 1,114 0 diffs vs CPU and
WARP, thin 353, survival 6.19 GB, ten captures 2+2 edge pixels as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
This commit is contained in:
1 parent
bb082f3ae9
commit
94d50edb47
9 files changed
+753
-47
No files matched your search
@@ -1556,6 +1556,12 @@ namespace
|
||||
bool bGpuFarWarmupOnly=false;
|
||||
std::string GpuWarmupEntryFilter;
|
||||
std::thread GpuShaderWarmupThread;
|
||||
std::thread GpuWarmupPolicyThread;
|
||||
std::atomic<bool> bGpuWarmupPolicyResolutionFinished{false};
|
||||
bool bGpuWarmupPolicyResolutionStarted=false;
|
||||
bool bGpuWarmupLaunchPolicyResolved=false;
|
||||
bool bGpuWarmupCacheMarkerMatches=false;
|
||||
double GpuWarmupPolicyResolutionMs=0.0;
|
||||
std::shared_ptr<FGpuFarPreparationBatch> GpuFarPreparationState;
|
||||
std::mutex GpuFarPreparedResultsMutex;
|
||||
std::deque<FPreparedGpuFarInputResult> GpuFarPreparedResults;
|
||||
@@ -1685,6 +1691,7 @@ namespace
|
||||
double BatchUploadBudgetMilliseconds=2.0;
|
||||
|
||||
~FApp(){
|
||||
if(GpuWarmupPolicyThread.joinable())GpuWarmupPolicyThread.join();
|
||||
if(GpuShaderWarmupThread.joinable())GpuShaderWarmupThread.join();
|
||||
StopGeneration(true);ReleaseMeshes();
|
||||
if(SolidRasterizer)SolidRasterizer->Release();if(WireRasterizer)WireRasterizer->Release();
|
||||
@@ -2061,10 +2068,13 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
return true;
|
||||
};
|
||||
|
||||
MixText("gpu-far-warmup-signature-v1");
|
||||
MixText("gpu-far-warmup-signature-v2");
|
||||
const std::filesystem::path ShaderImplementation=GpuFarShaderPath.parent_path()
|
||||
.parent_path()/"gpu_field_port"/"GpuFieldPort.cpp";
|
||||
if(!MixFile(GpuFarShaderPath,true)||!MixFile(ShaderImplementation,true))return false;
|
||||
const std::filesystem::path ViewerImplementation=GpuFarShaderPath.parent_path()
|
||||
.parent_path()/"gpu_field_port"/"GpuFarViewer.h";
|
||||
if(!MixFile(GpuFarShaderPath,true)||!MixFile(ShaderImplementation,true)
|
||||
||!MixFile(ViewerImplementation,true))return false;
|
||||
const std::filesystem::path PrecompiledDirectory=GpuFarShaderPath.parent_path()
|
||||
.parent_path()/"gpu_field_port"/"precompiled";
|
||||
for(const char* Entry:WarmupEntries)
|
||||
@@ -2083,49 +2093,105 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ResolveGpuWarmupLaunchPolicy()
|
||||
void StartGpuWarmupPolicyResolutionAsync()
|
||||
{
|
||||
if(!bGpuFarEnabled||!bGpuFarShaderPrewarm)return;
|
||||
const bool bKeyAvailable=BuildGpuWarmupCacheKey();
|
||||
bool bCacheMarkerMatches=false;
|
||||
if(bKeyAvailable&&!GpuWarmupStatePath.empty())
|
||||
{
|
||||
std::ifstream Marker(GpuWarmupStatePath,std::ios::binary);
|
||||
std::string SavedKey;
|
||||
if(Marker&&std::getline(Marker,SavedKey))
|
||||
bCacheMarkerMatches=SavedKey==GpuWarmupCacheKey;
|
||||
}
|
||||
if(!bGpuFarEnabled||!bGpuFarShaderPrewarm||bGpuWarmupPolicyResolutionStarted)return;
|
||||
bGpuWarmupPolicyResolutionStarted=true;
|
||||
bGpuWarmupPolicyResolutionFinished.store(false,std::memory_order_relaxed);
|
||||
bGpuWarmupLaunchPolicyResolved=false;
|
||||
bGpuWarmupCacheMarkerMatches=false;
|
||||
GpuWarmupPolicyResolutionMs=0.0;
|
||||
if(bGpuFarWarmupBeforeWorkers
|
||||
||GpuWarmupLaunchPolicy==EGpuWarmupLaunchPolicy::ForceDeferred)
|
||||
bGpuWarmupDeferredUntilFirstView=true;
|
||||
else if(GpuWarmupLaunchPolicy==EGpuWarmupLaunchPolicy::ForceEager)
|
||||
bGpuWarmupDeferredUntilFirstView=false;
|
||||
else
|
||||
bGpuWarmupDeferredUntilFirstView=true;
|
||||
|
||||
GpuWarmupPolicyThread=std::thread([this]
|
||||
{
|
||||
const auto ResolveStart=std::chrono::steady_clock::now();
|
||||
bool bCacheMarkerMatches=false;
|
||||
try
|
||||
{
|
||||
const bool bKeyAvailable=BuildGpuWarmupCacheKey();
|
||||
if(bKeyAvailable&&!GpuWarmupStatePath.empty())
|
||||
{
|
||||
std::ifstream Marker(GpuWarmupStatePath,std::ios::binary);
|
||||
std::string SavedKey;
|
||||
if(Marker&&std::getline(Marker,SavedKey))
|
||||
bCacheMarkerMatches=SavedKey==GpuWarmupCacheKey;
|
||||
}
|
||||
}
|
||||
catch(const std::exception& Error)
|
||||
{
|
||||
std::fprintf(stderr,"[GpuWarmupPolicyError] %s\n",Error.what());
|
||||
}
|
||||
bGpuWarmupCacheMarkerMatches=bCacheMarkerMatches;
|
||||
GpuWarmupPolicyResolutionMs=std::chrono::duration<double,std::milli>(
|
||||
std::chrono::steady_clock::now()-ResolveStart).count();
|
||||
bGpuWarmupPolicyResolutionFinished.store(true,std::memory_order_release);
|
||||
});
|
||||
std::printf("[ColdTimeline] event=gpu_warmup_policy_async_started at_ms=%.3f default_route=%s\n",
|
||||
std::chrono::duration<double,std::milli>(
|
||||
std::chrono::steady_clock::now()-ColdProcessStart).count(),
|
||||
bGpuWarmupDeferredUntilFirstView?"after_first_CPU_view":"startup_overlap");
|
||||
}
|
||||
|
||||
bool ResolveGpuWarmupLaunchPolicy(bool bWaitForResolution=false)
|
||||
{
|
||||
if(!bGpuFarEnabled||!bGpuFarShaderPrewarm)return true;
|
||||
if(!bGpuWarmupPolicyResolutionStarted)StartGpuWarmupPolicyResolutionAsync();
|
||||
if(bGpuWarmupLaunchPolicyResolved)return true;
|
||||
if(!bGpuWarmupPolicyResolutionFinished.load(std::memory_order_acquire))
|
||||
{
|
||||
if(!bWaitForResolution)return false;
|
||||
if(GpuWarmupPolicyThread.joinable())GpuWarmupPolicyThread.join();
|
||||
}
|
||||
else if(GpuWarmupPolicyThread.joinable())GpuWarmupPolicyThread.join();
|
||||
|
||||
if(!bGpuWarmupPolicyResolutionFinished.load(std::memory_order_acquire))return false;
|
||||
if(bGpuFarWarmupBeforeWorkers)
|
||||
{
|
||||
bGpuWarmupDeferredUntilFirstView=false;
|
||||
std::printf("[GpuWarmupLaunchDecision] mode=before_workers cache_marker=%s key_available=%s identity=%s\n",
|
||||
bCacheMarkerMatches?"match":"miss",bKeyAvailable?"yes":"no",
|
||||
bKeyAvailable?GpuWarmupCacheIdentity.c_str():"unavailable");
|
||||
return;
|
||||
std::printf("[GpuWarmupLaunchDecision] mode=before_workers cache_marker=%s key_available=%s identity=%s resolution_ms=%.3f\n",
|
||||
bGpuWarmupCacheMarkerMatches?"match":"miss",
|
||||
bGpuWarmupCacheKeyAvailable?"yes":"no",
|
||||
bGpuWarmupCacheKeyAvailable?GpuWarmupCacheIdentity.c_str():"unavailable",
|
||||
GpuWarmupPolicyResolutionMs);
|
||||
bGpuWarmupLaunchPolicyResolved=true;
|
||||
return true;
|
||||
}
|
||||
|
||||
const bool bDeferredRouteWasAlreadyStarted=bGpuWarmupDeferredStarted;
|
||||
if(GpuWarmupLaunchPolicy==EGpuWarmupLaunchPolicy::ForceDeferred)
|
||||
bGpuWarmupDeferredUntilFirstView=true;
|
||||
else if(GpuWarmupLaunchPolicy==EGpuWarmupLaunchPolicy::ForceEager)
|
||||
bGpuWarmupDeferredUntilFirstView=false;
|
||||
else
|
||||
bGpuWarmupDeferredUntilFirstView=!bCacheMarkerMatches;
|
||||
bGpuWarmupDeferredUntilFirstView=!bGpuWarmupCacheMarkerMatches
|
||||
||bDeferredRouteWasAlreadyStarted;
|
||||
|
||||
const char* Mode=GpuWarmupLaunchPolicy==EGpuWarmupLaunchPolicy::ForceDeferred
|
||||
?"forced_cold_start":(GpuWarmupLaunchPolicy==EGpuWarmupLaunchPolicy::ForceEager
|
||||
?"forced_cached_start":"auto");
|
||||
std::printf("[GpuWarmupLaunchDecision] mode=%s cache_marker=%s route=%s key_available=%s state_path=%s identity=%s\n",
|
||||
Mode,bCacheMarkerMatches?"match":"miss",
|
||||
std::printf("[GpuWarmupLaunchDecision] mode=%s cache_marker=%s route=%s key_available=%s state_path=%s identity=%s resolution_ms=%.3f\n",
|
||||
Mode,bGpuWarmupCacheMarkerMatches?"match":"miss",
|
||||
bGpuWarmupDeferredUntilFirstView?"after_first_CPU_view":"startup_overlap",
|
||||
bKeyAvailable?"yes":"no",GpuWarmupStatePath.string().c_str(),
|
||||
bKeyAvailable?GpuWarmupCacheIdentity.c_str():"unavailable");
|
||||
bGpuWarmupCacheKeyAvailable?"yes":"no",GpuWarmupStatePath.string().c_str(),
|
||||
bGpuWarmupCacheKeyAvailable?GpuWarmupCacheIdentity.c_str():"unavailable",
|
||||
GpuWarmupPolicyResolutionMs);
|
||||
bGpuWarmupLaunchPolicyResolved=true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void MarkGpuWarmupCacheReady()
|
||||
{
|
||||
if(!bGpuFarShaderPrewarm||bGpuFarWarmupResourcesOnly
|
||||
||!GpuWarmupEntryFilter.empty()||!bGpuWarmupCacheKeyAvailable
|
||||
||GpuWarmupStatePath.empty())return;
|
||||
||!GpuWarmupEntryFilter.empty()||GpuWarmupStatePath.empty())return;
|
||||
ResolveGpuWarmupLaunchPolicy(true);
|
||||
if(!bGpuWarmupCacheKeyAvailable)return;
|
||||
const std::filesystem::path TemporaryPath=GpuWarmupStatePath.wstring()
|
||||
+L"."+std::to_wstring(GetCurrentProcessId())+L".tmp";
|
||||
{
|
||||
@@ -2463,6 +2529,7 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
{std::fprintf(stderr,"World load failed: %s\n",Error.c_str());MessageBoxA(Window,Error.c_str(),"VoxelForge viewer",MB_ICONERROR);return;}
|
||||
std::printf("[ColdTimeline] stage=generation_setup configured_ms=%.3f\n",
|
||||
std::chrono::duration<double,std::milli>(std::chrono::steady_clock::now()-ColdProcessStart).count());
|
||||
ResolveGpuWarmupLaunchPolicy(false);
|
||||
const bool bPipelineCanStartNow=!bGpuWarmupDeferredUntilFirstView
|
||||
||bGpuWarmupDeferredStarted;
|
||||
if(bGpuFarEnabled&&bPipelineCanStartNow&&!EnsureGpuFarPipeline(Error))
|
||||
@@ -3410,6 +3477,7 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
void PumpGpuFarGeneration(double MaxPumpBudgetMilliseconds=8.0)
|
||||
{
|
||||
if(!bGpuFarEnabled||!ShapeWorld||!ShapeWorld->hasFarWorld()||!Device||!Context)return;
|
||||
ResolveGpuWarmupLaunchPolicy(false);
|
||||
if(bGpuWarmupDeferredUntilFirstView&&!bGpuWarmupDeferredStarted)
|
||||
{
|
||||
if(!bWholeViewPresented)return;
|
||||
@@ -3431,6 +3499,9 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
std::string PipelineError;
|
||||
if(!EnsureGpuFarPipeline(PipelineError))
|
||||
{bGpuFarEnabled=false;AddGpuFarCpuFallbackTiles(DesiredTiles);return;}
|
||||
if(bGpuFarShaderPrewarm&&!bGpuWarmupDeferredUntilFirstView
|
||||
&&!bGpuWarmupCompleted&&!GpuShaderWarmupThread.joinable())
|
||||
StartGpuShaderWarmupAsync();
|
||||
StartGpuFarPreparation();
|
||||
if(!CompleteGpuShaderWarmupAndRoute())return;
|
||||
StartGpuFarPreparation();
|
||||
@@ -3438,12 +3509,12 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
const bool bColdDrainBeforeWholeView=!bInitialClipmapReported&&!bGpuFarAuditEnabled
|
||||
&&!bDisableGpuColdStartDrain&&bGpuFarWarmupBeforeWorkers;
|
||||
constexpr std::size_t StartupFirstGpuBatchTarget=32;
|
||||
constexpr std::size_t StartupGpuBatchTarget=256;
|
||||
constexpr std::size_t StartupGpuBatchTarget=384;
|
||||
constexpr double StartupGpuPumpBudgetMilliseconds=16.0;
|
||||
const bool bWaitForStreamingGpuBatch=!bColdDrainBeforeWholeView
|
||||
&&!bGpuFarAuditEnabled&&!bInitialClipmapReported;
|
||||
const std::size_t GpuPumpTileLimit=bWaitForStreamingGpuBatch
|
||||
?(GpuFarSubmissionBatches==0?StartupFirstGpuBatchTarget:StartupGpuBatchTarget):32;
|
||||
const std::size_t GpuPumpTileLimit=bGpuFarAuditEnabled?StartupFirstGpuBatchTarget
|
||||
:(GpuFarSubmissionBatches==0?StartupFirstGpuBatchTarget:StartupGpuBatchTarget);
|
||||
const double GpuPumpBudgetMilliseconds=std::min(MaxPumpBudgetMilliseconds,
|
||||
bWaitForStreamingGpuBatch?StartupGpuPumpBudgetMilliseconds:4.0);
|
||||
if(bWaitForStreamingGpuBatch
|
||||
@@ -5277,7 +5348,20 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
if(!GApp)return DefWindowProc(H,Message,W,L);
|
||||
switch(Message)
|
||||
{
|
||||
case WM_SIZE:if(W!=SIZE_MINIMIZED)GApp->Resize(LOWORD(L),HIWORD(L));return 0;
|
||||
case WM_SIZE:
|
||||
if(W!=SIZE_MINIMIZED)
|
||||
{
|
||||
const UINT NewWidth=LOWORD(L),NewHeight=HIWORD(L);
|
||||
const bool bResizeNeeded=static_cast<int32>(NewWidth)!=GApp->Width
|
||||
||static_cast<int32>(NewHeight)!=GApp->Height;
|
||||
const auto ResizeStart=std::chrono::steady_clock::now();
|
||||
if(bResizeNeeded)GApp->Resize(NewWidth,NewHeight);
|
||||
std::printf("[ColdTimeline] event=viewer_window_size width=%u height=%u resized=%s duration_ms=%.3f\n",
|
||||
NewWidth,NewHeight,bResizeNeeded?"yes":"no",
|
||||
std::chrono::duration<double,std::milli>(
|
||||
std::chrono::steady_clock::now()-ResizeStart).count());
|
||||
}
|
||||
return 0;
|
||||
case WM_KEYDOWN:
|
||||
{
|
||||
const bool bWasDown=(L&(1ll<<30))!=0;if(W<256)GApp->Keys[W]=true;
|
||||
@@ -7379,17 +7463,30 @@ int main(int Argc,char** Argv)
|
||||
std::printf("[ColdTimeline] stage=viewer_device_init end_ms=%.3f duration_ms=%.3f\n",
|
||||
std::chrono::duration<double,std::milli>(std::chrono::steady_clock::now()-ColdProcessStart).count(),
|
||||
std::chrono::duration<double,std::milli>(std::chrono::steady_clock::now()-DeviceInitStart).count());
|
||||
App.ResolveGpuWarmupLaunchPolicy();
|
||||
App.StartGpuWarmupPolicyResolutionAsync();
|
||||
if(!App.bGpuFarWarmupOnly)
|
||||
{
|
||||
ShowWindow(App.Window,SW_SHOW);UpdateWindow(App.Window);
|
||||
const auto WindowShowStart=std::chrono::steady_clock::now();
|
||||
ShowWindow(App.Window,SW_SHOW);
|
||||
std::printf("[ColdTimeline] stage=viewer_window_show duration_ms=%.3f\n",
|
||||
std::chrono::duration<double,std::milli>(
|
||||
std::chrono::steady_clock::now()-WindowShowStart).count());
|
||||
const auto WindowUpdateStart=std::chrono::steady_clock::now();
|
||||
UpdateWindow(App.Window);
|
||||
std::printf("[ColdTimeline] stage=viewer_window_update duration_ms=%.3f\n",
|
||||
std::chrono::duration<double,std::milli>(
|
||||
std::chrono::steady_clock::now()-WindowUpdateStart).count());
|
||||
const auto StartupBannerStart=std::chrono::steady_clock::now();
|
||||
std::printf("Controls: hold right mouse to look; WASD move; Space/Ctrl (E/Q) up/down; Shift faster; wheel changes speed; F wireframe; G toggles legacy/detailed round walls; H toggles CPU/GPU far tiles; 1-9 toggle LOD; 0 toggle all levels; N/P change seed; T swaps base/round tunnels; V swaps owner density/shape intervals; Esc quit.\n");
|
||||
std::printf("Owner data: %s; starting at first-strate open-space sample (%.2f, %.2f, %.2f) m.\n",
|
||||
App.DataPath.c_str(),App.Position.X,App.Position.Y,App.Position.Z);
|
||||
std::printf("[ColdTimeline] stage=viewer_startup_banner duration_ms=%.3f\n",
|
||||
std::chrono::duration<double,std::milli>(
|
||||
std::chrono::steady_clock::now()-StartupBannerStart).count());
|
||||
}
|
||||
std::fflush(stdout);
|
||||
if(App.bGpuFarEnabled&&(App.bGpuFarWarmupOnly||App.bGpuFarWarmupBeforeWorkers))
|
||||
{
|
||||
App.ResolveGpuWarmupLaunchPolicy(true);
|
||||
std::string GpuInitError;
|
||||
if(!App.EnsureGpuFarPipeline(GpuInitError))return 3;
|
||||
}
|
||||
@@ -7433,6 +7530,9 @@ int main(int Argc,char** Argv)
|
||||
App.bGpuWarmupCompleted=true;
|
||||
std::printf("[GpuShaderWarmupBeforeWorkers] completed_before_generation_workers=true\n");
|
||||
}
|
||||
std::printf("[ColdTimeline] event=generation_setup_call at_ms=%.3f\n",
|
||||
std::chrono::duration<double,std::milli>(
|
||||
std::chrono::steady_clock::now()-ColdProcessStart).count());
|
||||
App.StartGeneration();
|
||||
MSG Message{};
|
||||
while(Message.message!=WM_QUIT)
|
||||
|
||||
Reference in new issue
Block a user