xycalc: how much X does it take to run Y?

How much RAM does a 500 GB MongoDB actually need? How many IOPS before EBS starts microbursting? These questions get answered on the internet constantly — with a number and no provenance. xycalc answers them from a corpus with two guarantees, both enforced by a build that fails when either is broken: every number cites a source, and every number names the software version it applies to. MongoDB’s eviction defaults, ClickHouse’s settings, EBS’s per-volume limits — all of them move between releases. “80%” isn’t a fact. “80% on MongoDB 6.0” is.

There’s a third guarantee it makes by admission rather than refusal: every model states how much it’s actually been checked against reality. A model nobody has validated prints unvalidated (n=0) on every single invocation. That’s the normal state of a new model — what wouldn’t be normal is leaving it unsaid.

$ xycalc sizing mongodb.wt-cache --storage-size 500GB --index-size 40GB

  FLOOR
    Collection data on disk                + 500.0 GB   ->   500.0 GB
  AMPLIFIER
    Decompression into cache           x 2.5 (1.5-3.5)   ->     1.3 TB
  FLOOR
    Indexes                                 + 40.0 GB   ->     1.3 TB
  AMPLIFIER
    Eviction headroom                           / 80%   ->     1.6 TB

  ANSWER   1.6 TB
  band     987.5 GB - 2.2 TB
  ~ thinly validated (n=1, 1 within band, mean absolute error 41.1%)

A 500 GB database doesn’t want a 500 GB cache — it wants about 1.6 TB, and MongoDB’s own documentation then tells you not to configure that. xycalc prints the contradiction as a constraint instead of hiding it, because the useful output of a sizing question is often the discovery that you asked the wrong one.

The shape of a model

Every model is a sequence of typed terms — floor (the irreducible requirement), amplifier (what raises it above the floor), headroom (what the tail costs, not the mean), constraint (binds without computing, like “the vendor says don’t”). Every value carries a lo/mode/hi band the whole way through, because a point estimate on a sizing question is a claim nobody can honestly make. Data lives as YAML under data/; the code reads it and never hardcodes a figure — a number sitting in a Python module is treated as a bug, because it bypasses both gates. That also means a new model is YAML, never code.

What’s actually there right now

Four models across three investigations that turned out to be one failure told in three parts: the cache can’t hold the whole database, so misses go to disk; the disk throttles on the peak second, and the metrics most people watch average that away; the throttle becomes a concurrency ceiling, and the queue behind it doesn’t drain — which is why a slow disk makes MongoDB stop returning queries rather than merely slow down. mongodb.wt-cache has survived exactly one validation run: n=1, inside the band, +41.1% at the mode against a real MongoDB 7.0.39 benchmark — a number that’s close to meaningless on its own; the decomposition is the actual point, since the compression coefficient was off by about 64% while the structural terms understated resident bytes by 13.9%. Two errors, opposite signs, one percentage. The other three models — host RAM, EBS IOPS provisioning, and a ticket-throughput ceiling — are still unvalidated (n=0) and say so on every run. The EBS model is honest about something worse than being unvalidated: its only amplifier is a guess with a band spanning a factor of 6.7, because the figure it needs is structurally unrecoverable from minute-averaged cloud metrics.

Bring your own reality

local/ is a gitignored overlay merged on top of the public data at build time — how a deployment feeds its own production telemetry into the models to validate them against its own reality, without publishing any of it and without forking the code. One codebase, two data footprints. A checkout with no local/ builds the public corpus and says so on every build.

Contributing

The bar for a pull request isn’t “is this true,” it’s “can a stranger check it” — a source, the sentence the figure was read from, and the versions it applies to. xycalc build && xycalc audit && pytest -q is the whole gate, and CI runs those as three separate jobs. Real measurements are worth more here than code: ClickHouse, Redis, Celery, and NVMe are already named in the systems file and deliberately left empty, and the roadmap lists ten more designed experiments, each naming its question and what would falsify it.

python3.12 -m venv .venv && .venv/bin/pip install -e ".[dev,gui]"
.venv/bin/xycalc sizing mongodb.wt-cache --storage-size 500GB --index-size 40GB

Code is MIT; the corpus and docs are CC BY 4.0.


From my swamp to yours.

github.com/gmhoward9289-ops/xycalc