Table of Contents

Class RuntimeOptions

Namespace
Typhon.Engine
Assembly
Typhon.Engine.dll

Configuration options for the DAG scheduler and runtime tick loop.

public class RuntimeOptions
Inheritance
RuntimeOptions
Inherited Members

Constructors

RuntimeOptions()

public RuntimeOptions()

Properties

AdaptiveFenceCost

When true, MigrationCost and AabbCost are continuously calibrated from a 64-tick sliding window of per-chunk measurements. Static FenceCostModel values seed the model at startup; subsequent ticks converge toward the measured µs/unit. Disable for repeatable benchmarks or to pin behaviour to the static seed.

public bool AdaptiveFenceCost { get; set; }

Property Value

bool

BaseTickRate

Target tick rate in Hz. Default: 60. The scheduler uses metronome-style tick advancement to prevent drift.

public int BaseTickRate { get; set; }

Property Value

int

CostBasedChunking

Size parallel QuerySystem chunks by their measured cost rather than their entity count. Default: true.

public bool CostBasedChunking { get; set; }

Property Value

bool

Remarks

From its second dispatch on, a system's chunk count comes from its previous dispatch's worker time per entity. Its chunks spread over the width, round(WorkerCount × ChunksPerWorker), as long as each carries 25–100 µs of work; below that band it gets fewer chunks of 25 µs, above it more chunks than the width, of 100 µs, up to twice the width, which the workers claim as they come free, so the pool no longer waits on one long last chunk. At most one entity per chunk, and beyond the width at most one cluster per chunk.

A system's first dispatch, a checkerboard system and a system with its own MinChunkSize keep the entity rule: min(round(WorkerCount × ChunksPerWorker), ceil(entities / ParallelQueryMinChunkSize)).

EnableParallelFence

When true (default), WriteTickFence is parallelized across the worker pool via the internal sub-DAG (FenceExec). When false, the runtime falls back to the legacy single-threaded serial fence — useful for diagnostics and as a safety fallback if a regression is suspected. Enabling adds FenceExec to the scheduler's full system array, but SystemCount reports user-registered systems only — see AllSystemCount for the total including internal systems.

public bool EnableParallelFence { get; set; }

Property Value

bool

EntityCommandsPerTick

