Skip to content

Latest commit

 

History

History
201 lines (176 loc) · 13 KB

device-cellular.md

File metadata and controls

201 lines (176 loc) · 13 KB

Experimental device-native cellular process

DeviceCellular is a separate experimental Julia/KernelAbstractions process, exported by Interior. Construct it from a CPU CellularEcology reference and a World on the selected backend. The World may have no fields or scratch buffers: all chemical/material arrays are process-owned. Existing nonzero World nutrient is rejected to prevent confusing the two inventories. Generic step!, Experiment, process ports and record_state are supported; Arena deliberately rejects it until an adapter supplies the full statistics/recording contract. This is not an interchangeable backend switch for CPU CellularEcology.

The complete step keeps resource fields, capacity-major recurrent states and genomes, physical exchange supports, spatial contact bins, bonds, division admission, stable identities and inheritance on the device. Capacity is fixed; a failed radius bound, mechanical resolution, identity range, nonfinite write, or unrepresentable accounting debit latches a status. Later queued submissions leave all device arrays and bindings unchanged. The failing step can be partial; there is no transactional rollback. attempted_steps is a host submission count, not a completed physical step count.

The controller, adaptive hidden state, local plastic marks, complementary precursor metabolism and work/heat accounting follow the current cellular laws. Changes are explicit: junctions use simultaneous donor-limited network exchange; contacts use mutual bounded-degree proposals; mechanical evolution uses checked fixed substeps and conservatively funded motors instead of CPU backtracking. Narrow spatial bins use the actual maximum body radius rebuilt on device. The query stencil covers every eligible periodic pair, including thin grids; persistent stretched bonds are enumerated separately. The projected execution recipe caches narrow typed stage arguments. execution=:staged retains a wider argument reference recipe. A fusion candidate provided no useful additional whole-loop gain and was removed.

Genotype mutation and developmental partition use a counter-based seeded device random stream. This is inherited stochastic variation, not evidence of evolved fitness. Optional typed anabolic callbacks provide pre-respiration planning, a shared growth/export allocator, post-division inheritance, and habitat completion before the step is marked complete. The base nothing hook preserves its physiology; paid catalyst/sorption composition is developed separately. It shares finite work/precursor requests rather than requiring growth to exhaust precursors before construction.

Physical arrays have fixed canonical roles, with guarded device commits from scratch. References remain valid across steps. The process owns a private ResourcePool representation; If World nutrient is present, it must explicitly be zero. Replacing owned arrays, their shapes, process parameters or grid geometry fails preflight. Direct array-content edits are the caller's responsibility. Both finite resource budgets and cumulative per-cell ledgers have high/low Float32 compensation. Waste smaller than a representable grid increment is retained in a compensated inert residue. Grid/scatter arithmetic remains Float32 and is audited with explicit tolerances, not claimed mathematically exact.

device_cellular_step!(w,p,dt;check_status=true,execution=:projected) checks a four-byte status each step by default. Batching with check_status=false requires a bounded explicit device_cellular_status! or device_cellular_statistics boundary. Statistics reduce on device and download 244 bytes per observation. Their Float32 reduction roundoff makes them monitoring data; device_cellular_audit( device_cellular_snapshot(p)) downloads all arrays and sums in Float64 for budget checks. Neither full downloads nor controller-only work are hidden inside the reported full-step timing.

device_cellular_checkpoint(w,p) synchronizes and emits a complete host-array payload, including scratch, bin/free-list buffers, compensated budgets, IDs and RNG/submission counters. device_cellular_restore(w,payload) allocates independent arrays on the chosen backend and checks the exact source pin, Julia version, array roles/shapes/types and complete-state boundary. A failed partial state cannot be checkpointed. The payload may be serialized by the caller using Julia Serialization within the pinned execution environment; never deserialize an untrusted file. Exact replay across different GPU hardware is not promised.

Initial native AMD evidence

