Table of Contents

Parallel Tick Fence

Spreads the post-tick WriteTickFence step — cluster migrations, AABB refresh, WAL publish — across the worker pool instead of running it on one thread.

Status: ✅ Implemented · Visibility: Public · Level: 🟣 Advanced · Category: Tick-Based Execution Engine

🎯 What it solves

WriteTickFence applies cluster migrations (moving an entity to a cluster for its new grid cell when it crosses a cell boundary), recomputes spatial AABBs, and publishes WAL records for the tick's dirty cluster content. Run serially on the single TickDriver thread, it can dominate tick time on a large simulation with heavy migration/AABB churn — one thread working while the rest of the worker pool the runtime just spun up for the tick DAG sits idle, capping how far a tick can scale with core count. The Parallel Tick Fence spreads that work across all workers so it scales the same way the rest of the tick does.

⚙️ How it works (in brief)

The fence is split into four chained phases — Prep, Migrate, AabbRefresh, Finalize — each dispatched as a chunk-parallel system on the worker pool right after the user's tick DAG completes. A per-tick work planner sizes chunks from measured per-unit cost (continuously recalibrated from a sliding window of recent ticks) and bin-packs work evenly across workers rather than splitting by a fixed count, so one slow chunk doesn't stall the tick while idle workers wait. The parallel dispatch is entirely internal — it is tuned, not invoked, through RuntimeOptions.

WriteTickFence itself is public, and calling it is not optional outside the runtime. Under TyphonRuntime the fence is invoked automatically at tick end and application code never touches it. A host embedding the engine without the runtime must call dbe.WriteTickFence(n) itself, once per tick — see Embedding without the runtime. What is internal is how the fence spreads its work across workers, not whether the fence runs.

💻 Usage

var options = new RuntimeOptions
{
    EnableParallelFence = true,       // default — parallelize WriteTickFence across workers
    FenceChunkOversubscription = 2,   // chunk-count cap = oversubscription x WorkerCount
    AdaptiveFenceCost = true,         // recalibrate migration/AABB cost from measured wall-time
};

using var runtime = TyphonRuntime.Create(engine, schedule => { /* ... */ }, options);
Option Default Effect
EnableParallelFence true Parallel fence sub-DAG vs. the single-threaded WriteTickFence
FenceChunkOversubscription 2 Chunk-count cap = oversubscription × WorkerCount; smooths per-worker preemption jitter
FenceCostModel AntHill-calibrated defaults Seeds per-unit cost (migration ≈ 33µs/entity, AABB ≈ 2.4µs/cluster)
AdaptiveFenceCost true Continuously recalibrates FenceCostModel from a 64-tick sliding window; disable to pin the static seed for repeatable benchmarks

⚠️ Guarantees & limits

  • Application code never interacts with the fence DAG directly — there is no API surface beyond the RuntimeOptions knobs above.
  • EnableParallelFence = false falls back to the serial WriteTickFence on the TickDriver thread — useful for diagnostics or as a regression safety valve; observable behavior is otherwise equivalent.
  • Both the parallel and serial paths feed the engine's mandatory WAL + checkpoint pipeline to drain the dirty pages they touch — this is not an opt-in durability mode, it's how dirty cluster state always gets to disk.
  • Chunk sizing targets ~200µs of CPU per chunk; below that floor, per-dispatch overhead (worker wake, page cache attach) would dominate the chunk's own cost.
  • Per-chunk dirty-page tracking uses a local pooled ChangeSet, its marks released at chunk end (via ReleaseDirtyMarks) — this does not change the engine's WAL/checkpoint contract for the rest of the tick.
  • Runs after the user's tick DAG completes and before UoW.Flush() — its WAL publishes land in the same fsync as the tick's other commits, not a tick later.

🧪 Tests

  • ParallelFenceTests — opt-in/opt-out fence correctness, migration storms, spawn+mutation ticks, no-corruption/no-duplicate-chunk-execution
  • AdaptiveFenceCostTests — AdaptiveFenceCost on/off, cost-model recalibration from measured wall-time
  • FenceWorkPlanPackTests — chunk bin-packing against oversubscription cap and per-unit cost