benchmark dashboard · Apple M-series

Stratum — Streaming Primitives

Four streaming primitives — TopK, HeavyHitters, Cardinality (HLL), Filter (Galois) — composed around a shared mergeable-summary property. Dual Python/native backend, Arrow bridge to DuckDB/Polars/DataFusion.

Membrane check
0.26 ns
Galois contains()
5.94 ns
Filter bits/key
10.4 bpk
Bulk throughput (Py)
191 M ev/s
§1 Overall Profile

Performance Radar — Stratum vs the canonical alternatives

Six normalized axes covering the dimensions that actually distinguish streaming primitives. Stratum's strength: tail latency, mergeability, SQL interop. Trade-offs: bulk-build time (slower than heapq's tight C loop at small N), Python FFI per-call overhead.

§2 Throughput

Bulk Top-K throughput — 2 M random uint64, K=100

Wall-clock throughput building the Top-K from a fixed array. Higher is better. The Python backend's win comes from numpy.argpartition (O(N), SIMD-vectorised). Stratum native pays Python→C FFI overhead in this Python-driven bulk test; in a pure C++/Rust hot loop the membrane runs at 3.8 B ops/s.

ApproachThroughputStateNotes
Python heapq12.0 M ev/s3,720 BGIL-bound; GC tail
Stratum (python) 191.3 M ev/s800 Bnumpy argpartition
Stratum (native) 25.5 M ev/s3,200 BPython→C FFI bulk path
Redis ZADD (localhost)~0.1 M ev/sTCP round-trip dominated (estimated)
§3 Per-event Tail Latency

p50, p99, p99.99 — lower is better, flatter is better

The story Stratum's native backend is built around. Python's heapq has a smooth low p50 but a long tail from GC pauses and dict resizes. Stratum's hot path cannot spike: it's one atomic-relaxed load (0.26 ns) plus a branchless 8-popcount filter probe (5.94 ns). No allocation, no branch the predictor doesn't know, no syscall.

§4 Pareto Frontier

State size vs throughput — upper-left dominates

Where each approach sits in the size/speed trade-off. Stratum primitives sit on the frontier because their state size is bounded by K (Top-K, heavy hitters) or by a fixed register array (HyperLogLog), independent of stream size.

§5 Galois Filter Build

Filter construction — 100k uint64 keys

The honest weakness, exposed: the real Gaussian-elimination Cuckoo builder is slower than building a Bloom filter. We solve 8 GF(2) linear systems per block — costs more than 7 hash + 7 SetBit ops. We win the query side, not the build side.

§6 Architecture

Four primitives, one shared shape

Every primitive sits on the same architectural skeleton: shared-nothing per-shard workers, lock-free SPSC ring buffers, mmap snapshots, and a deterministic merge() operation. The math comes from four different 1980s–2010s papers; the fit is the contribution.

🔥

TopK — EVT membrane

extreme value theory
  • Hot path: 1 atomic-relaxed load, 1 compare. 0.26 ns measured.
  • Insight: ~99.9% of events fail the threshold and need no further work.
  • Background: async double-buffered nth_element on flush.
  • Merge: concat top-Ks + nth_element. Trivially associative.
📊

HeavyHitters — Misra-Gries

Misra & Gries 1982
  • Hot path: open-address hash probe + increment. ~10 ns.
  • Guarantee: any key with freq > N/(K+1) is tracked.
  • Snapshot: 416 bytes for K=32.
  • Merge: union, top-K, subtract (K+1)-th. Preserves error bound exactly.
🎯

Cardinality — HyperLogLog

Flajolet 2007 · Heule 2013
  • Hot path: 1 hash, 1 clzll, 1 max update. ~12 ns.
  • State: 16 KB at p=14 → ~0.81% std err.
  • Measured: 0.03% error over 1M; 1.36% on a 750k union.
  • Merge: elementwise max of registers. Exact union.
🔍

Filter — Galois bipartite

Ribbon family · Dillinger & Walzer 2021
  • Hot path: 8 branchless parities. 5.94 ns scalar, ~1 ns AVX-512.
  • Build: per-block GF(2) Gaussian elimination, 8 RHS at once.
  • Memory: 10.41 bits/key default; 8.67 bpk asymptotic.
  • FP rate: measured 0.76%, predicted 0.78% (≈ 2/256).
§7 Roadmap

Development timeline

Seven versions shipped over one week. Each builds on the previous; nothing was thrown away. Honest failure modes documented in CHANGELOG.md.

v0.1
Handoff core
Lock-free SPSC + EVT membrane + bench-grade Galois.
v0.2
Hardening
mmap arena, C ABI, Python bindings, CMake, tests.
v0.3
Real Galois build
Gaussian-elim Cuckoo, zero false negatives. Rust crate.
v0.4
HTTP + SSE dashboard
400-line server, delta-encoded stream, browser UI.
v0.5
Dual backend
Python (numpy) + native — competitive at both ends.
v0.6
Mergeable summaries
Misra-Gries → persistence + distribution + frequencies.
v0.7
SQL bridge
Arrow → DuckDB/Polars. HyperLogLog. Public release.
§8 Live Data

Paste your bench_micro output

Run code/build/bench_micro on your machine and paste the output below. The dashboard re-renders with your measured numbers overlaid against the baseline. Everything runs client-side.

Recognised lines: contains: X ns/op, membrane: X ns/op, build: ... (X Mkeys/s), memory: X bits/key.