Back to Streaming Sketching

Sketch Benchmark Laboratory

September 28, 2026 Wasil Zafar 21 min read

Make sketch tradeoffs reproducible and decision-ready.

Table of Contents

  1. Decide What a Fair Benchmark Must Reveal
  2. Design Workloads, Oracles and Reproducibility
  3. Build the Pluggable Experiment Harness
  4. Find Crossovers and Break the Candidates
  5. Publish the Benchmark Dossier

Decide What a Fair Benchmark Must Reveal

A sketch benchmark is like a wind tunnel for compact streaming algorithms. A wind tunnel does not merely announce that one wing “won”; it controls the airflow, measures lift and drag repeatedly, records uncertainty, and exposes the conditions where the result changes. Likewise, the laboratory feeds known workloads to exact and approximate implementations, records accuracy and systems cost, and identifies the crossover where one design becomes the better engineering choice.

Suppose the true distinct count is 100. Three seeded trials estimate 96, 101, and 108. Their signed errors are −4, +1, and +8; relative absolute errors are 4%, 1%, and 8%. Reporting only the mean estimate 101.7 hides the 8% tail. A useful report gives the distribution, confidence interval, memory, update/query throughput, merge cost, and workload conditions. It also asks whether a stated 95% interval actually covers truth about 95% of the time.

A workload generator produces a versioned stream from parameters and a seed. An exact oracle computes ground truth with a method whose limits are understood. An error distribution is the collection of trial-level errors, not one average. Calibration compares nominal confidence with empirical coverage. Throughput is completed operations divided by measured steady-state time; latency distributions, CPU, allocation, and peak resident memory remain separate. Merge cost measures compatible partial-state combination. An adversarial case stresses assumptions such as uniform hashing, positive updates, order independence, or bounded cardinality.

Stakeholders are algorithm authors, platform engineers, SREs, capacity planners, reviewers, and product owners choosing a production sketch. Acceptance requires deterministic replay, independent exact truth, standardized adapters, repeated seeded trials, controlled warm-up and measurement, raw immutable results, environment fingerprints, statistically defensible summaries, resource guards, and a decision table tied to explicit SLOs and budgets.

From wind tunnel to sketch benchmark laboratoryA controlled workload and seed schedule feed exact truth and sketch candidates; repeated measurements become distributions and a decision report. Test conditionsworkload • seed • hostwarm-up • trials Parallel instrumentsexact oraclesketch adapters Repeated evidenceerror • latency • memorycoverage • merge cost Pickby SLO Accuracy envelopeSystems costtime + memoryConfidenceempirical coverageCrossoverdecision region Every recommendation remains attached to conditions, raw trials, and uncertainty.
TermIntuitive meaningExact exampleNon-exampleAssumptionQuestion answered
Workload specificationRecipe for the streamZipf(1.1), N=1M, seed=42“Production-like data”Generator/version is fixedWhat exactly was tested?
Exact oracleGround-truth instrumentPython set for distinct countAnother HLL estimateOracle fits and is independently checkedWhat is the correct answer?
TrialOne isolated seeded runCandidate A on seed 42Reusing warm state unknowinglySetup/teardown is declaredWhat is one experimental unit?
Error distributionTrial-level deviation patternp50=1.2%, p95=3.8%Mean estimate aloneTrials represent target conditionsHow variable and severe is error?
CalibrationNominal versus observed confidence95% interval covers truth in 94.7% trialsNarrow interval with unknown coverageTrials/seeds are independent enoughCan confidence metadata be trusted?
ThroughputSteady-state completed operations/time8.2M updates/s after warm-upLoop iterations including setupTimer and workload are controlledHow much work can the sketch sustain?
Peak memoryMaximum attributable working state1.3 MiB measured in-processSerialized payload onlyAllocator/runtime are recordedWhat capacity does deployment need?
Merge costTime/bytes to combine partial states64 HLL shards merged in 4 msRebuilding from raw eventsStates are compatibleIs distributed aggregation affordable?
CrossoverRegion where preferred design changesExact set wins below 20k keys; HLL aboveOne universal winnerDecision weights are explicitWhich design fits this regime?
Warm-up

