wip(standalone): GPU step 11 -- per-shader cold cost measured; far EmitCS split, still CPU wins
Cold first-use per shader (queue ms): EvaluateFarField 1757, EmitNear 2429, FarConnectorRings 784, FarSkirts 507+975; the far EmitCS dropped 2327 -> 3.2 by splitting out the near midpoint fallback into EmitNearCS. Warm-up under 0xFF00 ~2.0 s (worker count and thread priority do not change it; 0xFFFF run: 1.71 s). Whole view median CPU 1.428 s vs hybrid 3.154 s. Audits unchanged. AMD DxCache was last written 2026-10-06 23:27 -- shaders may no longer be cached across launches (unverified). 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
10580650cb
commit
b6ac950073
19 files changed
+908
-24
No files matched your search
@@ -120,7 +120,7 @@ if ($Target -eq 'All') {
|
||||
Sort-Object -Property FullName -Descending | Select-Object -First 1
|
||||
if ($FxC) {
|
||||
[IO.Directory]::CreateDirectory($PrecompiledShaderDir) | Out-Null
|
||||
foreach ($Entry in @('EvaluateFarFieldCS','ClassifyCS','ClassifyFarCS','ScanGroupsCS','EmitCS','NoiseProbeCS','BuildFarConnectorRingsCS','EmitFarConnectorPanelsCS','ClassifyFarSkirtsCS','ScanFarSkirtsCS','EmitFarSkirtsCS')) {
|
||||
foreach ($Entry in @('EvaluateFarFieldCS','ClassifyCS','ClassifyFarCS','ScanGroupsCS','EmitCS','EmitNearCS','NoiseProbeCS','BuildFarConnectorRingsCS','EmitFarConnectorPanelsCS','ClassifyFarSkirtsCS','ScanFarSkirtsCS','EmitFarSkirtsCS')) {
|
||||
$ShaderBinary = Join-Path $PrecompiledShaderDir ($Entry+'.cso')
|
||||
$CommandLine = '"{0}" /nologo /T cs_5_0 /E {1} /O3 /Gis /Ges /Fo "{2}" "{3}"' -f $FxC.FullName,$Entry,$ShaderBinary,$ShaderSource
|
||||
Invoke-FieldViewerBuildCommand $CommandLine "precompile HLSL entry $Entry"
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parent
|
||||
VIEWS = (
|
||||
"chamber",
|
||||
"tunnel",
|
||||
"passage",
|
||||
"far",
|
||||
"passage_floor_closeup",
|
||||
"tunnel_bend",
|
||||
"remote_yaw0",
|
||||
"remote_yaw90",
|
||||
"remote_yaw180",
|
||||
"remote_yaw270",
|
||||
)
|
||||
|
||||
rows = []
|
||||
for view in VIEWS:
|
||||
cpu_path = ROOT / f"step10final_cpu_{view}.png"
|
||||
gpu_path = ROOT / f"step10final_gpu_{view}.png"
|
||||
cpu = np.asarray(Image.open(cpu_path).convert("RGB"), dtype=np.int16)
|
||||
gpu = np.asarray(Image.open(gpu_path).convert("RGB"), dtype=np.int16)
|
||||
if cpu.shape != gpu.shape:
|
||||
raise RuntimeError(f"dimension mismatch for {view}: {cpu.shape} vs {gpu.shape}")
|
||||
diff = np.abs(cpu - gpu)
|
||||
pixel_max = diff.max(axis=2)
|
||||
rows.append(
|
||||
(
|
||||
view,
|
||||
f"{cpu.shape[1]}x{cpu.shape[0]}",
|
||||
float(diff.mean()),
|
||||
float(np.sqrt(np.square(diff, dtype=np.float64).mean())),
|
||||
float(np.count_nonzero(pixel_max) * 100.0 / pixel_max.size),
|
||||
float(np.count_nonzero(pixel_max > 32) * 100.0 / pixel_max.size),
|
||||
int(pixel_max.max()),
|
||||
)
|
||||
)
|
||||
|
||||
lines = [
|
||||
"# Step 10 full-residency capture comparison",
|
||||
"",
|
||||
"All ten CPU/GPU pairs were captured after `[InitialClipmapReady]`. Images were compared as RGB arrays; no full-size capture was opened in an image viewer.",
|
||||
"",
|
||||
"| View | Size | RGB MAE | RGB RMSE | Changed pixels | Pixels max channel >32 | Max channel |",
|
||||
"|---|---:|---:|---:|---:|---:|---:|",
|
||||
]
|
||||
for row in rows:
|
||||
view, size, mae, rmse, changed, over32, maximum = row
|
||||
lines.append(
|
||||
f"| {view} | {size} | {mae:.4f} | {rmse:.4f} | {changed:.4f}% | {over32:.4f}% | {maximum} |"
|
||||
)
|
||||
|
||||
report = ROOT / "step10_capture_comparison.md"
|
||||
report.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
||||
print(report.read_text(encoding="utf-8"), end="")
|
||||
@@ -0,0 +1,59 @@
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parent
|
||||
VIEWS = (
|
||||
"chamber",
|
||||
"tunnel",
|
||||
"passage",
|
||||
"far",
|
||||
"passage_floor_closeup",
|
||||
"tunnel_bend",
|
||||
"remote_yaw0",
|
||||
"remote_yaw90",
|
||||
"remote_yaw180",
|
||||
"remote_yaw270",
|
||||
)
|
||||
|
||||
rows = []
|
||||
for view in VIEWS:
|
||||
cpu_path = ROOT / f"step11_cpu_{view}.png"
|
||||
gpu_path = ROOT / f"step11_gpu_{view}.png"
|
||||
cpu = np.asarray(Image.open(cpu_path).convert("RGB"), dtype=np.int16)
|
||||
gpu = np.asarray(Image.open(gpu_path).convert("RGB"), dtype=np.int16)
|
||||
if cpu.shape != gpu.shape:
|
||||
raise RuntimeError(f"dimension mismatch for {view}: {cpu.shape} vs {gpu.shape}")
|
||||
diff = np.abs(cpu - gpu)
|
||||
pixel_max = diff.max(axis=2)
|
||||
rows.append(
|
||||
(
|
||||
view,
|
||||
f"{cpu.shape[1]}x{cpu.shape[0]}",
|
||||
float(diff.mean()),
|
||||
float(np.sqrt(np.square(diff, dtype=np.float64).mean())),
|
||||
float(np.count_nonzero(pixel_max) * 100.0 / pixel_max.size),
|
||||
float(np.count_nonzero(pixel_max > 32) * 100.0 / pixel_max.size),
|
||||
int(pixel_max.max()),
|
||||
)
|
||||
)
|
||||
|
||||
lines = [
|
||||
"# Step 11 full-residency capture comparison",
|
||||
"",
|
||||
"All ten CPU/GPU pairs were captured after `[InitialClipmapReady]`. The files were compared numerically as RGB arrays and were not opened in an image viewer.",
|
||||
"",
|
||||
"| View | Size | RGB MAE | RGB RMSE | Changed pixels | Pixels max channel >32 | Max channel |",
|
||||
"|---|---:|---:|---:|---:|---:|---:|",
|
||||
]
|
||||
for row in rows:
|
||||
view, size, mae, rmse, changed, over32, maximum = row
|
||||
lines.append(
|
||||
f"| {view} | {size} | {mae:.4f} | {rmse:.4f} | {changed:.4f}% | {over32:.4f}% | {maximum} |"
|
||||
)
|
||||
|
||||
report = ROOT / "step11_capture_comparison.md"
|
||||
report.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
||||
print(report.read_text(encoding="utf-8"), end="")
|
||||
@@ -25,7 +25,8 @@ namespace VoxelForgeGpuFarViewer
|
||||
bool InitializeFarPipeline(ID3D11Device* device,ID3D11DeviceContext* context,
|
||||
const std::filesystem::path& shaderPath,std::string& error);
|
||||
bool QueueFarShaderWarmup(ID3D11Device* device,ID3D11DeviceContext* context,
|
||||
const std::filesystem::path& shaderPath,bool dispatchShaders,std::string& error);
|
||||
const std::filesystem::path& shaderPath,bool dispatchShaders,
|
||||
const std::string& entryFilter,std::string& error);
|
||||
bool CompleteFarShaderWarmup(ID3D11Device* device,ID3D11DeviceContext* context,
|
||||
const std::filesystem::path& shaderPath,std::string& error);
|
||||
bool ReserveFarOutputPool(ID3D11Device* device,ID3D11DeviceContext* context,
|
||||
|
||||
@@ -551,7 +551,7 @@ namespace
|
||||
ComPtr<ID3D11Device> device;
|
||||
ComPtr<ID3D11DeviceContext> context;
|
||||
ComPtr<ID3D11DeviceContext> immediateContext,deferredContext;
|
||||
ComPtr<ID3D11ComputeShader> fieldEval, classify, fieldClassify, scan, emit, noiseProbe;
|
||||
ComPtr<ID3D11ComputeShader> fieldEval, classify, fieldClassify, scan, emit, emitNear, noiseProbe;
|
||||
ComPtr<ID3D11ComputeShader> connectorRings,connectorPanels;
|
||||
ComPtr<ID3D11ComputeShader> classifyFarSkirts,scanFarSkirts,emitFarSkirts;
|
||||
ComPtr<IDXGIAdapter3> memoryAdapter;
|
||||
@@ -599,6 +599,7 @@ namespace
|
||||
Create("ClassifyFarCS",fieldClassify);
|
||||
Create("ScanGroupsCS",scan);
|
||||
Create("EmitCS",emit);
|
||||
Create("EmitNearCS",emitNear);
|
||||
Create("NoiseProbeCS",noiseProbe);
|
||||
Create("BuildFarConnectorRingsCS",connectorRings);
|
||||
Create("EmitFarConnectorPanelsCS",connectorPanels);
|
||||
@@ -609,13 +610,21 @@ namespace
|
||||
std::chrono::duration<double,std::milli>(std::chrono::steady_clock::now()-PipelineStart).count());
|
||||
}
|
||||
|
||||
void QueueTinyShaderWarmup(bool dispatchShaders)
|
||||
void QueueTinyShaderWarmup(bool dispatchShaders,const std::string& entryFilter)
|
||||
{
|
||||
const auto WarmupStart=Clock::now();
|
||||
static constexpr std::array<std::string_view,12> entries={
|
||||
"EvaluateFarFieldCS","ClassifyCS","ClassifyFarCS","ScanGroupsCS","EmitCS",
|
||||
"EmitNearCS","BuildFarConnectorRingsCS","EmitFarConnectorPanelsCS",
|
||||
"ClassifyFarSkirtsCS","ScanFarSkirtsCS","EmitFarSkirtsCS","NoiseProbeCS"};
|
||||
if(!entryFilter.empty()&&std::find(entries.begin(),entries.end(),entryFilter)==entries.end())
|
||||
throw std::runtime_error("unknown shader warmup entry: "+entryFilter);
|
||||
constexpr std::uint32_t sampleCount=27,cellCount=1,groupCount=1;
|
||||
TileConstants tile{};
|
||||
tile.cells=1;tile.sampleDim=3;tile.cellCount=cellCount;tile.groupCount=groupCount;
|
||||
tile.stepVoxels=1;tile.voxelSizeCm=25.0f;tile.outputVertexCapacity=3;
|
||||
tile.stepVoxels=entryFilter=="EmitNearCS"?1:2;
|
||||
tile.nearFieldMode=entryFilter=="EmitNearCS"?1u:0u;
|
||||
tile.voxelSizeCm=25.0f;tile.outputVertexCapacity=3;
|
||||
FarFieldConstants field{};
|
||||
field.strataLo=-100.0f;field.strataHi=100.0f;field.strataBlend=12.0f;
|
||||
field.sampleCount=sampleCount;field.spatialBinMask=0;field.spatialBinSize=64;
|
||||
@@ -645,16 +654,19 @@ namespace
|
||||
auto detailLayers=Structured<FarFieldDetailLayerGpu>(nullptr,1,D3D11_BIND_SHADER_RESOURCE);
|
||||
std::array<std::uint32_t,sampleCount> packedProxy{};packedProxy.fill(InvalidIndex);
|
||||
auto proxies=Structured(packedProxy.data(),packedProxy.size(),D3D11_BIND_SHADER_RESOURCE);
|
||||
auto density=Structured<float>(nullptr,sampleCount,D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_UNORDERED_ACCESS);
|
||||
auto nearNormal=Structured<float>(nullptr,sampleCount,D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_UNORDERED_ACCESS);
|
||||
std::array<float,sampleCount> zeroDensity{};
|
||||
auto density=Structured(zeroDensity.data(),sampleCount,D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_UNORDERED_ACCESS);
|
||||
auto nearNormal=Structured(zeroDensity.data(),sampleCount,D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_UNORDERED_ACCESS);
|
||||
auto evalCounters=Structured<std::uint32_t>(nullptr,sampleCount,D3D11_BIND_UNORDERED_ACCESS);
|
||||
auto signs=Structured(&zeroWord,1,D3D11_BIND_SHADER_RESOURCE);
|
||||
std::array<std::int32_t,256*16> triTable{};triTable.fill(-1);
|
||||
auto triangles=Structured(triTable.data(),triTable.size(),D3D11_BIND_SHADER_RESOURCE);
|
||||
auto cases=Structured<std::uint32_t>(nullptr,cellCount,D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_UNORDERED_ACCESS);
|
||||
auto localOffsets=Structured<std::uint32_t>(nullptr,cellCount,D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_UNORDERED_ACCESS);
|
||||
auto groupCounts=Structured<std::uint32_t>(nullptr,groupCount,D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_UNORDERED_ACCESS);
|
||||
auto groupOffsets=Structured<std::uint32_t>(nullptr,groupCount,D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_UNORDERED_ACCESS);
|
||||
std::array<std::uint32_t,cellCount> zeroCell{};
|
||||
std::array<std::uint32_t,groupCount> zeroGroup{};
|
||||
auto cases=Structured(zeroCell.data(),cellCount,D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_UNORDERED_ACCESS);
|
||||
auto localOffsets=Structured(zeroCell.data(),cellCount,D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_UNORDERED_ACCESS);
|
||||
auto groupCounts=Structured(zeroGroup.data(),groupCount,D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_UNORDERED_ACCESS);
|
||||
auto groupOffsets=Structured(zeroGroup.data(),groupCount,D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_UNORDERED_ACCESS);
|
||||
auto midpointIds=Structured(&invalidWord,1,D3D11_BIND_SHADER_RESOURCE);
|
||||
MidpointRecord emptyMidpoint{};
|
||||
auto midpointRecords=Structured(&emptyMidpoint,1,D3D11_BIND_SHADER_RESOURCE);
|
||||
@@ -699,6 +711,16 @@ namespace
|
||||
auto indices=RawMeshBuffer(3u*sizeof(std::uint32_t),D3D11_BIND_UNORDERED_ACCESS);
|
||||
auto panelVertices=RawMeshBuffer(64u*sizeof(GpuVertex),D3D11_BIND_UNORDERED_ACCESS);
|
||||
auto panelIndices=RawMeshBuffer(64u*sizeof(std::uint32_t),D3D11_BIND_UNORDERED_ACCESS);
|
||||
std::array<std::uint32_t,11> zeroArgs{};
|
||||
std::array<GpuVertex,3> zeroVertices{};
|
||||
std::array<GpuVertex,64> zeroPanelVertices{};
|
||||
std::array<std::uint32_t,3> zeroIndices{};
|
||||
std::array<std::uint32_t,64> zeroPanelIndices{};
|
||||
context->UpdateSubresource(args.Get(),0,nullptr,zeroArgs.data(),0,0);
|
||||
context->UpdateSubresource(vertices.Get(),0,nullptr,zeroVertices.data(),0,0);
|
||||
context->UpdateSubresource(indices.Get(),0,nullptr,zeroIndices.data(),0,0);
|
||||
context->UpdateSubresource(panelVertices.Get(),0,nullptr,zeroPanelVertices.data(),0,0);
|
||||
context->UpdateSubresource(panelIndices.Get(),0,nullptr,zeroPanelIndices.data(),0,0);
|
||||
auto argsUav=RawUav(args.Get(),11);
|
||||
auto vertexUav=RawUav(vertices.Get(),static_cast<UINT>(3u*sizeof(GpuVertex)/4u));
|
||||
auto vertexSrv=RawSrv(vertices.Get(),static_cast<UINT>(3u*sizeof(GpuVertex)/4u));
|
||||
@@ -721,6 +743,7 @@ namespace
|
||||
|
||||
ID3D11Buffer* constants[3]={tileCb.Get(),fieldCb.Get(),connectorCb.Get()};
|
||||
context->CSSetConstantBuffers(0,3,constants);
|
||||
std::uint32_t dispatchCount=0;
|
||||
auto ClearBindings=[&](UINT srvCount=20)
|
||||
{
|
||||
ID3D11ShaderResourceView* nullSrvs[20]{};
|
||||
@@ -730,8 +753,12 @@ namespace
|
||||
};
|
||||
auto Dispatch=[&](ID3D11ComputeShader* shader,const char* entry)
|
||||
{
|
||||
if(!entryFilter.empty()&&entryFilter!=entry)return;
|
||||
if(entryFilter.empty()&&(std::string_view(entry)=="ClassifyCS"
|
||||
||std::string_view(entry)=="EmitNearCS"||std::string_view(entry)=="NoiseProbeCS"))return;
|
||||
const auto start=Clock::now();
|
||||
context->CSSetShader(shader,nullptr,0);context->Dispatch(1,1,1);
|
||||
++dispatchCount;
|
||||
std::printf("[GpuShaderWarmup] entry=%s dispatch_call_ms=%.3f groups=1\n",entry,
|
||||
std::chrono::duration<double,std::milli>(Clock::now()-start).count());
|
||||
};
|
||||
@@ -774,6 +801,7 @@ namespace
|
||||
ID3D11UnorderedAccessView* emitUavs[8]{};emitUavs[5]=vertexUav.Get();emitUavs[6]=indexUav.Get();
|
||||
context->CSSetUnorderedAccessViews(0,8,emitUavs,nullptr);
|
||||
Dispatch(emit.Get(),"EmitCS");ClearBindings();
|
||||
Dispatch(emitNear.Get(),"EmitNearCS");ClearBindings();
|
||||
|
||||
ID3D11ShaderResourceView* ringSrvs[5]={connectorPanelSrv.Get(),nullptr,shapeSrv.Get(),binSrv.Get(),shapeIdSrv.Get()};
|
||||
context->CSSetShaderResources(8,5,ringSrvs);
|
||||
@@ -819,8 +847,11 @@ namespace
|
||||
D3D11_QUERY_DESC eventDesc{D3D11_QUERY_EVENT,0};
|
||||
Check(device->CreateQuery(&eventDesc,&shaderWarmupCompletion),"CreateQuery(shader warmup completion)");
|
||||
context->End(shaderWarmupCompletion.Get());context->Flush();
|
||||
std::printf("[GpuShaderWarmup] dispatched=11 tiny_samples=%u tiny_cells=%u queue_ms=%.3f completion=pending\n",
|
||||
sampleCount,cellCount,std::chrono::duration<double,std::milli>(Clock::now()-WarmupStart).count());
|
||||
if(dispatchShaders&&dispatchCount==0)
|
||||
throw std::runtime_error("shader warmup selected no dispatches");
|
||||
std::printf("[GpuShaderWarmup] dispatched=%u selected=%s tiny_samples=%u tiny_cells=%u queue_ms=%.3f completion=pending\n",
|
||||
dispatchCount,entryFilter.empty()?"production":entryFilter.c_str(),sampleCount,cellCount,
|
||||
std::chrono::duration<double,std::milli>(Clock::now()-WarmupStart).count());
|
||||
}
|
||||
|
||||
bool CompleteTinyShaderWarmup()
|
||||
@@ -1628,7 +1659,7 @@ namespace
|
||||
context->CSSetUnorderedAccessViews(0, 8, nullUavs, nullptr);
|
||||
|
||||
beginKernel(3);
|
||||
context->CSSetShader(emit.Get(), nullptr, 0);
|
||||
context->CSSetShader((farField&&tile.step>1?emit.Get():emitNear.Get()), nullptr, 0);
|
||||
ID3D11ShaderResourceView* emitSrvs[19]{};
|
||||
emitSrvs[1] = triSrv.Get(); emitSrvs[2] = densitySrv.Get(); emitSrvs[3] = caseSrv.Get();
|
||||
emitSrvs[4] = localOffsetSrv.Get(); emitSrvs[5] = groupOffsetSrv.Get();
|
||||
@@ -3092,11 +3123,12 @@ namespace VoxelForgeGpuFarViewer
|
||||
}
|
||||
|
||||
bool QueueFarShaderWarmup(ID3D11Device* device,ID3D11DeviceContext* context,
|
||||
const std::filesystem::path& shaderPath,bool dispatchShaders,std::string& error)
|
||||
const std::filesystem::path& shaderPath,bool dispatchShaders,
|
||||
const std::string& entryFilter,std::string& error)
|
||||
{
|
||||
try
|
||||
{
|
||||
GetFarViewerRunner(device,context,shaderPath).QueueTinyShaderWarmup(dispatchShaders);
|
||||
GetFarViewerRunner(device,context,shaderPath).QueueTinyShaderWarmup(dispatchShaders,entryFilter);
|
||||
return true;
|
||||
}
|
||||
catch(const std::exception& e){error=e.what();return false;}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
[CmdletBinding()]
|
||||
param([string]$ExecutableName='VoxelForgeGpuFieldStep11Warmup.exe')
|
||||
|
||||
$ErrorActionPreference='Stop'
|
||||
$HostProcess=Get-Process -Id $PID
|
||||
$HostProcess.PriorityClass='BelowNormal'
|
||||
$HostProcess.ProcessorAffinity=[IntPtr]0xFF00
|
||||
$StandaloneRoot=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\..\..'))
|
||||
$ExecutablePath=Join-Path $StandaloneRoot ('bin\'+$ExecutableName)
|
||||
if([IO.Path]::GetFileName($ExecutableName)-ne$ExecutableName-or[IO.Path]::GetExtension($ExecutableName)-ne'.exe')
|
||||
{throw 'ExecutableName must be an executable filename.'}
|
||||
if(-not(Test-Path -LiteralPath $ExecutablePath -PathType Leaf)){throw "Viewer not found: $ExecutablePath"}
|
||||
|
||||
$Name='step11_allcpu_affinity_gpu'
|
||||
$Arguments=@('--clip-radius=3','--workers=8','--quit-after-clipmap','--gpu-far',
|
||||
'--gpu-far-no-present-hold','--affinity-all-cpu')
|
||||
$StdoutPath=Join-Path $PSScriptRoot ($Name+'.stdout.log')
|
||||
$StderrPath=Join-Path $PSScriptRoot ($Name+'.stderr.log')
|
||||
$EightGB=8L*1024L*1024L*1024L
|
||||
Write-Output "STEP11_ALLCPU_RUN name=$Name priority=BelowNormal affinity=0xFFFF workers=8 command=`"$ExecutablePath`" $($Arguments -join ' ')"
|
||||
for($Attempt=0;$Attempt-lt2;$Attempt++)
|
||||
{
|
||||
if($Attempt-gt0)
|
||||
{Write-Output '0xC0000142 encountered; waiting 60 seconds before the single permitted retry.';Start-Sleep -Seconds 60}
|
||||
Remove-Item -LiteralPath $StdoutPath,$StderrPath -Force -ErrorAction SilentlyContinue
|
||||
$HostRunClock=[Diagnostics.Stopwatch]::StartNew()
|
||||
$Child=Start-Process -FilePath $ExecutablePath -ArgumentList $Arguments -WorkingDirectory $StandaloneRoot `
|
||||
-WindowStyle Hidden -PassThru -RedirectStandardOutput $StdoutPath -RedirectStandardError $StderrPath
|
||||
$PeakPrivate=0L;$OverMemoryLimit=$false
|
||||
try
|
||||
{
|
||||
while(-not$Child.HasExited)
|
||||
{
|
||||
$Child.Refresh();if($Child.HasExited){break}
|
||||
$Child.PriorityClass='BelowNormal'
|
||||
$PeakPrivate=[Math]::Max($PeakPrivate,$Child.PrivateMemorySize64)
|
||||
if($Child.PrivateMemorySize64-ge$EightGB)
|
||||
{$OverMemoryLimit=$true;$Child.Kill();$Child.WaitForExit();break}
|
||||
Start-Sleep -Milliseconds 50
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if(-not$Child.HasExited){$Child.Kill();$Child.WaitForExit()}
|
||||
}
|
||||
$Child.WaitForExit();$Child.Refresh();$HostRunClock.Stop();$HostRunMs=$HostRunClock.Elapsed.TotalMilliseconds
|
||||
$ViewerExitCode=$Child.ExitCode
|
||||
if($ViewerExitCode-eq-1073741502-and$Attempt-eq0)
|
||||
{continue}
|
||||
if($ViewerExitCode-eq-1073741502){throw '0xC0000142 repeated after its single retry; stopping.'}
|
||||
if($OverMemoryLimit){throw "Viewer stopped at the 8 GiB private-memory ceiling: $Name"}
|
||||
$LogText=Get-Content -LiteralPath $StdoutPath -Raw
|
||||
if(-not$LogText.Contains('[InitialClipmapReady]'))
|
||||
{throw "Full clipmap was not ready in $Name; exit=$ViewerExitCode"}
|
||||
$Ready=[regex]::Match($LogText,'(?m)^\[InitialClipmapReady\] ([0-9.]+) s')
|
||||
$Presented=[regex]::Match($LogText,'(?m)^\[WholeViewPresented\] at_ms=([0-9.]+) present_ms=([0-9.]+).*hr=0x([0-9A-Fa-f]{8})')
|
||||
$Warmup=[regex]::Match($LogText,'(?m)^\[GpuShaderWarmup\] dispatched=[0-9]+ .*queue_ms=([0-9.]+)')
|
||||
$Wait=[regex]::Match($LogText,'(?m)^\[GpuShaderWarmup\] completion_wait_ms=([0-9.]+)')
|
||||
if(-not$Presented.Success){throw "Whole-view present marker missing in $Name"}
|
||||
$WarmupMs=if($Warmup.Success){[double]$Warmup.Groups[1].Value+$(if($Wait.Success){[double]$Wait.Groups[1].Value}else{0.0})}else{0.0}
|
||||
$Memory=[regex]::Match($LogText,'(?m)^\[GpuFarMemory\] dxgi_local_sampled_peak_mb=([0-9.]+)')
|
||||
$CombinedGB=$PeakPrivate/1GB
|
||||
if($Memory.Success){$CombinedGB=($PeakPrivate+[double]$Memory.Groups[1].Value*1MB)/1GB}
|
||||
if($CombinedGB-ge8.0){throw "Viewer exceeded conservative private + DXGI-local 8 GiB ceiling: $Name ($CombinedGB GiB)"}
|
||||
$Controls=[regex]::Match($LogText,'(?m)^\[ProcessControls\].*')
|
||||
Write-Output "STEP11_ALLCPU_RESULT name=$Name warmup_ms=$([math]::Round($WarmupMs,3)) ready_ms=$([math]::Round([double]$Ready.Groups[1].Value*1000,3)) viewer_whole_view_present_return_ms=$($Presented.Groups[1].Value) present_ms=$($Presented.Groups[2].Value) present_hr=0x$($Presented.Groups[3].Value.ToUpperInvariant()) host_process_exit_ms=$([math]::Round($HostRunMs,3)) peak_private_gb=$([math]::Round($PeakPrivate/1GB,2)) conservative_private_plus_dxgi_gb=$([math]::Round($CombinedGB,2)) controls=`"$($Controls.Value)`" exit=$ViewerExitCode"
|
||||
if($ViewerExitCode-ne0){throw "Viewer returned $ViewerExitCode`: $Name"}
|
||||
break
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
[CmdletBinding()]
|
||||
param([string]$ExecutableName='VoxelForgeGpuFieldStep11Warmup.exe')
|
||||
|
||||
$ErrorActionPreference='Stop'
|
||||
$HostProcess=Get-Process -Id $PID
|
||||
$HostProcess.PriorityClass='BelowNormal'
|
||||
$HostProcess.ProcessorAffinity=[IntPtr]0xFF00
|
||||
$StandaloneRoot=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\..\..'))
|
||||
$ExecutablePath=Join-Path $StandaloneRoot ('bin\'+$ExecutableName)
|
||||
if([IO.Path]::GetFileName($ExecutableName)-ne$ExecutableName-or[IO.Path]::GetExtension($ExecutableName)-ne'.exe')
|
||||
{throw 'ExecutableName must be an executable filename.'}
|
||||
if(-not(Test-Path -LiteralPath $ExecutablePath -PathType Leaf)){throw "Viewer not found: $ExecutablePath"}
|
||||
$Views=@(
|
||||
@{Name='chamber';Camera='-11.75,-123.25,-19.85,0,0'},
|
||||
@{Name='tunnel';Camera='-11.75,-123.25,-19.85,90,0'},
|
||||
@{Name='passage';Camera='-39.19,6.27,-28.51,63,0'},
|
||||
@{Name='far';Camera='-11.61244,-118.2212,-19.8452,0,0'},
|
||||
@{Name='passage_floor_closeup';Camera='-39.19,6.27,-25.51,63,-25'},
|
||||
@{Name='tunnel_bend';Camera='-198.97,-99.57,-45.58,33.59,23.17'},
|
||||
@{Name='remote_yaw0';Camera='500,0,0,0,0'},
|
||||
@{Name='remote_yaw90';Camera='500,0,0,90,0'},
|
||||
@{Name='remote_yaw180';Camera='500,0,0,180,0'},
|
||||
@{Name='remote_yaw270';Camera='500,0,0,270,0'}
|
||||
)
|
||||
$EightGB=8L*1024L*1024L*1024L
|
||||
foreach($View in $Views)
|
||||
{
|
||||
foreach($Mode in @('cpu','gpu'))
|
||||
{
|
||||
$Stem="step11_${Mode}_$($View.Name)"
|
||||
$CaptureName="$Stem.png"
|
||||
$Arguments=@('--clip-radius=3','--workers=8','--quit-after-clipmap','--capture-after-clipmap',
|
||||
"--camera=$($View.Camera)","--$Mode-far",
|
||||
"--capture=Research/OwnerShapeWorld/gpu_field_port/$CaptureName")
|
||||
$StdoutPath=Join-Path $PSScriptRoot ($Stem+'.stdout.log')
|
||||
$StderrPath=Join-Path $PSScriptRoot ($Stem+'.stderr.log')
|
||||
$CapturePath=Join-Path $PSScriptRoot $CaptureName
|
||||
Write-Output "STEP11_CAPTURE mode=$Mode view=$($View.Name) affinity=0xFF00 command=`"$ExecutablePath`" $($Arguments -join ' ')"
|
||||
for($Attempt=0;$Attempt-lt2;$Attempt++)
|
||||
{
|
||||
if($Attempt-gt0)
|
||||
{Write-Output '0xC0000142 encountered; waiting 60 seconds before the single permitted retry.';Start-Sleep -Seconds 60}
|
||||
Remove-Item -LiteralPath $StdoutPath,$StderrPath -Force -ErrorAction SilentlyContinue
|
||||
$Child=Start-Process -FilePath $ExecutablePath -ArgumentList $Arguments -WorkingDirectory $StandaloneRoot `
|
||||
-WindowStyle Hidden -PassThru -RedirectStandardOutput $StdoutPath -RedirectStandardError $StderrPath
|
||||
$PeakPrivate=0L;$OverMemoryLimit=$false
|
||||
try
|
||||
{
|
||||
while(-not$Child.HasExited)
|
||||
{
|
||||
$Child.Refresh();if($Child.HasExited){break}
|
||||
$Child.PriorityClass='BelowNormal';$Child.ProcessorAffinity=[IntPtr]0xFF00
|
||||
$PeakPrivate=[Math]::Max($PeakPrivate,$Child.PrivateMemorySize64)
|
||||
if($PeakPrivate-ge$EightGB)
|
||||
{$OverMemoryLimit=$true;$Child.Kill();$Child.WaitForExit();break}
|
||||
Start-Sleep -Milliseconds 100
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if(-not$Child.HasExited){$Child.Kill();$Child.WaitForExit()}
|
||||
}
|
||||
$Child.WaitForExit();$Child.Refresh()
|
||||
if($Child.ExitCode-eq-1073741502-and$Attempt-eq0){continue}
|
||||
if($Child.ExitCode-eq-1073741502){throw '0xC0000142 repeated after its single permitted retry.'}
|
||||
if($OverMemoryLimit){throw "Capture viewer stopped at the 8 GiB private-memory ceiling: $Stem"}
|
||||
$LogText=Get-Content -LiteralPath $StdoutPath -Raw
|
||||
if(-not$LogText.Contains('[InitialClipmapReady]')-or-not(Test-Path -LiteralPath $CapturePath -PathType Leaf))
|
||||
{throw "Full-residency capture missing: $Stem; exit=$($Child.ExitCode)"}
|
||||
$Memory=[regex]::Match($LogText,'(?m)^\[GpuFarMemory\] dxgi_local_sampled_peak_mb=([0-9.]+)')
|
||||
$CombinedGB=$PeakPrivate/1GB
|
||||
if($Memory.Success){$CombinedGB=($PeakPrivate+[double]$Memory.Groups[1].Value*1MB)/1GB}
|
||||
if($CombinedGB-ge8.0){throw "Capture exceeded conservative private + DXGI-local 8 GiB ceiling: $Stem ($CombinedGB GiB)"}
|
||||
$Ready=[regex]::Match($LogText,'(?m)^\[InitialClipmapReady\] ([0-9.]+) s')
|
||||
Write-Output "STEP11_CAPTURE_DONE mode=$Mode view=$($View.Name) ready_s=$($Ready.Groups[1].Value) peak_private_gb=$([math]::Round($PeakPrivate/1GB,2)) conservative_private_plus_dxgi_gb=$([math]::Round($CombinedGB,2)) path=$CapturePath exit=$($Child.ExitCode)"
|
||||
if($Child.ExitCode-ne0){throw "Capture viewer returned $($Child.ExitCode): $Stem"}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
[CmdletBinding()]
|
||||
param([string]$ExecutableName='VoxelForgeGpuFieldStep11Warmup.exe')
|
||||
|
||||
$ErrorActionPreference='Stop'
|
||||
$HostProcess=Get-Process -Id $PID
|
||||
$HostProcess.PriorityClass='BelowNormal'
|
||||
$HostProcess.ProcessorAffinity=[IntPtr]0xFF00
|
||||
$StandaloneRoot=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\..\..'))
|
||||
$ExecutablePath=Join-Path $StandaloneRoot ('bin\'+$ExecutableName)
|
||||
if([IO.Path]::GetFileName($ExecutableName)-ne$ExecutableName-or[IO.Path]::GetExtension($ExecutableName)-ne'.exe')
|
||||
{throw 'ExecutableName must be an executable filename.'}
|
||||
if(-not(Test-Path -LiteralPath $ExecutablePath -PathType Leaf)){throw "Viewer not found: $ExecutablePath"}
|
||||
$Reference=$null
|
||||
foreach($Workers in @(1,8))
|
||||
{
|
||||
$Name="step11_cpu_reference_w$Workers"
|
||||
$StdoutPath=Join-Path $PSScriptRoot ($Name+'.stdout.log')
|
||||
$StderrPath=Join-Path $PSScriptRoot ($Name+'.stderr.log')
|
||||
$Arguments=@('--stream-benchmark','--shape-world','--force-generate','--stream-hash',
|
||||
'--clip-radius=3',"--workers=$Workers")
|
||||
Write-Output "STEP11_CPU_REFERENCE workers=$Workers affinity=0xFF00 priority=BelowNormal command=`"$ExecutablePath`" $($Arguments -join ' ')"
|
||||
for($Attempt=0;$Attempt-lt2;$Attempt++)
|
||||
{
|
||||
if($Attempt-gt0)
|
||||
{Write-Output '0xC0000142 encountered; waiting 60 seconds before the single permitted retry.';Start-Sleep -Seconds 60}
|
||||
Remove-Item -LiteralPath $StdoutPath,$StderrPath -Force -ErrorAction SilentlyContinue
|
||||
$Child=Start-Process -FilePath $ExecutablePath -ArgumentList $Arguments -WorkingDirectory $StandaloneRoot `
|
||||
-WindowStyle Hidden -PassThru -RedirectStandardOutput $StdoutPath -RedirectStandardError $StderrPath
|
||||
$PeakPrivate=0L;$OverMemoryLimit=$false
|
||||
try
|
||||
{
|
||||
while(-not$Child.HasExited)
|
||||
{
|
||||
$Child.Refresh();if($Child.HasExited){break}
|
||||
$Child.PriorityClass='BelowNormal';$Child.ProcessorAffinity=[IntPtr]0xFF00
|
||||
$PeakPrivate=[Math]::Max($PeakPrivate,$Child.PrivateMemorySize64)
|
||||
if($PeakPrivate-ge8GB)
|
||||
{$OverMemoryLimit=$true;$Child.Kill();$Child.WaitForExit();break}
|
||||
Start-Sleep -Milliseconds 100
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if(-not$Child.HasExited){$Child.Kill();$Child.WaitForExit()}
|
||||
}
|
||||
$Child.WaitForExit();$Child.Refresh()
|
||||
if($Child.ExitCode-eq-1073741502-and$Attempt-eq0){continue}
|
||||
if($Child.ExitCode-eq-1073741502){throw '0xC0000142 repeated after its single retry; stopping.'}
|
||||
if($OverMemoryLimit){throw "CPU reference stopped at the 8 GiB private-memory ceiling: W$Workers"}
|
||||
$LogText=Get-Content -LiteralPath $StdoutPath -Raw
|
||||
$Stream=[regex]::Match($LogText,'(?m)^\[StreamFullClipmap\].*generated=2226/2226.*density_hash=(0x[0-9a-fA-F]+) mesh_hash=(0x[0-9a-fA-F]+) payload_hash=(0x[0-9a-fA-F]+) topology_hash=(0x[0-9a-fA-F]+)')
|
||||
$Walkability=[regex]::Match($LogText,'(?m)^\[Walkability\] PASS 5642/5642')
|
||||
if(-not$Stream.Success-or-not$Walkability.Success)
|
||||
{throw "CPU reference failed full-generation/hash/walkability checks for W$Workers; exit=$($Child.ExitCode)"}
|
||||
$Hashes=@($Stream.Groups[1].Value.ToLowerInvariant(),$Stream.Groups[2].Value.ToLowerInvariant(),
|
||||
$Stream.Groups[3].Value.ToLowerInvariant(),$Stream.Groups[4].Value.ToLowerInvariant())
|
||||
if($null-eq$Reference){$Reference=$Hashes}
|
||||
elseif(($Reference-join'|')-ne($Hashes-join'|')){throw 'CPU hashes differ between W1 and W8.'}
|
||||
Write-Output "STEP11_CPU_REFERENCE_RESULT workers=$Workers hashes=$($Hashes -join ',') walkability=5642/5642 peak_private_gb=$([math]::Round($PeakPrivate/1GB,2)) exit=$($Child.ExitCode)"
|
||||
if($Child.ExitCode-ne0){throw "CPU reference returned $($Child.ExitCode): W$Workers"}
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
[CmdletBinding()]
|
||||
param([string]$ExecutableName='VoxelForgeGpuFieldStep11Warmup.exe')
|
||||
|
||||
$ErrorActionPreference='Stop'
|
||||
$HostProcess=Get-Process -Id $PID
|
||||
$HostProcess.PriorityClass='BelowNormal'
|
||||
$HostProcess.ProcessorAffinity=[IntPtr]0xFF00
|
||||
$StandaloneRoot=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\..\..'))
|
||||
$ExecutablePath=Join-Path $StandaloneRoot ('bin\'+$ExecutableName)
|
||||
if([IO.Path]::GetFileName($ExecutableName)-ne$ExecutableName-or[IO.Path]::GetExtension($ExecutableName)-ne'.exe')
|
||||
{throw 'ExecutableName must be an executable filename.'}
|
||||
if(-not(Test-Path -LiteralPath $ExecutablePath -PathType Leaf)){throw "Viewer not found: $ExecutablePath"}
|
||||
|
||||
$Runs=@(
|
||||
@{Mode='cpu';Name='step11_race_cpu_A'},
|
||||
@{Mode='gpu';Name='step11_race_gpu_A'},
|
||||
@{Mode='gpu';Name='step11_race_gpu_B'},
|
||||
@{Mode='cpu';Name='step11_race_cpu_B'}
|
||||
)
|
||||
$EightGB=8L*1024L*1024L*1024L
|
||||
foreach($Run in $Runs)
|
||||
{
|
||||
$Arguments=@('--clip-radius=3','--workers=8','--quit-after-clipmap',"--$($Run.Mode)-far")
|
||||
if($Run.Mode-eq'gpu'){$Arguments+='--gpu-far-no-present-hold'}
|
||||
$StdoutPath=Join-Path $PSScriptRoot ($Run.Name+'.stdout.log')
|
||||
$StderrPath=Join-Path $PSScriptRoot ($Run.Name+'.stderr.log')
|
||||
Write-Output "STEP11_RACE_RUN mode=$($Run.Mode) name=$($Run.Name) priority=BelowNormal affinity=0xFF00 workers=8 command=`"$ExecutablePath`" $($Arguments -join ' ')"
|
||||
for($Attempt=0;$Attempt-lt2;$Attempt++)
|
||||
{
|
||||
if($Attempt-gt0)
|
||||
{Write-Output '0xC0000142 encountered; waiting 60 seconds before the single permitted retry.';Start-Sleep -Seconds 60}
|
||||
Remove-Item -LiteralPath $StdoutPath,$StderrPath -Force -ErrorAction SilentlyContinue
|
||||
$HostRunClock=[Diagnostics.Stopwatch]::StartNew()
|
||||
$Child=Start-Process -FilePath $ExecutablePath -ArgumentList $Arguments -WorkingDirectory $StandaloneRoot `
|
||||
-WindowStyle Hidden -PassThru -RedirectStandardOutput $StdoutPath -RedirectStandardError $StderrPath
|
||||
$PeakPrivate=0L;$OverMemoryLimit=$false
|
||||
try
|
||||
{
|
||||
while(-not$Child.HasExited)
|
||||
{
|
||||
$Child.Refresh();if($Child.HasExited){break}
|
||||
$Child.PriorityClass='BelowNormal';$Child.ProcessorAffinity=[IntPtr]0xFF00
|
||||
$PeakPrivate=[Math]::Max($PeakPrivate,$Child.PrivateMemorySize64)
|
||||
if($Child.PrivateMemorySize64-ge$EightGB)
|
||||
{$OverMemoryLimit=$true;$Child.Kill();$Child.WaitForExit();break}
|
||||
Start-Sleep -Milliseconds 50
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if(-not$Child.HasExited){$Child.Kill();$Child.WaitForExit()}
|
||||
}
|
||||
$Child.WaitForExit();$Child.Refresh();$HostRunClock.Stop();$HostRunMs=$HostRunClock.Elapsed.TotalMilliseconds
|
||||
$ViewerExitCode=$Child.ExitCode
|
||||
if($ViewerExitCode-eq-1073741502-and$Attempt-eq0){continue}
|
||||
if($ViewerExitCode-eq-1073741502){throw '0xC0000142 repeated after its single retry; stopping.'}
|
||||
if($OverMemoryLimit){throw "Viewer stopped at the 8 GiB private-memory ceiling: $($Run.Name)"}
|
||||
$LogText=Get-Content -LiteralPath $StdoutPath -Raw
|
||||
if(-not$LogText.Contains('[InitialClipmapReady]'))
|
||||
{throw "Full clipmap was not ready in $($Run.Name); exit=$ViewerExitCode"}
|
||||
$Ready=[regex]::Match($LogText,'(?m)^\[InitialClipmapReady\] ([0-9.]+) s')
|
||||
$Presented=[regex]::Match($LogText,'(?m)^\[WholeViewPresented\] at_ms=([0-9.]+) present_ms=([0-9.]+).*hr=0x([0-9A-Fa-f]{8})')
|
||||
if(-not$Presented.Success){throw "Whole-view present marker missing in $($Run.Name)"}
|
||||
$Warmup=[regex]::Match($LogText,'(?m)^\[GpuShaderWarmup\] dispatched=[0-9]+ .*queue_ms=([0-9.]+)')
|
||||
$Wait=[regex]::Match($LogText,'(?m)^\[GpuShaderWarmup\] completion_wait_ms=([0-9.]+)')
|
||||
$WarmupMs=if($Warmup.Success){[double]$Warmup.Groups[1].Value+$(if($Wait.Success){[double]$Wait.Groups[1].Value}else{0.0})}else{0.0}
|
||||
$Memory=[regex]::Match($LogText,'(?m)^\[GpuFarMemory\] dxgi_local_sampled_peak_mb=([0-9.]+)')
|
||||
$CombinedGB=$PeakPrivate/1GB
|
||||
if($Memory.Success){$CombinedGB=($PeakPrivate+[double]$Memory.Groups[1].Value*1MB)/1GB}
|
||||
if($CombinedGB-ge8.0){throw "Viewer exceeded conservative private + DXGI-local 8 GiB ceiling: $($Run.Name) ($CombinedGB GiB)"}
|
||||
Write-Output "STEP11_RACE_RESULT mode=$($Run.Mode) name=$($Run.Name) warmup_ms=$([math]::Round($WarmupMs,3)) ready_ms=$([math]::Round([double]$Ready.Groups[1].Value*1000,3)) viewer_whole_view_present_return_ms=$($Presented.Groups[1].Value) present_ms=$($Presented.Groups[2].Value) present_hr=0x$($Presented.Groups[3].Value.ToUpperInvariant()) host_process_exit_ms=$([math]::Round($HostRunMs,3)) peak_private_gb=$([math]::Round($PeakPrivate/1GB,2)) conservative_private_plus_dxgi_gb=$([math]::Round($CombinedGB,2)) exit=$ViewerExitCode"
|
||||
$Controls=[regex]::Match($LogText,'(?m)^\[ProcessControls\].*')
|
||||
if($Controls.Success){Write-Output $Controls.Value}
|
||||
if($ViewerExitCode-ne0){throw "Viewer returned $ViewerExitCode`: $($Run.Name)"}
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
[CmdletBinding()]
|
||||
param([string]$ExecutableName='VoxelForgeGpuFieldStep11Warmup.exe')
|
||||
|
||||
$ErrorActionPreference='Stop'
|
||||
$HostProcess=Get-Process -Id $PID
|
||||
$HostProcess.PriorityClass='BelowNormal'
|
||||
$HostProcess.ProcessorAffinity=[IntPtr]0xFF00
|
||||
$StandaloneRoot=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\..\..'))
|
||||
$ExecutablePath=Join-Path $StandaloneRoot ('bin\'+$ExecutableName)
|
||||
if([IO.Path]::GetFileName($ExecutableName)-ne$ExecutableName-or[IO.Path]::GetExtension($ExecutableName)-ne'.exe')
|
||||
{throw 'ExecutableName must be an executable filename.'}
|
||||
if(-not(Test-Path -LiteralPath $ExecutablePath -PathType Leaf)){throw "Viewer not found: $ExecutablePath"}
|
||||
$Arguments=@('--clip-radius=3','--workers=8','--quit-after-clipmap','--gpu-far-audit','--gpu-far-prewarm')
|
||||
$Name='step11_gpu_survival'
|
||||
$StdoutPath=Join-Path $PSScriptRoot ($Name+'.stdout.log')
|
||||
$StderrPath=Join-Path $PSScriptRoot ($Name+'.stderr.log')
|
||||
$EightGB=8L*1024L*1024L*1024L
|
||||
Write-Output "STEP11_SURVIVAL_RUN command=`"$ExecutablePath`" $($Arguments -join ' ')"
|
||||
for($Attempt=0;$Attempt-lt2;$Attempt++)
|
||||
{
|
||||
if($Attempt-gt0)
|
||||
{Write-Output '0xC0000142 encountered; waiting 60 seconds before the single permitted retry.';Start-Sleep -Seconds 60}
|
||||
Remove-Item -LiteralPath $StdoutPath,$StderrPath -Force -ErrorAction SilentlyContinue
|
||||
$Child=Start-Process -FilePath $ExecutablePath -ArgumentList $Arguments -WorkingDirectory $StandaloneRoot `
|
||||
-WindowStyle Hidden -PassThru -RedirectStandardOutput $StdoutPath -RedirectStandardError $StderrPath
|
||||
$PeakPrivate=0L;$OverMemoryLimit=$false
|
||||
try
|
||||
{
|
||||
while(-not$Child.HasExited)
|
||||
{
|
||||
$Child.Refresh();if($Child.HasExited){break}
|
||||
$Child.PriorityClass='BelowNormal';$Child.ProcessorAffinity=[IntPtr]0xFF00
|
||||
$PeakPrivate=[Math]::Max($PeakPrivate,$Child.PrivateMemorySize64)
|
||||
if($Child.PrivateMemorySize64-ge$EightGB)
|
||||
{$OverMemoryLimit=$true;$Child.Kill();$Child.WaitForExit();break}
|
||||
Start-Sleep -Milliseconds 100
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if(-not$Child.HasExited){$Child.Kill();$Child.WaitForExit()}
|
||||
}
|
||||
$Child.WaitForExit();$Child.Refresh()
|
||||
if($Child.ExitCode-eq-1073741502-and$Attempt-eq0){continue}
|
||||
if($Child.ExitCode-eq-1073741502){throw '0xC0000142 repeated after its single retry; stopping.'}
|
||||
if($OverMemoryLimit){throw 'GPU survival audit stopped at the private-memory ceiling.'}
|
||||
$LogText=Get-Content -LiteralPath $StdoutPath -Raw
|
||||
if(-not$LogText.Contains('[InitialClipmapReady]')){throw "GPU survival audit did not reach full residency; exit=$($Child.ExitCode)"}
|
||||
$Audit=[regex]::Match($LogText,'(?m)^\[GpuFarSurvivalAudit\].*status=(PASS|FAIL)')
|
||||
$Memory=[regex]::Match($LogText,'(?m)^\[GpuFarMemory\] dxgi_local_sampled_peak_mb=([0-9.]+)')
|
||||
if(-not$Audit.Success){throw 'GPU survival audit result marker missing.'}
|
||||
$DxgiMB=if($Memory.Success){[double]$Memory.Groups[1].Value}else{0.0}
|
||||
$CombinedGB=($PeakPrivate+$DxgiMB*1MB)/1GB
|
||||
if($CombinedGB-ge8.0){throw "GPU survival exceeded conservative private + DXGI-local 8 GiB ceiling: $CombinedGB GiB"}
|
||||
Write-Output "STEP11_SURVIVAL_RESULT audit=$($Audit.Groups[1].Value) peak_private_gb=$([math]::Round($PeakPrivate/1GB,2)) dxgi_local_peak_mb=$DxgiMB conservative_private_plus_dxgi_gb=$([math]::Round($CombinedGB,2)) exit=$($Child.ExitCode) stdout=$StdoutPath stderr=$StderrPath"
|
||||
if($Audit.Groups[1].Value-ne'PASS'){throw 'GPU survival audit failed.'}
|
||||
if($Child.ExitCode-ne0){throw "Viewer returned $($Child.ExitCode)"}
|
||||
break
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
[CmdletBinding()]
|
||||
param([string]$ExecutableName='VoxelForgeGpuFieldStep11Warmup.exe')
|
||||
|
||||
$ErrorActionPreference='Stop'
|
||||
$HostProcess=Get-Process -Id $PID
|
||||
$HostProcess.PriorityClass='BelowNormal'
|
||||
$HostProcess.ProcessorAffinity=[IntPtr]0xFF00
|
||||
$StandaloneRoot=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\..\..'))
|
||||
$ExecutablePath=Join-Path $StandaloneRoot ('bin\'+$ExecutableName)
|
||||
if([IO.Path]::GetFileName($ExecutableName)-ne$ExecutableName-or[IO.Path]::GetExtension($ExecutableName)-ne'.exe')
|
||||
{throw 'ExecutableName must be an executable filename.'}
|
||||
if(-not(Test-Path -LiteralPath $ExecutablePath -PathType Leaf)){throw "Viewer not found: $ExecutablePath"}
|
||||
|
||||
$Entries=@('EvaluateFarFieldCS','ClassifyCS','ClassifyFarCS','ScanGroupsCS','EmitCS','EmitNearCS',
|
||||
'BuildFarConnectorRingsCS','EmitFarConnectorPanelsCS','ClassifyFarSkirtsCS',
|
||||
'ScanFarSkirtsCS','EmitFarSkirtsCS','NoiseProbeCS')
|
||||
$EightGB=8L*1024L*1024L*1024L
|
||||
foreach($Entry in $Entries)
|
||||
{
|
||||
$Name='step11_shader_'+$Entry
|
||||
$StdoutPath=Join-Path $PSScriptRoot ($Name+'.stdout.log')
|
||||
$StderrPath=Join-Path $PSScriptRoot ($Name+'.stderr.log')
|
||||
$Arguments=@('--workers=8','--gpu-far-warmup-only',"--gpu-far-warmup-entry=$Entry")
|
||||
Write-Output "STEP11_SHADER_RUN entry=$Entry freshness=fresh_process affinity=0xFF00 command=`"$ExecutablePath`" $($Arguments -join ' ')"
|
||||
for($Attempt=0;$Attempt-lt2;$Attempt++)
|
||||
{
|
||||
if($Attempt-gt0)
|
||||
{Write-Output '0xC0000142 encountered; waiting 60 seconds before the single permitted retry.';Start-Sleep -Seconds 60}
|
||||
Remove-Item -LiteralPath $StdoutPath,$StderrPath -Force -ErrorAction SilentlyContinue
|
||||
$HostRunClock=[Diagnostics.Stopwatch]::StartNew()
|
||||
$Child=Start-Process -FilePath $ExecutablePath -ArgumentList $Arguments -WorkingDirectory $StandaloneRoot `
|
||||
-WindowStyle Hidden -PassThru -RedirectStandardOutput $StdoutPath -RedirectStandardError $StderrPath
|
||||
$PeakPrivate=0L;$OverMemoryLimit=$false
|
||||
try
|
||||
{
|
||||
while(-not$Child.HasExited)
|
||||
{
|
||||
$Child.Refresh();if($Child.HasExited){break}
|
||||
$Child.PriorityClass='BelowNormal';$Child.ProcessorAffinity=[IntPtr]0xFF00
|
||||
$PeakPrivate=[Math]::Max($PeakPrivate,$Child.PrivateMemorySize64)
|
||||
if($Child.PrivateMemorySize64-ge$EightGB)
|
||||
{$OverMemoryLimit=$true;$Child.Kill();$Child.WaitForExit();break}
|
||||
Start-Sleep -Milliseconds 50
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if(-not$Child.HasExited){$Child.Kill();$Child.WaitForExit()}
|
||||
}
|
||||
$Child.WaitForExit();$Child.Refresh();$HostRunClock.Stop();$HostRunMs=$HostRunClock.Elapsed.TotalMilliseconds
|
||||
$ViewerExitCode=$Child.ExitCode
|
||||
if($ViewerExitCode-eq-1073741502-and$Attempt-eq0){continue}
|
||||
if($ViewerExitCode-eq-1073741502){throw '0xC0000142 repeated after its single retry; stopping.'}
|
||||
if($OverMemoryLimit){throw "Warmup process stopped at the 8 GiB private-memory ceiling: $Entry"}
|
||||
$LogText=Get-Content -LiteralPath $StdoutPath -Raw
|
||||
$Selected=[regex]::Match($LogText,'(?m)^\[GpuShaderWarmup\] dispatched=1 selected='+[regex]::Escape($Entry)+'.*queue_ms=([0-9.]+)')
|
||||
$Dispatch=[regex]::Match($LogText,'(?m)^\[GpuShaderWarmup\] entry='+[regex]::Escape($Entry)+' dispatch_call_ms=([0-9.]+)')
|
||||
$Wait=[regex]::Match($LogText,'(?m)^\[GpuShaderWarmup\] completion_wait_ms=([0-9.]+)')
|
||||
$Create=[regex]::Match($LogText,'(?m)^\[GpuPipelineProfile\] stage=shader_object_create entry='+[regex]::Escape($Entry)+' duration_ms=([0-9.]+)')
|
||||
if(-not$Selected.Success-or-not$Dispatch.Success-or-not$Wait.Success-or-not$Create.Success)
|
||||
{throw "Isolated warmup markers missing for $Entry; exit=$ViewerExitCode"}
|
||||
$Memory=[regex]::Match($LogText,'(?m)^\[GpuFarMemory\] dxgi_local_sampled_peak_mb=([0-9.]+)')
|
||||
$CombinedGB=$PeakPrivate/1GB
|
||||
if($Memory.Success){$CombinedGB=($PeakPrivate+[double]$Memory.Groups[1].Value*1MB)/1GB}
|
||||
if($CombinedGB-ge8.0){throw "Warmup exceeded conservative private + DXGI-local 8 GiB ceiling: $Entry ($CombinedGB GiB)"}
|
||||
Write-Output "STEP11_SHADER_RESULT entry=$Entry object_create_ms=$($Create.Groups[1].Value) dispatch_call_ms=$($Dispatch.Groups[1].Value) isolated_queue_ms=$($Selected.Groups[1].Value) completion_wait_ms=$($Wait.Groups[1].Value) host_process_exit_ms=$([math]::Round($HostRunMs,3)) peak_private_gb=$([math]::Round($PeakPrivate/1GB,2)) conservative_private_plus_dxgi_gb=$([math]::Round($CombinedGB,2)) exit=$ViewerExitCode"
|
||||
if($ViewerExitCode-ne0){throw "Warmup process returned $ViewerExitCode for $Entry"}
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
[CmdletBinding()]
|
||||
param([string]$ExecutableName='VoxelForgeGpuFieldStep11Warmup.exe')
|
||||
|
||||
$ErrorActionPreference='Stop'
|
||||
$HostProcess=Get-Process -Id $PID
|
||||
$HostProcess.PriorityClass='BelowNormal'
|
||||
$HostProcess.ProcessorAffinity=[IntPtr]0xFF00
|
||||
$StandaloneRoot=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\..\..'))
|
||||
$ExecutablePath=Join-Path $StandaloneRoot ('bin\'+$ExecutableName)
|
||||
if([IO.Path]::GetFileName($ExecutableName)-ne$ExecutableName-or[IO.Path]::GetExtension($ExecutableName)-ne'.exe')
|
||||
{throw 'ExecutableName must be an executable filename.'}
|
||||
if(-not(Test-Path -LiteralPath $ExecutablePath -PathType Leaf)){throw "Viewer not found: $ExecutablePath"}
|
||||
|
||||
$Runs=@(
|
||||
@{Name='step11_warmup_workers8';Workers=8;Mode='overlap'},
|
||||
@{Name='step11_warmup_workers4';Workers=4;Mode='overlap'},
|
||||
@{Name='step11_warmup_workers7';Workers=7;Mode='overlap'},
|
||||
@{Name='step11_warmup_workers6';Workers=6;Mode='overlap'},
|
||||
@{Name='step11_warmup_thread_normal';Workers=8;Mode='normal_priority'},
|
||||
@{Name='step11_warmup_before_workers';Workers=8;Mode='before_workers'}
|
||||
)
|
||||
$EightGB=8L*1024L*1024L*1024L
|
||||
foreach($Run in $Runs)
|
||||
{
|
||||
$Arguments=@('--clip-radius=3',"--workers=$($Run.Workers)",'--quit-after-clipmap','--gpu-far-no-present-hold')
|
||||
if($Run.Mode-eq'overlap'){$Arguments+='--gpu-far-prewarm'}
|
||||
elseif($Run.Mode-eq'normal_priority'){$Arguments+=@('--gpu-far-prewarm','--gpu-far-warmup-normal-priority')}
|
||||
else{$Arguments+='--gpu-far-warmup-before-workers'}
|
||||
$StdoutPath=Join-Path $PSScriptRoot ($Run.Name+'.stdout.log')
|
||||
$StderrPath=Join-Path $PSScriptRoot ($Run.Name+'.stderr.log')
|
||||
Write-Output "STEP11_RUN name=$($Run.Name) mode=$($Run.Mode) workers=$($Run.Workers) affinity=0xFF00 command=`"$ExecutablePath`" $($Arguments -join ' ')"
|
||||
for($Attempt=0;$Attempt-lt2;$Attempt++)
|
||||
{
|
||||
if($Attempt-gt0)
|
||||
{Write-Output '0xC0000142 encountered; waiting 60 seconds before the single permitted retry.';Start-Sleep -Seconds 60}
|
||||
Remove-Item -LiteralPath $StdoutPath,$StderrPath -Force -ErrorAction SilentlyContinue
|
||||
$HostRunClock=[Diagnostics.Stopwatch]::StartNew()
|
||||
$Child=Start-Process -FilePath $ExecutablePath -ArgumentList $Arguments -WorkingDirectory $StandaloneRoot `
|
||||
-WindowStyle Hidden -PassThru -RedirectStandardOutput $StdoutPath -RedirectStandardError $StderrPath
|
||||
$PeakPrivate=0L;$OverMemoryLimit=$false
|
||||
try
|
||||
{
|
||||
while(-not$Child.HasExited)
|
||||
{
|
||||
$Child.Refresh();if($Child.HasExited){break}
|
||||
$Child.PriorityClass='BelowNormal';$Child.ProcessorAffinity=[IntPtr]0xFF00
|
||||
$PeakPrivate=[Math]::Max($PeakPrivate,$Child.PrivateMemorySize64)
|
||||
if($Child.PrivateMemorySize64-ge$EightGB)
|
||||
{$OverMemoryLimit=$true;$Child.Kill();$Child.WaitForExit();break}
|
||||
Start-Sleep -Milliseconds 50
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if(-not$Child.HasExited){$Child.Kill();$Child.WaitForExit()}
|
||||
}
|
||||
$Child.WaitForExit();$Child.Refresh();$HostRunClock.Stop();$HostRunMs=$HostRunClock.Elapsed.TotalMilliseconds
|
||||
$ViewerExitCode=$Child.ExitCode
|
||||
if($ViewerExitCode-eq-1073741502-and$Attempt-eq0){continue}
|
||||
if($ViewerExitCode-eq-1073741502){throw '0xC0000142 repeated after its single retry; stopping.'}
|
||||
if($OverMemoryLimit){throw "Viewer stopped at the 8 GiB private-memory ceiling: $($Run.Name)"}
|
||||
$LogText=Get-Content -LiteralPath $StdoutPath -Raw
|
||||
if(-not$LogText.Contains('[InitialClipmapReady]'))
|
||||
{throw "Full clipmap was not ready in $($Run.Name); exit=$ViewerExitCode"}
|
||||
$Ready=[regex]::Match($LogText,'(?m)^\[InitialClipmapReady\] ([0-9.]+) s')
|
||||
$Presented=[regex]::Match($LogText,'(?m)^\[WholeViewPresented\] at_ms=([0-9.]+) present_ms=([0-9.]+).*hr=0x([0-9A-Fa-f]{8})')
|
||||
$Queue=[regex]::Match($LogText,'(?m)^\[GpuShaderWarmup\] dispatched=[0-9]+ .*queue_ms=([0-9.]+)')
|
||||
$Wait=[regex]::Match($LogText,'(?m)^\[GpuShaderWarmup\] completion_wait_ms=([0-9.]+)')
|
||||
if(-not$Presented.Success){throw "Whole-view present marker missing in $($Run.Name)"}
|
||||
$WarmupMs=if($Queue.Success){[double]$Queue.Groups[1].Value+$(if($Wait.Success){[double]$Wait.Groups[1].Value}else{0.0})}else{0.0}
|
||||
$Memory=[regex]::Match($LogText,'(?m)^\[GpuFarMemory\] dxgi_local_sampled_peak_mb=([0-9.]+)')
|
||||
$CombinedGB=$PeakPrivate/1GB
|
||||
if($Memory.Success){$CombinedGB=($PeakPrivate+[double]$Memory.Groups[1].Value*1MB)/1GB}
|
||||
if($CombinedGB-ge8.0){throw "Viewer exceeded conservative private + DXGI-local 8 GiB ceiling: $($Run.Name) ($CombinedGB GiB)"}
|
||||
Write-Output "STEP11_RESULT name=$($Run.Name) mode=$($Run.Mode) workers=$($Run.Workers) warmup_ms=$([math]::Round($WarmupMs,3)) ready_ms=$([math]::Round([double]$Ready.Groups[1].Value*1000,3)) whole_view_present_return_ms=$($Presented.Groups[1].Value) present_ms=$($Presented.Groups[2].Value) present_hr=0x$($Presented.Groups[3].Value.ToUpperInvariant()) host_process_exit_ms=$([math]::Round($HostRunMs,3)) peak_private_gb=$([math]::Round($PeakPrivate/1GB,2)) conservative_private_plus_dxgi_gb=$([math]::Round($CombinedGB,2)) exit=$ViewerExitCode"
|
||||
if($Run.Mode-eq'normal_priority')
|
||||
{Select-String -Path $StdoutPath -Pattern '^\[GpuShaderWarmupThread\]|^\[GpuShaderWarmup\] queue_thread=' | ForEach-Object {Write-Output $_.Line}}
|
||||
if($Run.Mode-eq'before_workers')
|
||||
{Select-String -Path $StdoutPath -Pattern '^\[GpuShaderWarmup\] queue_thread=|^\[GpuShaderWarmupBeforeWorkers\]' | ForEach-Object {Write-Output $_.Line}}
|
||||
$Timeline=[regex]::Match($LogText,'(?m)^\[GpuFarTimeline\].*')
|
||||
if($Timeline.Success){Write-Output $Timeline.Value}
|
||||
if($ViewerExitCode-ne0){throw "Viewer returned $ViewerExitCode`: $($Run.Name)"}
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
# GPU field port, step 11: warm-up controls and far emitter split
|
||||
|
||||
Date: 2026-10-07. The Step 11 viewer and agreement runner were built from `Standalone\` sources with `/MP8`, BelowNormal process priority, and affinity `0xFF00`. All viewer runs were serial, hidden, and closed at exit. No `0xC0000142` retry was needed. The only affinity exception was the single 8-worker viewer run at `0xFFFF`. No capture was opened in an image viewer.
|
||||
|
||||
## Warm-up controls
|
||||
|
||||
`warm-up ms` is the logged queue time plus its completion wait. Each run reports whole-view readiness from `[InitialClipmapReady]` and the subsequent `[WholeViewPresented] at_ms` clock. The pre-split controls used the original 11-entry warm-up; after the split, startup dispatches the nine kernels used by the viewer's far path.
|
||||
|
||||
| Control | Warm-up before / after split | Ready / whole-view present before | Ready / whole-view present after |
|
||||
|---|---:|---:|---:|
|
||||
| 8 workers, `0xFF00` | 2,609 / 2,038 ms | 3,501 / 3,502.360 ms | 3,059 / 3,059.825 ms |
|
||||
| 7 workers, `0xFF00` | 2,725 / 1,986 ms | 3,433 / 3,434.035 ms | 3,152 / 3,152.550 ms |
|
||||
| 6 workers, `0xFF00` | 2,614 / 2,127 ms | 3,283 / 3,283.377 ms | 3,143 / 3,144.162 ms |
|
||||
| 4 workers, `0xFF00` | 2,579 / 2,068 ms | 3,190 / 3,190.884 ms | 3,199 / 3,200.342 ms |
|
||||
| 8 workers, warm-up thread at normal base priority | 2,669 / 2,076 ms | 3,498 / 3,498.548 ms | 3,089 / 3,090.267 ms |
|
||||
| 8 workers, warm-up completes before generation workers | 2,367 / 1,758 ms | 3,623 / 3,623.833 ms | 3,306 / 3,306.937 ms |
|
||||
|
||||
Worker-count effects were not monotonic: the fastest post-split readiness was the 8-worker run, and changing the warm-up thread to normal base priority produced no meaningful improvement. Completing warm-up before generation workers shortened the queue by about 280 ms versus the overlapping 8-worker control, but made the full view about 247 ms slower because that time could no longer overlap generation.
|
||||
|
||||
Each worker/priority control is one fresh launch per variant, so small readiness differences can be run variation. The two post-split GPU race launches independently measured 2,001 and 2,033 ms of warm-up.
|
||||
|
||||
The one allowed all-CPU-affinity run used BelowNormal priority, 8 workers, and verified process mask `0xFFFF`: warm-up **1,710 ms**, ready **2,766 ms**, whole-view present return **2,767.140 ms**, host process exit **2,936.462 ms**. This is about 0.29 s faster warm-up and 0.39 s faster readiness than the post-split `0xFF00` 8-worker control, but it remains well behind CPU.
|
||||
|
||||
## Isolated shader first use
|
||||
|
||||
Each entry ran alone in a fresh viewer process at BelowNormal / `0xFF00`; no earlier dispatch of that entry occurred in that process. `queue ms` covers tiny-resource setup, dispatch submission, and `Flush`, so it measures the first-use path rather than a driver-internal compiler timer. The direct `Dispatch` call was only 0.003–0.007 ms and completion waits were at most 16 ms. Driver compilation is consistent with the long queue times, but was not directly observed.
|
||||
|
||||
| Entry | Original queue ms | After split queue ms |
|
||||
|---|---:|---:|
|
||||
| `EvaluateFarFieldCS` | 1,839 | 1,757 |
|
||||
| `ClassifyCS` | 3.2 | 3.1 |
|
||||
| `ClassifyFarCS` | 3.0 | 3.0 |
|
||||
| `ScanGroupsCS` | 3.2 | 3.1 |
|
||||
| `EmitCS` (original mixed path → far specialization) | 2,327 | 3.2 |
|
||||
| `EmitNearCS` (retained original step-one path) | — | 2,429 |
|
||||
| `BuildFarConnectorRingsCS` | 820 | 784 |
|
||||
| `EmitFarConnectorPanelsCS` | 3.3 | 3.4 |
|
||||
| `ClassifyFarSkirtsCS` | 478 | 507 |
|
||||
| `ScanFarSkirtsCS` | 2.8 | 3.1 |
|
||||
| `EmitFarSkirtsCS` | 1,031 | 975 |
|
||||
| `NoiseProbeCS` | 3.3 | 3.4 |
|
||||
|
||||
The original `EmitCS` root helper included an analytic midpoint fallback that calls `NearFieldDensityAt`, which expands into the shared primitive-distance and owner-detail field routines. That fallback is only reachable for `StepVoxels == 1`; far tiles use larger steps. I split the step-one code into `EmitNearCS` and made `EmitCS` retain CPU-authored midpoint records while omitting that unreachable branch for the far path. FXC no longer reports X4714 for far `EmitCS`; the warning remains on `EmitNearCS`. The viewer dispatches the specialized entry for far tiles with `tile.step > 1`, preserving the original path for step-one callers. This reduced the far emitter's isolated queue from **2.327 s to 3.2 ms**. Other first-use costs remain, especially field evaluation, connector rings, and skirt emission.
|
||||
|
||||
Startup warm-up now dispatches the nine kernels used by the viewer's far path. It omits the CPU-path classifier, the step-one emitter, and the noise diagnostic. Under `0xFF00`, its queue fell from roughly **2.6–2.7 s to 2.0–2.13 s** in the worker sweep.
|
||||
|
||||
## Fresh-launch whole-view race
|
||||
|
||||
Order was CPU A, GPU A, GPU B, CPU B. Every launch used 8 workers, BelowNormal, and `0xFF00`.
|
||||
|
||||
| Run | Ready | `[WholeViewPresented]` | Host process exit | Warm-up |
|
||||
|---|---:|---:|---:|---:|
|
||||
| CPU A | 1,503 ms | 1,503.159 ms | 1,718.840 ms | — |
|
||||
| GPU A | 3,183 ms | 3,183.824 ms | 3,367.918 ms | 2,001 ms |
|
||||
| GPU B | 3,124 ms | 3,124.843 ms | 3,291.548 ms | 2,033 ms |
|
||||
| CPU B | 1,352 ms | 1,352.567 ms | 1,488.795 ms | — |
|
||||
|
||||
Median viewer-clock time was **1.428 s CPU vs 3.154 s hybrid**, a **1.726 s / 2.21×** CPU lead. Median host-clock time was **1.604 s CPU vs 3.330 s hybrid**, a **1.726 s / 2.08×** CPU lead. The hybrid is still slower. Its measured floor includes about 2.0 s of shader warm-up; far input preparation was 104 ms, GPU busy time about 199 ms, and the GPU queue envelope 610–859 ms. These stages overlap, so they should not be added as independent durations.
|
||||
|
||||
The all-CPU-affinity result is separate from the race: **2.767 s** whole-view present return versus the normal-rule CPU median of **1.428 s**. All automated `Present` calls returned `DXGI_STATUS_OCCLUDED` (`0x087A0001`), so these clocks measure readiness and API return, not physical scanout.
|
||||
|
||||
## Correctness and memory
|
||||
|
||||
- Whole-far agreement: 1,114 eligible tiles, 152 near-transition tiles skipped; **zero GPU and WARP topology differences**, zero protected-exception differences across 127,401 cells, zero thin-feature differences across 353 cells, and bit-identical repeated GPU outputs.
|
||||
- GPU-mesh survival audit: **PASS** at full clipmap residency; peak 3.46 GiB private plus 2,402.1 MiB DXGI local, **5.81 GiB combined**.
|
||||
- CPU reference at workers 1 and 8: identical density `0xdb2991c73215af4c`, mesh `0x8236c5edd7fc8e4f`, payload `0x4c48fa75a543d58e`, and topology `0xbea22e76b34a4dfc`; walkability **5,642/5,642** in both runs.
|
||||
- Ten CPU/GPU capture pairs reached `[InitialClipmapReady]`. Maximum combined capture memory was **6.11 GiB**. Numeric RGB comparison is in [step11_capture_comparison.md](step11_capture_comparison.md); the results remain within the Step 10 ranges.
|
||||
|
||||
Primary artifacts: `RunStep11WarmupControls.ps1`, `RunStep11ShaderFirstUse.ps1`, `RunStep11FinalInterleaved.ps1`, `RunStep11AllCpuAffinity.ps1`, `RunStep11GpuSurvival.ps1`, `RunStep11CpuReference.ps1`, `RunStep11CaptureMatrix.ps1`, `step11_whole_far_agreement.stdout.log`, `step11_gpu_survival.stdout.log`, and the `step11_*` run logs.
|
||||
|
||||
The previously reported direct-GPU LOD3/4 coverage loss and movement-crossing output-slot overflow remain unresolved; this step made no changes to those lower-priority paths. No commit, push, or stash was made.
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,16 @@
|
||||
# Step 10 full-residency capture comparison
|
||||
|
||||
All ten CPU/GPU pairs were captured after `[InitialClipmapReady]`. Images were compared as RGB arrays; no full-size capture was opened in an image viewer.
|
||||
|
||||
| View | Size | RGB MAE | RGB RMSE | Changed pixels | Pixels max channel >32 | Max channel |
|
||||
|---|---:|---:|---:|---:|---:|---:|
|
||||
| chamber | 1280x800 | 0.6076 | 1.8655 | 42.6368% | 0.0183% | 124 |
|
||||
| tunnel | 1280x800 | 0.6383 | 3.3799 | 31.7335% | 0.2772% | 130 |
|
||||
| passage | 1280x800 | 1.6092 | 3.6878 | 50.4982% | 0.1733% | 52 |
|
||||
| far | 1280x800 | 0.7909 | 2.1558 | 44.8325% | 0.0198% | 128 |
|
||||
| passage_floor_closeup | 1280x800 | 0.9314 | 2.4800 | 43.0219% | 0.0500% | 100 |
|
||||
| tunnel_bend | 1280x800 | 0.8129 | 2.1599 | 40.9629% | 0.0708% | 55 |
|
||||
| remote_yaw0 | 1280x800 | 0.2002 | 2.6637 | 4.2874% | 0.2415% | 125 |
|
||||
| remote_yaw90 | 1280x800 | 0.4083 | 4.3552 | 2.2432% | 0.6948% | 94 |
|
||||
| remote_yaw180 | 1280x800 | 0.0484 | 1.3206 | 2.9787% | 0.0341% | 102 |
|
||||
| remote_yaw270 | 1280x800 | 0.2355 | 3.1104 | 5.5592% | 0.4098% | 107 |
|
||||
@@ -0,0 +1,16 @@
|
||||
# Step 11 full-residency capture comparison
|
||||
|
||||
All ten CPU/GPU pairs were captured after `[InitialClipmapReady]`. The files were compared numerically as RGB arrays and were not opened in an image viewer.
|
||||
|
||||
| View | Size | RGB MAE | RGB RMSE | Changed pixels | Pixels max channel >32 | Max channel |
|
||||
|---|---:|---:|---:|---:|---:|---:|
|
||||
| chamber | 1280x800 | 0.6076 | 1.8655 | 42.6368% | 0.0183% | 124 |
|
||||
| tunnel | 1280x800 | 0.6383 | 3.3799 | 31.7335% | 0.2772% | 130 |
|
||||
| passage | 1280x800 | 1.6092 | 3.6878 | 50.4982% | 0.1733% | 52 |
|
||||
| far | 1280x800 | 0.7909 | 2.1558 | 44.8325% | 0.0198% | 128 |
|
||||
| passage_floor_closeup | 1280x800 | 0.9314 | 2.4800 | 43.0219% | 0.0500% | 100 |
|
||||
| tunnel_bend | 1280x800 | 0.8129 | 2.1599 | 40.9629% | 0.0708% | 55 |
|
||||
| remote_yaw0 | 1280x800 | 0.1994 | 2.6632 | 4.2472% | 0.2415% | 125 |
|
||||
| remote_yaw90 | 1280x800 | 0.4087 | 4.3554 | 2.2590% | 0.6948% | 94 |
|
||||
| remote_yaw180 | 1280x800 | 0.0484 | 1.3206 | 2.9787% | 0.0341% | 102 |
|
||||
| remote_yaw270 | 1280x800 | 0.2355 | 3.1104 | 5.5593% | 0.4098% | 107 |
|
||||
Reference in new issue
Block a user