The first populated 3D run used RX 6750 XT, two launch-host threads pinned to CPUs 10,11, an 8 GiB process budget, 16³ resource grid, capacity 1024 and 16 mechanical substeps. Over 100 steps of dt .01, population 512→960, with 480 births, 32 deaths and 1,998 final bonds. Complete-step throughput was 39.32/s, including 244-byte compact observations/failure checks every 8 steps. Process-owned resident arrays occupied 8,417,656 bytes; measured host allocation was229,789,552 bytes over 100 steps. Construction, compilation and full audit downloads were outside that timer. Strict Float64 material residual was 5.70e-6 over 4362.88 initial material; potential/work/heat residual was 4.89e-5 over 14110.72 initial potential.

Evidence is outputs/device-cellular-native-v8/benchmark.json; immutable remote source and log are /othersys/tmp/intmat-probe-20261014/device-cellular-v8. Model hash 831b0ac1b2784657e59c9d6ecf370c26633e42db2c16eb2d5efcdbf8827265b6; kernel hash 825d6b5bdf2eeec57e771eecfdd7c55f2bea1f6b19c51a137facdf37b596fbf7. This is a first working whole-loop sample, not a speedup relative to the existing CPU adaptive law.

The pinned AMD runtime hits an LLVM 18 EarlyCSE/MemorySSA compiler segmentation fault in some junction specializations at device optimization level 2. The probe and benchmark expose DEVICE_AMD_OPTLEVEL=1: it changes only the current process's cached AMDGPU compiler configuration, avoiding that pass. It neither patches installed packages nor changes Julia's host -O flag. This uses private AMDGPU internals and is a pinned-runtime workaround, not a portable public API. The normal-optimization 2D 20-step fixture also passed with two births, one death and exact CPU-KA/device primary array agreement. Broader 3D parity and sustained checkpoint/restart trajectories remain required before production integration.

Run focused tests with julia --project test/device_cellular.jl; execute the portable probe with scripts/probe_device_cellular.jl cpu|amd|metal NEW_OUTPUT. The full benchmark uses DEVICE_BACKEND, DEVICE_CELLS_SIDE, DEVICE_STEPS, DEVICE_BATCH, and DEVICE_MECHANICAL_SUBSTEPS; output destinations must be fresh.

Sustained closed system and robust bin measurements

The earlier capacity-1024 trajectory saturated and recorded 130,053 blocked birth attempts; it is a throughput fixture, not an unconstrained ecological result. A separate capacity-20,000 run covered a conservative material-based live-count bound of 17,451.6. Over 2,000 steps, 512 founders became 1,418 living cells with 938 births, 32 deaths, 3,651 bonds and zero blocked births. Whole trajectory rate was 29.53 steps/s, including 81.3 MB of selected-field downloads and 6.42 MB of compact active-row frame files. This run predates the narrow-bin optimization. Strict material residual was 1.10e-5 and the potential/work/heat residual was −0.001283 over initial potential 14,110.72. It is a finite, closed food supply, not a claim of long-term ecological balance.

Every restored checkpoint array matched exactly. A subsequent 20-step AMD continuation differed by at most 9.54e-7 in position and 1.19e-7 in resources; only linked-bin list order differed among integer arrays. Future GPU trajectories are not bitwise reproducible under atomic floating-point accumulation. The runner declares short-replay tolerances of 1e-4 for primary physical arrays and 1e-3 for all floating arrays, with identity/bond arrays unchanged. Checkpoints pin source files, controller layout and Julia version; run metadata records backend/device, compiler optimization and project/manifest hashes.

Five alternating pairs of 200 complete steps measured narrow versus wide bins with the same projected recipe and 16 mechanical substeps. Median speedups were 2.722× at 512 founders (113.20 versus 41.61 steps/s), and 3.003× at 4,096 founders (88.07 versus 29.28 steps/s). All samples exercised births, deaths and contacts, had zero blocked births, matched active identities and had identical final bond sets. These are domain-enlargement comparisons at fixed spacing, not spatial refinement. They accelerate this declared experimental device law, not a controller-only surrogate or a claimed equivalent CPU adaptive arena.

