wip(assembler): round S2 (Sol) -- shared per-tile feature queries for every Core family; island placement 30x faster
Island-only worker context replaced by a shared worker-local candidate domain (WorldAssemblyFeatureTileListV1 / ScopedWorldAssemblyFeatureQueriesV1) serving SurfaceWorld, FloatingIslands and far-shell queries; a per-domain cost hint keeps the full scan on small plans. Content placement prepares the same queries and skips proven air: owner island cell p95 7.07 -> 0.24 ms; populated fixture 572 exact placements, 3.27 s -> 29 ms. Full/candidate hashes equal with dropped-feature controls on both families; S1 default W1/W8/W16 hashes reproduced; Core-off and M2 fixtures pass. Default contract for future families in ARCHITECTURE 8.23. Run on gpt-6.1-sol medium. 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
d6e69420e8
commit
6ddb834b1c
19 files changed
+1849
-132
No files matched your search
@@ -1138,3 +1138,59 @@ link-safety passed. No 0xC0000142 retry or new UECC folder occurred. I did not o
|
||||
editor or build his project, edit any .uasset, create a link, commit, push or stash.
|
||||
|
||||
— Luna
|
||||
|
||||
|
||||
## World assembler S2 / M3 Round 6 — 2026-10-18
|
||||
|
||||
The shared engine now owns a family-neutral, worker-local feature-query scope. I removed the
|
||||
island-only context from ShapeWorld; SurfaceWorld finite features, island groups, meshing, far-shell
|
||||
field calls, decoration cells and landmark columns use the same domain/identity/halo contract.
|
||||
S1's root-aware positive-density bounds and ordered connector composition are preserved.
|
||||
|
||||
The measurements matter here: the staged SurfaceWorld has one finite shelf, and the staged island
|
||||
plan has four islands. Forced candidate bookkeeping gave no useful small-plan gain and regressed
|
||||
the island tile timings by 7–13%. I added a shared cost hint, resolved once per domain, so these
|
||||
small plans keep their full evaluator. Richer plans still use candidates. With the actual staged
|
||||
owner template expanded to 256 islands, forced-list p95 was 110.570 -> 7.3619 ms (about 15x), with
|
||||
identical hashes and a detected dropped-feature control. The composed surface stress (64 shelves,
|
||||
one XY height writer and one cap writer) was 0.7084 -> 0.4078 ms, again exact with its control caught.
|
||||
The S1 57x stress number used a different Round 3 template, so I do not compare those as a regression.
|
||||
|
||||
The placement cost came from marching almost the entire strate and using a full plan at every
|
||||
step. Family-declared solid-support bounds now feed a shared column range query, alongside the
|
||||
same feature scopes. We skip only certified air and keep the old march phase, bisection,
|
||||
interpolation and transforms. Owner-palette p95 fell 7.0706 -> 0.2385 ms, with 58.84 density calls
|
||||
per cell versus S1's 7,763.38. Its sampled authored palette still places zero objects; I keep that
|
||||
limitation explicit rather than claiming those timings include spawning trees.
|
||||
|
||||
A separate populated fixture produced 572 placements across 14 cells. All 572 full/candidate
|
||||
transforms match exactly, all canonical anchor checks pass, and the largest density residual is
|
||||
0.035156 Core voxel units. The 64-cell active batch, including merge and real HISM application,
|
||||
was 3271.147 -> 29.105 ms. All 572 instances were applied and then cleared. This is synchronous
|
||||
CPU work under null RHI; it excludes rendering, GPU upload, async tree completion and owner tree
|
||||
Blueprint logic. One run failed the new count assertion because normal region application clears
|
||||
live landmark footprints. I isolated the validation fixture from those footprints; normal content
|
||||
keeps them enabled. The corrected run passes.
|
||||
|
||||
BuildHost SurfaceWorld passed its full actor/streaming/collision/edit checks and W1/W8/W16 with
|
||||
S1's default 25 cm hashes. The final island actor also keeps S1's entire W1/W8/W16 matrix. The final
|
||||
focused surface replay checks LOD0/1/7/8 full-versus-default tile hashes after the cost hint. M2 V1/V2
|
||||
fixture repeats, borders, MC identity and all 125 doorway phases pass. A separate Core-off run
|
||||
proves unchanged legacy density and 12.5 cm scale. All builds/link audits passed. No timeout,
|
||||
0xC0000142 or new UECC folder occurred. The failed HISM fixture run exited normally with test status 1.
|
||||
|
||||
My next structural suggestion is an immutable per-strate family-provider table, carrying declared
|
||||
bounds, cost hints, value certificates and optional support/surface queries. It would avoid repeating
|
||||
concrete family enumeration and rebuilding metadata in each consumer. I have not rebuilt that
|
||||
boundary this round; the report lists the allocation, many-strate, hash and stale-provider evidence
|
||||
needed first. Preserve the existing bounded biome lattice and cave interval machinery meanwhile.
|
||||
|
||||
New source files are `Round6/SharedFeatureListAudit.cpp` and `Round6/BuildSharedFeatureListAudit.ps1`
|
||||
under WorldAssemblerM3. The report lists every modified source, likely compile spots, all failed and
|
||||
replayed runs, timing limitations and the plain-words owner note. CODEMAP section 3 and ARCHITECTURE
|
||||
section 8.23 are updated. No owner project/editor was opened, closed or built. No .uasset was edited,
|
||||
and no link, commit, push or stash was created.
|
||||
|
||||
[Full S2 report](../../WorldAssemblerM3/Round6/REPORT.md).
|
||||
|
||||
— Sol
|
||||
@@ -0,0 +1,61 @@
|
||||
[CmdletBinding()]
|
||||
param([string]$IslandAssemblyPath, [string]$SurfaceAssemblyPath)
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$PluginRoot = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\..\..\..'))
|
||||
$HostOutput = Join-Path $PluginRoot 'Saved\BuildHost\HostProject\Plugins\VoxelForge\Saved\CoreWorldValidation\User\Saved\CoreWorldValidation\Output'
|
||||
if (!$IslandAssemblyPath) { $IslandAssemblyPath = Join-Path $HostOutput 's2_assembly_FloatingIslands.json' }
|
||||
if (!$SurfaceAssemblyPath) { $SurfaceAssemblyPath = Join-Path $HostOutput 's2_assembly_SurfaceWorld.json' }
|
||||
$Results = Join-Path $PSScriptRoot 'results'
|
||||
$BuildRoot = Join-Path $PluginRoot 'Standalone\Build\VoxelForgeCore'
|
||||
$Exe = Join-Path $BuildRoot 'SharedFeatureListAudit.exe'
|
||||
$Rsp = Join-Path $BuildRoot 'shared-feature-list-audit.rsp'
|
||||
$VcVars = 'E:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat'
|
||||
$Source = Join-Path $PSScriptRoot 'SharedFeatureListAudit.cpp'
|
||||
$Library = Join-Path $BuildRoot 'VoxelForgeCore.lib'
|
||||
foreach ($Required in @($IslandAssemblyPath,$SurfaceAssemblyPath,$VcVars,$Library,$Source)) {
|
||||
if (!(Test-Path -LiteralPath $Required -PathType Leaf)) { throw "Missing audit input: $Required" }
|
||||
}
|
||||
[IO.Directory]::CreateDirectory($Results) | Out-Null
|
||||
$Lines = @('/nologo','/std:c++20','/O2','/arch:AVX2','/fp:precise','/EHsc',
|
||||
('/I"{0}"' -f (Join-Path $PluginRoot 'Standalone\Core\include')),
|
||||
('/Fe"{0}"' -f $Exe),('"{0}"' -f $Source),('"{0}"' -f $Library))
|
||||
[IO.File]::WriteAllLines($Rsp,$Lines,[Text.UTF8Encoding]::new($false))
|
||||
Push-Location $BuildRoot
|
||||
try {
|
||||
$Command = 'call "{0}" >nul && cl.exe @"{1}"' -f $VcVars,$Rsp
|
||||
& $env:ComSpec /d /s /c $Command
|
||||
if ($LASTEXITCODE -eq -1073741502) { & $env:ComSpec /d /s /c $Command }
|
||||
if ($LASTEXITCODE -ne 0) { throw "Audit compile failed: $LASTEXITCODE" }
|
||||
} finally { Pop-Location }
|
||||
for ($Attempt=1;$Attempt -le 2;++$Attempt) {
|
||||
$Stdout = Join-Path $Results "shared_audit_attempt_$Attempt.stdout.log"
|
||||
$Stderr = Join-Path $Results "shared_audit_attempt_$Attempt.stderr.log"
|
||||
$Process = Start-Process -FilePath $Exe -WindowStyle Hidden -PassThru -WorkingDirectory $BuildRoot `
|
||||
-ArgumentList @(('"{0}"' -f $IslandAssemblyPath),('"{0}"' -f $SurfaceAssemblyPath),('"{0}"' -f $Results)) `
|
||||
-RedirectStandardOutput $Stdout -RedirectStandardError $Stderr
|
||||
$Process.PriorityClass = [Diagnostics.ProcessPriorityClass]::Normal
|
||||
$Process.ProcessorAffinity = [IntPtr]0xFFF
|
||||
$Timer = [Diagnostics.Stopwatch]::StartNew()
|
||||
$Peak = 0L
|
||||
while (!$Process.WaitForExit(250)) {
|
||||
$Process.Refresh()
|
||||
$Peak = [Math]::Max($Peak,$Process.PrivateMemorySize64)
|
||||
if ($Timer.Elapsed.TotalSeconds -gt 900 -or $Peak -gt 8GB) {
|
||||
Stop-Process -Id $Process.Id -Force
|
||||
throw 'Shared audit exceeded 15 minutes or 8 GiB.'
|
||||
}
|
||||
}
|
||||
$Process.WaitForExit()
|
||||
$Process.Refresh()
|
||||
$ExitCode = $Process.ExitCode
|
||||
if ($null -eq $ExitCode -and (Select-String -LiteralPath $Stdout -SimpleMatch 'SHARED_FEATURE_AUDIT_PASS' -Quiet)) { $ExitCode=0 }
|
||||
"attempt=$Attempt exit=$ExitCode elapsed_s=$($Timer.Elapsed.TotalSeconds) peak_private_bytes=$Peak" |
|
||||
Add-Content (Join-Path $Results 'shared_audit_ledger.txt')
|
||||
Get-Content $Stdout
|
||||
Get-Content $Stderr
|
||||
if ($ExitCode -eq -1073741502 -and $Attempt -eq 1) { continue }
|
||||
if ($ExitCode -ne 0 -or !(Select-String -LiteralPath $Stdout -SimpleMatch 'SHARED_FEATURE_AUDIT_PASS' -Quiet)) {
|
||||
throw "Shared feature audit failed: $ExitCode"
|
||||
}
|
||||
break
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
# World assembler S2 / M3 Round 6
|
||||
|
||||
Date: 2026-10-18. Author: Sol. Base: `d6e6942`, branch `assembler/world`. No commit, push or stash.
|
||||
|
||||
## Shared engine change
|
||||
|
||||
The island-only worker context has been removed from `ShapeWorldInternal.h`.
|
||||
`WorldAssemblyFeatureTileListV1` and `ScopedWorldAssemblyFeatureQueriesV1` now carry a shared,
|
||||
worker-local candidate domain, keyed by immutable recipe/plan identity. Nested scopes restore their
|
||||
predecessor; samples outside the prepared domain use the full evaluator. Tile preparation includes
|
||||
the mesher's normal halo and prepares both existing native families. Derived far-shell field calls
|
||||
stay in that scope too. The old island payload names remain aliases so S1 research tools still build.
|
||||
|
||||
Families retain their mathematics: SurfaceWorld declares XY influence for column writers and finite
|
||||
no-op boxes for volumetric exceptions; islands retain S1's root-aware positive-density certificate
|
||||
and ordered island/connector groups. The engine never assumes that density magnitude is Euclidean
|
||||
distance. Unknown operations stay active. A shared `candidateEvaluationUseful` cost hint is resolved
|
||||
once per domain. The measured one-feature SurfaceWorld and four-island plans prefer the full scan;
|
||||
larger plans retain culling. Audits force candidates on small plans to prove their bounds too. No density arithmetic, recipe serialization/version,
|
||||
voxel-size resolution, queue, Epoch, edit lock or streaming policy was changed.
|
||||
|
||||
The default contract for future caves, shafts, pits, passages and rivers is documented in
|
||||
ARCHITECTURE §8.23. Declare conservative bounds and any value-side proof needed to preserve exact
|
||||
positive values. Preserve operation order; unknown proofs evaluate normally. An air-base family can
|
||||
also declare conservative solid support, allowing the shared column union to shorten a search.
|
||||
Solid-base caves cannot use that air proof. Every new proof needs equal full/candidate hashes and a
|
||||
dropped-needed-feature control.
|
||||
|
||||
Surface biome-site selection already searches a fixed local lattice and is cached by XY. It is not
|
||||
a global feature scan. We preserve that machinery and target its finite feature loops. Existing
|
||||
cave extraction keeps its existing line/spatial bins; this round makes no new cave performance claim.
|
||||
FarShells remains derived repair geometry with existing connector/stratum candidate filtering, rather
|
||||
than becoming another canonical generator. Its field queries inherit the shared scope.
|
||||
|
||||
## Placement cause and correction
|
||||
|
||||
Native island placement previously scanned the entire owner strate, calling a full-plan evaluator
|
||||
at each step. The owner workload used about 7,763 density queries per cell in S1. Its sampling cell
|
||||
was mostly air, so optimizing only the top-anchor helper did not remove the dominant work.
|
||||
|
||||
Snapshots now declare conservative support bounds once. Decoration cells and landmark columns
|
||||
prepare the same shared feature queries as meshing. A shared support-union query skips proven air,
|
||||
including entirely empty columns. The march retains its original lattice phase, crossing budget,
|
||||
four bisections, interpolation, normals and placement hashes. No alternate approximate top surface
|
||||
was introduced. Companion queries get their own nested domain when needed.
|
||||
|
||||
Validation preserves the owner's palette and reports it separately from a deliberately populated
|
||||
fixture. That fixture uses dense deterministic floor placements, both water classifications, the
|
||||
resolved biome tags, and a staged decoration mesh (engine cube fallback if none is available).
|
||||
It checks exact full/candidate transforms and canonical island density residuals, then merges and
|
||||
applies real HISM regions and clears them immediately. CPU totals include cell preparation, merge
|
||||
and region application; the identical application/merge cost is shared by both comparison totals.
|
||||
The isolated HISM fixture bypasses live landmark footprints, which otherwise suppress its instances.
|
||||
Normal region application keeps those footprints enabled. Null RHI does not measure GPU upload,
|
||||
rendering, a rendered frame, or asynchronous cluster-tree completion. Existing native content
|
||||
snapshots still describe the planned base field; this round does not add edit-aware reanchoring.
|
||||
|
||||
## Measurements and proof
|
||||
|
||||
The field audit replays the plans exported from BuildHost's staged owner route. These are the
|
||||
same transient owner-height fixtures described in Round 4: the saved settings point to `DA_Strate4`,
|
||||
while the logged SurfaceWorld layout is reconstructed from `DA_Strate1` without saving an asset.
|
||||
No Season is assigned in these copies. The island plan has 4 islands and 3 connectors; the surface
|
||||
plan has one finite type-4 shelf. The stress cases extend those plans to 256 islands/240 connectors
|
||||
and 64 surface shelves plus one XY height writer and one XY cap writer. They do not change any production recipe.
|
||||
|
||||
### Forced candidate proof and cost
|
||||
|
||||
Each island row samples 64 tiles / 64,000 points, including the normal halo. Each surface row
|
||||
samples 64 tiles / 46,656 points and hashes density, ground, cap and biome ID (186,624 values).
|
||||
Surface timings start both paths with cold column caches by changing only the local validation
|
||||
cache epoch. Final timing replay ran without an overlapping build or Unreal process.
|
||||
|
||||
| Family / plan | Full-scan p95 ms | Forced-candidate p95 ms | List build p95 ms | Full and candidate hash | Negative control |
|
||||
|---|---:|---:|---:|---|---|
|
||||
| Islands, staged owner | 0.9803 | 1.0194 | 0.0012 | `cb94db3ca317d001` | detected |
|
||||
| Islands, 256 stress | 110.570 | 7.3619 | 0.0803 | `d83bac7778f3d62a` | detected |
|
||||
| Surface, staged owner | 0.4748 | 0.4559 | 0.0003 | `4207efd4ac869108` | detected |
|
||||
| Surface, 64 shelves + height/cap writers | 0.7084 | 0.4078 | 0.0011 | `f1c6ea123284cc38` | detected |
|
||||
|
||||
Every row has zero mismatches. Each control removes a needed feature; the island control removes
|
||||
its group certificate too. The shared-scope audit also checks identity/domain fallback, nested empty
|
||||
scope restoration, scope teardown and the full-scan cost hint.
|
||||
|
||||
The owner island point audit offers no useful culling gain. Stress p95 improves about **15×**;
|
||||
3,362 stress lists cost 216.615 ms in total (108 owner lists cost 0.0766 ms). The stress template comes
|
||||
from the actual staged owner plan, whereas S1's standalone audit used Round 3's manifest; its 57×
|
||||
figure is not an apples-to-apples regression comparison.
|
||||
|
||||
Surface's single feature has no material point-query gain. Its column computation alone is about
|
||||
0.368 ms of the 0.475 ms p95, and the existing bounded biome/cap path stays intact. The stress case
|
||||
reduces p95 by about 42% while column cost stays similar (0.3699/0.3552 ms). There is no reason to
|
||||
force a global biome/cap feature list into this owner plan.
|
||||
|
||||
Warmed BuildHost tile timings initially exposed a 7–13% island regression from forcing group
|
||||
bookkeeping on four islands. That led to the shared cost hint. The final default path keeps its small-plan timing:
|
||||
|
||||
| Staged plan | LOD | Full tile p95 ms | Default shared-engine p95 ms | Full / shared shell p95 ms |
|
||||
|---|---:|---:|---:|---:|
|
||||
| Islands | 0 | 94.984 | 95.094 | 0.0002 / 0.0003 |
|
||||
| Islands | 1 | 87.280 | 87.577 | 0.0005 / 0.0003 |
|
||||
| Islands | 7 | 20.442 | 20.409 | 16.918 / 16.882 |
|
||||
| Islands | 8 | 73.038 | 72.923 | 69.930 / 69.844 |
|
||||
| Surface | 0 | 11.238 | 11.178 | 0.0001 / 0.0001 |
|
||||
| Surface | 1 | 7.346 | 7.354 | 0.0001 / 0.0001 |
|
||||
| Surface | 7 | 32.739 | 32.381 | 26.378 / 26.021 |
|
||||
| Surface | 8 | 168.545 | 168.063 | 135.960 / 136.310 |
|
||||
|
||||
Each row measures eight owner clipmap keys after warming both routes, including list preparation,
|
||||
meshing and density hashes. All four output hashes match on every paired key. This is a small,
|
||||
hash-capture workload, not a rendered-frame percentile. The far-shell stage excludes LOD8 cap
|
||||
refinement. There is no measured reason to add another shell-specific feature index for these
|
||||
small owner plans; larger canonical fields inherit their family culling through the shared scope.
|
||||
|
||||
### Island placement and active populated cost
|
||||
|
||||
| Workload | Full scan | Shared engine | Result |
|
||||
|---|---:|---:|---|
|
||||
| Owner palette, cell p95 | 7.0706 ms | 0.2385 ms | about 29.6× faster |
|
||||
| Owner palette, 64-cell preparation | 412.960 ms | 3.840 ms | same zero authored placements |
|
||||
| Populated fixture, populated-cell p95 | 53.9875 ms | 2.1501 ms | 14 populated cells / 572 placements |
|
||||
| Populated fixture, all 64 cells | 3270.478 ms | 28.436 ms | exact transforms match |
|
||||
| Merge / real HISM apply | 0.0623 / 0.6068 ms | same products/cost | 572 applied instances |
|
||||
| Populated active batch CPU total | 3271.147 ms | 29.105 ms | about 112× faster |
|
||||
|
||||
Candidate density calls are 58.84 per authored cell, versus S1's 7,763.38 for the same owner plan.
|
||||
Legacy remains 193.25 calls/cell and 0.2855 ms p95. Stationary manager update p95 is 0.0005 ms;
|
||||
that idle number is separate from the active batch totals above.
|
||||
|
||||
All 572 populated transforms match their full-scan counterparts exactly. All 572 canonical island
|
||||
anchor checks pass; maximum density residual is 0.035156 Core voxel density units. The existing
|
||||
terrain/content tests pass on both island and connector: island height difference is 0.373 cm,
|
||||
connector difference 0.096 cm. Capsule contacts, Blueprint carve/fill, water and atmosphere pass.
|
||||
No approximate anchor shortcut is used.
|
||||
|
||||
The six-entry authored palette still produces zero placements in these 64 cells. The populated
|
||||
fixture is explicit synthetic coverage; it does not claim the cost of the owner's tree Blueprint
|
||||
logic or rendered foliage. Active totals sum worker preparation and synchronous merge/application
|
||||
calls over the whole batch, not one frame. Footprint suppression is disabled only for the isolated
|
||||
fixture, which is immediately cleared. Async HISM tree completion and rendering are not included.
|
||||
The earlier SurfaceWorld populated diagnostic produced 8,192 synthetic transforms with exact
|
||||
full/candidate agreement, but had no mesh application in that build and warm-cache ordering;
|
||||
its speed figures are not used as a SurfaceWorld improvement claim.
|
||||
|
||||
### Default identity
|
||||
|
||||
No recipe version was bumped: all changes select exact evaluators or skip certified air.
|
||||
The full SurfaceWorld actor run reproduced S1's W1/W8/W16 matrix:
|
||||
`0cd2a1a4152ee4aa / 17775c835711e5a3 / a27224958fc27d7b / 3821fea90b134ce4`
|
||||
(density / mesh / payload / topology). Island assembly/recipe/plan remain
|
||||
`9c372e7bfb5b8310 / 5e0370d9f95f1c15 / dbbda4932378047a`.
|
||||
The final-source island W1/W8/W16 matrix is also exactly S1:
|
||||
`4dcfb37585d7d986 / 725a18374c5623de / fb345d8cb319d18b / 76f2846be8efb5f4`.
|
||||
|
||||
The full SurfaceWorld actor pass precedes the final cost hint; the final-source focused replay
|
||||
checks its LOD0/1/7/8 full-versus-default hashes after that selection-only change. Core-off's separate
|
||||
final run proves unchanged legacy density at three probes and 12.5 cm. M2 V1/V2 five-fixture repeats,
|
||||
same-LOD borders, V2 MC identity and 125 doorway phases all pass. Existing doorway contour
|
||||
mismatch remains 22.844 cm in that fixture audit; this round does not claim a new seam solution.
|
||||
|
||||
### Run ledger and limits
|
||||
|
||||
| Run | Result / limit |
|
||||
|---|---|
|
||||
| Standalone Core library builds (four iterations) | all first-attempt passes; final link-safety audit checks 220,200 symbol lines |
|
||||
| BuildHost UBT/UHT builds (six iterations) | all first-attempt passes; latest 62.03 s; 18 Core shims, link-safety 95,738 symbol lines; five staged asset hashes verified |
|
||||
| Preliminary island actor | pass, about 3m57s, 3.19 GiB peak; canonical hashes and 572 anchor checks |
|
||||
| Full SurfaceWorld actor | pass, about 12m15s, 3.58 GiB peak; streaming, collisions, motion, edits, geometry/anchors, W1/W8/W16 |
|
||||
| Island actor with new HISM fixture | exit 1, about 4m14s; landmark footprint suppression hit the fixture count assertion; field/worker/anchor gates passed |
|
||||
| Final island actor, cost hint and isolated HISM fixture | pass, about 3m52s, 3.03 GiB peak; W1/W8/W16, 572 exact anchors and applied instances |
|
||||
| Final focused SurfaceWorld tile replay | pass, about 21s, 2.70 GiB peak; 32 paired LOD0/1/7/8 keys, all hashes equal |
|
||||
| Final M2 V1/V2 fixtures | pass, about 17s, 2.34 GiB peak; repeats, borders, MC identity, 125 doorway phases |
|
||||
| Final Core-off | pass, about 14s, 2.14 GiB peak; legacy density and scale unchanged |
|
||||
| Final composed standalone audit | pass, 7.87s, about 64 MiB peak; all four full/candidate rows exact and controls detected |
|
||||
|
||||
Build iterations cover initial integration, added diagnostics, active fixture application, warmed
|
||||
measurements, duplicate-validation removal, and the cost-hint/fixture fix. Their logs are the six
|
||||
`results/host_build*.log` files and four `results/core_build*.log` files. The standalone audit was
|
||||
replayed as those diagnostics were refined; the final composed stress also exercises XY height/cap
|
||||
writers at unrelated Z values. Every replay passed its field/control assertions.
|
||||
|
||||
One actor run failed its new populated-HISM count
|
||||
assertion after passing field/worker/anchor gates: normal `ApplyRegion` also clears live landmark
|
||||
footprints. The fixture now explicitly isolates those footprints; normal application defaults to
|
||||
keeping them enabled. The failed log is `results/islands_hism_fixture_failed.log` (exit 1, no crash).
|
||||
|
||||
Preliminary surface tile timings used a cold full path followed by a warm candidate path. Those
|
||||
numbers are discarded; the final focused replay warms both paths. The first standalone audit
|
||||
also overlapped compilation; it passed functional controls, but its timings are discarded. Idle
|
||||
replays and the final-source replay are all recorded in `results/shared_audit_ledger.txt`.
|
||||
An audit iteration removed duplicate plan validation from scoped island samples. All standalone
|
||||
field audits passed; `vswhere.exe` was not found by the installed VC setup script, but CL compiled
|
||||
and the audit ran successfully. A documentation-edit attempt failed on Python's default Windows
|
||||
encoding; it changed no files and was corrected with UTF-8/apply_patch.
|
||||
|
||||
The first preliminary island launch used the existing launcher; I applied 12-CPU affinity during
|
||||
that run, then added `-corelimit=12` and 12-CPU affinity to the launcher for subsequent runs. Builds
|
||||
used at most eight UBT actions, or eight UBT plus four standalone compiler actions. W16 remains a
|
||||
logical determinism partition under the 12-CPU execution cap. Each Unreal launch checks 4 GiB free
|
||||
RAM and refuses another Unreal process. Every process is guarded at 8 GiB and 900 seconds.
|
||||
No viewer or GPU capture was launched. No run exceeded its memory/time guard, no timeout occurred,
|
||||
and no run returned `0xC0000142` (so its one-retry rule was never needed).
|
||||
|
||||
Crash audit: `Saved/BuildHost/HostProject/Saved/Crashes/` still contains only
|
||||
`UECC-Windows-F1A3EFD5469F5DD62E68EBBACAC84376_0000` (2026-09-17). The isolated User crash root
|
||||
still contains only `UECC-Windows-7B23387E4235BCFEDE42BC9D637E41CB_0000` (2026-10-08).
|
||||
No new UECC folder exists in the host, staged plugin or isolated User crash roots. The final
|
||||
commandlets finished with zero errors; known missing staged `/Game/VoxelForge/Blocks/NewDataAsset`
|
||||
and certificate-store warnings remain. The failed fixture run logged its explicit test error and
|
||||
exited normally.
|
||||
|
||||
Evidence: `results/SUMMARY.json`, `results/shared_audit_attempt_1.stdout.log`,
|
||||
`results/island_tile_lists.json`, `results/shared_audit_ledger.txt`, `results/surface_full_actor.log`,
|
||||
`results/islands_full_actor_final.log`, `results/surface_warmed_final.log`,
|
||||
`results/m2_fixtures_final.log` and `results/core_off_final.log`. Owner plans exported under
|
||||
BuildHost's isolated User Saved directory are the standalone replay inputs.
|
||||
|
||||
No owner project/editor was opened, closed or built, no `.uasset` was edited, and no junction,
|
||||
symlink, commit, push or stash was created. All authored writes and build outputs stayed inside
|
||||
this plugin's workspace/BuildHost.
|
||||
|
||||
|
||||
## My view of the boundary
|
||||
|
||||
The next structural improvement should be a prepared immutable family-provider table per strate.
|
||||
Today the shared scope is generic, but the world and content snapshot adapters still enumerate the
|
||||
two concrete field families, and preparation rebuilds metadata vectors for each query. A provider
|
||||
could publish stable feature IDs, bounds, an optional value certificate and optional surface/support
|
||||
queries once, while the engine handles consumer domains, ordering, cache lifetime and instrumentation.
|
||||
That would also give future cave/rivers placement the same entry point without adding another
|
||||
content snapshot class. I have not rebuilt the architecture for that proposal in this round.
|
||||
|
||||
Evidence required before doing it: a many-strate preparation profile showing the cost of rebuilding
|
||||
bounds/group summaries; separate point-evaluation and list-build allocation counts; equal full versus
|
||||
prepared hashes across owner plans, halos and edited epochs; a deliberately stale-provider control;
|
||||
and no regression in time to collision-ready terrain or peak memory. Preserve the current bounded
|
||||
lattice path for procedural biomes and the current cave interval engine until a measured replacement
|
||||
wins. A universal list of shapes would not capture those processes or their proofs.
|
||||
|
||||
## Files and compile spots
|
||||
|
||||
New source files:
|
||||
|
||||
- `Standalone/Research/WorldAssemblerM3/Round6/SharedFeatureListAudit.cpp` — standalone owner/stress audit.
|
||||
- `Standalone/Research/WorldAssemblerM3/Round6/BuildSharedFeatureListAudit.ps1` — guarded audit compile/run script.
|
||||
|
||||
Modified runtime/Core sources:
|
||||
|
||||
- `Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h`
|
||||
- `Standalone/Core/src/WorldAssemblerInternal.h`
|
||||
- `Standalone/Core/src/FloatingIslandsInternal.h`
|
||||
- `Standalone/Core/src/ShapeWorldInternal.h`
|
||||
- `Standalone/Core/src/VoxelForgeCore.cpp`
|
||||
- `Source/VoxelForge/Private/VoxelContentManager.cpp`
|
||||
- `Source/VoxelForge/Public/VoxelContentManager.h`
|
||||
- `Source/VoxelForgeEditor/Private/VoxelForgeExploreCommandlet.cpp`
|
||||
|
||||
Also updated `Tools/TestVoxelForgeCoreWorldHost.ps1`, CODEMAP §3, ARCHITECTURE §8.23 and the dialogue.
|
||||
Likely compile spots: the public Core API/export boundary and canonical Core shim; shared scope/TLS
|
||||
linkage; `VoxelContentManager.h` parsing and its runtime translation unit; editor commandlet timing
|
||||
and fixture code. No new runtime translation unit or manifest shim is required.
|
||||
|
||||
## Owner note
|
||||
|
||||
Keep Core enabled at the existing 25 cm setting. There is no new generator setting to configure.
|
||||
The shared engine now narrows terrain searches for both native families and skips empty space when
|
||||
placing island content. Terrain shapes and default hashes are preserved. The populated validation
|
||||
fixture measures placement without changing your decoration assets. Ready to build your project
|
||||
when you choose; I only build and launch the isolated plugin BuildHost.
|
||||
@@ -0,0 +1,601 @@
|
||||
#include "VoxelForgeCore/VoxelForgeCore.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <numeric>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace VoxelForgeCore;
|
||||
using Clock = std::chrono::steady_clock;
|
||||
constexpr std::int64_t Q = WorldAssemblySubvoxelsPerVoxel;
|
||||
constexpr std::int64_t TileQ = 32 * Q;
|
||||
constexpr std::int64_t TileStepQ = 4 * Q;
|
||||
constexpr std::int64_t MesherHaloQ = Q;
|
||||
|
||||
struct Tile
|
||||
{
|
||||
std::array<std::int64_t, 3> minimum{};
|
||||
std::array<std::int64_t, 3> maximum{};
|
||||
FloatingIslandTileFeatureListV1 featureList;
|
||||
double buildMilliseconds = 0.0;
|
||||
};
|
||||
|
||||
struct Measurement
|
||||
{
|
||||
std::uint64_t tilesBuilt = 0;
|
||||
std::uint64_t sampledTiles = 0;
|
||||
std::uint64_t samples = 0;
|
||||
std::uint64_t candidateEvaluations = 0;
|
||||
std::uint64_t fullEvaluations = 0;
|
||||
std::uint64_t exactMismatches = 0;
|
||||
std::uint64_t droppedFeatureDetected = 0;
|
||||
double listBuildTotalMilliseconds = 0.0;
|
||||
double listBuildP95Milliseconds = 0.0;
|
||||
double beforeP95Milliseconds = 0.0;
|
||||
double afterP95Milliseconds = 0.0;
|
||||
double beforeMedianMilliseconds = 0.0;
|
||||
double afterMedianMilliseconds = 0.0;
|
||||
double meanCandidateFeatures = 0.0;
|
||||
double p95CandidateFeatures = 0.0;
|
||||
std::string beforeHash;
|
||||
std::string afterHash;
|
||||
bool negativeControlPassed = false;
|
||||
};
|
||||
|
||||
std::string Hex64(std::uint64_t value)
|
||||
{
|
||||
std::ostringstream output;
|
||||
output << std::hex << std::setfill('0') << std::setw(16) << value;
|
||||
return output.str();
|
||||
}
|
||||
|
||||
std::uint64_t HashValues(const std::vector<std::int64_t>& values)
|
||||
{
|
||||
std::uint64_t hash = 14695981039346656037ull;
|
||||
for (const auto value : values)
|
||||
for (int byte = 0; byte < 8; ++byte)
|
||||
{
|
||||
hash ^= static_cast<std::uint8_t>(static_cast<std::uint64_t>(value) >> (byte * 8));
|
||||
hash *= 1099511628211ull;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
double Percentile95(std::vector<double> values)
|
||||
{
|
||||
if (values.empty()) return 0.0;
|
||||
std::sort(values.begin(), values.end());
|
||||
const std::size_t index = (values.size() * 95 + 99) / 100 - 1;
|
||||
return values[std::min(index, values.size() - 1)];
|
||||
}
|
||||
|
||||
double Median(std::vector<double> values)
|
||||
{
|
||||
if (values.empty()) return 0.0;
|
||||
std::sort(values.begin(), values.end());
|
||||
const std::size_t middle = values.size() / 2;
|
||||
if (values.size() & 1u) return values[middle];
|
||||
return 0.5 * (values[middle - 1] + values[middle]);
|
||||
}
|
||||
|
||||
std::int64_t FloorDiv(std::int64_t value, std::int64_t divisor)
|
||||
{
|
||||
std::int64_t quotient = value / divisor;
|
||||
const std::int64_t remainder = value % divisor;
|
||||
if (remainder != 0 && ((remainder < 0) != (divisor < 0))) --quotient;
|
||||
return quotient;
|
||||
}
|
||||
|
||||
void ShiftBounds(std::array<std::int64_t, 3>& minimum,
|
||||
std::array<std::int64_t, 3>& maximum, const std::array<std::int64_t, 3>& delta)
|
||||
{
|
||||
for (std::size_t axis = 0; axis < 3; ++axis)
|
||||
{ minimum[axis] += delta[axis]; maximum[axis] += delta[axis]; }
|
||||
}
|
||||
|
||||
std::uint64_t SyntheticId(std::uint32_t index, std::uint64_t salt)
|
||||
{
|
||||
std::uint64_t value = (static_cast<std::uint64_t>(index) << 32) ^ salt;
|
||||
value += 0x9e3779b97f4a7c15ull;
|
||||
value = (value ^ (value >> 30)) * 0xbf58476d1ce4e5b9ull;
|
||||
value = (value ^ (value >> 27)) * 0x94d049bb133111ebull;
|
||||
value ^= value >> 31;
|
||||
return value == 0 ? 1 : value;
|
||||
}
|
||||
|
||||
FloatingIslandPlanV1 MakeStressPlan(const FloatingIslandRecipeV1& recipe,
|
||||
const FloatingIslandPlanV1& source, std::size_t islandCount)
|
||||
{
|
||||
if (source.islands.empty()) throw std::runtime_error("source plan has no island template");
|
||||
FloatingIslandPlanV1 result;
|
||||
result.islands.reserve(islandCount);
|
||||
const auto& prototype = source.islands.front();
|
||||
constexpr std::size_t Columns = 16;
|
||||
const std::int64_t spacing = 80 * Q;
|
||||
for (std::size_t index = 0; index < islandCount; ++index)
|
||||
{
|
||||
FloatingIslandAnchorV1 island = prototype;
|
||||
const std::int64_t dx = static_cast<std::int64_t>(index % Columns) * spacing;
|
||||
const std::int64_t dy = static_cast<std::int64_t>(index / Columns) * spacing;
|
||||
const std::int64_t dz = static_cast<std::int64_t>(index % 3) * 4 * Q;
|
||||
const std::array<std::int64_t, 3> delta{dx, dy, dz};
|
||||
island.centerSubvoxels = {prototype.centerSubvoxels[0] + dx,
|
||||
prototype.centerSubvoxels[1] + dy, prototype.centerSubvoxels[2] + dz};
|
||||
island.topZSubvoxels += dz;
|
||||
island.bottomZSubvoxels += dz;
|
||||
ShiftBounds(island.influenceMinimumSubvoxels, island.influenceMaximumSubvoxels, delta);
|
||||
island.ordinal = static_cast<std::uint32_t>(index);
|
||||
island.stableId = SyntheticId(static_cast<std::uint32_t>(index), 0x49534c414e44ull);
|
||||
result.islands.push_back(island);
|
||||
}
|
||||
|
||||
result.clusterEdges.reserve(islandCount - islandCount / Columns);
|
||||
for (std::size_t index = 0; index < islandCount; ++index)
|
||||
{
|
||||
if (index % Columns + 1 >= Columns || index + 1 >= islandCount) continue;
|
||||
const auto& from = result.islands[index];
|
||||
const auto& to = result.islands[index + 1];
|
||||
FloatingIslandConnectorV1 edge;
|
||||
edge.stableId = SyntheticId(static_cast<std::uint32_t>(index), 0x425249444745ull);
|
||||
edge.fromIslandId = from.stableId;
|
||||
edge.toIslandId = to.stableId;
|
||||
edge.startSubvoxels = {from.centerSubvoxels[0] + from.radiusSubvoxels,
|
||||
from.centerSubvoxels[1], from.topZSubvoxels};
|
||||
edge.endSubvoxels = {to.centerSubvoxels[0] - to.radiusSubvoxels,
|
||||
to.centerSubvoxels[1], to.topZSubvoxels};
|
||||
edge.halfWidthSubvoxels = recipe.bridgeHalfWidthSubvoxels;
|
||||
edge.thicknessSubvoxels = recipe.bridgeThicknessSubvoxels;
|
||||
const std::int64_t pad = recipe.blendRadiusSubvoxels + recipe.roughnessSubvoxels;
|
||||
const std::int64_t archDepth = recipe.geometryVersion >= 2
|
||||
? 2 * edge.thicknessSubvoxels : 0;
|
||||
const std::int64_t xyPad = edge.halfWidthSubvoxels + pad;
|
||||
edge.influenceMinimumSubvoxels = {
|
||||
std::min(edge.startSubvoxels[0], edge.endSubvoxels[0]) - xyPad,
|
||||
std::min(edge.startSubvoxels[1], edge.endSubvoxels[1]) - xyPad,
|
||||
std::min(edge.startSubvoxels[2], edge.endSubvoxels[2])
|
||||
- edge.thicknessSubvoxels - pad - archDepth};
|
||||
edge.influenceMaximumSubvoxels = {
|
||||
std::max(edge.startSubvoxels[0], edge.endSubvoxels[0]) + xyPad,
|
||||
std::max(edge.startSubvoxels[1], edge.endSubvoxels[1]) + xyPad,
|
||||
std::max(edge.startSubvoxels[2], edge.endSubvoxels[2]) + pad};
|
||||
result.clusterEdges.push_back(edge);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<Tile> BuildMixedTiles(const FloatingIslandFieldV1& field,
|
||||
const std::array<std::int64_t, 3>& tileLimitMinimum,
|
||||
const std::array<std::int64_t, 3>& tileLimitMaximum,
|
||||
Measurement& measurement)
|
||||
{
|
||||
std::vector<Tile> tiles;
|
||||
for (std::int64_t z = tileLimitMinimum[2]; z <= tileLimitMaximum[2]; z += TileQ)
|
||||
for (std::int64_t y = tileLimitMinimum[1]; y <= tileLimitMaximum[1]; y += TileQ)
|
||||
for (std::int64_t x = tileLimitMinimum[0]; x <= tileLimitMaximum[0]; x += TileQ)
|
||||
{
|
||||
Tile tile;
|
||||
tile.minimum = {x, y, z};
|
||||
tile.maximum = {x + TileQ, y + TileQ, z + TileQ};
|
||||
const std::array<std::int64_t, 3> sampleMinimum{
|
||||
x - MesherHaloQ, y - MesherHaloQ, z - MesherHaloQ};
|
||||
const std::array<std::int64_t, 3> sampleMaximum{
|
||||
x + TileQ + MesherHaloQ, y + TileQ + MesherHaloQ, z + TileQ + MesherHaloQ};
|
||||
const auto begin = Clock::now();
|
||||
tile.featureList = field.buildFeatureTileList(sampleMinimum, sampleMaximum);
|
||||
tile.buildMilliseconds = std::chrono::duration<double, std::milli>(Clock::now() - begin).count();
|
||||
measurement.listBuildTotalMilliseconds += tile.buildMilliseconds;
|
||||
++measurement.tilesBuilt;
|
||||
if (!tile.featureList.featureIndices.empty()) tiles.push_back(std::move(tile));
|
||||
}
|
||||
return tiles;
|
||||
}
|
||||
|
||||
Measurement MeasureField(const FloatingIslandFieldV1& field,
|
||||
std::array<std::int64_t, 3> limitMinimum,
|
||||
std::array<std::int64_t, 3> limitMaximum)
|
||||
{
|
||||
Measurement measurement;
|
||||
for (std::size_t axis = 0; axis < 3; ++axis)
|
||||
{
|
||||
limitMinimum[axis] = FloorDiv(limitMinimum[axis], TileQ) * TileQ;
|
||||
limitMaximum[axis] = FloorDiv(limitMaximum[axis], TileQ) * TileQ;
|
||||
}
|
||||
auto tiles = BuildMixedTiles(field, limitMinimum, limitMaximum, measurement);
|
||||
if (tiles.empty()) throw std::runtime_error("tile bounds produced no candidate tiles");
|
||||
std::vector<double> buildTimes, candidateCounts;
|
||||
buildTimes.reserve(tiles.size()); candidateCounts.reserve(tiles.size());
|
||||
for (const Tile& tile : tiles)
|
||||
{ buildTimes.push_back(tile.buildMilliseconds); candidateCounts.push_back(static_cast<double>(tile.featureList.featureIndices.size())); }
|
||||
measurement.listBuildP95Milliseconds = Percentile95(std::move(buildTimes));
|
||||
measurement.meanCandidateFeatures = std::accumulate(candidateCounts.begin(), candidateCounts.end(), 0.0)
|
||||
/ static_cast<double>(candidateCounts.size());
|
||||
measurement.p95CandidateFeatures = Percentile95(std::move(candidateCounts));
|
||||
|
||||
constexpr std::size_t MaximumSampleTiles = 64;
|
||||
if (tiles.size() > MaximumSampleTiles)
|
||||
{
|
||||
std::vector<Tile> selected;
|
||||
selected.reserve(MaximumSampleTiles);
|
||||
for (std::size_t slot = 0; slot < MaximumSampleTiles; ++slot)
|
||||
{
|
||||
const std::size_t index = slot * (tiles.size() - 1) / (MaximumSampleTiles - 1);
|
||||
selected.push_back(std::move(tiles[index]));
|
||||
}
|
||||
tiles = std::move(selected);
|
||||
}
|
||||
|
||||
std::vector<double> beforeTimes, afterTimes;
|
||||
std::vector<std::int64_t> beforeValues, afterValues;
|
||||
beforeTimes.reserve(tiles.size()); afterTimes.reserve(tiles.size());
|
||||
for (const Tile& tile : tiles)
|
||||
{
|
||||
// Cover the mesher's one-sample LOD0 halo as well as the tile at four-voxel spacing.
|
||||
// Couvrir la marge d'un echantillon du maillage LOD0 et la tuile a pas de quatre voxels.
|
||||
const auto buildAxis = [](std::int64_t minimum, std::int64_t maximum)
|
||||
{
|
||||
std::vector<std::int64_t> values;
|
||||
const std::int64_t start = minimum - MesherHaloQ;
|
||||
const std::int64_t end = maximum + MesherHaloQ;
|
||||
for (std::int64_t value = start; value <= end; value += TileStepQ)
|
||||
values.push_back(value);
|
||||
if (values.empty() || values.back() != end) values.push_back(end);
|
||||
return values;
|
||||
};
|
||||
const auto xs = buildAxis(tile.minimum[0], tile.maximum[0]);
|
||||
const auto ys = buildAxis(tile.minimum[1], tile.maximum[1]);
|
||||
const auto zs = buildAxis(tile.minimum[2], tile.maximum[2]);
|
||||
std::vector<std::array<std::int64_t, 3>> points;
|
||||
points.reserve(xs.size() * ys.size() * zs.size());
|
||||
for (const std::int64_t z : zs)
|
||||
for (const std::int64_t y : ys)
|
||||
for (const std::int64_t x : xs)
|
||||
points.push_back({x, y, z});
|
||||
measurement.samples += points.size();
|
||||
measurement.fullEvaluations += points.size();
|
||||
measurement.candidateEvaluations += points.size() * tile.featureList.featureIndices.size();
|
||||
|
||||
const auto beforeStart = Clock::now();
|
||||
for (const auto& point : points)
|
||||
beforeValues.push_back(field.densitySubvoxels(point[0], point[1], point[2]));
|
||||
beforeTimes.push_back(std::chrono::duration<double, std::milli>(Clock::now() - beforeStart).count());
|
||||
|
||||
const auto afterStart = Clock::now();
|
||||
const WorldAssemblyFeatureQueryV1 query{field.recipe(),field.plan(),tile.featureList};
|
||||
{
|
||||
const ScopedWorldAssemblyFeatureQueriesV1 scope(std::span(&query,1),true);
|
||||
for (const auto& point : points)
|
||||
afterValues.push_back(field.densitySubvoxels(point[0],point[1],point[2]));
|
||||
}
|
||||
afterTimes.push_back(std::chrono::duration<double, std::milli>(Clock::now() - afterStart).count());
|
||||
++measurement.sampledTiles;
|
||||
}
|
||||
measurement.beforeP95Milliseconds = Percentile95(beforeTimes);
|
||||
measurement.afterP95Milliseconds = Percentile95(afterTimes);
|
||||
measurement.beforeMedianMilliseconds = Median(beforeTimes);
|
||||
measurement.afterMedianMilliseconds = Median(afterTimes);
|
||||
measurement.beforeHash = Hex64(HashValues(beforeValues));
|
||||
measurement.afterHash = Hex64(HashValues(afterValues));
|
||||
const std::size_t common = std::min(beforeValues.size(), afterValues.size());
|
||||
for (std::size_t index = 0; index < common; ++index)
|
||||
if (beforeValues[index] != afterValues[index]) ++measurement.exactMismatches;
|
||||
|
||||
if (field.plan() && !field.plan()->islands.empty())
|
||||
{
|
||||
constexpr std::uint32_t droppedFeature = 0;
|
||||
const auto& island = field.plan()->islands.front();
|
||||
const std::array<std::int64_t, 3> point{island.centerSubvoxels[0], island.centerSubvoxels[1],
|
||||
island.bottomZSubvoxels + (island.topZSubvoxels - island.bottomZSubvoxels) / 2};
|
||||
std::array<std::int64_t, 3> minimum{};
|
||||
std::array<std::int64_t, 3> maximum{};
|
||||
for (std::size_t axis = 0; axis < 3; ++axis)
|
||||
{
|
||||
minimum[axis] = FloorDiv(point[axis], TileQ) * TileQ;
|
||||
maximum[axis] = minimum[axis] + TileQ;
|
||||
}
|
||||
auto sampleMinimum = minimum;
|
||||
auto sampleMaximum = maximum;
|
||||
for (std::size_t axis = 0; axis < 3; ++axis)
|
||||
{
|
||||
sampleMinimum[axis] -= MesherHaloQ;
|
||||
sampleMaximum[axis] += MesherHaloQ;
|
||||
}
|
||||
FloatingIslandTileFeatureListV1 dropped = field.buildFeatureTileList(
|
||||
sampleMinimum, sampleMaximum);
|
||||
auto candidate = std::lower_bound(dropped.featureIndices.begin(), dropped.featureIndices.end(),
|
||||
droppedFeature);
|
||||
if (candidate != dropped.featureIndices.end() && *candidate == droppedFeature)
|
||||
{
|
||||
dropped.featureIndices.erase(candidate);
|
||||
for (std::size_t axis = 0; axis < 3; ++axis)
|
||||
{
|
||||
dropped.groupBounds[droppedFeature].minimumSubvoxels[axis] += 100000000000ll;
|
||||
dropped.groupBounds[droppedFeature].maximumSubvoxels[axis] += 100000000000ll;
|
||||
}
|
||||
const auto order = std::find(dropped.groupSearchOrder.begin(),
|
||||
dropped.groupSearchOrder.end(), droppedFeature);
|
||||
if (order != dropped.groupSearchOrder.end())
|
||||
{
|
||||
const std::size_t orderIndex = static_cast<std::size_t>(order - dropped.groupSearchOrder.begin());
|
||||
dropped.groupSearchOrder.erase(order);
|
||||
dropped.groupDistanceLowerBoundsSubvoxels.erase(
|
||||
dropped.groupDistanceLowerBoundsSubvoxels.begin() + orderIndex);
|
||||
dropped.groupSearchComplete = false;
|
||||
const auto full = field.densitySubvoxels(point[0], point[1], point[2]);
|
||||
const WorldAssemblyFeatureQueryV1 badQuery{field.recipe(),field.plan(),dropped};
|
||||
const ScopedWorldAssemblyFeatureQueriesV1 badScope(std::span(&badQuery,1),true);
|
||||
const auto bad = field.densitySubvoxels(point[0],point[1],point[2]);
|
||||
if (full != bad) ++measurement.droppedFeatureDetected;
|
||||
}
|
||||
}
|
||||
}
|
||||
measurement.negativeControlPassed = measurement.droppedFeatureDetected > 0;
|
||||
return measurement;
|
||||
}
|
||||
|
||||
void Print(const char* label, const Measurement& measurement,
|
||||
std::size_t islandCount, std::size_t connectorCount)
|
||||
{
|
||||
std::cout << label << " islands=" << islandCount << " connectors=" << connectorCount
|
||||
<< " forced_candidates=1 list_tiles_built=" << measurement.tilesBuilt
|
||||
<< " sampled_tiles=" << measurement.sampledTiles
|
||||
<< " sample_count=" << measurement.samples
|
||||
<< " mean_candidates=" << measurement.meanCandidateFeatures
|
||||
<< " p95_candidates=" << measurement.p95CandidateFeatures
|
||||
<< " list_build_total_ms=" << measurement.listBuildTotalMilliseconds
|
||||
<< " list_build_p95_ms=" << measurement.listBuildP95Milliseconds
|
||||
<< " full_tile_p95_ms=" << measurement.beforeP95Milliseconds
|
||||
<< " candidate_tile_p95_ms=" << measurement.afterP95Milliseconds
|
||||
<< " full_tile_median_ms=" << measurement.beforeMedianMilliseconds
|
||||
<< " candidate_tile_median_ms=" << measurement.afterMedianMilliseconds
|
||||
<< " exact_mismatches=" << measurement.exactMismatches
|
||||
<< " full_hash=" << measurement.beforeHash
|
||||
<< " candidate_hash=" << measurement.afterHash
|
||||
<< " negative_control_detected=" << measurement.negativeControlPassed << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
int IslandAuditMain(int argc, char** argv)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (argc != 3)
|
||||
{ std::cerr << "usage: FloatingIslandTileListAudit <manifest.json> <output.json>\n"; return 2; }
|
||||
std::ifstream input(argv[1], std::ios::binary);
|
||||
if (!input) throw std::runtime_error("could not open the recorded round-3 island manifest");
|
||||
const std::string json{std::istreambuf_iterator<char>(input), std::istreambuf_iterator<char>()};
|
||||
std::string error;
|
||||
const auto manifest = FloatingIslandManifestV1::FromJson(json, error);
|
||||
if (!manifest || !manifest->validate(error)) throw std::runtime_error("manifest invalid: " + error);
|
||||
|
||||
FloatingIslandFieldV1 field(manifest->recipe, manifest->plan);
|
||||
if (!field.isValid()) throw std::runtime_error("round-3 production field did not validate");
|
||||
const auto bounds = field.influenceBounds();
|
||||
const auto& center=manifest->plan.islands.front().centerSubvoxels;
|
||||
WorldAssemblyFeatureQueryV1 guardQuery{field.recipe(),field.plan(),field.buildFeatureTileList(center,center)};
|
||||
if(!guardQuery.features.candidateEvaluationUseful)
|
||||
{
|
||||
const ScopedWorldAssemblyFeatureQueriesV1 preferredFull(std::span(&guardQuery,1));
|
||||
if(ScopedWorldAssemblyFeatureQueriesV1::find(field.recipe(),field.plan(),center[0],center[1],center[2]))
|
||||
throw std::runtime_error("shared scope ignored the full-scan cost hint");
|
||||
}
|
||||
const auto outsideX=center[0]+1000*Q;
|
||||
const auto outsideFull=field.densitySubvoxels(outsideX,center[1],center[2]);
|
||||
{
|
||||
const ScopedWorldAssemblyFeatureQueriesV1 scope(std::span(&guardQuery,1),true);
|
||||
if(field.densitySubvoxels(outsideX,center[1],center[2])!=outsideFull)
|
||||
throw std::runtime_error("outside-domain fallback changed density");
|
||||
{
|
||||
const ScopedWorldAssemblyFeatureQueriesV1 emptyScope(std::span<const WorldAssemblyFeatureQueryV1>{});
|
||||
if(ScopedWorldAssemblyFeatureQueriesV1::find(field.recipe(),field.plan(),center[0],center[1],center[2]))
|
||||
throw std::runtime_error("nested empty scope inherited candidates");
|
||||
}
|
||||
if(!ScopedWorldAssemblyFeatureQueriesV1::find(field.recipe(),field.plan(),center[0],center[1],center[2]))
|
||||
throw std::runtime_error("nested scope did not restore candidates");
|
||||
}
|
||||
if(ScopedWorldAssemblyFeatureQueriesV1::find(field.recipe(),field.plan(),center[0],center[1],center[2]))
|
||||
throw std::runtime_error("scope leaked candidates");
|
||||
const Measurement today = MeasureField(field, bounds.minimumSubvoxels, bounds.maximumSubvoxels);
|
||||
|
||||
const FloatingIslandPlanV1 stressPlan = MakeStressPlan(manifest->recipe, manifest->plan, 256);
|
||||
FloatingIslandFieldV1 stressField(manifest->recipe, stressPlan);
|
||||
if (!stressField.isValid()) throw std::runtime_error("synthetic stress field did not validate");
|
||||
const auto stressBounds = stressField.influenceBounds();
|
||||
const Measurement stress = MeasureField(stressField,
|
||||
stressBounds.minimumSubvoxels, stressBounds.maximumSubvoxels);
|
||||
|
||||
Print("today", today, manifest->plan.islands.size(), manifest->plan.clusterEdges.size());
|
||||
Print("stress", stress, stressPlan.islands.size(), stressPlan.clusterEdges.size());
|
||||
std::ofstream output(argv[2], std::ios::trunc);
|
||||
if (!output) throw std::runtime_error("could not create audit result JSON");
|
||||
output << std::setprecision(12) << "{\n"
|
||||
<< " \"baseline\":{\"islands\":" << manifest->plan.islands.size()
|
||||
<< ",\"connectors\":" << manifest->plan.clusterEdges.size()
|
||||
<< ",\"tiles_built\":" << today.tilesBuilt << ",\"sampled_tiles\":" << today.sampledTiles
|
||||
<< ",\"samples\":" << today.samples << ",\"mean_candidates\":" << today.meanCandidateFeatures
|
||||
<< ",\"p95_candidates\":" << today.p95CandidateFeatures
|
||||
<< ",\"list_build_total_ms\":" << today.listBuildTotalMilliseconds
|
||||
<< ",\"list_build_p95_ms\":" << today.listBuildP95Milliseconds
|
||||
<< ",\"before_p95_ms\":" << today.beforeP95Milliseconds
|
||||
<< ",\"after_p95_ms\":" << today.afterP95Milliseconds
|
||||
<< ",\"before_median_ms\":" << today.beforeMedianMilliseconds
|
||||
<< ",\"after_median_ms\":" << today.afterMedianMilliseconds
|
||||
<< ",\"exact_mismatches\":" << today.exactMismatches
|
||||
<< ",\"before_hash\":\"" << today.beforeHash << "\",\"after_hash\":\"" << today.afterHash
|
||||
<< "\",\"negative_control\":" << (today.negativeControlPassed ? "true" : "false") << "},\n"
|
||||
<< " \"stress\":{\"islands\":" << stressPlan.islands.size()
|
||||
<< ",\"connectors\":" << stressPlan.clusterEdges.size()
|
||||
<< ",\"tiles_built\":" << stress.tilesBuilt << ",\"sampled_tiles\":" << stress.sampledTiles
|
||||
<< ",\"samples\":" << stress.samples << ",\"mean_candidates\":" << stress.meanCandidateFeatures
|
||||
<< ",\"p95_candidates\":" << stress.p95CandidateFeatures
|
||||
<< ",\"list_build_total_ms\":" << stress.listBuildTotalMilliseconds
|
||||
<< ",\"list_build_p95_ms\":" << stress.listBuildP95Milliseconds
|
||||
<< ",\"before_p95_ms\":" << stress.beforeP95Milliseconds
|
||||
<< ",\"after_p95_ms\":" << stress.afterP95Milliseconds
|
||||
<< ",\"before_median_ms\":" << stress.beforeMedianMilliseconds
|
||||
<< ",\"after_median_ms\":" << stress.afterMedianMilliseconds
|
||||
<< ",\"exact_mismatches\":" << stress.exactMismatches
|
||||
<< ",\"before_hash\":\"" << stress.beforeHash << "\",\"after_hash\":\"" << stress.afterHash
|
||||
<< "\",\"negative_control\":" << (stress.negativeControlPassed ? "true" : "false") << "}\n}\n";
|
||||
if (!today.negativeControlPassed || !stress.negativeControlPassed)
|
||||
throw std::runtime_error("dropped-feature negative control was not detected");
|
||||
if (today.exactMismatches || stress.exactMismatches)
|
||||
throw std::runtime_error("tile feature evaluation changed canonical field values");
|
||||
std::cout << "TILE_LIST_AUDIT_PASS\n";
|
||||
return 0;
|
||||
}
|
||||
catch (const std::exception& exception)
|
||||
{
|
||||
std::cerr << "FLOATING_ISLAND_TILE_LIST_AUDIT_FAIL: " << exception.what() << '\n';
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Surface finite features use the same scope as islands. Biome sites stay in their fixed local window.
|
||||
// Les features finies de surface partagent la portee; les sites biomes restent dans leur fenetre locale.
|
||||
void MeasureSurface(WorldAssemblyRecipeV1 recipe, WorldAssemblyStratumPlanV1 plan,
|
||||
const char* label, bool stress)
|
||||
{
|
||||
if(stress)
|
||||
{
|
||||
const auto originals=plan.features;
|
||||
for(int copy=1;copy<64;++copy)
|
||||
for(auto feature:originals)
|
||||
{
|
||||
feature.stableId=SyntheticId(static_cast<std::uint32_t>(plan.features.size()),0x53555246);
|
||||
for(int axis=0;axis<2;++axis)
|
||||
{
|
||||
const auto delta=(axis==0 ? copy%8 : copy/8)*512*Q;
|
||||
feature.minimumSubvoxels[axis]+=delta;
|
||||
feature.maximumSubvoxels[axis]+=delta;
|
||||
}
|
||||
plan.features.push_back(feature);
|
||||
}
|
||||
}
|
||||
if(stress)
|
||||
{
|
||||
// One composed stress case also exercises XY column writers at unrelated Z values.
|
||||
// Une fixture composee couvre aussi les modificateurs XY a des altitudes independantes.
|
||||
const auto& shelf=plan.features.front();
|
||||
WorldAssemblyFeatureV1 cliff;
|
||||
cliff.stableId=SyntheticId(10000,0x434c494646);
|
||||
cliff.type=1;
|
||||
cliff.minimumSubvoxels={(shelf.minimumSubvoxels[0]+shelf.maximumSubvoxels[0])/2-8*Q,
|
||||
(shelf.minimumSubvoxels[1]+shelf.maximumSubvoxels[1])/2-8*Q,0};
|
||||
cliff.maximumSubvoxels={cliff.minimumSubvoxels[0]+16*Q,cliff.minimumSubvoxels[1]+16*Q,0};
|
||||
cliff.parametersSubvoxels={8*Q,8*Q,0,0};
|
||||
auto cap=cliff;
|
||||
cap.stableId=SyntheticId(10001,0x434150);
|
||||
cap.type=3;
|
||||
cap.parametersSubvoxels={4*Q,32*Q,8*Q,0};
|
||||
plan.features.push_back(cliff);
|
||||
plan.features.push_back(cap);
|
||||
}
|
||||
if(stress) plan.contentHash ^= 0x5354524553534341ull; // Separate validation cache epochs. / Epoques distinctes.
|
||||
Heightfield2D field(recipe,plan);
|
||||
std::vector<double> fullTimes,candidateTimes,buildTimes,counts,fullColumnTimes,candidateColumnTimes;
|
||||
std::vector<std::int64_t> fullValues,candidateValues;
|
||||
std::uint64_t mismatches=0;
|
||||
bool negative=false;
|
||||
if(plan.features.empty())throw std::runtime_error("surface has no finite features to audit");
|
||||
// 64 bounded tile probes, spanning each feature and its faces, including normal halos.
|
||||
for(int tile=0;tile<64;++tile)
|
||||
{
|
||||
const auto& feature=plan.features[static_cast<std::size_t>(tile)%plan.features.size()];
|
||||
const std::int64_t x=(feature.minimumSubvoxels[0]+feature.maximumSubvoxels[0])/2;
|
||||
const std::int64_t y=(feature.minimumSubvoxels[1]+feature.maximumSubvoxels[1])/2;
|
||||
const auto column=field.point(x,y,0);
|
||||
const std::int64_t z=(tile%3==0) ? column.groundHeightSubvoxels :
|
||||
(tile%3==1 ? column.capHeightSubvoxels :
|
||||
(feature.minimumSubvoxels[2]+feature.maximumSubvoxels[2])/2);
|
||||
const std::array<std::int64_t,3> lo{x-17*Q,y-17*Q,z-17*Q};
|
||||
const std::array<std::int64_t,3> hi{x+17*Q,y+17*Q,z+17*Q};
|
||||
const auto buildStart=Clock::now();
|
||||
WorldAssemblyFeatureQueryV1 query{field.recipe(),field.plan(),field.buildFeatureTileList(lo,hi)};
|
||||
buildTimes.push_back(std::chrono::duration<double,std::milli>(Clock::now()-buildStart).count());
|
||||
counts.push_back(static_cast<double>(query.features.featureIndices.size()));
|
||||
auto sample=[&](std::vector<std::int64_t>& values)
|
||||
{
|
||||
for(int iz=0;iz<9;++iz)for(int iy=0;iy<9;++iy)for(int ix=0;ix<9;++ix)
|
||||
{
|
||||
const auto p=field.point(lo[0]+ix*4*Q,lo[1]+iy*4*Q,lo[2]+iz*4*Q);
|
||||
values.push_back(p.densitySubvoxels);
|
||||
values.push_back(p.groundHeightSubvoxels);
|
||||
values.push_back(p.capHeightSubvoxels);
|
||||
values.push_back(p.biomeId);
|
||||
}
|
||||
};
|
||||
// Change only the local cache epoch: both timed paths start with cold columns.
|
||||
// Epoch de cache local seulement : les deux parcours partent de colonnes froides.
|
||||
++plan.contentHash;
|
||||
Heightfield2D::resetThreadColumnCacheStats();
|
||||
const auto start=Clock::now();sample(fullValues);
|
||||
fullTimes.push_back(std::chrono::duration<double,std::milli>(Clock::now()-start).count());
|
||||
fullColumnTimes.push_back(Heightfield2D::threadColumnCacheStats().columnComputeMilliseconds);
|
||||
++plan.contentHash;
|
||||
Heightfield2D::resetThreadColumnCacheStats();
|
||||
const auto candidateStart=Clock::now();
|
||||
{const ScopedWorldAssemblyFeatureQueriesV1 scope(std::span(&query,1),true);sample(candidateValues);}
|
||||
candidateTimes.push_back(std::chrono::duration<double,std::milli>(Clock::now()-candidateStart).count());
|
||||
candidateColumnTimes.push_back(Heightfield2D::threadColumnCacheStats().columnComputeMilliseconds);
|
||||
if(!negative)
|
||||
{
|
||||
if (!query.features.featureIndices.empty())
|
||||
query.features.featureIndices.erase(query.features.featureIndices.begin());
|
||||
std::vector<std::int64_t> bad;
|
||||
++plan.contentHash;
|
||||
{const ScopedWorldAssemblyFeatureQueriesV1 scope(std::span(&query,1),true);sample(bad);}
|
||||
const auto offset=fullValues.size()-bad.size();
|
||||
for(std::size_t i=0;i<bad.size();++i)if(bad[i]!=fullValues[offset+i])negative=true;
|
||||
++plan.contentHash; // Discard deliberately poisoned negative-control columns. / Purger le controle negatif.
|
||||
}
|
||||
}
|
||||
for(std::size_t i=0;i<fullValues.size();++i)if(fullValues[i]!=candidateValues[i])++mismatches;
|
||||
std::cout<<"surface label="<<label<<" forced_candidates=1 features="<<plan.features.size()
|
||||
<<" values="<<fullValues.size()<<" full_hash="<<Hex64(HashValues(fullValues))
|
||||
<<" candidate_hash="<<Hex64(HashValues(candidateValues))
|
||||
<<" mismatches="<<mismatches<<" negative_control="<<negative
|
||||
<<" full_p95_ms="<<Percentile95(fullTimes)<<" candidate_p95_ms="<<Percentile95(candidateTimes)
|
||||
<<" build_p95_ms="<<Percentile95(buildTimes)<<" candidates_p95="<<Percentile95(counts)
|
||||
<<" full_column_p95_ms="<<Percentile95(fullColumnTimes)
|
||||
<<" candidate_column_p95_ms="<<Percentile95(candidateColumnTimes)<<'\n';
|
||||
if(mismatches||!negative)throw std::runtime_error("surface candidate proof failed");
|
||||
}
|
||||
|
||||
int main(int argc,char** argv)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(argc!=4)throw std::runtime_error("usage: audit owner_island_assembly owner_surface_assembly results_dir");
|
||||
const auto read=[](const char* path)
|
||||
{std::ifstream input(path);return std::string(std::istreambuf_iterator<char>(input),{});};
|
||||
std::string error;
|
||||
auto islands=WorldAssemblyManifest::FromJson(read(argv[1]),error);
|
||||
if(!islands||islands->floatingIslands.empty())throw std::runtime_error("island assembly: "+error);
|
||||
const auto islandPath=std::filesystem::path(argv[3])/"owner_island_manifest.json";
|
||||
{std::ofstream output(islandPath);output<<islands->floatingIslands.front().manifest.ToJson();}
|
||||
std::string exe=argv[0],islandFile=islandPath.string();
|
||||
std::string resultFile=(std::filesystem::path(argv[3])/"island_tile_lists.json").string();
|
||||
char* islandArgs[]{exe.data(),islandFile.data(),resultFile.data()};
|
||||
if(IslandAuditMain(3,islandArgs)!=0)return 1;
|
||||
auto surface=WorldAssemblyManifest::FromJson(read(argv[2]),error);
|
||||
if(!surface||surface->plan.strates.empty())throw std::runtime_error("surface assembly: "+error);
|
||||
MeasureSurface(surface->recipe,surface->plan.strates.front(),"owner",false);
|
||||
MeasureSurface(surface->recipe,surface->plan.strates.front(),"stress64",true);
|
||||
std::cout<<"SHARED_FEATURE_AUDIT_PASS\n";
|
||||
return 0;
|
||||
}
|
||||
catch(const std::exception& e){std::cerr<<"SHARED_FEATURE_AUDIT_FAIL: "<<e.what()<<'\n';return 1;}
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
{
|
||||
"field_audit": [
|
||||
{
|
||||
"islands": 4,
|
||||
"connectors": 3,
|
||||
"forced_candidates": 1,
|
||||
"list_tiles_built": 108,
|
||||
"sampled_tiles": 64,
|
||||
"sample_count": 64000,
|
||||
"mean_candidates": 2.63158,
|
||||
"p95_candidates": 6,
|
||||
"list_build_total_ms": 0.0766,
|
||||
"list_build_p95_ms": 0.0012,
|
||||
"full_tile_p95_ms": 0.9803,
|
||||
"candidate_tile_p95_ms": 1.0194,
|
||||
"full_tile_median_ms": 0.85265,
|
||||
"candidate_tile_median_ms": 0.88875,
|
||||
"exact_mismatches": 0,
|
||||
"full_hash": "cb94db3ca317d001",
|
||||
"candidate_hash": "cb94db3ca317d001",
|
||||
"negative_control_detected": 1
|
||||
},
|
||||
{
|
||||
"islands": 256,
|
||||
"connectors": 240,
|
||||
"forced_candidates": 1,
|
||||
"list_tiles_built": 3362,
|
||||
"sampled_tiles": 64,
|
||||
"sample_count": 64000,
|
||||
"mean_candidates": 3.31231,
|
||||
"p95_candidates": 4,
|
||||
"list_build_total_ms": 216.615,
|
||||
"list_build_p95_ms": 0.0803,
|
||||
"full_tile_p95_ms": 110.57,
|
||||
"candidate_tile_p95_ms": 7.3619,
|
||||
"full_tile_median_ms": 109.41,
|
||||
"candidate_tile_median_ms": 4.12255,
|
||||
"exact_mismatches": 0,
|
||||
"full_hash": "d83bac7778f3d62a",
|
||||
"candidate_hash": "d83bac7778f3d62a",
|
||||
"negative_control_detected": 1
|
||||
},
|
||||
{
|
||||
"label": "owner",
|
||||
"forced_candidates": 1,
|
||||
"features": 1,
|
||||
"values": 186624,
|
||||
"full_hash": "4207efd4ac869108",
|
||||
"candidate_hash": "4207efd4ac869108",
|
||||
"mismatches": 0,
|
||||
"negative_control": 1,
|
||||
"full_p95_ms": 0.4748,
|
||||
"candidate_p95_ms": 0.4559,
|
||||
"build_p95_ms": 0.0003,
|
||||
"candidates_p95": 1,
|
||||
"full_column_p95_ms": 0.3679,
|
||||
"candidate_column_p95_ms": 0.3693
|
||||
},
|
||||
{
|
||||
"label": "stress64",
|
||||
"forced_candidates": 1,
|
||||
"features": 66,
|
||||
"values": 186624,
|
||||
"full_hash": "f1c6ea123284cc38",
|
||||
"candidate_hash": "f1c6ea123284cc38",
|
||||
"mismatches": 0,
|
||||
"negative_control": 1,
|
||||
"full_p95_ms": 0.7084,
|
||||
"candidate_p95_ms": 0.4078,
|
||||
"build_p95_ms": 0.0011,
|
||||
"candidates_p95": 1,
|
||||
"full_column_p95_ms": 0.3699,
|
||||
"candidate_column_p95_ms": 0.3552
|
||||
}
|
||||
],
|
||||
"default_tile_audit": [
|
||||
{
|
||||
"label": "islands",
|
||||
"lod": 0,
|
||||
"tiles": 8,
|
||||
"hashes_identical": 1,
|
||||
"full_p95_ms": 94.9835,
|
||||
"candidate_p95_ms": 95.0935,
|
||||
"list_p95_ms": 0.0021,
|
||||
"full_shell_p95_ms": 0.0002,
|
||||
"candidate_shell_p95_ms": 0.0003
|
||||
},
|
||||
{
|
||||
"label": "islands",
|
||||
"lod": 1,
|
||||
"tiles": 8,
|
||||
"hashes_identical": 1,
|
||||
"full_p95_ms": 87.2796,
|
||||
"candidate_p95_ms": 87.5774,
|
||||
"list_p95_ms": 0.0035,
|
||||
"full_shell_p95_ms": 0.0005,
|
||||
"candidate_shell_p95_ms": 0.0003
|
||||
},
|
||||
{
|
||||
"label": "islands",
|
||||
"lod": 7,
|
||||
"tiles": 8,
|
||||
"hashes_identical": 1,
|
||||
"full_p95_ms": 20.4421,
|
||||
"candidate_p95_ms": 20.4088,
|
||||
"list_p95_ms": 0.0017,
|
||||
"full_shell_p95_ms": 16.9176,
|
||||
"candidate_shell_p95_ms": 16.8824
|
||||
},
|
||||
{
|
||||
"label": "islands",
|
||||
"lod": 8,
|
||||
"tiles": 8,
|
||||
"hashes_identical": 1,
|
||||
"full_p95_ms": 73.0376,
|
||||
"candidate_p95_ms": 72.9233,
|
||||
"list_p95_ms": 0.0016,
|
||||
"full_shell_p95_ms": 69.9303,
|
||||
"candidate_shell_p95_ms": 69.8442
|
||||
},
|
||||
{
|
||||
"label": "surface",
|
||||
"lod": 0,
|
||||
"tiles": 8,
|
||||
"hashes_identical": 1,
|
||||
"full_p95_ms": 11.2377,
|
||||
"candidate_p95_ms": 11.1781,
|
||||
"list_p95_ms": 0.0006,
|
||||
"full_shell_p95_ms": 0.0001,
|
||||
"candidate_shell_p95_ms": 0.0001
|
||||
},
|
||||
{
|
||||
"label": "surface",
|
||||
"lod": 1,
|
||||
"tiles": 8,
|
||||
"hashes_identical": 1,
|
||||
"full_p95_ms": 7.3458,
|
||||
"candidate_p95_ms": 7.3544,
|
||||
"list_p95_ms": 0.0007,
|
||||
"full_shell_p95_ms": 0.0001,
|
||||
"candidate_shell_p95_ms": 0.0001
|
||||
},
|
||||
{
|
||||
"label": "surface",
|
||||
"lod": 7,
|
||||
"tiles": 8,
|
||||
"hashes_identical": 1,
|
||||
"full_p95_ms": 32.7389,
|
||||
"candidate_p95_ms": 32.3814,
|
||||
"list_p95_ms": 0.0006,
|
||||
"full_shell_p95_ms": 26.3776,
|
||||
"candidate_shell_p95_ms": 26.021
|
||||
},
|
||||
{
|
||||
"label": "surface",
|
||||
"lod": 8,
|
||||
"tiles": 8,
|
||||
"hashes_identical": 1,
|
||||
"full_p95_ms": 168.5449,
|
||||
"candidate_p95_ms": 168.0627,
|
||||
"list_p95_ms": 0.0008,
|
||||
"full_shell_p95_ms": 135.9596,
|
||||
"candidate_shell_p95_ms": 136.31
|
||||
}
|
||||
],
|
||||
"island_placement": [
|
||||
{
|
||||
"label": "FloatingIslands",
|
||||
"authored_full_p95_ms": 7.0706,
|
||||
"authored_candidate_p95_ms": 0.2385,
|
||||
"authored_active_batch_full_ms": 412.95957,
|
||||
"authored_active_batch_candidate_ms": 3.84022,
|
||||
"populated_cells": 14,
|
||||
"populated_placements": 572,
|
||||
"populated_full_p95_ms": 53.9875,
|
||||
"populated_candidate_p95_ms": 2.1501,
|
||||
"exact_transform_comparisons": 572,
|
||||
"anchor_checks": 572,
|
||||
"max_density_residual": 0.035156
|
||||
}
|
||||
],
|
||||
"island_active": [
|
||||
{
|
||||
"label": "FloatingIslands",
|
||||
"cells": 64,
|
||||
"placements": 572,
|
||||
"full_batch_ms": 3270.4782,
|
||||
"candidate_batch_ms": 28.43621,
|
||||
"merge_ms": 0.06231,
|
||||
"apply_ms": 0.6068,
|
||||
"applied_instances": 572,
|
||||
"full_total_cpu_ms": 3271.14731,
|
||||
"candidate_total_cpu_ms": 29.10532,
|
||||
"rhi": "null"
|
||||
}
|
||||
],
|
||||
"hash_matrices": [
|
||||
{
|
||||
"worker_hash_matrix": "1/8/16",
|
||||
"stable": 1,
|
||||
"density": "0x4dcfb37585d7d986",
|
||||
"mesh": "0x725a18374c5623de",
|
||||
"payload": "0xfb345d8cb319d18b",
|
||||
"topology": "0x76f2846be8efb5f4"
|
||||
},
|
||||
{
|
||||
"worker_hash_matrix": "1/8/16",
|
||||
"stable": 1,
|
||||
"density": "0x0cd2a1a4152ee4aa",
|
||||
"mesh": "0x17775c835711e5a3",
|
||||
"payload": "0xa27224958fc27d7b",
|
||||
"topology": "0x3821fea90b134ce4"
|
||||
}
|
||||
],
|
||||
"limits": {
|
||||
"unreal_core_limit": 12,
|
||||
"max_ubt_actions": 8,
|
||||
"max_standalone_compile_actions": 4,
|
||||
"process_limit_gib": 8,
|
||||
"launch_memory_gate_gib": 4,
|
||||
"step_limit_seconds": 900
|
||||
},
|
||||
"known_failed_run": "islands_hism_fixture_failed.log: exit 1; fixture collided with live landmark suppression; isolated fixture passes."
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"baseline":{"islands":4,"connectors":3,"tiles_built":108,"sampled_tiles":64,"samples":64000,"mean_candidates":2.63157894737,"p95_candidates":6,"list_build_total_ms":0.0766,"list_build_p95_ms":0.0012,"before_p95_ms":0.9803,"after_p95_ms":1.0194,"before_median_ms":0.85265,"after_median_ms":0.88875,"exact_mismatches":0,"before_hash":"cb94db3ca317d001","after_hash":"cb94db3ca317d001","negative_control":true},
|
||||
"stress":{"islands":256,"connectors":240,"tiles_built":3362,"sampled_tiles":64,"samples":64000,"mean_candidates":3.31231409875,"p95_candidates":4,"list_build_total_ms":216.6153,"list_build_p95_ms":0.0803,"before_p95_ms":110.5695,"after_p95_ms":7.3619,"before_median_ms":109.40955,"after_median_ms":4.12255,"exact_mismatches":0,"before_hash":"d83bac7778f3d62a","after_hash":"d83bac7778f3d62a","negative_control":true}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"schema_version":1,"content_hash":"87222553193002d8","recipe":{"schema_version":1,"units_per_voxel":256,"owner_voxel_size_microns":125000,"core_voxel_size_microns":250000,"owner_to_core_scale_numerator":1,"owner_to_core_scale_denominator":2,"seed":0,"origin_x_q":0,"origin_y_q":0,"center_top_z_q":-126976,"layout_min_z_q":-258048,"layout_max_z_q":4096,"primary_island_count":3,"island_density_q16":32768,"spacing_q":14336,"minimum_radius_q":3072,"maximum_radius_q":6144,"thickness_ratio_q16":39322,"vertical_jitter_q16":39322,"top_flatten_q16":39322,"taper_end_min_q16":29491,"taper_end_max_q16":45875,"geometry_version":2,"crust_depth_bonus_q16":9830,"root_depth_ratio_q16":49152,"blend_radius_q":768,"contour_warp_q":1613,"roughness_q":384,"boundary_seal_q":512,"bridge_half_width_q":768,"bridge_thickness_q":1024,"route_constraints":{"version":1,"capsule_radius_q":348,"capsule_height_q":1802,"maximum_grade_q16":17560,"sweep_spacing_q":128,"support_probe_radius_q":230,"support_search_depth_q":512,"minimum_clearance_q":128,"minimum_support_probes":3},"content_hash":"5e0370d9f95f1c15"},"plan":{"content_hash":"dbbda4932378047a","islands":[{"stable_id":"e6e461e18b3a9c87","ordinal":0,"center_q":[-10035,4422,-129150],"radius_q":3605,"top_half_q":721,"top_z_q":-128429,"bottom_z_q":-133837,"taper_end_q16":41663,"bounds_min_q":[-17941,-3484,-136525],"bounds_max_q":[-2129,12328,-125741]},{"stable_id":"2bc1820baba047f6","ordinal":1,"center_q":[0,-5178,-127714],"radius_q":3693,"top_half_q":738,"top_z_q":-126976,"bottom_z_q":-132516,"taper_end_q16":33506,"bounds_min_q":[-7994,-13172,-135204],"bounds_max_q":[7994,2816,-124288]},{"stable_id":"adc259cbe2a395e9","ordinal":2,"center_q":[10035,4681,-127887],"radius_q":5181,"top_half_q":1036,"top_z_q":-126851,"bottom_z_q":-134623,"taper_end_q16":39164,"bounds_min_q":[553,-4801,-137311],"bounds_max_q":[19517,14163,-124163]},{"stable_id":"7855fb022cc561c9","ordinal":3,"center_q":[-6451,-19514,-124414],"radius_q":5840,"top_half_q":1168,"top_z_q":-123246,"bottom_z_q":-132006,"taper_end_q16":33440,"bounds_min_q":[-16592,-29655,-134694],"bounds_max_q":[3690,-9373,-120558]}],"cluster_edges":[{"stable_id":"eaa5dd310e846520","from_island_id":"e6e461e18b3a9c87","to_island_id":"2bc1820baba047f6","start_q":[-8680,3126,-128554],"end_q":[-1388,-3851,-126819],"half_width_q":768,"thickness_q":1024,"bounds_min_q":[-10600,-5771,-132778],"bounds_max_q":[532,5046,-125667],"sharp_tag_ready":true},{"stable_id":"034023599b466c51","from_island_id":"2bc1820baba047f6","to_island_id":"adc259cbe2a395e9","start_q":[1370,-3832,-126951],"end_q":[8113,2793,-126831],"half_width_q":768,"thickness_q":1024,"bounds_min_q":[-550,-5752,-131175],"bounds_max_q":[10033,4713,-125679],"sharp_tag_ready":true},{"stable_id":"4962fa885545fb26","from_island_id":"2bc1820baba047f6","to_island_id":"7855fb022cc561c9","start_q":[-788,-6929,-126846],"end_q":[-5205,-16745,-123222],"half_width_q":768,"thickness_q":1024,"bounds_min_q":[-7125,-18665,-131070],"bounds_max_q":[1132,-5009,-122070],"sharp_tag_ready":true}],"route":[{"feature_id":"2e805a1f1f778cbb","position_q":[-10035,4422,-127367],"radius_q":1024},{"feature_id":"5be3b2b1e01722ea","position_q":[-9318,3736,-127414],"radius_q":1024},{"feature_id":"ab4eda612c1f03b5","position_q":[-8601,3051,-127336],"radius_q":1024},{"feature_id":"ba2fd2b050d0dd8c","position_q":[-7885,2365,-127288],"radius_q":1024},{"feature_id":"fc5829ee129fdc4f","position_q":[-7168,1679,-127113],"radius_q":1024},{"feature_id":"1393bb00329a9d5e","position_q":[-6451,993,-126951],"radius_q":1024},{"feature_id":"1dabc9715c93e2c9","position_q":[-5734,308,-126760],"radius_q":1024},{"feature_id":"0ea2008a85e73050","position_q":[-5018,-378,-126563],"radius_q":1024},{"feature_id":"754f55a5f1465cf3","position_q":[-4301,-1064,-126408],"radius_q":1024},{"feature_id":"1b6752776b4a7d22","position_q":[-3584,-1749,-126236],"radius_q":1024},{"feature_id":"0ab3b704db76084d","position_q":[-2867,-2435,-126017],"radius_q":1024},{"feature_id":"bd6980911e0879c4","position_q":[-2150,-3121,-125838],"radius_q":1024},{"feature_id":"ad164d7d0c049d87","position_q":[-1434,-3807,-125738],"radius_q":1024},{"feature_id":"9661463acbada2d6","position_q":[-717,-4492,-125928],"radius_q":1024},{"feature_id":"280a96547fadb0a1","position_q":[0,-5178,-125908],"radius_q":1024},{"feature_id":"531455b42fc13108","position_q":[717,-4474,-125939],"radius_q":1024},{"feature_id":"55d04c20849d7fcb","position_q":[1434,-3770,-125798],"radius_q":1024},{"feature_id":"ac4ebe80860dbdfa","position_q":[2150,-3065,-125893],"radius_q":1024},{"feature_id":"ff942855bf8e3fc5","position_q":[2867,-2361,-125886],"radius_q":1024},{"feature_id":"e6b8bba6c6acaf9c","position_q":[3584,-1657,-125861],"radius_q":1024},{"feature_id":"ae47379bbd4f7fdf","position_q":[4301,-953,-125839],"radius_q":1024},{"feature_id":"98779442384a30ee","position_q":[5018,-249,-125844],"radius_q":1024},{"feature_id":"f4c7757b2ee9fe19","position_q":[5734,456,-125814],"radius_q":1024},{"feature_id":"3ea33fae0fLine truncated
|
||||
@@ -0,0 +1,9 @@
|
||||
attempt=1 exit=0 elapsed_s=8.7570529 peak_private_bytes=68067328
|
||||
Final timing replay: no overlapping BuildHost build or Unreal process.
|
||||
attempt=1 exit=0 elapsed_s=8.0385819 peak_private_bytes=66658304
|
||||
Final source timing replay: redundant scoped validation removed; idle build/Unreal.
|
||||
attempt=1 exit=0 elapsed_s=7.9966612 peak_private_bytes=66658304
|
||||
Final cost-hint source: force candidates for proof; no overlapping build/Unreal.
|
||||
attempt=1 exit=0 elapsed_s=8.0365247 peak_private_bytes=65884160
|
||||
Final composed stress: 64 shelves plus XY cliff/cap writers; no overlapping build/Unreal.
|
||||
attempt=1 exit=0 elapsed_s=7.8703235 peak_private_bytes=66654208
|
||||
Reference in new issue
Block a user