Decide What a Fair Benchmark Must Reveal

Truth is 100; estimates are 96, 101, and 108. Compute signed errors −4,+1,+8, absolute relative errors 4%,1%,8%, median absolute relative error 4%, and worst case 8%. If the runs take 10, 12, and 11 ms for 100,000 updates, their throughputs are 10.0M, 8.33M, and 9.09M updates/s; report the individual trials before summarizing. Checkpoint: ranking by mean estimate alone favours the candidate because 101.7 looks close, but a 5% tail-error SLO fails. Reflection: what decision changes if the production objective values p95 error more than average throughput?

Design Workloads, Oracles and Reproducibility

The laboratory benchmarks counters, membership filters, cardinality estimators, frequency sketches, samplers, and quantile summaries through a common lifecycle: configure, update, query, merge, serialize, restore, and report state bytes. Users submit a declarative experiment containing dataset/generator version, distribution parameters, event count, seed schedule, sketch adapter/version, parameter grid, warm-up, repetitions, isolation mode, metrics, budgets, and acceptance rules. The scheduler expands this into immutable run manifests and sends them to isolated workers.

Workload families include uniform, Zipf, bursty, drifting, duplicate-heavy, ordered, shuffled, turnstile where supported, high-cardinality, heavy-tail latency, partitioned merge, and adversarial hash/counter cases. Exact oracles use integers, sets, dictionaries, sorted arrays, or reservoir inclusion accounting and are cross-checked on small fixtures. A result row contains manifest digest, seed, host/runtime fingerprint, timestamps, truth, estimate, error metrics, update/query/merge timings, peak memory, serialized bytes, status, and raw artifact checksums.

Target SLOs include deterministic regeneration of every workload, zero result mixing across manifest digests, 99.9% runner availability, run-start p99 below 30 seconds, ≤2% timing drift between calibrated reference runs on a stable pool, and hard CPU/memory/time quotas. Privacy rules default to synthetic data; production replays require minimization, access control, encryption, expiry, and provenance. Threats include malicious adapters, fork bombs, dataset exfiltration, clock manipulation, cherry-picked seeds, changed dependencies, corrupted artifacts, poisoned baselines, and over-parallelization that distorts measurements.

Sketch Benchmark Laboratory: Design Workloads, Oracles and Reproducibility
flowchart TD
    U[Experiment author] --> V[Validate specification]
    V --> X[Expand parameter grid]
    X --> M[Immutable run manifests]
    M --> Q[Resource-aware scheduler]
    Q --> W[Isolated workers]
    D[Generators and datasets] --> W
    A[Sketch adapters] --> W
    O[Exact oracles] --> W
    W --> R[Raw trial artifacts]
    R --> C[Statistical analysis]
    C --> P[Decision report]
    P --> G[Review and approval]
    W --> T[Metrics traces audit]
    classDef navy fill:#17365D,color:#fff,stroke:#102844;
    classDef teal fill:#147D84,color:#fff,stroke:#0c5c61;
    classDef crimson fill:#C6284D,color:#fff,stroke:#8e1935;
    classDef purple fill:#6C3BAA,color:#fff,stroke:#482675;
    class U,D,A,O navy;
    class V,X,M,Q,W teal;
    class R,C,P purple;
    class G,T crimson;
