vike
Concepts

The latency gate

The execution core's fold is measured in CI on reserved cores and gated on its tail, not its median — and only three of the harness's variants gate on a derived budget, because an uncalibrated ceiling is worse than no gate at all.

The execution core's drain loop is the one thread in the platform with a latency budget, and the budget is enforced rather than aspired to: crates/vike-core/tests/runtime_latency.rs runs in CI on a dedicated runner whose cores are reserved for it, under real-time scheduling, and fails the run if the tail moves. This page is what it measures, what it deliberately does not, and how to read a number from it without being misled.

What is gated: the tail, on three variants

Three tests assert derived ceilings — baseline, journal (the write-ahead append cost isolated, no cadence snapshot) and journal-snap (the production journal configuration, snapshots included). Each feeds Ingest::Event(Event::Fill) — the venue-reply lane — through the core 100 000 times and asserts the whole tail, not a single p99. The harness header says why: until it did, the gate computed p50, p99.9, max and the count of hops over 100 µs purely in order to print them, and a reference run went green with a p99.9 of 37 741 ns and one 141.86 ms core hop. For a market maker the tail is the number that costs money; p99 is the number that looks good.

Every ceiling is a derived constant with the measurements that produced it beside it in the source. The reference row every constant descends from: baseline p50 271 ns, p99 551 ns, p99.9 2 104 ns, max 25 709 ns, zero hops over 100 µs. The baseline keeps the platform's long-standing P99_BUDGET_NS of 10 µs, with BASELINE_P999_NS at 50 µs, BASELINE_MAX_NS at 2 ms — placed between the shielded and un-shielded scheduling regimes, so it reddens if the shielding silently stops applying — and BASELINE_HOPS_OVER_100US at 2. The two journal variants gate on a separately calibrated JOURNAL_P99_NS of 20 µs: the 10 µs literal was never derived for them, and the main branch itself measured 9 809 ns against it — 98.1 % of the bar, on code containing no change under test. Deriving that one constant honestly took 98 CI attempts harvested across 250 runs.

The journal ceilings are a ratchet, not a budget

JOURNAL_P999_NS (100 µs), JOURNAL_MAX_NS (10 ms) and JOURNAL_HOPS_OVER_100US (50) record today's measured tail so it stops being invisible; they are meant to be lowered as the journal's I/O policy improves, and they move together or not at all. They have been lowered once — from 250 µs, 500 ms and 100 — after two fixes took blocking msync calls off the fold thread. The hop count is the one that catches that defect as arithmetic rather than weather: a run at the production snapshot_every takes 100 000 / 1024 = 97 cadence snapshots, and the pre-fix reps read 102, 97, 101 and 120 hops over 100 µs — one per snapshot. Read that number first on any red, and read p50 before anything: a p50 that doubles means the box, not the code. The sync policy is where the fix lives.

Only three variants gate on a derived budget

The order-submit lane, the book hop and the client-order-id variants are measured and assert nothing about timing at all. The snapshot publish is measured too, at three order counts — and keeps one pre-existing sanity assert, the 64-order build's p50 under 1 ms, roughly 100x above the ~10 µs it actually measures. That is a liveness check against the build doing something structurally different, not a derived budget. No ceiling here descends from a calibrated baseline, on purpose. An uncalibrated ceiling is a flaky gate, which is worse than no gate at all, because people learn to re-run it rather than read it. A measured, persisted, trendable series catches drift for an afternoon's work and leaves the ceiling as a later decision derived from a baseline instead of guessed. A new measurement variant is not a budget in waiting; a ceiling means somebody derived one.

One path is deliberately not measured, and the harness records why: the live recorder's flush is a disk-bound Parquet write on its own thread, and the failure that actually cost ~110k rows was a compactor holding the series lock while the sink discarded batches — which shows up in RecorderHandle's dropped and discarded counters, not as a slow flush.

Two facts that mislead everyone once

Serial execution is load-bearing, not tidiness. The harness runs under --test-threads=1, and crates/vike-core/tests/runtime_latency.rs's SPIN_DEADLINE carries the measurement: every harness thread busy-spins waiting for its worker, and CI pins the binary to a small reserved core set under real-time scheduling. Run in parallel, the spinners occupy every core and starve the workers they are waiting on — priority inversion, not slowness, and a spin that never terminates is a SCHED_FIFO process nothing can preempt: this gate's history holds a livelocked binary at 380 % CPU with no progress for over five minutes, during which a /proc scan on the same host went from 53 ms to over 120 s and degraded everything else running there. Serial execution also makes the numbers honest: run in parallel, these tests contend for the very cores whose tail they report.

Publish is per-event work on a quiet venue. The core publishes its snapshot on a coalesced cadence while busy and immediately when the queue goes idle. On a venue whose events arrive sporadically, that is a publish after every event — so anything CoreSnapshot::build does is on the per-event path this gate measures, and deferring work "to publish time" relocates it rather than avoiding it. Not hypothetical: rendering the recent-events ring lazily at publish moved the baseline p99 from 481 ns to 2 039 ns; rendering at push again brought it to 606 ns.

Reading a number

Every run — pass or fail — appends one JSON row per (run, attempt, variant) to a persisted series on the CI box, keyed on commit, with the attempt's journal-free baseline_p99_ns denormalized onto it. That baseline is the canary no journal change can move, and it is the field that separates a disturbed box from a real regression. Two things to know before quoting a figure: across the ordinary load range the median barely moves while the tail does — baseline p50 read 271–451 ns across every load bucket measured — so a four- or six-figure "p50" quoted anywhere is a tail percentile that has been mislabelled, and that same stability is what makes the doubled-p50 tell above work, since it takes a genuinely disturbed box to shift a median load alone leaves alone (a p50 that tracks the change under test is real signal, and the journal fixes moved it); and the series is the answer, not the job log — before it existed, "is this creeping on main?" cost two separate hand-harvests of the CI API.

What this means for a change to the core

Nothing on the fold path may log per-message — instrument per-order boundaries and fault transitions only. Everything that can run off the fold belongs in a crate that consumes the published snapshot, event and journal streams without sitting in this loop. An honest A/B of a hot-path change is run on the reserved-core box, serially, interleaving the variants and taking medians of at least eight reps — single runs produced contradictory rankings all day. The procedure is on running the latency gate.

On this page