Days AGO Executor
Implemented model coverage, safe-horizon execution, and backend capabilities.
Scope: Days AGO. src/scenario/compile.rs lowers supported TOML scenarios into SimulationImage; callers then select Scalar, CPU, Metal, or CUDA explicitly, for example with days --engine.
Compiled model
The current image supports:
- static FatTree, Torus, Dragonfly, Spectrum-X rail, and custom topologies
- one LP per host and one LP per switch egress queue
- integer nanosecond time with no timestamp quantization
- FIFO, strict priority, WFQ, DRR, and WRR scheduling
- TailDrop admission and the ECN ramp (Kmin/Kmax/Pmax in bytes, stateless draw), one ramp or one per link rate
- constant-rate, non-preemptive links with uniform, tiered, or per-link-class propagation and rate
- deterministic packet-distribution traffic, TCP Reno/CUBIC, DCQCN, and RoCE queue pairs
- exact PFC per-priority pause state on switch links and host links
RingAllReduce,AllGather,ReduceScatter,AllToAll, andSendRecvcollectives over TCP or RoCE queue pairs, delay-only compute stages, counted joins between stage groups, and delay-only stage notifies for same-server messages on the rail fabric- shortest-path, semantic
FatTreeEcmp, and SimAI Murmur3SimAiEcmprouting
Exact lowering retains host attachment LPs. Each host has an unbounded injection stage toward its switch and a bounded delivery queue in the reverse direction. The compiler assigns stable semantic node, link, flow, and payload IDs before constructing initial state and events.
The image has a closed set of model and event kinds. Runtime callbacks, dynamic LP migration, multi-device placement, and automatic backend selection are not part of the contract.
Execution paths
Global scalar uses one canonical event calendar and accepts zero-delay channels. The other paths use conservative safe-horizon rounds:
- Round scalar is the single-threaded per-LP reference.
- CPU uses persistent workers with static whole-LP ownership and barrier exchange.
- Metal and CUDA execute the same LP/event contract from bounded device arenas.
At each round, the executor finds the global frontier, adds the minimum channel lookahead, drains events below that exclusive horizon, canonically sorts remote outboxes, and merges them at the barrier. No parallel path speculates beyond the safe horizon.
Backend capability matrix
| Capability | Scalar | CPU | Metal | CUDA |
|---|---|---|---|---|
| FIFO, strict priority, WFQ, DRR, WRR | Yes | Yes | Yes | Yes |
| TailDrop, ECN ramp | Yes | Yes | Yes | Yes |
| TCP Reno, TCP CUBIC | Yes | Yes | Yes | Yes |
| PFC, on switch links and host links | Yes | Yes | Yes | Yes |
| DCQCN | Yes | Yes | Yes | Yes |
| RoCE queue pairs (Go-back-N) | Yes | Yes | Yes | Yes |
| Collective and compute stages, counted joins, stage notifies | Yes | Yes | Yes | Yes |
| Zero-delay channels | Yes | Rejected | Rejected | Rejected |
Metal and CUDA use checked 320-bit rational components for WFQ. Validation checks checkpoint widths and static weight bounds; runtime arithmetic faults rather than committing an overflowing result. Scalar and CPU use unbounded BigUint rational arithmetic.
Device RunResult values contain the canonical state and measurement surface. Scalar and CPU can retain diagnostic-only observation planes; Metal and CUDA omit them. Byte comparisons normalize those reference-only fields first.
Device planning, retry, and readback
The Metal and CUDA planners derive all arena sizes before a kernel attempt. Large record arenas are striped by their owning LP, stream, receiver class, or flow. Plane-wide and per-entity caps remain explicit and are checked before use. Stage flows are charged by how many of a host's stages can be active at once, not by their count, and a windowed queue pair with its timeout off by its window; Full-observation logs are sized for the requested run, not the whole scenario. A plan that needs more device memory than the device's limit is refused before anything is allocated, with a typed DeviceMemoryExceeded error. See Internals.
Capacity overflow is refuse-or-run: a failed attempt emits no partial result. The host records the reported demand, raises only the relevant capacity floor, replans, and retries up to max_capacity_retries. A successful run returns the converged floors as CapacityWarmStart.
CapacityWarmStart is a sizing hint for a later run of the same image. It can skip known failed plans. It contains no simulated state, checkpoint, or device cache.
Metal and CUDA plan readback after execution. They copy fixed planes directly. For variable striped arenas, they read metadata and run a gather kernel that copies live records in canonical entity and ring order. Invalid metadata returns an error, and compact readback decodes to the same bytes as full-capacity readback.
The configs/benchmarks/lookahead/rq9_frontier_closed_k32.toml fixture defines 32 groups of 8,192 resident flows, or 262,144 flows. The days CLI runs it on any engine and fingerprints the complete result of a device run. The CUDA build contains device images for sm_86, sm_89 and sm_121.
Rejection boundaries
Each layer reports errors once it has enough information:
| Boundary | Examples |
|---|---|
| Scenario compilation | An unknown key in any table (named with its table); nonzero time_quantum_ns; VirtualClock; the legacy drop policies RED, RED_ECN and ECN_THRESHOLD; BBR; unsupported flow dependencies or explicit per-flow routes; unsupported pairing/collective form; an after list that leaves a host uncovered; an AICB scenario whose trace, SimAI.conf or topology fails a check |
| Backend validation | Zero-lookahead parallel channel; invalid device WFQ width; device queue capacity beyond 32 bits |
| Device planning | Arithmetic/memory-size overflow, an invalid arena layout, or a plan over the device's memory limit (DeviceMemoryExceeded, before any allocation) |
| Device attempt and retry | Capacity demand beyond the current plan or configured cap, invalid readback metadata, or checked arithmetic overflow |
Compilation and validation errors name the rejected field, mechanism, or backend and, for device-only gaps, direct callers to scalar or CPU. Unsupported configuration is never silently ignored: every Days AGO table refuses an unknown key, naming the key and the table, and the only keys accepted without being read are the legacy engine's twelve root keys (LEGACY_ENGINE_ROOT_KEYS; see Overview).
See /docs/internals for the code-level round, capacity, warm-start, and compaction paths.