Benchmarks#
The benchmark scripts compare local builds and check performance regressions. They do not define published performance numbers.
See the 2026-08-27 benchmark snapshot for the latest dated local results.
C ABI overhead#
Compare native Kvist calls with matching C ABI calls:
KVIST_ROOT=/path/to/kvist \
KVIST_BIN=/path/to/kvist-bin \
KVIST_PACKAGES_DIR=/path/to/kvist/packages \
bench/compare_abi.sh
DataScript read queries#
The DataScript adapter runs the same query shapes through DataScript, Datalevin, and VevDB's in-tree Clojure wrapper.
It requires JDK 25, Clojure CLI, and a Datalevin checkout:
scripts/build_native_library.sh
DATALEVIN_BENCH=/path/to/datalevin/benchmarks/datascript-bench \
bench/datascript_bench/run_compare.sh
Pass query names to run a subset:
DATALEVIN_BENCH=/path/to/datalevin/benchmarks/datascript-bench \
bench/datascript_bench/run_compare.sh q1 q2 q2-switch
See DataScript benchmark adapter for workloads and timing options.
Transactions#
Build bench/write_bench.kvist for native in-memory and durable Vev writes.
The matching Datomic adapter targets either an in-memory database or a local
dev transactor:
bench/write_bench/run_datomic.sh \
--uri datomic:mem://vev-write-bench \
--batch 100 \
--total 10000
Small resident durable transactions#
resident_small_transactions.kvist measures one durable commit at a time on
one long-lived resident connection. It covers a new fact, cardinality-one
replacement, explicit retract, retractEntity, and a Ro-shaped replacement
with three transaction-provenance facts. Every shape runs from the same seed on
both a 50-entity and a 2,000-entity database.
python3 bench/check_resident_small_transactions.py --mode both --samples 40
The output includes median/p95, effective tx-data datoms, phase time and phase
percentages. --mode full forces the reference full-build-db path; the
default incremental mode uses production selection. The checked-in budget is
for incremental mode and intentionally leaves headroom for CI variance.
See resident transaction performance for the architecture, invariants, and a same-machine before/after profile.
Public Kvist/native transaction boundary#
kvist_transaction_boundary.kvist measures the actual public Kvist package,
the retained EDN compatibility path, native engine phases, report ownership,
exact DB retains, and structured report materialization:
python3 bench/check_kvist_transaction_boundary.py --samples 100
The checked budget conservatively sums phase p95 values and limits the large/Ro-like overhead outside ordinary engine work to 1 ms. The benchmark can also run the exact Ro transaction against two disposable Ro demo databases. See Kvist/native transaction boundary for commands, measurements, API rationale, and ownership rules.
The same executable includes small, large, wide-schema, and
schema-churn databases and append, replacement, cas,
explicit-retract, retract-entity, and ro-like workloads. Its profile
output includes detailed resolution/planning times, operation counts, and
effective transaction datoms. Exact Ro diagnostics select
--ro-workload ro-demo, ro-demo-no-provenance, or
ro-demo-resolved-ids against independent disposable database copies.
Registered transaction-function expansion has a deterministic source-backed durable row:
kvist build bench/durable_transaction_function.kvist \
--out build/bench/durable-transaction-function
build/bench/durable-transaction-function --samples 100 --warmup 20
See resident transaction resolution and planning for the root cause, scaling matrix, reference-planner differential, and current budgets.
Durable storage amplification#
The deterministic storage benchmark writes 1,000 application assertions using
five transaction shapes. Its default committed mode performs one real SQLite
commit for every logical transaction. It checkpoints the WAL before measuring
the SQLite file, reports file/live/freelist bytes, checkpoint and novelty
bases, every durable index artifact, dbstat object sizes, and transaction,
open, and query latency:
python3 bench/storage_amplification.py --build
Pass --output-dir to retain the databases for inspection, --json-output
to save the measurements, and --budgets to enforce a checked-in or local
JSON budget. A shape such as --shape 1000x1 means 1,000 logical
transactions containing one assertion each. Every transaction also records
the normal :db/txInstant datom.
--mode logical exercises the atomic multi-transaction API instead. That mode
is useful for its distinct all-or-nothing contract, but it is not a substitute
for measuring visibility and durability after every small commit.
The checked-in regression budget covers file bytes per datom, incremental bytes per logical transaction, derived row counts, and process-level open, query, and transaction latency:
python3 bench/storage_amplification.py --build \
--budgets bench/storage_amplification_budget.json
Latency limits are deliberately broad enough for CI machines; dated result files remain the useful same-machine comparison.
Recursive rules#
Compare VevDB with a local DataScript checkout:
KVIST_ROOT=/path/to/kvist \
KVIST_BIN=/path/to/kvist-bin \
KVIST_PACKAGES_DIR=/path/to/kvist/packages \
DATASCRIPT_ROOT=/path/to/datascript \
bench/compare_query_rules.sh
Use bench/compare_query_rules_stress.sh for the larger cases.
Math genealogy#
Export Datalevin's math benchmark data, then run the four rule workloads:
MATH_BENCH_JSON=/path/to/data.json.gz \
bench/math_bench/run_export.sh
KVIST_ROOT=/path/to/kvist \
KVIST_BIN=/path/to/kvist-bin \
KVIST_PACKAGES_DIR=/path/to/kvist/packages \
bench/math_bench/run_vev.sh
MusicBrainz#
MusicBrainz benchmarks use the durable store created by the MusicBrainz validation workflow:
scripts/musicbrainz_clojure_vev_matrix.sh --help
scripts/compare_musicbrainz_workshop.sh --help
To check the restored durable performance and result fingerprints on the reference machine:
scripts/compare_musicbrainz_workshop.sh \
--engine vev \
--skip-kvist \
--prepared-vev \
--warmup-runs 10 \
--measure-runs 25 \
--budget-file bench/musicbrainz_durable_budget.edn
The checked-in budget is a same-machine regression guard, not a portable CI limit. It validates the benchmark settings, row counts, fingerprints, and median workload times.