Optimistic parallel discrete-event simulation on the BEAM (spec §7).
The engine handles every Time Warp mechanic — speculative execution, rollback,
anti-messages, GVT, fossil collection. A domain author implements only
TimeWarp.Model.
{:ok, sim} =
TimeWarp.start_run(
model: Terminal.Model,
lps: %{quay_1 => args, yard_a => args}, # lp_id => init_args
seed: 42,
until: {:vtime, 86_400_000},
init_events: [{quay_1, 0, :vessel_arrives}],
gvt_interval_ms: 50,
time_window: :none, # see caveat below (§11.3)
check_purity: false, # Mitigation 3b: purity probe
thrash_guard: nil # or {rate_per_s, window_ms} (Mitigation 2)
)
{:done, _} = TimeWarp.await(sim)
report = TimeWarp.report(sim)Options
:model— aTimeWarp.Modelimplementation (required).:lps—%{lp_id => init_args}(required).:seed— integer seed for per-LP PRNGs (default0).:until—{:vtime, t}run horizon, or:infinity(default).:init_events—[{target, at, payload}]genesis events kicking off the run.:gvt_interval_ms— wall-clock cadence of GVT cycles (default50).:check_purity— run the double-call purity probe (Mitigation 3b, defaultfalse).:thrash_guard—{rollbacks_per_s, window_ms}circuit breaker (Mitigation 2).:time_window—{:vtime, W}to bound optimism to[GVT, GVT+W](§11.3), or:none(default). Deadlock-free (the effective bound ismax(GVT+W, global_min_event)). W trades parallelism for conflict, not a free storm fix — see the note below.:cancellation—:aggressive(default) |:lazy(§5.5). Lazy suppresses an anti-message when re-execution re-emits an identical event; it only pays on models whose straggler-path events are PRNG-free (seeTimeWarp.Model— it is inert and can amplify the storm on random models like PHOLD).
:time_window is a parallelism trade, not a storm fix
A tight W caps how far any LP speculates past GVT, so it bounds rollback
depth and the storm for any workload — but it does so by throttling
parallelism. A W tight enough to tame a high-conflict storm has throttled
execution toward conservative (§11.5): the right answer there is that the
workload is a poor fit for optimism, not that a smaller W is a win. Find W
empirically per workload; a value tuned on one model says nothing about another.
Summary
Functions
Block until the run terminates. Returns {:done, info} or {:failed, reason}.
Snapshot of the run: GVT, per-LP state/stats, and aggregate totals.
Start a run. Returns {:ok, sim} where sim is the handle for await/report.
Types
@type config() :: keyword()
Functions
Block until the run terminates. Returns {:done, info} or {:failed, reason}.
Snapshot of the run: GVT, per-LP state/stats, and aggregate totals.
Start a run. Returns {:ok, sim} where sim is the handle for await/report.