Exact candidate coverage is separate from Float32 trajectory agreement. Independent brute-force checks found no missing pairs among 9,190 eligible pairs, including 600 threshold/boundary cases. In the paired trajectories, maximum position differences were 3.15e-5 (512 founders) and 0.001135 (4,096 founders); maximum position RMS values were 1.63e-6 and 1.16e-5. The larger fixture's maximum hidden-state/resource differences were 0.00330/0.000653. Different bin traversal and atomic accumulation order can affect threshold histories.

Compact tracked measurements are in docs/device-cellular-results.json. Full source-copied trajectories are under outputs/device-cellular-native-v12/ and paired-bin evidence under outputs/device-cellular-native-v15/. scripts/run_device_cellular.jl writes initial/final complete checkpoints and bounded actual frames. DEVICE_CAPACITY is independent of founder count; DEVICE_REQUIRE_HEADROOM=1 checks the conservative material forecast. Frames store active rows, original slot indices, IDs/parents/lineages/generations, positions/radii, neural states, metabolites and bonds; bond slots refer to the original slot indices. DEVICE_CAPTURE bounds capture frequency.

The base cellular implementation has been exercised on CPU-KA and native AMD. The script's Metal selector is available for a future compatibility gate; it is not evidence that this full cellular pipeline has already passed on Metal.

The final default 50-step random-controller 3D CPU-KA/AMD probe passed with position error 1.31e-6, hidden-state error 7.45e-8 and resource error 9.69e-8, including two births, one death and nonzero recurrent activity. A separate 500-step capacity-20,000 default run sustained 82.26 steps/s including actual captures; it restored every checkpoint array exactly and its 20-step continuation had maximum floating error 1.19e-7. Evidence is source-pinned in outputs/device-cellular-native-v16/. Focused base tests pass 25 assertions; protocol and independent coverage tests are maintained separately.

Optional physical-support representation

DeviceCellular(w, reference; support_strategy=:axis) stores separable periodic coordinate indices and squared distances for each cell, then regenerates radial weights as each kernel visits the physical support. The default remains :materialized. Both strategies use the same sampling, fair resource allocation, waste return and body-permeability kernels through device_support_edges(device_support_descriptor(p), slot). The descriptor borrows process arrays; retain it only while that process owns the same arrays. Axis storage grows with the sum of candidate axis lengths rather than their product. It still visits every eligible voxel and retains the specified physical radius. It is a memory representation change, not a smaller neighborhood approximation.

device_cellular_initialize(w, positions; support_strategy=:axis, ...) creates founders without constructing a CPU CellStencil. It shares parameter validation and the seeded genome prior with CellularEcology; the CPU struct layout is unchanged. Only founder-sized biological arrays are staged on the host, instead of downloading and re-uploading every capacity-sized scratch array. initial means resource concentration, converted to voxel mass. Uniform source/sink masks and finite total rate/budget tuples define the initial resource law. Temporary resource initialization buffers live on the selected backend. This factory does not yet accept patterned resource initializers.

Fresh checkpoints use format version 2, record the support strategy explicitly, and pin the support and founder-initialization helpers. Existing frozen runs keep their own source/checkpoint implementation; this runtime does not reinterpret version-1 checkpoints. The first native AMD measurement found a storage/throughput tradeoff: the original axis iterator saved 221× support storage at 256³ but ran at 0.189× materialized throughput. See physical-support measurements. The earlier v16 performance results describe materialized support only.

The existing full-loop probe/benchmark/trajectory scripts accept DEVICE_SUPPORT_STRATEGY=axis; their default recipe and materialized strategy remain unchanged. Those reference-based recipes still build a CPU founder stencil. Use the direct factory for large fine-grid initialization instead of mistaking the script's legacy setup cost for a requirement of the new backend.