1 of 1 lane measured
VectorDBBench
Qualified vector search quality, throughput, serial latency, serving demand, and database volume across operating points.
vector-vdbbench-50k
complete50K
Three fresh Antfly lifecycles at the calibrated 50K operating point, reporting quality, throughput, latency, serving demand, and database volume.
Methodology scope · protocol · interpretation
VectorDBBench methodology
Antfly subject and execution lane
Circus accepts an explicit subject manifest containing the asserted release tag,
commit, and Linux/arm64 Antfly binary. It records the binary path, SHA-256,
architecture, and observed --version output, while treating the supplied tag
and commit as release metadata. The honed matrix mounts that binary read-only
into Antfly’s Linux container. Every comparison engine runs in the same private
Docker network; no native macOS database is mixed into this benchmark.
The public benchmarks/VectorDBBench checkout remains clean. Circus-owned
parameter selection, compatibility fixes, query partitioning, and diagnostics
live in benchmarks/VectorDBBench-harness and are loaded as a runtime overlay.
Workloads and query protocol
The publication matrix contains six engines on both upstream workloads:
Performance1536D50K: 50,000 vectors with 1,536 dimensions.Performance768D1M: 1,000,000 vectors with 768 dimensions.
For each workload, the 1,000 upstream query/ground-truth pairs are ranked by a fixed SHA-256 seed and split into 200 calibration queries and 800 publication queries. Their exact overlap is zero; both partition fingerprints are retained.
Each engine/workload trial has one fresh service and one fixed index lifecycle:
- Start lifecycle memory sampling before indexing.
- Load and build the index once using fixed construction parameters.
- Sweep only the query-time parameter on the 200-query calibration partition.
- Freeze the lowest setting reaching recall 0.955. If none qualifies, retain the highest-recall setting and mark it below the qualification floor.
- Without rebuilding, run the selected setting on the untouched 800-query partition at 1, 5, 10, 20, and 30 concurrent clients for 30 seconds each, followed by the upstream serial quality and latency pass.
- Capture one diagnostic post-workload storage observation, gracefully stop and verify the service, capture final storage, retain the artifacts, and only then reclaim the engine’s data.
The 50K and 1M settings are selected independently because the larger graph may need a higher search setting. Publication results never influence selection. A row below the 0.950 publication floor remains visible and is not silently retuned or omitted. No process-restart measurement is published.
Tuned and fixed parameters
| Engine | Fixed index/build parameters | Query-time selection |
|---|---|---|
| Antfly | AKNN, one shard, packed float32 queries | search_effort sweep |
| Milvus | HNSW M=16, efConstruction=256 | ef_search sweep |
| Chroma | HNSW M=16, efConstruction=256 | fixed ef_search=256 qualification |
| Weaviate | HNSW maxConnections=16, efConstruction=256 | ef sweep |
| pgvector | HNSW m=16, ef_construction=128 | ef_search sweep |
| Elasticsearch | HNSW m=16, ef_construction=100 | num_candidates sweep |
The final report prints the selected value for every workload and engine.
Weaviate and Elasticsearch are local containers; their upstream adapter class
names (WeaviateCloud and ElasticCloud) do not describe the deployment.
Memory
The headline Demand peak MB is the maximum sampled cgroup-v2 anon + shmem
from before indexing through readiness, calibration, and publication queries.
It excludes reclaimable file cache and follows MEASURING_ANTFLY.md. Sampling
runs every 200 ms and retains a JSONL timeline. Cache-inclusive
memory.current and kernel memory.peak are supplementary raw diagnostics.
Honed publication requires three fresh lifecycles per engine/workload. The headline table shows each arithmetic mean; detail artifacts retain every observation, the mean, and the individual-trial range. A trial is rejected if the canonical sampler reports a failure, misses any container in the service stack, starts after indexing, stops before publication finishes, or leaves a timeline gap above five seconds. Peak throughput, its concurrency, C=30 throughput and concurrent p99, recall, nDCG, serial latency, and memory are arithmetic means of the three compatible lifecycle observations. Raw curves and ranges remain retained. The selected setting and protocol identity must match across all three trials.
The complete Antfly standalone container is measured, so all Antfly processes and threads in that cgroup are included. Termite is not part of this workload because VectorDBBench supplies precomputed vectors.
Persistent database volume
Every publication engine receives one newly created, run-labeled Docker
local volume at its complete persistence root. The digest-pinned Alpine probe
captures whole-volume allocated and apparent bytes once at empty, ready,
and post_workload, then at the verified post-stop final barrier.
Host-path/no-network Antfly is rejected for comparative storage. Pre-stop
background compaction remains diagnostic and does not gate the post-stop metric.
Final allocated bytes are the headline. The same three construction lifecycles
define performance, memory, and storage aggregates. Every value, arithmetic
mean, range, receipt, and barrier sample remains under raw/storage.
Internal Antfly scale diagnostic
make vdbbench-scale-fast and make vdbbench-scale-big run an Antfly-only
diagnostic beside the cross-engine publication matrix. The fast profile uses
20K, 40K, 60K, 80K, and 100K vectors; the big profile uses 200K, 400K, 600K,
800K, and 1M vectors. make vdbbench-scale selects both. All points use 768
dimensions and the same 200-query calibration partition, disjoint 800-query
held-out partition, serial pass, and 1/5/10/20/30-client 30-second capped sweep
described above.
The diagnostic has exactly two fresh index lifecycles per point. Trial one runs
from the smallest to largest selected corpus; trial two reverses that order.
This controls simple order effects without claiming the three-lifecycle
publication cohort. The aggregate and every row set
publication_eligible: false, retain both raw values plus their arithmetic
mean and range, and state the two-lifecycle caveat. Scale results must not be
merged into the honed cross-engine cohort.
The source corpus is the pinned upstream Cohere 768-dimensional 1M-vector fixture. Circus verifies its immutable source files, computes exact cosine top-k ground truth against deterministic prefix sizes, and writes explicit custom-dataset manifests. A streaming iterator is bounded by the manifest’s declared prefix size; a smaller point cannot consume rows belonging to a larger shared Parquet file.
Each point/trial is an immutable publication-cache cell with workload-specific
dataset identity. A cache miss receives one fresh retry, never an in-place
resume. Only a complete positive lifecycle or a classified held-out
capacity/rejection result can be promoted. The canonical diagnostic artifact
retains every cell’s receipt/cache reference, query-partition digest, selected
search effort, request-error evidence, memory timeline, final allocated volume,
and insert_duration + optimize_duration build time.
Output and retention
The canonical artifact contains report.md, normalized result.json,
provenance, a receipt, selected settings, the raw capped-concurrency JSON/CSV
diagnostic, memory rows and timelines, logs, supervisor/status evidence, and
upstream result JSON. Standard publication runs VectorDBBench’s increasing
concurrency progression at 1, 5, 10, 20, and 30 clients. Normalized rows report
peak QPS and its concurrency as well as qps_c30 and p99_c30_ms.
A lifecycle that completes the selected-setting, held-out capped sweep but has
explicit nonzero request rejections is retained as a classified capacity
terminal negative. It is reusable only with the exact concurrency schedule,
query partition, selected setting, full memory timeline, quiet-host assertion,
logs, and supervisor evidence. Setup/index/configuration failures, crashes,
timeouts, partial lifecycles, and unknown failures are never reusable
publication cells.
Database volumes are deleted only after the verified final capture unless an
operator explicitly opts into retaining them for debugging. The retained
storage.json receipt and complete optional-trial evidence are results; the
live volume is not.
Run evidence parameters · variation · provenance
Benchmark parameters
{"concurrency_duration_seconds":30,"concurrency_schedule":[1,5,10,20,30],"query_count":800,"workloads":["1536d-50K"]}Trial variation
[{"engine":"Antfly","ranges":{"demand_working_set":{"maximum":1024.7,"mean":967.8,"minimum":916.5,"unit":"MB"},"final_database_volume":{"maximum":538.243072,"mean":534.553941,"minimum":532.553728,"unit":"MB"}},"workload":"1536d-50K"},{"engine":"Chroma","ranges":{"demand_working_set":{"maximum":468.9,"mean":463.3,"minimum":455.4,"unit":"MB"},"p99_at_peak_concurrency":{"maximum":176.7,"mean":176.467,"minimum":176.3,"unit":"ms"}},"workload":"1536d-50K"},{"engine":"ElasticCloud","ranges":{"demand_working_set":{"maximum":1871.2,"mean":1861.3,"minimum":1854.6,"unit":"MB"},"final_database_volume":{"maximum":312.430592,"mean":312.380075,"minimum":312.352768,"unit":"MB"},"p99_at_peak_concurrency":{"maximum":13.7,"mean":13.5,"minimum":13.4,"unit":"ms"}},"workload":"1536d-50K"},{"engine":"Milvus","ranges":{"demand_working_set":{"maximum":2577.1,"mean":2490.3,"minimum":2428.4,"unit":"MB"},"final_database_volume":{"maximum":1741.217792,"mean":1741.202773,"minimum":1741.193216,"unit":"MB"},"p99_at_peak_concurrency":{"maximum":10.6,"mean":10.433,"minimum":10.3,"unit":"ms"}},"workload":"1536d-50K"},{"engine":"PgVector","ranges":{"demand_working_set":{"maximum":2303.9,"mean":2303.8,"minimum":2303.7,"unit":"MB"},"final_database_volume":{"maximum":1523.970048,"mean":1523.965952,"minimum":1523.961856,"unit":"MB"},"p99_at_peak_concurrency":{"maximum":35.6,"mean":33.7,"minimum":32.6,"unit":"ms"}},"workload":"1536d-50K"},{"engine":"WeaviateCloud","ranges":{"demand_working_set":{"maximum":965.9,"mean":938.5,"minimum":912.1,"unit":"MB"},"final_database_volume":{"maximum":391.360512,"mean":391.277227,"minimum":391.172096,"unit":"MB"},"p99_at_peak_concurrency":{"maximum":86.5,"mean":85.533,"minimum":83.7,"unit":"ms"}},"workload":"1536d-50K"}]Peer versions
Peer versions were not recorded in the published result fields.
Evidence digests
- Receipt
c5e1c66b128511a17ed9394d15e5dd888d44424520d7374c794311bc72306bf2- Aggregate
6a14a044e7e414d833a10b34069db8e1e043ae631354ea1cf73b313c4a0d65b3- Provenance
73e2877a476489463206ebfba43923197329a3eae2cd2a002de827940f9f2325- Harness commit
1d66908788c25a92d0a35a01a0230e629d1c97d6
Scope notes
- This campaign ran Antfly only; the evidence does not support a cross-engine ranking.
- All three lifecycles reused one independently calibrated configuration and retained disjoint publication measurements.
- Completed
- Antfly
v0.1.3·- Runtime
- 45m 37s
- Platform
- linux · aarch64
- Machine
- c4a-standard-4 · 4 CPU · 16.7 GB
- Build
- Not recorded · Zig Not recorded
This campaign ran Antfly only; the evidence does not support a cross-engine ranking.
All three lifecycles reused one independently calibrated configuration and retained disjoint publication measurements.
Peak throughput
Antfly v0.1.3 (1b070b5d) · linux-aarch64 · c4a-standard-4 · 1536d-50K · Higher is better
Serial query p95
Antfly v0.1.3 (1b070b5d) · linux-aarch64 · c4a-standard-4 · 1536d-50K · Lower is better
Demand working set
Antfly v0.1.3 (1b070b5d) · linux-aarch64 · c4a-standard-4 · 1536d-50K · Lower is better
Final database volume
Antfly v0.1.3 (1b070b5d) · linux-aarch64 · c4a-standard-4 · 1536d-50K · Lower is better
Performance, quality, and resource evidence
Antfly v0.1.3 · 1b070b5d
| Engine | Workload | Recall | nDCG | Peak QPS queries/s | p95 ms | Demand working set MB | Cache-inclusive peak MB | Final database volume MB | Trials |
|---|---|---|---|---|---|---|---|---|---|
| Antfly | 1536d-50K | 0.997 | 0.998 | 65.5 | 20.90 | 967.8 MB | Not measured | 534.6 MB | 3 |
| Chroma | 1536d-50K | 0.987 | 0.989 | 179.9 | 8.07 | 463.3 MB | 809.2 MB | Not recorded MB | 3 |
| ElasticCloud | 1536d-50K | 0.960 | 0.967 | 4,600.1 | 1.97 | 1,861.3 MB | 4,318.4 MB | 312.4 MB | 3 |
| Milvus | 1536d-50K | 0.963 | 0.970 | 5,643.1 | 1.50 | 2,490.3 MB | 4,565.6 MB | 1,741.2 MB | 3 |
| PgVector | 1536d-50K | 0.969 | 0.975 | 2,432.3 | 4.17 | 2,303.8 MB | 3,265.2 MB | 1,524.0 MB | 3 |
| WeaviateCloud | 1536d-50K | 0.955 | 0.963 | 995.6 | 6.60 | 938.5 MB | 1,553.7 MB | 391.3 MB | 3 |