Benchmark laboratory context and trust boundariesAuthors submit specifications through a control boundary; isolated worker pools consume approved adapters and datasets, then write immutable results to a separate evidence store. Controlled execution boundary Authors / CIsigned specifications Coordinatorvalidate • schedule Worker pool Aisolated trialsfailure domain 1 Worker pool Bisolated trialsfailure domain 2 Analysis and report APIdigest-scoped evidence Dataset registrygoverned inputs Evidence storeimmutable artifacts Operatorscontrol boundary Workers, registries, evidence storage, and control plane have distinct trust and failure boundaries.
CandidateGuaranteeScale / latencyMemoryOperational burdenPrivacyFailure recoveryDecision
Ad hoc notebookFlexible explorationSmall/manualUser-dependentHidden state and environmentEasy to leak dataRerun if possibleReject as authoritative; allow exploration only
Single-process harnessDeterministic local orderGood for small sweepsHost-limitedSimpleLocal controlsRestart whole runSelect for unit fixtures and developer smoke tests
Container per experimentEnvironment isolationModerate startup costQuota per containerImage/version managementStronger boundaryRetry immutable manifestSelect for standard reproducible trials
Process per trialStrong trial isolationHigher scheduling overheadHard per-trial limitMore orchestrationLimits adapter blast radiusRetry one trialSelect for untrusted or leak-sensitive adapters
Shared long-lived workersHighest throughputLow startup latencyRisk of state contaminationWarm-up/cache complexityWeaker isolationWorker recycleUse only for calibrated trusted suites
Synthetic generatorsExact provenance and scale controlVery highStreaming generationMust model realityNo production dataRegenerate by seedSelect as baseline
Sanitized production replayHigh ecological validityI/O-boundDataset storageGovernance and driftHighest privacy burdenVersioned immutable copySelect only with approval and expiry
Mean-only reportSimple point summaryCheapTinyMisleading tailsNeutralEasyReject
Raw trials + robust summariesAuditable distributions and uncertaintyMore analysis timeArtifact retentionSchema/version disciplineGovern raw fieldsRecompute report from artifactsSelect as evidence model

The central invariant is that every reported point is traceable to one immutable manifest, seed, adapter, oracle, environment, and raw trial. Launch is blocked by mixed digests, missing raw samples, unbounded execution, unverifiable truth, silent retries, or statistically unsupported rankings.

Build the Pluggable Experiment Harness

Build vertically. Slice 1 generates a seeded stream, computes exact truth, runs one adapter, and emits a raw JSON-compatible result. Slice 2 adds repeated seeds, error distributions, timing warm-up, and deterministic replay. Slice 3 adds parameter grids, merge trials, memory/serialization metrics, and isolated execution. Slice 4 adds artifact checksums, comparative reports, regression gates, and signed approvals. Each slice has a fixture whose expected digest and metrics are independently testable.

The adapter contract is intentionally small: create(config), update(key,value), query(request), merge(other), serialize(), and state_bytes(). Capabilities declare whether deletions, weights, merge, or confidence intervals are supported; the scheduler never invents unsupported operations. Run schemas are versioned. Resource validation happens before grid expansion and again before worker launch. Old results remain readable through explicit schema migrations; incompatible adapters are quarantined rather than coerced.

from dataclasses import dataclass
from hashlib import sha256
from math import log
from random import Random
from statistics import median
from time import perf_counter_ns
import json

class ExactDistinct:
    name = "exact_set"
    def __init__(self, _: dict): self.values = set()
    def update(self, key: int, value: int = 1) -> None: self.values.add(key)
    def query(self) -> float: return float(len(self.values))
    def merge(self, other: "ExactDistinct") -> None: self.values |= other.values
    def state_bytes(self) -> int: return 8 * len(self.values)

