Multi-core simulation: grain movement and heat across a worker pool (t88 phase 3)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,88 @@ What agents have done, newest first. Add an entry for every piece of work: the d
|
||||
note or request it was for, what changed, the files touched, the tests run, and anything left
|
||||
open or not verified. Keep each entry short; the git history has the details.
|
||||
|
||||
## 2026-10-28: t88 phase 3 resume, final review and verification (Codex)
|
||||
|
||||
- Preserved the interrupted uncommitted implementation and reviewed the schedule, shared
|
||||
writes, deferred effects, startup gate, test changes and profiler against the Phase 3 brief.
|
||||
- Reproduced a deferred-liquid bug before fixing it: replaying liquid() rolled the movement
|
||||
chance twice. Extracted liquidSearch() so the deferred search resumes at its exact direction
|
||||
and distance without another random draw; removed the now-unneeded RNG replay records.
|
||||
Added a failing-then-passing regression and a long water shelf to the repeated 320-tick
|
||||
inline/1/2/8-worker and reversed-order fixture.
|
||||
- Chunk passes now skip per-cell renderDirty stores in wakeXY/wakeHeatXY; the scanned chunk
|
||||
and write halo provide their invalidation. Outside passes, explicit invalidation remains.
|
||||
- All headless suites passed. Initial sandboxed browser gate failed (no GPU device); an
|
||||
elevated capability check confirms RTX 5070 WebGPU, isolation and 24 cores. Firefox still
|
||||
has no adapter and correctly requires WebGPU. Final host-GPU browser gate in progress.
|
||||
- Files additionally changed on resume: sim/{cells,workers,world}, test/t_threads.js,
|
||||
PROJECT_MAP and tracking. Full fresh profile, two-minute live run and screenshot inspection
|
||||
pending. No commit; DESIGN and owner's Context untouched.
|
||||
|
||||
## 2026-10-27: t88 phase 3, multi-core simulation (Codex; verification in progress)
|
||||
|
||||
- SharedArrayBuffer allocation for world arrays (ArrayBuffer only when unavailable in Node).
|
||||
Four (chunkX&1, chunkY&1) movement passes then four heat passes. Each chunk scopes RS to
|
||||
hash(world seed,tick,chunk,pass), restoring the global machine/worldgen RNG afterwards.
|
||||
Long liquid reads outside a 24-cell horizontal halo are deferred and replayed in chunk order;
|
||||
movement writes reach at most 8 cells, so parallel read/write regions cannot overlap.
|
||||
- Pass-local wake/heat flags merge by maximum; per-chunk heat outputs merge first. Discoveries,
|
||||
events, fuel ignition counts, wheel flow, cloud moisture, broken machines and partLost merge
|
||||
in chunk order. Flyers/launchGrain remain reachable only from main-thread transport, not these
|
||||
cell passes; their existing state is included in the determinism hash. Direct shared writes
|
||||
are disjoint cell/powder outputs or idempotent render/roof bits.
|
||||
- Browser Blob pool uses min(16,hardwareConcurrency-2,setting), at least one. Main thread owns
|
||||
machines, transport and game logic, processes a batch in each pass, then polls Atomics.load.
|
||||
No Atomics.wait on the document: it is prohibited by
|
||||
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics/wait
|
||||
and https://tc39.es/ecma262/2024/multipage/structured-data.html. Polling is synchronous and
|
||||
occupies the main core; it preserves atomic ticks so input/save/render cannot race workers.
|
||||
No whole-simulation worker or asynchronous rendering overlap. Worker timeouts/errors stop
|
||||
frame simulation. Small jobs run inline and larger batches use only enough helpers to
|
||||
amortize dispatch (32 movement or 8 heat chunks per helper). Pool setting applies on load.
|
||||
- Invalidation: remove swap's duplicate hot marks, gas marks and repeated coordinate-to-chunk
|
||||
function calls. Each scanned movement chunk marks its halo once; heat marks conduction edges.
|
||||
wake functions reuse their already computed chunk index for one direct render bit store;
|
||||
rare swaps/building/fog/dig/background writes retain explicit marks. Paused clean draws upload
|
||||
zero world cells. GPU equality passes without changing any tolerance.
|
||||
- Measurements so far: fresh Phase 2 settled/factory/heat 3.537/4.077/5.824 ms/tick vs frozen
|
||||
baseline 3.715/3.657/4.938. Isolated removal of hot dirty calls in a temporary Phase 2 copy
|
||||
gave 3.530/3.921/5.936: it did NOT recover the full 15% on its own. Do not claim it did.
|
||||
Initial unbatched pool factory 4.21; batched trial 3.04 ms/tick. Full final matrix pending.
|
||||
- Final full matrix (`/tmp/t88-phase3-final.json`, `/tmp/t88-phase3-final-perf.txt`, 218.0 s),
|
||||
RTX 5070, 24 logical cores, 1920x1080, 2048x1024 world. Pool 16 helpers, peak active 4
|
||||
(settled) / 5 (factory, heat), plus main-thread batch. All values below are ms.
|
||||
settled: baseline 3.715 -> wall/main occupied 1.897 (1.96x); main compute excluding polling 1.624, polling 0.272.
|
||||
factory: baseline 3.657 -> wall/main occupied 2.495 (1.47x); main compute excluding polling 2.037, polling 0.458.
|
||||
heat: baseline 4.938 -> wall/main occupied 2.649 (1.86x); main compute excluding polling 2.236, polling 0.412.
|
||||
Real-loop CPU work p50/p95, zoom 2 / zoom 6; pixel then smooth:
|
||||
settled: pixel 7.08/8.58 / 2.77/3.83; smooth 8.46/9.98 / 2.98/4.13.
|
||||
factory: pixel 8.48/10.05 / 4.96/5.95; smooth 9.59/10.80 / 5.13/6.12.
|
||||
heat: pixel 8.53/10.56 / 4.88/6.03; smooth 10.05/11.51 / 5.17/6.21.
|
||||
Frame intervals p50/p95 are 16.67/16.67 for all these runs (60 fps). Tick wall time and
|
||||
occupied main-thread time are equal: polling blocks this core; rendering does not overlap.
|
||||
The final threaded sim meets the baseline target in every scene; standalone dirty-only
|
||||
recovery remains unproven/unmet (numbers above). Recommend a future whole-simulation worker
|
||||
to remove the remaining 1.90-2.65 ms from the main thread; it would require an explicit
|
||||
ownership/input/save boundary and is outside this phase.
|
||||
- Re-baseline: three worldgen material hashes and seeded pile bounds (57x17 -> 46x19 grains).
|
||||
The heat oracle retains its unoptimized per-cell computation, updated for buffered pass
|
||||
outputs, and is compared against all four new passes. Same throughput assertions retained:
|
||||
conveyor feed heap widened, downhill-screen warm-up lengthened; load-wake deadline kept at
|
||||
eight ticks, fuel consumption checked later instead of demanding a random burn on that tick.
|
||||
Frozen renderer PNGs and tolerances unchanged: original Phase 2 world bytes captured from the
|
||||
Phase 2 simulation (only invalidation edits) in the temporary copy, compressed as golden-world fixtures, so changed
|
||||
terrain doesn't get counted as changed renderer pixels.
|
||||
- Headless suites pass; repeated inline/1/2/8 real-worker hashes pass (world arrays + JS effects).
|
||||
Extended test passes 320 busy ticks including stamp wrap, reversed chunk order, Node fallback.
|
||||
First full browser gate: gameplay 361, smooth 28, console 18, capabilities 7, GPU equality 12,
|
||||
light 71 and Firefox 2 pass; golden sky failed due changed worldgen terrain. Frozen-input
|
||||
golden rerun, final browser gate, full profile and 2-minute play-through pending.
|
||||
- Files: sim/{world,cells,heat,workers,fog,machines,weather}, ui/{threads,title,state,settings,loop},
|
||||
render/gpu/device, build.py/manifest; harness, threads/heat/load/corner/conveyor/screen/capability/
|
||||
golden tests and fixtures; profiler, README, TESTING, PROJECT_MAP and t88 tracking.
|
||||
No commit; DESIGN and owner's task context untouched. Phase 3 remains in progress.
|
||||
|
||||
## 2026-10-27: t88 phase 2d, required WebGPU and dirty uploads (Codex)
|
||||
|
||||
- Per-32x32-chunk `renderDirty` marks cell writes, heat with its conduction halo, stationary
|
||||
|
||||
Reference in New Issue
Block a user