Metabolism: region pool — SharedArrayBuffer arena, band-parallel phases (block sums / VM decisions / advection+reaction), bit-identical to serial; 5.9x at 41k organisms; provider protocol sketched
This commit is contained in:
@@ -249,6 +249,52 @@ and wander); rock has a budget that survives a whole film (calm songs keep
|
||||
sparse stone, percussive ones accumulate walls); agriculture consumes stone
|
||||
instead of minting it. 44 tests green; realtime holds at 640×360.
|
||||
|
||||
### The region pool + the browser as workhorse (landed)
|
||||
|
||||
**Node stays CPU** — it is the dev, test and export path, simple on purpose.
|
||||
**The browser is the workhorse**: it renders, it previews, and it has the
|
||||
GPU. The compute architecture, in three layers:
|
||||
|
||||
1. **Think slower than you move** (landed): the strains decide every
|
||||
`vmEvery`-th substep (default 2) and empty ground never thinks. Measured
|
||||
at field 128 with 41 k organisms: 25 → 20 ms/frame, ecology unchanged.
|
||||
2. **The region pool** (landed): the field is carved into horizontal
|
||||
coarse-row bands; every shared array lives in ONE SharedArrayBuffer
|
||||
(`arenaLayout`), and `World`'s substep splits into three band-local
|
||||
phases — block sums, the strain programs, advection+reaction — separated
|
||||
by atomics barriers (`beginPhase`). The main thread keeps only the
|
||||
cross-band work: the war front (hits land at aim targets), the swap, the
|
||||
rock economy, politics, decay. The mail carries the frame, the decide
|
||||
flag, warmth, the living bodies and the current swap orders (the
|
||||
workers' named arrays follow the main's swaps through the mail).
|
||||
**Measured: 52.3 → 14.7 ms/frame (2 workers) → 8.9 ms/frame (4 workers)
|
||||
at 41 k organisms — near-linear.** And the invariant that makes it safe:
|
||||
the phases are EXACT partitions, so a parallel world is the serial world
|
||||
BIT FOR BIT (pinned by a test across 0/2/4 workers). Node runs it on
|
||||
`worker_threads` (lazily resolved, so the browser still loads the
|
||||
module); the browser will run the same pool inside its simulation worker.
|
||||
3. **The GPU** (first slice landed): the strain programs are uniform over
|
||||
thousands of blocks — one dispatch per strain covers the whole decision
|
||||
layer. `src/sim/gpu.js` + `tools/gpu-check.js` (browser-side validation
|
||||
against the CPU interpreter) await device time.
|
||||
|
||||
**The browser as the server's worker (protocol sketch, next).** Once
|
||||
rendering exists, the browser becomes a compute provider to the node farm:
|
||||
|
||||
- the farm (node) holds prepared songs (`out/prepared/*.json`) and a job
|
||||
queue: `(songId, seed, frameFrom, frameTo)`;
|
||||
- a browser provider connects (WebSocket), registers its capability
|
||||
(GPU? cores?), receives a prepared artifact + a frame range, runs
|
||||
`Run` inside its worker pool with the GPU decision layer, and streams
|
||||
back encoded frames (PNG or raw) keyed by frame number;
|
||||
- the farm stitches the frames into the film. Sim runs are sequential in
|
||||
time, so the parallel unit is the TAKE (a song × seed × range), not a
|
||||
frame — many takes in flight across many providers, with the farm
|
||||
checkpointing world state at range boundaries so a provider can resume.
|
||||
|
||||
Determinism policy unchanged: node's CPU path is the canonical exporter;
|
||||
the GPU/preview paths are the same world to within float noise.
|
||||
|
||||
### The decision layer on the GPU (analysis, first slice landed)
|
||||
|
||||
The profile of a heavy frame (field 128, ~40 000 organisms planted) says:
|
||||
|
||||
Reference in New Issue
Block a user