class LinearCounter:
    name = "linear_counting"
    def __init__(self, config: dict):
        self.bits = int(config["bits"])
        if not 32 <= self.bits <= 1_000_000: raise ValueError("unsafe bitmap size")
        self.bitmap = bytearray((self.bits + 7) // 8)
    def update(self, key: int, value: int = 1) -> None:
        slot = int.from_bytes(sha256(str(key).encode()).digest()[:8], "big") % self.bits
        self.bitmap[slot // 8] |= 1 << (slot % 8)
    def query(self) -> float:
        occupied = sum(byte.bit_count() for byte in self.bitmap)
        zeros = self.bits - occupied
        return float("inf") if zeros == 0 else -self.bits * log(zeros / self.bits)
    def merge(self, other: "LinearCounter") -> None:
        if self.bits != other.bits: raise ValueError("incompatible bitmap sizes")
        self.bitmap = bytearray(a | b for a, b in zip(self.bitmap, other.bitmap))
    def state_bytes(self) -> int: return len(self.bitmap)

@dataclass(frozen=True)
class Experiment:
    events: int = 20_000
    universe: int = 4_000
    seeds: tuple[int, ...] = (11, 13, 17, 19, 23)
    bits: int = 16_384
    max_work: int = 1_000_000
    schema_version: int = 1
    def validate(self) -> None:
        if self.schema_version != 1: raise ValueError("unsupported schema")
        if not self.seeds or self.events <= 0 or self.universe <= 0: raise ValueError("invalid workload")
        if self.events * len(self.seeds) > self.max_work: raise ValueError("experiment exceeds work budget")

def workload(spec: Experiment, seed: int) -> list[int]:
    rng = Random(seed)
    return [rng.randrange(spec.universe) for _ in range(spec.events)]

def trial(adapter_type, config: dict, values: list[int]) -> dict:
    oracle = ExactDistinct({})
    candidate = adapter_type(config)
    start = perf_counter_ns()
    for key in values:
        oracle.update(key); candidate.update(key)
    elapsed = perf_counter_ns() - start
    truth, estimate = oracle.query(), candidate.query()
    return {"truth": truth, "estimate": estimate,
            "relative_error": abs(estimate-truth)/truth if truth else 0.0,
            "updates_per_second": len(values)/(elapsed/1e9),
            "state_bytes": candidate.state_bytes()}

def run(spec: Experiment) -> dict:
    spec.validate()
    raw = [trial(LinearCounter, {"bits": spec.bits}, workload(spec, seed)) for seed in spec.seeds]
    digest = sha256(json.dumps(spec.__dict__, sort_keys=True, default=list).encode()).hexdigest()[:16]
    errors = sorted(row["relative_error"] for row in raw)
    return {"manifest_digest": digest, "adapter": LinearCounter.name, "raw_trials": raw,
            "median_relative_error": median(errors), "max_relative_error": max(errors)}

def self_test() -> None:
    spec = Experiment(events=5_000, universe=1_000, seeds=(3,5,7), bits=8_192)
    first, second = run(spec), run(spec)
    assert first["manifest_digest"] == second["manifest_digest"]
    assert [(r["truth"], r["estimate"]) for r in first["raw_trials"]] == [(r["truth"], r["estimate"]) for r in second["raw_trials"]]
    assert first["max_relative_error"] < 0.10
    left, right = LinearCounter({"bits": 1024}), LinearCounter({"bits": 1024})
    for x in range(50): left.update(x)
    for x in range(50,100): right.update(x)
    left.merge(right)
    assert abs(left.query()-100) / 100 < 0.10
    try: left.merge(LinearCounter({"bits": 2048}))
    except ValueError: pass
    else: raise AssertionError("incompatible merge accepted")
    try: Experiment(events=600_000, seeds=(1,2)).validate()
    except ValueError: pass
    else: raise AssertionError("work budget not enforced")
    print("benchmark checks passed", first["manifest_digest"], round(first["median_relative_error"], 4))

if __name__ == "__main__": self_test()
Sketch Benchmark Laboratory: Build the Pluggable Experiment Harness
flowchart TD
    S[Versioned run schema] --> G[Seeded generator]
    G --> O[Exact oracle fixture]
    O --> A[One adapter trial]
    A --> R[Repeated seeds and raw rows]
    R --> P[Parameter and merge sweeps]
    P --> I[Isolated workers and quotas]
    I --> E[Immutable evidence]
    E --> C[Comparative canary report]
    C -->|Gates pass| D[Publish decision]
    C -->|Drift or invariant fail| B[Rollback baseline]
    B --> O
    classDef navy fill:#17365D,color:#fff,stroke:#102844;
    classDef teal fill:#147D84,color:#fff,stroke:#0c5c61;
    classDef crimson fill:#C6284D,color:#fff,stroke:#8e1935;
    classDef purple fill:#6C3BAA,color:#fff,stroke:#482675;
    class S,G,O navy;
    class A,R,P,I teal;
    class E,C purple;
    class D,B crimson;
Build

Build the Pluggable Experiment Harness: Sketch Benchmark Laboratory

Create schema.py, generators.py, oracles.py, adapters.py, runner.py, and report.py. Generate 5,000 uniform draws over 1,000 keys with seeds 3, 5, and 7. Checkpoint 1: repeated generation produces identical stream digests and exact distinct truth. Run an 8,192-bit linear counter; checkpoint 2 records three raw estimates, errors, update rates, and state bytes, with maximum relative error below 10% on the fixture. Split keys 0–99 across two compatible counters, merge, and require estimate error below 10%; reject a 1,024/2,048-bit merge. Expand a small parameter grid and verify stable manifest digests regardless of scheduling order. Exceed the work budget, corrupt one artifact, and omit a seed; each must fail visibly. Done means deterministic replay, exact truth, adapter conformance, merge verification, raw evidence, quotas, and report regeneration pass in one command.

Find Crossovers and Break the Candidates

Verification tests the laboratory before trusting what it says about sketches. Unit and property tests cover generators, seed isolation, oracle identities, adapter capability declarations, merge equivalence, serialization, quantiles, manifest hashing, and schema migration. Metamorphic tests shuffle insertion order for order-invariant algorithms, repartition mergeable streams, duplicate or scale weights where the mathematics predicts a response, and compare restored state with uninterrupted execution.

An approachable end-to-end study compares an exact set with linear counting from 100 to 1 million distinct keys, identifying the point where fixed bitmap memory beats the exact baseline while error remains acceptable. The professional matrix covers HLL, Bloom/Cuckoo filters, CMS/Count Sketch, reservoir sampling, and KLL/GK quantiles across uniform, Zipf, drift, heavy-tail, merge, and adversarial workloads. Each cell runs at least 30 preregistered seeds, reports p50/p95/p99 accuracy and latency, empirical confidence coverage, peak memory, serialized bytes, throughput, merge cost, failures, and cost per billion updates.

Failure injection kills workers mid-trial, throttles CPU, fills disk, corrupts artifacts, delays object storage, changes the clock source, poisons a baseline, leaks adapter state between runs, and schedules noisy neighbours. Metrics expose queue/run time, retries by reason, quota kills, host calibration drift, timer anomalies, artifact checksum failures, oracle disagreements, seed coverage, and report exclusions. Audit logs preserve manifest approval, adapter/dataset provenance, retry lineage, exclusions, baseline changes, and the final decision owner.

Verification and observability surfaceHarness tests, reference workloads, adversarial trials, calibration metrics, traces, alerts, and audit evidence support publish, hold, or invalidate decisions. Harness property testsseeds • oracle • merge Reference sweepsaccuracy • cost • crossover Faults + adversariesnoise • corruption • bias Metrics + tracesrunner and sketch signals Audit evidencemanifest • retry • exclusion Alertsdrift • quota • integrity Evidence dossierraw rows + decision Reviewerpublish • holdinvalidate An attractive chart cannot outrank failed integrity, calibration, or reproducibility gates.
Requirement / guaranteeTest oracleWorkloadMetric and thresholdFailure injectionEvidenceOwner
Workloads replay exactlyStream digestEvery generator/seed100% digest equalityGenerator dependency changeGolden digests and lockfileWorkload owner
Truth is correctIndependent brute-force fixtureSmall exhaustive streamsZero oracle mismatchCorrupt oracle stateCross-oracle reportCorrectness lead
Adapter contract is honestCapability/conformance suiteUpdate/query/merge/restoreUnsupported operations rejected; supported ones passVersion and dimension mismatchConformance logAdapter owner
Error claims are calibratedExact truth across seeds30+ trials per matrix cellEmpirical coverage within preregistered toleranceBiased seed subsetCoverage curve and seed manifestStatistics reviewer
Timing is stable enoughHost calibration benchmarkRepeated reference kernelDrift ≤2% on stable poolCPU throttle/noisy neighbourCalibration seriesPerformance engineer
Resources are boundedOS/container telemetryLargest grid and stateQuota enforced before/at limitMemory bomb and disk fillQuota-kill auditPlatform lead
Merge behaviour matches contractSingle-pass reference1, 8, 64 partitionsError/estimate within algorithm contractMissing/incompatible shardMerge matrixAlgorithms reviewer
Results remain reproducibleArtifact reanalysisPublished benchmarkReport regenerates from raw rows/checksumsDelete derived chartRebuild log and digestsReproducibility owner
Runner recovers safelyManifest/retry lineageWorker loss mid-trialNo silent sample duplication; availability ≥99.9%Kill worker/storage delayRetry DAG and incident timelineSRE
Private data stays governedAccess and expiry oracleSanitized replayZero unauthorized reads; expiry enforcedForged dataset tokenSecurity test and access auditPrivacy owner
Production

Find Crossovers and Break the Candidates: Sketch Benchmark Laboratory

Run a preregistered matrix across 6 algorithms, 8 workload families, 6 parameter sizes, and 30 seeds, with exact truth where feasible and shard counts 1, 8, and 64. Require complete seed coverage, zero oracle/conformance failures, reference-host timing drift ≤2%, reproducible report digests, enforced quotas, and each selected design meeting its stated p95 error, memory, throughput, and merge budget. At 20% progress throttle one worker; expect calibration quarantine. At 40% kill a trial and require lineage-preserving retry. At 60% corrupt one artifact; expect checksum exclusion and incomplete-cell failure. At 80% poison the baseline; expect review hold. Invalidate the recommendation for any cherry-picked seed, mixed manifest digest, missing raw sample, integrity failure, or unexplained regression. Record PUBLISH, CONDITIONAL, or INVALID with crossover plots, uncertainty, cost, exclusions, owners, and condition expiry.

Publish the Benchmark Dossier

The deliverable includes adapter and experiment schemas, generator/oracle specifications, parameter calculators, a pinned execution image, environment fingerprints, preregistration, immutable raw results, checksums, analysis code, comparative tables, crossover plots, calibration curves, benchmark report, correctness dossier, privacy review, incident notes, and an operational runbook. Every chart links back to raw rows and a manifest digest; every recommendation states its workload region, SLO weights, limitations, and rejected alternatives.

The runbook begins with queue delay, timing drift, oracle mismatch, quota kill, missing seed, corrupt artifact, adapter crash, storage outage, and baseline regression. It supplies diagnostics, exclusion rules, retry policy, escalation, invalidation criteria, and evidence-preservation steps. The demonstration regenerates a seeded fixture, runs exact and linear-counting adapters, shows raw error and memory rows, verifies compatible merge, rejects incompatible merge and excessive work, recomputes the report, then changes the decision weights to reveal a crossover.

Peer reviewers ask: Was the hypothesis and seed schedule fixed before results? Are workloads representative and adversarial? Is the oracle independent? Are warm-up, isolation, timing, and memory methods defensible? Are tails and failures visible? Does merging preserve the advertised guarantee? Can every figure be regenerated? Is the recommendation conditional rather than universal? Handoff requires tagged code/images, checksums, clean one-command replay, signed review, retained raw evidence, rehearsed incident handling, ownership, and no undocumented exclusions.

Deliverable

Publish the Benchmark Dossier: Sketch Benchmark Laboratory

Final checklist: (1) build the pinned image from a clean checkout; (2) run harness conformance, generator/oracle, replay, calibration, load, security, and fault suites; (3) freeze manifest and seed schedule; (4) archive raw rows, logs, checksums, environment fingerprints, and analysis code; (5) regenerate every table and figure; (6) sign correctness, statistics, performance, and privacy reviews; (7) rehearse retry, exclusion, invalidation, and recovery; (8) assign report and baseline owners. Demo deterministic replay, exact truth, an adapter sweep, error distribution, resource/cost table, merge trial, corrupted-artifact rejection, and crossover decision. Score 0–2 for validity, reproducibility, oracle quality, statistical treatment, performance method, operational safety, privacy, and decision usefulness; require ≥14/16 with no zero. Stretch goals: energy measurement, cross-language adapters, continuous regression bisecting, and hardware-normalized models. Milestones: reference suite, multi-host calibration, then continuously verified decision envelopes.

Publish only when raw evidence, exact truth, calibration, resource controls, provenance, and one-command regeneration survive independent review. Known risks include benchmark gaming, unrepresentative generators, correlated seeds, timer noise, private-data leakage, and universalizing a local winner; ask which changed assumption reverses the choice, then make continuous crossover-regression detection the next milestone.