Entity commands (ctx.Commands.Spawn / Destroy) this runtime is sized for per tick, across every worker (#1099). Default 4 096.

public int EntityCommandsPerTick { get; init; }

Property Value

int

Remarks

A hint for sizing and a ceiling for loss — not a limit that fails the tick. The budget is split across worker slots at bind and each segment grows on demand toward the whole figure, so a skewed tick can legitimately exceed the per-slot share. Past the figure itself a command is dropped, OverflowCount counts it exactly, and the tick continues. That is a deliberate choice against failing the tick: this is a number an application has to pick before it has met its own worst tick, and the worst tick is the mass-death event nobody sizes correctly the first time. Losing some corpses loudly beats losing the frame.

It also derives the key-block size, which is why that is capped rather than trusted. Each producer takes a block of clamp(EntityCommandsPerTick / stride, 16, max(16, 1024 / stride)) keys per generation, and an unissued block tail is key space spent. The 1 024 product cap bounds that at about 0.57 % of an archetype's 2^48 keys per year at a continuous 50 Hz; derived uncapped from this option it would burn 36.8 % per year at stride 8 and 73.5 % at stride 32. So raising this option costs memory and nothing else.

EntityMapBulkMinEntriesPerBucket

Minimum expected entries per bucket (migrants / bucketCount) before migration stages its EntityMap patches for the bulk phase instead of applying them inline. Below it, the inline per-entity path runs and the phase emits nothing.

public float EntityMapBulkMinEntriesPerBucket { get; init; }

Property Value

float

Remarks

The bulk path's entire gain comes from entries sharing a bucket, and a small batch has none to share. Measured A/B on --fence-phase against a 400 000-entity archetype whose map holds ~57 000 buckets, comparing Migrate CPU + EntityMapUpdate CPU per migrant:

100 000 migrants (~1.8 per bucket): bulk 402 / 511 / 558 ns at W = 1 / 4 / 8 against inline 691 / 849 / 758. Bulk wins at every worker count.
10 000 migrants (~0.17 per bucket): bulk 1287 / 1240 / 1350 ns against inline 1571 / 1022 / 1066. Inline wins at W ≥ 2, and the spread within a single arm is wide enough that the two are not separable — the EntityMap term is a small part of a noisy Migrate phase at that batch size.

The default is set from the mechanism, not from a resolved crossover. Runs shorter than one entry amortise nothing by construction, so 1.0 is where the bulk path's advantage begins to exist at all; the crossover is somewhere below it and the benchmark could not resolve where. Treat the value as provisional and re-measure when step 10's re-clustering produces a realistic migration rate — that is the workload this should be tuned against, not the synthetic churn above.

Set to 0 to force the bulk path always, and MaxValue to force the inline path for any archetype whose map has buckets; both arms of the measurement above used exactly that, via --fence-phase --bulk-min=. The MaxValue sentinel relies on .NET Core 3.0+ SATURATING float-to-integer conversion — (long)(float.MaxValue * bucketCount) overflows to infinity and saturates to MaxValue, which no migrant count reaches. Under the older unspecified conversion the same expression could yield MinValue and force the BULK path instead, silently inverting the sentinel.

FenceChunkOversubscription

Oversubscription factor for fence-chunk dispatch: the chunk-count cap becomes FenceChunkOversubscription × WorkerCount. Above 1 lets the scheduler smooth out per-worker preemption jitter — a healthy worker can pick up the next queued chunk while a preempted worker finishes its current one. Must be ≥ 1. Default: 2.

public int FenceChunkOversubscription { get; set; }

Property Value

int

FenceCostModel

Cost model coefficients for the fence work-planner. Each per-stage cost is the hint count multiplied by the matching coefficient; the planner uses the total cost to pick chunk count and split splittable items. Defaults are 1.0 everywhere — tune from real-world traces.

When AdaptiveFenceCost is true (default), this value is only used as the initial seed; runtime continuously recalibrates MigrationCost and AabbCost from measured chunk wall-time.

public FenceCostModel FenceCostModel { get; set; }

Property Value

FenceCostModel

Overload

Overload detection and response configuration. Always active with sensible defaults.

public OverloadOptions Overload { get; set; }

Property Value

OverloadOptions

ParallelQueryMinChunkSize

Minimum number of entities per chunk for parallel QuerySystem dispatch. Controls granularity: fewer entities per chunk = more parallelism but more overhead (Transaction creation per chunk). Entity sets smaller than this value still use the parallel chunk path with totalChunks=1. Default: 64.

public int ParallelQueryMinChunkSize { get; set; }

Property Value

int

Subscriptions

Memory and policy rails for engine-owned replication — the pools, the per-session ceilings and the skip thresholds. Always present with defaults; a runtime with no session connected pays nothing for it.

public SubscriptionsOptions Subscriptions { get; set; }

Property Value

SubscriptionsOptions

Remarks

It lives here rather than on TyphonOptions because replication rides the tick: every budget below is spent by the subscriptions track, which the runtime dispatches, and none of it is database state. What an application declares — projections, profiles, commands — goes to Subscriptions instead; this is the operator's half of the same subsystem.

SystemExceptionPolicy

What an unhandled system exception means for the rest of the tick. Default: Isolate — fault isolation, the behaviour Typhon has always had. Set AbortTickAndStop for hosts that treat one tick as the unit of publication and must not publish a partially-executed tick (issue #567). That policy is terminal: the runtime stops ticking after the first fatal system exception.

public SystemExceptionPolicy SystemExceptionPolicy { get; set; }

Property Value

SystemExceptionPolicy

TelemetryRingCapacity

Capacity of the telemetry ring buffer (number of ticks retained). Must be a power of 2. Default: 1024 (~17 seconds at 60Hz, ~200KB).

public int TelemetryRingCapacity { get; set; }

Property Value

int

WorkerCount

Number of worker threads for parallel system execution. Set to -1 (default) for automatic: Math.Max(1, Environment.ProcessorCount - 4). Set to 1 for single-threaded debug mode (systems execute in topological order on the timer thread).

public int WorkerCount { get; set; }

Property Value

int