strawmANN benchmark report

strawmANN against Qdrant · AMD Ryzen AI 9 HX PRO 370 w/ Radeon 890M (24 logical) · generated 2026-10-13 06:33:55 CEST

Dataset
h-and-m-2048-angular-filters
Vectors
105,100 × 2,048 · 10,000 held-out queries
Metric
cosine
Storage datatype
strawmANN float32 · Qdrant float32 (default)
Quantization
none (fp32) · separate rows measure binary (1 bit/dim), PQ (product), SQ8 scalar, turboquant
strawmANN: 55/55 ok Qdrant: 55/55 ok

Summary

No matched-recall ratio is stated between strawmANN and Qdrant. W10-ef32: one pass apart from the other two (strawmANN pass 1 +10%) The per-row tables below carry the same refusal wherever it applies.

p99 latency at 90% load
strawmANN2.53 ms
Qdrant3.03 ms
W4-sat90, open loop, one offered rate
upload and index build
strawmANN24 s
Qdrant25 s
W1 + W2
peak memory (RSS)
strawmANN5.6 GiB
Qdrant10.1 GiB
largest before the concurrent-write rows (W11); of it, anonymous 632.1 MiB / 559.7 MiB
written to disk
strawmANN9.6 GiB
Qdrant47.5 GiB
before the concurrent-write rows (W11); they wrote 205.8 MiB / 28.7 GiB more

Where strawmANN is slower, past the noise floor:

Throughput against recall

Read it vertically: at any recall both engines reach, the higher curve is faster. Throughput from bfb W10, recall from the conformance sweep, joined on ef. ef is the same unit here: Qdrant held 2 segments for this run, one populated and 1 empty (read back per segment from the engine), and strawmANN held one graph, so equal ef is equal traversal width and the curves may be read at equal x. That is a property of this run, not of the engines.

Every figure is the median of 3 passes per engine, run alternately (A/B/A/B). What this does not establish.

Glossary
recall@10
Of the ten nearest neighbours a query really has, the share the engine returned. 1.0 is a perfect answer. "Really has" is settled by an exhaustive fp64 search, not by the other engine.
ef
The candidate-list size: how many nodes the index keeps in play while searching. Larger is slower and more accurate. It does not mean the same amount of work in both engines, which is why the headline holds recall fixed instead.
MRDE
Mean relative distance error: when the engine returns a wrong neighbour, how much further away it is than the right one. Small numbers mean the misses were near-misses.
qps
Queries per second. On a batched row one request carries several queries, and the request rate is shown under it.
p50 / p99 / p99.9
The latency half of requests beat, that 99% beat, that 99.9% beat. The tail is what a user notices.
closed / open loop
A closed loop sends the next request only when the last one comes back, so a slow server receives less work and its tail looks better than it is. An open loop sends at a fixed rate regardless.
noise floor
How much a number moves between identical runs on this machine. A ratio inside it is shown grey with ≈: no measured difference. Hover a ratio to see its band.
conformance tier
What the two engines were shown to agree on before any speed was quoted. T1 licenses a single engine's own numbers; T3 licenses comparing the two, and requires their recall to be statistically indistinguishable.
§ numbers
Sections of docs/spec.md, the written rule each claim in the appendix is measured against. §7.1 is the host gate, §7.4 the comparison rules, §8 what may be published.

Throughput

Queries per second; higher is better. The ratio is strawmANN over Qdrant: green is faster, red slower, grey ≈ inside the noise floor (hover a ratio for its band). A dash means the pair is not compared, and the note says why. An ef sweep is one row showing its range; every measurement is under All throughput rows.

workloadstrawmANNQdrantrationotes
W3search, fp32, single query1,2869951.29x
W4search, saturating (closed loop)4,6585,6730.82x
W5search batched (16 distinct dataset queries per request)4,649334 requests/s5,953405 requests/s0.78x
W6quantized: scalar10,8349,1711.18x
W6 ef 32 to 512SQ8 recall control (latency only)3,541 to 31,6833,582 to 21,6241.03 to 1.47x1 of 5 points at parity
W7quantized: binary + oversampling25,18116,4811.53x
W7-2bitquantized: binary quantization, 2 bits + oversampling21,16814,4381.47x
W7-1p5bitquantized: binary quantization, 1.5 bits + oversampling22,82614,678-one pass apart: Qdrant pass 2 -14%
W8quantized: PQ6,5074,8391.34x
W14-1bitquantized: TurboQuant, 1 bit + oversampling16,38613,9911.17x
W14-1p5bitquantized: TurboQuant, 1.5 bits + oversampling13,35112,8301.04x
W14-2bitquantized: TurboQuant, 2 bits + oversampling17,60213,260-one pass apart: Qdrant pass 2 -15%
W14-4bitquantized: TurboQuant, 4 bits + oversampling12,51912,2461.02x
W9exact / brute force7172parity
W10 ef 32 to 512recall control (latency only)1,731 to 12,0211,957 to 10,511parity1 of 5 points not compared one pass apart: strawmANN pass 1 +10%
W12-sel1filtered search, one keyword (~1% of bench12)5,5735,956parity
W12-sel10filtered search, any of 10 keywords (~10% of bench12)3,7012,9491.25x
W12-sel1 ef 32 to 512filtered recall control, one keyword (latency only)5,551 to 5,5676,061 to 6,0860.91x3 of 5 points at parity
W12-sel10 ef 32 to 512filtered recall control, any of 10 keywords (latency only)617 to 9,5621,150 to 6,2251.18 to 1.54x1 of 5 points not compared one pass apart: Qdrant pass 1 -25%
W13scroll / pagination56,85450,6971.12xstrawmANN: 91% is client and socket, not server Qdrant: 81% is client and socket, not server
W11-steadymixed read/write below the rebuild threshold: search bench2 while 5,255 synthetic points append4,2013,884-search-during-write; no recall join
W11mixed read/write: search bench2 while 21,020 synthetic points append (runs last)3,6982,695-drifted: Qdrant -19% across passes one pass apart: strawmANN pass 1 +10%

Throughput by workload

Higher is better. Hatched bars are rows the table does not compare (W0, W11): each bar is that engine's own rate, and the pair is not a result.

Recall

recall@10 against an exact fp64 search, not against the other engine. Equal ef is not equal work in the two engines, so the comparison that counts holds recall fixed and compares throughput there.

At matched recall

Recall by ef

efstrawmANNQdrant
recall@1recall@10recall@100MRDErecall@1recall@10recall@100MRDE
ef=320.99790.9941-1.47e-030.99710.9884-1.29e-03
ef=640.99880.9968-9.26e-040.99870.9944-6.77e-04
ef=1280.99950.99840.99214.77e-040.99950.99720.98703.02e-04
ef=2560.99970.99920.99743.55e-040.99960.99870.99601.40e-04
ef=5120.99990.99960.99928.67e-050.99980.99930.99861.18e-04
How recall was measured

10,000 held-out queries, limit 10, ε=9.537e-07, against the fp64 oracle rather than against the other engine. Base checksum 5a7faba68c84ce7c: the same corpus the latency rows were measured on. Each pass rebuilds the collection. Across 3 independent builds of it, recall@10 at ef=512 spread by: strawmANN 0.00027; Qdrant 0.00022. Over the same builds the engine reported unreachable nodes: strawmANN 0 of 105,100, in-degree zero 2 — a node nothing points at is invisible at any ef, so that is where a graph-quality difference shows rather than being inferred from the recall beside it. Level seed: strawmANN 0x57ea3111. Recorded as provenance: under this engine's level draw, six builds at four seeds sit within 0.00003 of recall@10 at ef 512, well inside the spread above.

What each quantization costs in recall

Colour is the encoding here, not the engine — the engines are the line style. Each sweep is joined on the quantization parameters it actually sent, so a curve speaks only for the search its row ran. Higher is better, and the encodings are not free: read this against the throughput their rows bought.

Latency

Client-side round trip. A closed loop understates the tail (a stalled server stops receiving requests), so this keeps the fixed-rate, open-loop rows, which offer the same load to both engines, plus single-client W3 and batched W5. Every row is under All latency rows.

workloadstrawmANNQdrant
p50p99p99.9p50p99p99.9
W3 search, fp32, single query756 µs1.39 ms1.74 ms995 µs1.42 ms1.55 ms
W4-sat50 search, fixed rate at 50% of saturation (open loop)893 µs1.57 ms1.80 ms1.10 ms1.68 ms2.35 ms
W4-sat70 search, fixed rate at 70% of saturation (open loop)1.01 ms2.11 ms2.46 ms1.18 ms2.31 ms2.79 ms
W4-sat90 search, fixed rate at 90% of saturation (open loop)1.15 ms2.53 ms3.45 ms1.42 ms3.03 ms4.09 ms
W5 search batched (16 distinct dataset queries per request)219.78 ms224.42 ms229.72 ms170.49 ms219.98 ms281.22 ms

Ingest and index build

Qdrant indexes while it ingests, so its upload time already contains most of the indexing; strawmANN uploads raw and builds afterwards. Compare the sum, not the upload line.

Where the load time goes

Solid is upload, hatched is the wait for Green. The bar's whole length is the sum this section asks you to compare; the split is why the upload line alone is not comparable between these engines.

workloadstrawmANNQdrant
W0-uploadd=4 floor: graph traversal with the distance taken out4.01 s4.01 s
W1ingest throughput (no index wait)1.05 s2.41 s
W2index build, time to Green23.07 s23.06 s
W6-uploadsearch, SQ8 scalar quantization15.05 s17.05 s
W7-uploadsearch, binary quantization6.02 s11.03 s
W7-2bit-uploadsearch, binary quantization9.03 s16.05 s
W7-1p5bit-uploadsearch, binary quantization9.03 s15.04 s
W8-uploadsearch, product quantization213.70 s136.36 s
W14-1bit-uploadupload24.09 s19.05 s
W14-1p5bit-uploadupload25.09 s20.06 s
W14-2bit-uploadupload25.09 s25.08 s
W14-4bit-uploadupload27.09 s26.07 s
W12-uploadupload23.09 s21.06 s
W1 + W2upload and index, together24.1 s25.5 s1.06x

Memory and disk

What each engine held in memory and moved to and from disk over the whole run. Per-row figures are under Storage and I/O.

strawmANNQdrant
storage on disk5.0 GiBallocated at --capacity4.6 GiB
peak memory (RSS)5.6 GiB10.1 GiB
read from disk24.0 KiB358.0 MiB
written to disk9.6 GiB47.5 GiB

Peak memory and storage on disk are read before the concurrent-write rows (W11): an engine rewriting segments maps old and new files at once, and RSS counts each mapping. Bytes written are summed over the same rows, since W11's volume is set by the harness's write rate; the other disk figures are totals over every row.

Appendix

How the run was set up, every row of every table, and the diagnostics behind them. Charts on a logarithmic axis say so on the axis: read the positions there, not the distances.

Run conditions and conformance

Measured as-deployed: the scheduler was left as it ships, so a difference is what a user would see rather than the engine in isolation, and ambient load is part of the measurement. Qdrant ran equal-work: asked for one populated graph (--segments 1), as strawmANN serves, so ef means the same thing on both sides. This is the configuration §8's comparative licensing is built around, and it is a control rather than a deployment. Its optimizer treats the count as a target; what it actually held is read back from the engine and stated under Collection config.

Conformance tier reached: T4 quantization fidelity. T1 passed, so single-engine performance rows are licensed (§8). T3 passed, so a strawmANN-vs-Qdrant throughput comparison is licensed: the engines are at equal recall (§7.4). Conformance hash 11ffa7b2560ce499.

On exact search the two engines' scores differ by at most 2.980e-07 (p99 1.192e-07), against a calibrated absolute ε of 9.537e-07. §8.1: bit-exactness is unachievable between two different summation orders, so this — equal values within a measured tolerance — is the claim the speed rests on.

Every figure is the median of 3 passes per row per engine, alternated A/B/A/B (§7.4), and the spread is this run's own over 42 of 55 rows. The ingest and index-build rows (W0-upload, W1, W2, W6-upload, W7-upload, W7-2bit-upload, W7-1p5bit-upload, W8-upload, W14-1bit-upload, W14-1p5bit-upload, W14-2bit-upload, W14-4bit-upload, W12-upload) have none, so no build time carries a verdict. Each pass rebuilds the index, so the bands include build variance and are wider than a floor measured against one standing graph.

Units are queries per second. bfb reports rps, which counts batch requests: at --search-batch-size 16 the two differ by 16x, and reading one as the other once turned a 2.2x speedup into an apparent 7x regression. The tables show the request rate wherever it diverges.

The open-loop rows are not a speed. W4-sat50/70/90 offer a fixed fraction of measured saturation; serving it means the engine kept up, not that it was faster, so no ratio is printed. They exist because --parallel is a closed loop, where a stalled server stops receiving requests and understates its own tail.

ef is the same unit here: Qdrant held 2 segments for this run, one populated and 1 empty (read back per segment from the engine), and strawmANN held one graph, so equal ef is equal traversal width and the curves may be read at equal x. That is a property of this run, not of the engines.

What was measured builds, dataset, host
strawmANN
sm-hnm-perf-1012
Qdrant
qd-hnm-perf-1012
enginecommit e292f0b4651a
ReleaseFast, native build, vnni on
binary sha256 d6f453ebe3803da4
built 2026-10-12T13:37:51Z with zig 0.16.0
version 1.19.2-dev
binary ~/.cache/strawmann/qdrant-dbeb0f73/qdrant
sha256 dbeb0f73dea2d371 build 878843e6 (from the server's banner, not a checkout)
native binary outside a checkout: sha256 is the identity (§8.9)
network native no container in the path, like strawmann
measured2026-10-13T00:48:31Z to 2026-10-13T03:46:47Z (3 passes)2026-10-13T01:24:07Z to 2026-10-13T04:25:29Z (3 passes)
profileas-deployed · both engines
§7.1 gatepass · both engines
environment hash373e8531fd3d1bf6 · both engines
load generatorbfb dev @ 96fd5f0 (qdrant/bfb#188; #187's dependency update on top of #186, BM25 k/b in qdrant#11012's nested params, #185's text requests and #172, findings 32's --rps reaping fix) · both engines
clientqdrant-client 1.16.1-dev (git dev branch) · both engines
launched as~/Workspace/strawmann/zig-out/bin/strawmann --port 6334 --capacity 131375 --connections 64 --workers 7 --io-threads 1 --pin --cpus 4-11 --data-dir ~/.cache/strawmann/strawmann-storage --default-placement cached~/.cache/strawmann/qdrant-dbeb0f73/qdrant
cores the engine could use4-11 (8 cores) requested by the harness
4-11 (8 cores) observed on 8 threads
0-23 (24 cores) observed on 1 thread
4-11 (8 cores) requested by the harness
4-11 (8 cores) observed on 42 threads

Dataset

h-and-m-2048-angular-filters, 105100 × 2048, cosine, 10000 held-out queries
ground truth: shipped, and diffed against our fp64 recompute
1 file, each pinned by sha256 in datasets.json

Host

AMD Ryzen AI 9 HX PRO 370 w/ Radeon 890M
24 logical cores · 58.6 GB · kernel 7.0.0-38-generic
memory bandwidth: 73.9 GB/s aggregate (24 threads) · 43.6 GB/s single core (59% of bus)
strawmann startup banner, 2026-10-13T00:48:31Z; the Qdrant run agrees within 10%
All throughput rows every measurement, with its notes
workloadstrawmANNQdrantrationotes
W0d=4 floor: graph traversal with the distance taken out4,9884,187-strawmANN pass 1 -34% against two passes that agree: one pass set the spread on this row, so a band built from it is not a noise band d=4 floor: this measures graph traversal and heaps with the distance taken out, not request plumbing (findings 28: 76% of the server's CPU was HNSW search, 24% kernel; the RPC path is a small remainder)
W3search, fp32, single query1,2869951.29x
W4search, saturating (closed loop)4,6585,6730.82x
W4-sat50search, fixed rate at 50% of saturation (open loop)2,3272,327offered
W4-sat70search, fixed rate at 70% of saturation (open loop)3,2583,258offered
W4-sat90search, fixed rate at 90% of saturation (open loop)4,1894,189offered
W5search batched (16 distinct dataset queries per request)4,649334 requests/s5,953405 requests/s0.78xper-batch latency (16 queries/request); queries: dataset, random-sample batched 16, so qps and rps differ by 16x; the ratio uses qps
W6quantized: scalar10,8349,1711.18x
W6-ef32SQ8 recall control, ef=32 (latency only)31,68321,6241.47xstrawmANN: -n 100000 (2x the table's 50000)
W6-ef64SQ8 recall control, ef=64 (latency only)18,62914,8601.25x
W6-ef128SQ8 recall control, ef=128 (latency only)10,8589,7281.12x
W6-ef256SQ8 recall control, ef=256 (latency only)6,2486,0491.03x
W6-ef512SQ8 recall control, ef=512 (latency only)3,5413,582paritywithin the ±2.8% band this dataset's noise floor puts on W6-ef512: no measured difference, not a small one
W7quantized: binary + oversampling25,18116,4811.53xstrawmANN: -n 100000 (2x the table's 50000)
W7-2bitquantized: binary quantization, 2 bits + oversampling21,16814,4381.47x
W7-1p5bitquantized: binary quantization, 1.5 bits + oversampling22,82614,678-Qdrant pass 2 -14% against two passes that agree: one pass set the spread on this row, so a band built from it is not a noise band
W8quantized: PQ6,5074,8391.34x
W14-1bitquantized: TurboQuant, 1 bit + oversampling16,38613,9911.17x
W14-1p5bitquantized: TurboQuant, 1.5 bits + oversampling13,35112,8301.04x
W14-2bitquantized: TurboQuant, 2 bits + oversampling17,60213,260-Qdrant pass 2 -15% against two passes that agree: one pass set the spread on this row, so a band built from it is not a noise band
W14-4bitquantized: TurboQuant, 4 bits + oversampling12,51912,2461.02x
W9exact / brute force7172paritywithin the ±3.3% band this dataset's noise floor puts on W9: no measured difference, not a small one brute force over the whole collection, no index involved
W10-ef32recall control, ef=32 (latency only)12,02110,511-strawmANN pass 1 +10% against two passes that agree: one pass set the spread on this row, so a band built from it is not a noise band
W10-ef64recall control, ef=64 (latency only)7,5157,152paritywithin the ±17.2% band this dataset's noise floor puts on W10-ef64: no measured difference, not a small one
W10-ef128recall control, ef=128 (latency only)4,6524,840paritywithin the ±16.2% band this dataset's noise floor puts on W10-ef128: no measured difference, not a small one
W10-ef256recall control, ef=256 (latency only)2,8593,139paritywithin the ±15.5% band this dataset's noise floor puts on W10-ef256: no measured difference, not a small one
W10-ef512recall control, ef=512 (latency only)1,7311,957paritywithin the ±16.2% band this dataset's noise floor puts on W10-ef512: no measured difference, not a small one
W12-sel1filtered search, one keyword (~1% of bench12)5,5735,956paritywithin the ±10.8% band this dataset's noise floor puts on W12-sel1: no measured difference, not a small one filtered search over a keyword payload index both engines were asked to build; whether each did is read back from the engine and refused beside the row when it did not. Recall is measured under the filter, against ground truth restricted to the matching set
W12-sel10filtered search, any of 10 keywords (~10% of bench12)3,7012,9491.25xfiltered search over a keyword payload index both engines were asked to build; whether each did is read back from the engine and refused beside the row when it did not. Recall is measured under the filter, against ground truth restricted to the matching set
W12-sel1-ef32filtered recall control, one keyword, ef=32 (latency only)5,5676,0860.91x
W12-sel1-ef64filtered recall control, one keyword, ef=64 (latency only)5,5636,0810.91x
W12-sel1-ef128filtered recall control, one keyword, ef=128 (latency only)5,5666,075paritywithin the ±10.8% band this dataset's noise floor puts on W12-sel1-ef128: no measured difference, not a small one
W12-sel1-ef256filtered recall control, one keyword, ef=256 (latency only)5,5676,070paritywithin the ±11.5% band this dataset's noise floor puts on W12-sel1-ef256: no measured difference, not a small one
W12-sel1-ef512filtered recall control, one keyword, ef=512 (latency only)5,5516,061paritywithin the ±11.7% band this dataset's noise floor puts on W12-sel1-ef512: no measured difference, not a small one
W12-sel10-ef32filtered recall control, any of 10 keywords, ef=32 (latency only)9,5626,2251.54x
W12-sel10-ef64filtered recall control, any of 10 keywords, ef=64 (latency only)6,0484,4651.35x
W12-sel10-ef128filtered recall control, any of 10 keywords, ef=128 (latency only)3,7052,9571.25x
W12-sel10-ef256filtered recall control, any of 10 keywords, ef=256 (latency only)2,2311,8841.18x
W12-sel10-ef512filtered recall control, any of 10 keywords, ef=512 (latency only)6171,150-Qdrant pass 1 -25% against two passes that agree: one pass set the spread on this row, so a band built from it is not a noise band
W13scroll / pagination56,85450,6971.12x-n 200000 (4x the table's 50000) strawmANN: 0.12 ms of the client's 0.13 ms p50 is not server time (12x), so 91% of this row is the load generator and the socket Qdrant: 0.12 ms of the client's 0.15 ms p50 is not server time (5x), so 81% of this row is the load generator and the socket 1.12x is 3.38x less work per query x 0.33x cores busy during the row (1.47 against 4.50) x 1.00x clock x 1.02x counted on-CPU share: the middle term is occupancy, not search speed
W11-steadymixed read/write below the rebuild threshold: search bench2 while 5,255 synthetic points append4,2013,884-strawmANN: qps over the 26.5 s of the append the search saw (4,262 over the whole search); append 198 points/s Qdrant: qps over the 26.5 s of the append the search saw (4,062 over the whole search); append 198 points/s search-during-write; no recall join
W11mixed read/write: search bench2 while 21,020 synthetic points append (runs last)3,6982,695-strawmANN: qps over the 70.3 s of the append the search saw (3,777 over the whole search); append 299 points/s Qdrant: qps over the 70.3 s of the append the search saw (2,862 over the whole search); append 299 points/s Qdrant -19% across its passes, monotonically: the spread on this row is drift rather than noise, so the median is a trend's midpoint and not a repeatable measurement strawmANN pass 1 +10% against two passes that agree: one pass set the spread on this row, so a band built from it is not a noise band search-during-write; no recall join

W10: throughput against ef

ef is the same unit here: Qdrant held 2 segments for this run, one populated and 1 empty (read back per segment from the engine), and strawmANN held one graph, so equal ef is equal traversal width and the curves may be read at equal x. That is a property of this run, not of the engines.
All latency rows closed loop included, p50 to max

A row flagged “… not server time” is one where the client saw far more than the server reported: below the rate at which a queue can form, what is left is the load generator's own scheduling.

workloadstrawmANN p50strawmANN p95strawmANN p99strawmANN p99.9strawmANN maxQdrant p50Qdrant p95Qdrant p99Qdrant p99.9Qdrant max
W0d=4 floor: graph traversal with the distance taken out closed loop 198 µs215 µs232 µs274 µs2.04 ms236 µs262 µs286 µs334 µs2.80 ms
W3search, fp32, single query closed loop 756 µs1.06 ms1.39 ms1.74 ms2.33 ms995 µs1.30 ms1.42 ms1.55 ms2.94 ms
W4search, saturating (closed loop) closed loop 13.70 ms14.81 ms15.31 ms22.16 ms32.02 ms10.99 ms16.82 ms23.66 ms35.93 ms48.64 ms
W4-sat50search, fixed rate at 50% of saturation (open loop) open loop 893 µs1.34 ms1.57 ms1.80 ms5.47 ms1.10 ms1.44 ms1.68 ms2.35 ms6.62 ms
W4-sat70search, fixed rate at 70% of saturation (open loop) open loop 1.01 ms1.79 ms2.11 ms2.46 ms6.29 ms1.18 ms1.92 ms2.31 ms2.79 ms10.19 ms
W4-sat90search, fixed rate at 90% of saturation (open loop) open loop 1.15 ms1.97 ms2.53 ms3.45 ms6.84 ms1.42 ms2.48 ms3.03 ms4.09 ms14.18 ms
W5search batched (16 distinct dataset queries per request) closed loop 219.78 ms223.09 ms224.42 ms229.72 ms241.36 ms170.49 ms192.05 ms219.98 ms281.22 ms294.32 ms
W6quantized: scalar closed loop 5.87 ms6.21 ms6.37 ms22.19 ms28.00 ms6.39 ms12.64 ms17.32 ms30.94 ms43.31 ms
W6-ef32SQ8 recall control, ef=32 (latency only) closed loop 2.00 ms2.11 ms2.18 ms3.10 ms22.91 ms2.75 ms4.79 ms6.26 ms23.28 ms28.47 ms
W6-ef64SQ8 recall control, ef=64 (latency only) closed loop 3.41 ms3.60 ms3.70 ms20.28 ms24.78 ms4.10 ms6.55 ms8.29 ms20.59 ms27.04 ms
W6-ef128SQ8 recall control, ef=128 (latency only) closed loop 5.87 ms6.22 ms6.37 ms20.46 ms26.58 ms6.37 ms9.19 ms11.13 ms25.44 ms31.60 ms
W6-ef256SQ8 recall control, ef=256 (latency only) closed loop 10.21 ms10.83 ms11.10 ms20.61 ms28.58 ms10.45 ms12.38 ms15.50 ms27.25 ms40.25 ms
W6-ef512SQ8 recall control, ef=512 (latency only) closed loop 18.02 ms19.09 ms19.54 ms27.05 ms41.29 ms17.81 ms19.32 ms20.39 ms31.94 ms48.19 ms
W7quantized: binary + oversampling closed loop 2.46 ms3.17 ms3.42 ms4.62 ms23.02 ms3.52 ms7.35 ms9.82 ms20.52 ms28.81 ms
W7-2bitquantized: binary quantization, 2 bits + oversampling closed loop 2.99 ms3.12 ms3.19 ms19.70 ms24.03 ms4.05 ms8.40 ms11.15 ms18.91 ms28.61 ms
W7-1p5bitquantized: binary quantization, 1.5 bits + oversampling closed loop 2.76 ms2.89 ms2.96 ms22.13 ms26.84 ms3.96 ms8.17 ms10.89 ms24.11 ms35.55 ms
W8quantized: PQ closed loop 9.79 ms10.39 ms10.65 ms18.39 ms27.25 ms12.88 ms19.50 ms26.27 ms36.45 ms47.02 ms
W14-1bitquantized: TurboQuant, 1 bit + oversampling closed loop 3.87 ms4.06 ms4.16 ms18.45 ms22.31 ms4.09 ms8.85 ms11.88 ms22.08 ms35.97 ms
W14-1p5bitquantized: TurboQuant, 1.5 bits + oversampling closed loop 4.77 ms5.00 ms5.11 ms18.61 ms23.50 ms4.43 ms9.72 ms13.33 ms21.51 ms32.94 ms
W14-2bitquantized: TurboQuant, 2 bits + oversampling closed loop 3.60 ms3.76 ms3.84 ms21.17 ms25.43 ms4.31 ms9.36 ms12.82 ms20.39 ms28.58 ms
W14-4bitquantized: TurboQuant, 4 bits + oversampling closed loop 5.08 ms5.34 ms5.46 ms21.95 ms26.87 ms4.71 ms9.96 ms13.59 ms24.53 ms32.68 ms
W9exact / brute force closed loop 108.80 ms141.35 ms156.20 ms178.24 ms181.53 ms112.97 ms119.36 ms128.28 ms137.30 ms144.99 ms
W10-ef32recall control, ef=32 (latency only) closed loop 656 µs861 µs971 µs1.26 ms3.85 ms708 µs1.17 ms1.39 ms1.82 ms3.85 ms
W10-ef64recall control, ef=64 (latency only) closed loop 1.05 ms1.44 ms1.63 ms1.86 ms5.98 ms1.02 ms1.76 ms2.07 ms2.61 ms6.49 ms
W10-ef128recall control, ef=128 (latency only) closed loop 1.69 ms2.43 ms2.75 ms3.17 ms7.79 ms1.55 ms2.55 ms3.02 ms3.73 ms7.42 ms
W10-ef256recall control, ef=256 (latency only) closed loop 2.75 ms4.06 ms4.61 ms5.33 ms9.30 ms2.44 ms3.84 ms4.48 ms5.48 ms8.62 ms
W10-ef512recall control, ef=512 (latency only) closed loop 4.52 ms6.78 ms7.71 ms8.86 ms11.54 ms3.98 ms6.01 ms7.05 ms8.31 ms11.51 ms
W12-sel1filtered search, one keyword (~1% of bench12) closed loop 11.46 ms11.94 ms12.17 ms27.69 ms35.72 ms10.31 ms17.17 ms23.38 ms35.30 ms55.39 ms
W12-sel10filtered search, any of 10 keywords (~10% of bench12) closed loop 17.23 ms18.58 ms19.15 ms28.35 ms42.70 ms21.70 ms23.64 ms24.65 ms34.13 ms50.31 ms
W12-sel1-ef32filtered recall control, one keyword, ef=32 (latency only) closed loop 11.47 ms11.95 ms12.22 ms21.70 ms30.17 ms10.32 ms13.33 ms16.57 ms29.99 ms39.25 ms
W12-sel1-ef64filtered recall control, one keyword, ef=64 (latency only) closed loop 11.47 ms11.94 ms12.19 ms28.12 ms36.24 ms10.32 ms13.19 ms16.63 ms32.25 ms40.46 ms
W12-sel1-ef128filtered recall control, one keyword, ef=128 (latency only) closed loop 11.48 ms11.94 ms12.16 ms19.89 ms28.50 ms10.33 ms13.30 ms16.63 ms29.17 ms38.24 ms
W12-sel1-ef256filtered recall control, one keyword, ef=256 (latency only) closed loop 11.47 ms11.96 ms12.22 ms25.88 ms33.52 ms10.34 ms13.39 ms16.65 ms28.27 ms38.63 ms
W12-sel1-ef512filtered recall control, one keyword, ef=512 (latency only) closed loop 11.49 ms11.98 ms12.26 ms18.52 ms26.99 ms10.36 ms13.28 ms16.60 ms26.28 ms36.06 ms
W12-sel10-ef32filtered recall control, any of 10 keywords, ef=32 (latency only) closed loop 6.66 ms7.18 ms7.41 ms20.13 ms26.32 ms10.13 ms11.84 ms14.42 ms26.50 ms38.94 ms
W12-sel10-ef64filtered recall control, any of 10 keywords, ef=64 (latency only) closed loop 10.54 ms11.41 ms11.76 ms22.91 ms31.67 ms14.22 ms15.84 ms16.96 ms27.92 ms42.06 ms
W12-sel10-ef128filtered recall control, any of 10 keywords, ef=128 (latency only) closed loop 17.22 ms18.57 ms19.15 ms24.39 ms38.87 ms21.59 ms23.56 ms24.69 ms34.31 ms52.91 ms
W12-sel10-ef256filtered recall control, any of 10 keywords, ef=256 (latency only) closed loop 28.63 ms30.82 ms31.71 ms33.11 ms53.57 ms33.95 ms36.71 ms37.90 ms41.08 ms61.63 ms
W12-sel10-ef512filtered recall control, any of 10 keywords, ef=512 (latency only) closed loop 105.09 ms111.89 ms113.64 ms115.55 ms117.52 ms55.72 ms59.71 ms61.51 ms68.08 ms108.21 ms
W13scroll / pagination closed loop 128 µs183 µs204 µs237 µs1.05 ms146 µs207 µs284 µs432 µs1.33 ms
W11-steadymixed read/write below the rebuild threshold: search bench2 while 5,255 synthetic points append closed loop 1.75 ms2.75 ms6.01 ms7.99 ms12.96 ms1.76 ms3.30 ms4.69 ms14.19 ms35.88 ms
W11mixed read/write: search bench2 while 21,020 synthetic points append (runs last) closed loop 1.90 ms3.94 ms7.01 ms8.94 ms17.49 ms2.26 ms5.42 ms9.47 ms20.95 ms1165.35 ms
Storage and I/O block layer and syscalls, per row

The syscall rows count every descriptor, sockets included, so on a search row they measure the network rather than the disk.

strawmANNQdrant
storage on disk5.0 GiBbefore W11-steady, W11allocated at --capacity4.6 GiBbefore W11-steady, W11
peak RSS5.6 GiB16.9 GiB10.1 GiB before the writers
of which anonymous632.1 MiB559.7 MiB
of which file-backed5.0 GiB7.0 GiB
disk read bytes24.0 KiB358.0 MiB
disk write bytes9.8 GiB76.2 GiB
disk read ops1811,628
disk write ops87,1231,311,864
syscall reads (all fds)10,737,63712,602
syscall writes (all fds)6,135,71011,434,222

measured via strawmANN: proc+cgroup / Qdrant: proc+cgroup. proc supplies syscall counts and block-layer bytes, cgroup supplies block-layer operations and bytes, so a row one interface does not carry reads n/a via …. unknown means it was not measured, and 0 means it was: an engine started with no --data-dir has no store, which is the row this section exists for. storage on disk is the level before the rows with a concurrent writer: during those an engine that rewrites segments is caught mid-rewrite, and the same row has read 3.47 and 10.11 GiB on two runs of one binary. peak RSS does include them, being a peak.

Per workload

A search row doing block-layer reads is an engine going to disk to answer a query.

workloadstrawmANN readstrawmANN writtenstrawmANN read opsstrawmANN write opsQdrant readQdrant writtenQdrant read opsQdrant write ops
W0-upload06.5 MiB0011.1 MiB37.5 MiB4171,329
W00001050000
W10821.1 MiB00504.0 KiB2.2 GiB5726,369
W20821.1 MiB013,25213.3 MiB3.9 GiB45668,054
W300030006
W400000000
W4-sat5000000000
W4-sat7000000000
W4-sat9000000000
W500000000
W6-upload0821.1 MiB013,24412.8 MiB4.3 GiB47175,362
W600000006
W6-ef3200000000
W6-ef6400030000
W6-ef12800000000
W6-ef25600000000
W6-ef51200000000
W7-upload0821.1 MiB0016.9 MiB4.7 GiB65777,977
W700013,2460000
W7-2bit-upload0821.1 MiB0013.8 MiB4.1 GiB48072,856
W7-2bit00000000
W7-1p5bit-upload0821.1 MiB0013.6 MiB4.1 GiB47771,686
W7-1p5bit00000000
W8-upload0821.1 MiB013,24513.5 MiB3.6 GiB39661,797
W800000000
W14-1bit-upload0821.1 MiB0317.2 MiB4.2 GiB59773,789
W14-1bit00000000
W14-1p5bit-upload0821.1 MiB03,74416.0 MiB4.1 GiB52872,269
W14-1p5bit00000000
W14-2bit-upload0821.1 MiB04,26015.3 MiB4.1 GiB51672,271
W14-2bit00000000
W14-4bit-upload0821.1 MiB09,43313.7 MiB4.3 GiB48976,122
W14-4bit00000000
W900000000
W10-ef3200000000
W10-ef6400000000
W10-ef12800000000
W10-ef25600000000
W10-ef51200000000
W12-upload24.0 KiB821.1 MiB1813,24420.1 MiB3.7 GiB69965,767
W12-sel100030000
W12-sel1000000000
W12-sel1-ef3200000000
W12-sel1-ef6400000000
W12-sel1-ef12800000000
W12-sel1-ef25600000000
W12-sel1-ef51200000000
W12-sel10-ef3200000000
W12-sel10-ef6400000000
W12-sel10-ef12800000000
W12-sel10-ef25600000000
W12-sel10-ef51200000000
W1300000000
W11-steady041.3 MiB067038.4 MiB5.9 GiB1,089103,029
W110164.5 MiB02,668141.9 MiB22.7 GiB4,299393,175
Scheduler and memory CPU use, run-queue wait, migrations

Whether the engine was running while it ran. of wall is CPU over elapsed, waiting is runnable-but-not-scheduled, migrations checks the pinning claim, and switches gives voluntary over involuntary — the scheduler taking the core away against the engine choosing to sleep, which per unit of work is the cheapest signal of lock contention there is. A dash is not a zero: an index build's threads exit before the row does, and threads shows what fraction of the row the survivors account for.

Time spent waiting for a core

Lower is better; the bar between a pair is the gap.

Peak memory per row

Peak RSS while the row ran, from the engine's own process. Unlike the disk counters this is not refused across the two engines: residency decides where bytes live, and this is what the process held either way.

workloadstrawmANNQdrant
cpuof wallwaitingswitches vol/involmigrationsfaults min/majthreadscpuof wallwaitingswitches vol/involmigrationsfaults min/majthreads
W0-upload9.1 s147%3.4 ms4,080 / 35113,124 / 09 2%14.0 s209%1,192.3 ms16,676 / 2,3361,61246,982 / 128,01243 13%
W07.5 s75%3.3 ms150,073 / 900 / 0912.2 s102%3.0 ms550,266 / 13140306 / 037 0%
W12.1 s65%1.2 ms99,163 / 10226,098 / 0916.6 s369%7,140.0 ms19,202 / 4,9914,550164,480 / 251,77154 58%
W2166.9 s635%88.1 ms99,436 / 7150229,690 / 09 1%142.8 s519%6,539.3 ms23,644 / 5,6535,266261,153 / 321,75346 0%
W335.6 s91%0.9 ms151,646 / 2603 / 0951.0 s101%4.1 ms553,594 / 1192441,013 / 038 0%
W477.4 s718%3.9 ms77,886 / 800144 / 0969.9 s789%80,158.3 ms42,075 / 39,5486,9635,016 / 076
W4-sat50169.0 s196%5.3 ms466,268 / 9208 / 09225.2 s262%12,107.6 ms1,836,405 / 8,100423,6313,625 / 068 0%
W4-sat70199.2 s324%7.2 ms428,985 / 89024 / 09230.5 s375%41,776.5 ms1,563,281 / 30,232541,6452,467 / 068
W4-sat90222.7 s465%15.2 ms391,208 / 137036 / 09257.1 s537%134,814.7 ms1,304,347 / 117,130591,4171,899 / 068
W576.4 s709%5.4 ms6,286 / 12901,244 / 0967.1 s798%91,452.0 ms7,003 / 14,2891,01818,963 / 076
W6-upload91.2 s500%42.4 ms28,884 / 4170505,838 / 09 2%72.4 s324%3,669.8 ms25,096 / 3,6143,490398,415 / 338,62742 0%
W633.9 s729%3.9 ms63,504 / 48012 / 0942.4 s773%97,717.4 ms62,680 / 49,24118,0583,063 / 080 92%
W6-ef3224.6 s762%3.0 ms40,659 / 34056 / 0917.6 s750%12,193.2 ms25,760 / 9,9515,489188 / 078
W6-ef6420.3 s745%1.9 ms44,199 / 29012 / 0925.8 s759%14,235.4 ms26,463 / 12,1605,334247 / 078
W6-ef12834.0 s732%2.6 ms63,218 / 3404 / 0940.3 s779%15,990.6 ms29,209 / 17,2454,426301 / 046
W6-ef25657.9 s720%3.1 ms76,992 / 75056 / 0965.8 s792%16,509.9 ms31,710 / 26,2761,565639 / 046
W6-ef512100.7 s711%5.0 ms86,034 / 11902 / 09111.4 s796%21,361.7 ms34,593 / 31,9233981,788 / 046
W7-upload18.7 s204%7.4 ms28,110 / 871237,913 / 09 8%38.9 s239%2,355.1 ms27,410 / 2,3184,215344,131 / 430,03041 0%
W730.2 s748%13.5 ms85,298 / 36072 / 0923.6 s768%76,278.3 ms96,004 / 63,73120,6211,606 / 076
W7-2bit-upload25.7 s211%10.0 ms28,550 / 1240246,078 / 09 6%44.6 s211%1,297.8 ms25,666 / 1,3033,462313,919 / 368,66250 0%
W7-2bit17.7 s739%1.2 ms49,399 / 1700 / 0926.9 s768%87,039.8 ms97,574 / 67,77022,3652,579 / 082
W7-1p5bit-upload23.6 s193%9.2 ms29,822 / 1160241,963 / 09 6%42.9 s211%1,413.8 ms25,327 / 1,8253,434313,190 / 365,44249 50%
W7-1p5bit16.5 s739%0.8 ms47,817 / 2000 / 0926.4 s767%85,089.0 ms97,877 / 70,02524,4482,443 / 078 91%
W8-upload1,672.3 s771%493.6 ms31,454 / 7,1940461,881 / 09 0%896.1 s634%2,043.8 ms296,356 / 11,52116,721253,675 / 287,89242 0%
W855.3 s716%2.9 ms84,699 / 6800 / 0981.7 s788%97,256.2 ms41,240 / 39,6728,2245,774 / 080
W14-1bit-upload173.0 s635%92.3 ms28,780 / 7450246,986 / 09 1%67.8 s263%2,871.3 ms28,288 / 14,2255,490321,067 / 379,30049 34%
W14-1bit22.6 s731%1.0 ms63,245 / 2600 / 0927.6 s765%90,490.1 ms91,233 / 65,03622,4672,573 / 088 91%
W14-1p5bit-upload176.7 s625%98.0 ms30,056 / 7850253,226 / 09 1%75.7 s270%3,280.1 ms30,105 / 29,7655,247332,541 / 365,83349 39%
W14-1p5bit27.5 s726%1.1 ms72,306 / 2900 / 0930.2 s768%93,034.4 ms78,779 / 57,42419,9482,831 / 088 76%
W14-2bit-upload173.8 s616%94.6 ms28,016 / 7540263,458 / 09 1%105.9 s325%3,606.2 ms33,704 / 43,1175,569337,763 / 369,10950 25%
W14-2bit21.1 s734%1.0 ms59,300 / 2200 / 0929.4 s772%91,222.8 ms88,209 / 63,40523,2442,644 / 089 95%
W14-4bit-upload177.1 s585%98.9 ms28,589 / 7820296,243 / 09 1%95.5 s272%4,046.0 ms55,165 / 92,3396,720385,139 / 399,02749 35%
W14-4bit29.4 s728%1.4 ms67,171 / 2400 / 0931.7 s769%93,865.0 ms77,787 / 56,29519,3102,939 / 088
W9196.9 s701%21.4 ms4,029 / 31500 / 09219.3 s786%10,502.0 ms19,943 / 11,1277,955749 / 048
W10-ef3228.9 s689%2.9 ms90,688 / 2900 / 0927.8 s580%10,977.5 ms238,325 / 21,77372,2561,345 / 048
W10-ef6446.9 s701%3.8 ms94,500 / 3800 / 0943.0 s612%28,598.2 ms284,023 / 40,116127,6461,051 / 071
W10-ef12876.3 s707%6.0 ms96,185 / 9000 / 0965.8 s635%41,026.0 ms310,847 / 40,795151,424309 / 063 0%
W10-ef256123.9 s707%9.2 ms98,133 / 15804 / 09105.2 s659%55,799.7 ms334,330 / 52,669174,169500 / 064
W10-ef512204.1 s706%14.2 ms98,987 / 26804 / 09174.5 s682%77,540.7 ms361,523 / 77,755192,033979 / 064
W12-upload167.3 s636%88.8 ms23,257 / 7091230,537 / 09 1%142.6 s515%9,459.2 ms22,413 / 8,9693,907216,135 / 352,93550 0%
W12-sel164.7 s718%3.8 ms65,706 / 6803 / 0966.1 s783%100,434.0 ms50,180 / 45,00911,4483,569 / 089
W12-sel1096.2 s710%3.0 ms90,626 / 7704 / 09135.4 s797%23,208.0 ms37,147 / 35,8022251,975 / 057 0%
W12-sel1-ef3264.8 s718%2.7 ms65,435 / 4300 / 0965.2 s789%20,047.1 ms29,967 / 23,0102,8331,655 / 057
W12-sel1-ef6464.8 s717%3.7 ms66,364 / 48012 / 0965.3 s790%19,925.6 ms30,336 / 23,1962,746847 / 057
W12-sel1-ef12864.8 s718%2.7 ms66,954 / 4100 / 0965.2 s788%20,076.5 ms30,372 / 23,0652,872551 / 057
W12-sel1-ef25664.8 s718%2.8 ms65,364 / 4204 / 0965.3 s789%20,329.7 ms30,974 / 22,9282,936747 / 057
W12-sel1-ef51264.9 s718%4.1 ms64,729 / 6600 / 0965.4 s789%20,046.9 ms30,192 / 23,3742,781861 / 057
W12-sel10-ef3238.0 s722%1.8 ms73,100 / 2400 / 0964.0 s792%14,998.0 ms32,728 / 27,2301,275764 / 057
W12-sel10-ef6459.5 s716%2.7 ms81,733 / 5800 / 0989.4 s795%17,598.1 ms32,616 / 30,2173331,685 / 057
W12-sel10-ef12896.1 s710%5.7 ms88,985 / 8800 / 09135.0 s797%23,156.1 ms37,712 / 35,6912843,332 / 057
W12-sel10-ef256158.5 s706%5.1 ms93,960 / 15600 / 09212.0 s798%32,264.0 ms48,591 / 46,7893452,603 / 057
W12-sel10-ef512572.0 s705%38.1 ms67,407 / 75800 / 09347.6 s799%46,649.3 ms63,783 / 62,1297307,761 / 057
W135.3 s145%3.0 ms228,124 / 500 / 0918.0 s440%2,068.1 ms740,810 / 14,537214,148328 / 073
W11-steady238.6 s712%17,930.8 ms270,196 / 8,1975535,060 / 09 94%224.5 s670%186,545.5 ms905,096 / 176,296439,330398,756 / 130,82778 97%
W11637.8 s718%88,083.3 ms630,351 / 43,396243129,726 / 09 90%606.9 s685%363,116.3 ms1,384,368 / 358,272528,5521,559,118 / 624,75452 41%
Waiting and stalls where the time went when the engine was not running

waiting is runnable and not scheduled, blocked on disk is not runnable at all, and pressure is PSI for the engine's cgroup (some = at least one task stalled, full = every runnable task).

Time stalled on I/O

Time every task in the engine's cgroup was stalled on I/O. Lower is better. 39 rows never stalled on I/O and are not drawn.

workloadstrawmANNQdrant
waitingblocked on diskcpu some/fullio some/fullmemory some/fullwaitingblocked on diskcpu some/fullio some/fullmemory some/full
W0-upload3.4 ms0 ms2 / 2 ms0 / 0 ms0 / 0 ms1,192.3 ms0 ms127 / 2 ms14 / 14 ms0 / 0 ms
W03.3 ms0 ms44 / 44 ms0 / 0 ms0 / 0 ms3.0 ms0 ms66 / 66 ms0 / 0 ms0 / 0 ms
W11.2 ms0 ms8 / 8 ms2 / 2 ms0 / 0 ms7,140.0 ms0 ms671 / 7 ms58 / 29 ms0 / 0 ms
W288.1 ms0 ms19 / 10 ms0 / 0 ms0 / 0 ms6,539.3 ms0 ms632 / 11 ms137 / 80 ms0 / 0 ms
W30.9 ms0 ms39 / 39 ms0 / 0 ms0 / 0 ms4.1 ms0 ms95 / 95 ms0 / 0 ms0 / 0 ms
W43.9 ms0 ms3 / 3 ms0 / 0 ms0 / 0 ms80,158.3 ms0 ms3,813 / 2 ms0 / 0 ms0 / 0 ms
W4-sat505.3 ms0 ms152 / 152 ms0 / 0 ms0 / 0 ms12,107.6 ms0 ms1,603 / 255 ms0 / 0 ms0 / 0 ms
W4-sat707.2 ms0 ms141 / 141 ms0 / 0 ms0 / 0 ms41,776.5 ms0 ms4,722 / 191 ms0 / 0 ms0 / 0 ms
W4-sat9015.2 ms0 ms113 / 113 ms0 / 0 ms0 / 0 ms134,814.7 ms0 ms12,135 / 138 ms0 / 0 ms0 / 0 ms
W55.4 ms0 ms2 / 2 ms0 / 0 ms0 / 0 ms91,452.0 ms0 ms3,915 / 1 ms0 / 0 ms0 / 0 ms
W6-upload42.4 ms0 ms9 / 5 ms0 / 0 ms0 / 0 ms3,669.8 ms0 ms356 / 10 ms234 / 185 ms0 / 0 ms
W63.9 ms0 ms3 / 3 ms0 / 0 ms0 / 0 ms97,717.4 ms0 ms3,852 / 4 ms0 / 0 ms0 / 0 ms
W6-ef323.0 ms0 ms3 / 3 ms0 / 0 ms0 / 0 ms12,193.2 ms0 ms1,317 / 2 ms0 / 0 ms0 / 0 ms
W6-ef641.9 ms0 ms2 / 2 ms0 / 0 ms0 / 0 ms14,235.4 ms0 ms1,526 / 2 ms0 / 0 ms0 / 0 ms
W6-ef1282.6 ms0 ms2 / 2 ms0 / 0 ms0 / 0 ms15,990.6 ms0 ms1,703 / 2 ms0 / 0 ms0 / 0 ms
W6-ef2563.1 ms0 ms2 / 2 ms0 / 0 ms0 / 0 ms16,509.9 ms0 ms1,868 / 1 ms0 / 0 ms0 / 0 ms
W6-ef5125.0 ms0 ms2 / 2 ms0 / 0 ms0 / 0 ms21,361.7 ms0 ms2,610 / 1 ms0 / 0 ms0 / 0 ms
W7-upload7.4 ms0 ms4 / 4 ms0 / 0 ms0 / 0 ms2,355.1 ms0 ms291 / 12 ms237 / 197 ms0 / 0 ms
W713.5 ms0 ms5 / 5 ms0 / 0 ms0 / 0 ms76,278.3 ms0 ms2,741 / 3 ms0 / 0 ms0 / 0 ms
W7-2bit-upload10.0 ms0 ms5 / 4 ms1 / 1 ms0 / 0 ms1,297.8 ms0 ms172 / 11 ms283 / 264 ms0 / 0 ms
W7-2bit1.2 ms0 ms2 / 2 ms0 / 0 ms0 / 0 ms87,039.8 ms0 ms3,142 / 3 ms0 / 0 ms0 / 0 ms
W7-1p5bit-upload9.2 ms0 ms5 / 5 ms1 / 1 ms0 / 0 ms1,413.8 ms0 ms168 / 11 ms274 / 248 ms0 / 0 ms
W7-1p5bit0.8 ms0 ms2 / 2 ms0 / 0 ms0 / 0 ms85,089.0 ms0 ms3,086 / 4 ms0 / 0 ms0 / 0 ms
W8-upload493.6 ms0 ms65 / 11 ms9 / 9 ms0 / 0 ms2,043.8 ms0 ms945 / 114 ms203 / 135 ms0 / 0 ms
W82.9 ms0 ms2 / 2 ms0 / 0 ms0 / 0 ms97,256.2 ms0 ms4,408 / 2 ms0 / 0 ms0 / 0 ms
W14-1bit-upload92.3 ms0 ms14 / 5 ms1 / 1 ms0 / 0 ms2,871.3 ms0 ms510 / 15 ms302 / 258 ms0 / 0 ms
W14-1bit1.0 ms0 ms2 / 2 ms0 / 0 ms0 / 0 ms90,490.1 ms0 ms3,245 / 3 ms0 / 0 ms0 / 0 ms
W14-1p5bit-upload98.0 ms0 ms16 / 5 ms1 / 1 ms0 / 0 ms3,280.1 ms0 ms484 / 17 ms179 / 148 ms0 / 0 ms
W14-1p5bit1.1 ms0 ms2 / 2 ms0 / 0 ms0 / 0 ms93,034.4 ms0 ms3,393 / 3 ms0 / 0 ms0 / 0 ms
W14-2bit-upload94.6 ms0 ms15 / 5 ms0 / 0 ms0 / 0 ms3,606.2 ms0 ms574 / 16 ms168 / 133 ms0 / 0 ms
W14-2bit1.0 ms0 ms2 / 2 ms0 / 0 ms0 / 0 ms91,222.8 ms0 ms3,357 / 3 ms0 / 0 ms0 / 0 ms
W14-4bit-upload98.9 ms0 ms16 / 6 ms1 / 1 ms0 / 0 ms4,046.0 ms0 ms589 / 21 ms271 / 216 ms0 / 0 ms
W14-4bit1.4 ms0 ms2 / 2 ms0 / 0 ms0 / 0 ms93,865.0 ms0 ms3,474 / 3 ms0 / 0 ms0 / 0 ms
W921.4 ms0 ms3 / 3 ms0 / 0 ms0 / 0 ms10,502.0 ms0 ms1,196 / 18 ms0 / 0 ms0 / 0 ms
W10-ef322.9 ms0 ms11 / 11 ms0 / 0 ms0 / 0 ms10,977.5 ms0 ms1,271 / 20 ms0 / 0 ms0 / 0 ms
W10-ef643.8 ms0 ms10 / 10 ms0 / 0 ms0 / 0 ms28,598.2 ms0 ms2,639 / 24 ms0 / 0 ms0 / 0 ms
W10-ef1286.0 ms0 ms9 / 9 ms0 / 0 ms0 / 0 ms41,026.0 ms0 ms3,822 / 23 ms0 / 0 ms0 / 0 ms
W10-ef2569.2 ms0 ms7 / 7 ms0 / 0 ms0 / 0 ms55,799.7 ms0 ms5,397 / 27 ms0 / 0 ms0 / 0 ms
W10-ef51214.2 ms0 ms6 / 6 ms0 / 0 ms0 / 0 ms77,540.7 ms0 ms7,885 / 37 ms0 / 0 ms0 / 0 ms
W12-upload88.8 ms0 ms14 / 5 ms11 / 11 ms0 / 0 ms9,459.2 ms0 ms876 / 9 ms380 / 306 ms0 / 0 ms
W12-sel13.8 ms0 ms3 / 3 ms0 / 0 ms0 / 0 ms100,434.0 ms0 ms4,457 / 3 ms0 / 0 ms0 / 0 ms
W12-sel103.0 ms0 ms2 / 2 ms0 / 0 ms0 / 0 ms23,208.0 ms0 ms2,881 / 1 ms0 / 0 ms0 / 0 ms
W12-sel1-ef322.7 ms0 ms2 / 2 ms0 / 0 ms0 / 0 ms20,047.1 ms0 ms2,168 / 1 ms0 / 0 ms0 / 0 ms
W12-sel1-ef643.7 ms0 ms2 / 2 ms0 / 0 ms0 / 0 ms19,925.6 ms0 ms2,163 / 1 ms0 / 0 ms0 / 0 ms
W12-sel1-ef1282.7 ms0 ms2 / 2 ms0 / 0 ms0 / 0 ms20,076.5 ms0 ms2,180 / 2 ms0 / 0 ms0 / 0 ms
W12-sel1-ef2562.8 ms0 ms2 / 2 ms0 / 0 ms0 / 0 ms20,329.7 ms0 ms2,201 / 2 ms0 / 0 ms0 / 0 ms
W12-sel1-ef5124.1 ms0 ms2 / 2 ms0 / 0 ms0 / 0 ms20,046.9 ms0 ms2,204 / 2 ms0 / 0 ms0 / 0 ms
W12-sel10-ef321.8 ms0 ms2 / 2 ms0 / 0 ms0 / 0 ms14,998.0 ms0 ms1,731 / 1 ms0 / 0 ms0 / 0 ms
W12-sel10-ef642.7 ms0 ms2 / 2 ms0 / 0 ms0 / 0 ms17,598.1 ms0 ms2,147 / 1 ms0 / 0 ms0 / 0 ms
W12-sel10-ef1285.7 ms0 ms2 / 2 ms0 / 0 ms0 / 0 ms23,156.1 ms0 ms2,863 / 1 ms0 / 0 ms0 / 0 ms
W12-sel10-ef2565.1 ms0 ms2 / 2 ms0 / 0 ms0 / 0 ms32,264.0 ms0 ms4,007 / 1 ms0 / 0 ms0 / 0 ms
W12-sel10-ef51238.1 ms0 ms10 / 10 ms0 / 0 ms0 / 0 ms46,649.3 ms0 ms5,810 / 2 ms0 / 0 ms0 / 0 ms
W133.0 ms0 ms22 / 22 ms0 / 0 ms0 / 0 ms2,068.1 ms0 ms283 / 49 ms0 / 0 ms0 / 0 ms
W11-steady17,930.8 ms0 ms3,029 / 28 ms0 / 0 ms0 / 0 ms186,545.5 ms0 ms14,110 / 76 ms89 / 20 ms0 / 0 ms
W1188,083.3 ms0 ms13,479 / 69 ms12 / 12 ms0 / 0 ms363,116.3 ms0 ms32,835 / 180 ms1,589 / 241 ms0 / 0 ms

A dash under blocked on disk is not a zero: most hosts ship with kernel.task_delayacct=0, which reports the field as a permanent zero and would manufacture the strongest claim here — that the memory-resident engine never waits for a device — out of a sysctl. bench/setup.py apply turns it on.

Hardware counters cycles, DRAM loads, TLB walks, IPC per query

What the core did per query, from perf stat attached to the engine for the same window as the /proc counters. §5's cost model is a set of claims about instructions per cycle, DRAM traffic and TLB reach; these are those quantities, measured on the row the headline quotes rather than on a microbenchmark.

What one query cost, in cycles

Lower is better; the bar between a pair is the gap. Load rows are absent: they have no queries to divide by, and an absolute count under a per-query axis would be a different quantity wearing this one's label.

Demand loads from DRAM per query

Demand loads served from DRAM, times the cache line this host reports. Lower is better. Demand only: the hardware prefetcher's fills are a separate counter and are not in this number, so a row that streams — an exact scan above all — moved far more than this says. On the graph rows, where there is little for a prefetcher to predict, it is most of the traffic and is the outstanding-miss quantity §5.2 argues the engine is limited by.

TLB walks per query

Data TLB misses that reached a page walk, per query. Lower is better. §5.5 argues a memory-resident index needs hugepage care; this is what not taking it costs, and `--no-huge-pages` is the A/B arm that prices it.

Instructions per cycle

How well the core was fed while it ran. Not a score: a low IPC on a memory-bound row is what §5.2 predicts, and a high one on a row that does more work per query is not a win. Read it beside the two charts above.

Branch mispredictions per 1k instructions

A graph traversal is a chain of data-dependent branches and none of them is predictable from the last query, so this is the column that separates a slow kernel from an unpredictable walk. Per thousand instructions rather than per branch: `branches` costs a PMU counter that `ref-cycles` needs more, and MPKI is the comparable form anyway.

workloadstrawmANNQdrant
IPCGHzbranch MPKIcycles/querydemand DRAM/queryTLB walks/queryIPCGHzbranch MPKIcycles/querydemand DRAM/queryTLB walks/query
W0-upload1.922.011.005x nominal5.39---1.852.001.004x nominal4.60---
W01.512.011.005x nominal5.48227,0134.3 KiB640.41.442.011.006x nominal3.12367,1806.7 KiB699.0
W11.902.011.006x nominal0.58---1.782.001.003x nominal0.90---
W20.422.001.004x nominal2.35---0.742.011.004x nominal1.67---
W30.702.011.005x nominal3.911,358,0603,984.1 KiB2,408.90.822.011.005x nominal2.121,914,1122,251.6 KiB4,389.1
W40.312.011.006x nominal3.193,087,0862,847.9 KiB2,346.90.532.011.006x nominal2.342,746,1822,111.1 KiB3,597.8
W4-sat500.582.011.006x nominal3.921,636,1223,592.4 KiB2,351.60.752.011.007x nominal2.542,091,7292,265.0 KiB4,358.1
W4-sat700.482.011.006x nominal3.901,953,6073,333.7 KiB2,329.90.722.011.006x nominal2.552,180,4252,235.4 KiB4,244.6
W4-sat900.432.011.006x nominal3.642,198,8432,999.3 KiB2,312.00.652.011.007x nominal2.632,413,3072,226.4 KiB4,109.6
W50.292.011.006x nominal3.363,054,3982,843.7 KiB2,289.30.492.011.006x nominal2.272,665,5991,999.1 KiB3,418.6
W6-upload0.892.011.005x nominal2.01---1.942.011.006x nominal1.47---
W60.622.011.006x nominal3.901,348,7792,203.8 KiB2,410.71.192.011.006x nominal2.041,639,081806.1 KiB2,463.0
W6-ef320.742.011.006x nominal2.53488,960710.0 KiB810.11.422.011.006x nominal1.45690,161299.7 KiB944.6
W6-ef640.662.011.007x nominal3.23804,5121,245.2 KiB1,362.91.312.011.006x nominal1.701,015,365472.3 KiB1,476.3
W6-ef1280.622.011.006x nominal3.891,348,6242,207.6 KiB2,411.41.222.011.006x nominal1.941,593,318779.4 KiB2,385.5
W6-ef2560.622.011.006x nominal4.452,306,1893,867.8 KiB4,494.91.162.011.005x nominal2.112,604,0061,317.0 KiB3,973.9
W6-ef5120.632.011.006x nominal4.934,023,1336,798.4 KiB8,721.91.112.011.006x nominal2.264,425,0862,299.2 KiB6,732.0
W7-upload1.412.011.005x nominal7.85---2.042.011.005x nominal4.60---
W71.142.011.006x nominal6.75597,965495.8 KiB1,173.71.272.011.006x nominal3.98865,700381.5 KiB1,522.2
W7-2bit-upload1.222.001.003x nominal6.78---1.992.011.005x nominal4.02---
W7-2bit1.122.001.004x nominal6.02701,132525.4 KiB1,581.31.252.011.005x nominal4.08991,485415.2 KiB1,880.6
W7-1p5bit-upload1.322.001.004x nominal6.91---2.012.011.005x nominal4.17---
W7-1p5bit1.162.011.005x nominal6.28651,968507.0 KiB1,467.01.242.001.004x nominal4.15970,861420.1 KiB1,760.9
W8-upload5.092.011.006x nominal0.47---5.562.011.006x nominal0.17---
W84.622.011.005x nominal0.432,200,549548.1 KiB2,067.03.352.011.006x nominal0.463,238,893599.0 KiB2,390.9
W14-1bit-upload0.592.011.005x nominal1.73---2.762.011.005x nominal1.56---
W14-1bit2.252.011.005x nominal1.87894,176513.9 KiB1,251.11.582.001.004x nominal2.361,032,007397.2 KiB1,622.6
W14-1p5bit-upload0.682.011.005x nominal1.54---2.752.011.005x nominal1.43---
W14-1p5bit2.452.011.005x nominal1.401,090,283523.2 KiB1,528.81.652.001.004x nominal2.161,141,107408.3 KiB1,794.7
W14-2bit-upload0.612.011.005x nominal1.81---3.062.011.006x nominal0.93---
W14-2bit1.932.011.006x nominal2.21835,894525.4 KiB1,568.51.552.011.005x nominal2.451,095,638417.0 KiB1,937.6
W14-4bit-upload0.642.011.005x nominal1.94---2.792.011.005x nominal1.15---
W14-4bit1.442.011.006x nominal2.081,165,316674.3 KiB2,091.91.392.001.004x nominal2.341,197,674465.2 KiB2,121.6
W90.252.011.006x nominal0.32197,387,221234,976.7 KiB65,606.60.362.011.006x nominal0.15219,292,12582,813.0 KiB212,458.4
W10-ef320.362.011.007x nominal2.231,136,821973.7 KiB812.70.792.011.007x nominal2.041,041,416828.0 KiB1,683.6
W10-ef640.322.011.006x nominal2.761,861,0511,668.2 KiB1,350.00.682.011.006x nominal2.391,620,2911,320.6 KiB2,582.8
W10-ef1280.312.011.006x nominal3.233,039,4482,809.5 KiB2,353.90.632.011.006x nominal2.532,492,0862,124.7 KiB3,979.4
W10-ef2560.312.011.006x nominal3.614,950,1924,775.9 KiB4,288.20.592.011.006x nominal2.744,023,5573,379.6 KiB6,257.4
W10-ef5120.322.011.007x nominal3.978,169,0438,138.8 KiB8,185.30.552.011.007x nominal2.916,798,5055,642.2 KiB9,982.0
W12-upload0.422.011.006x nominal2.42---0.762.011.006x nominal1.72---
W12-sel10.252.011.006x nominal2.042,582,6093,684.2 KiB1,886.30.522.011.006x nominal0.682,590,9192,079.2 KiB3,505.1
W12-sel100.972.011.006x nominal3.763,842,8924,591.9 KiB6,208.61.562.011.007x nominal3.765,400,0782,199.1 KiB3,289.1
W12-sel1-ef320.252.011.007x nominal2.042,585,1273,681.7 KiB1,886.60.522.011.006x nominal0.602,578,4702,023.9 KiB3,460.1
W12-sel1-ef640.252.011.007x nominal2.032,586,0803,660.5 KiB1,882.30.522.011.007x nominal0.592,581,4182,021.5 KiB3,458.5
W12-sel1-ef1280.252.011.007x nominal2.112,587,0953,669.5 KiB1,889.00.522.011.006x nominal0.602,578,1922,048.0 KiB3,457.8
W12-sel1-ef2560.252.011.006x nominal2.042,585,6293,663.7 KiB1,886.20.522.011.007x nominal0.622,581,3652,045.3 KiB3,464.9
W12-sel1-ef5120.252.011.006x nominal2.042,592,6163,673.4 KiB1,877.10.522.011.006x nominal0.632,583,1262,041.0 KiB3,464.4
W12-sel10-ef320.942.011.007x nominal2.981,517,0271,851.6 KiB1,967.91.522.011.006x nominal2.872,539,1761,068.4 KiB1,635.4
W12-sel10-ef640.942.011.006x nominal3.422,372,9402,898.0 KiB3,440.71.562.011.006x nominal3.293,554,0661,503.3 KiB2,252.1
W12-sel10-ef1280.972.011.006x nominal3.773,840,6074,585.7 KiB6,210.71.562.011.006x nominal3.755,381,0462,195.5 KiB3,306.3
W12-sel10-ef2561.022.011.007x nominal3.986,350,3907,349.3 KiB11,496.21.582.011.006x nominal4.168,461,6333,336.7 KiB4,964.0
W12-sel10-ef5120.222.011.006x nominal0.6322,930,32625,623.8 KiB14,959.61.572.011.006x nominal4.5613,888,4595,167.4 KiB7,658.8
W131.372.011.007x nominal1.2440,1620.9 KiB10.61.472.011.006x nominal1.39135,7141.3 KiB26.6
W11-steady0.312.011.006x nominal3.223,350,5533,158.3 KiB2,549.30.702.011.006x nominal2.103,133,0102,482.2 KiB4,558.6
W110.302.011.006x nominal3.073,811,1003,648.3 KiB2,862.50.722.011.006x nominal1.894,667,2143,242.6 KiB5,783.4

Nothing here is scaled. Where perf had to multiplex the group, the values it prints are extrapolations from the fraction of the row each counter was on, and they are withheld rather than shown — the same rule the scheduler table applies to a thread that exited. An event this host does not implement is likewise blank, never zero.

The two instruments disagree on these rows. Qdrant: perf and /proc disagree on minor faults by up to 49% on W0-upload, W1, W2, W6-upload, W7-upload, W7-2bit-upload, W7-1p5bit-upload, W8-upload, W14-1bit-upload, W14-1p5bit-upload, W14-2bit-upload, W14-4bit-upload, W12-upload, W11-steady, W11; Qdrant: perf and /proc disagree on context switches by up to 77% on W0-upload, W1, W2, W6-upload, W7-upload, W7-2bit-upload, W7-1p5bit-upload, W8-upload, W14-1bit-upload, W14-1p5bit-upload, W14-2bit-upload, W14-4bit-upload, W12-upload. perf keeps an exiting thread's counts and the /proc sums do not, so a gap here is usually the same lost-thread effect the scheduler table reports as coverage.

Collection config what each engine says it built

Read back from the engine rather than taken from the request. --segments 1 sets Qdrant's default_segment_number, which its optimizer treats as a target, and the segment count is the largest confound in the ef comparison. strawmANN held 1 segment; Qdrant held 2 segments.

Where the engines disagree a cell reads strawmANN / Qdrant, and is marked.

collectionsegmentspopulated segmentsrequested segmentspointsindexed vectorsvector sizehnsw mhnsw ef_constructquantizationshardsvector residency
bench01 / 2- / 1- / 1105,100105,100416100-1cached
bench11 / 5- / 5- / 1105,100 / 104,1320 / 10,2002,04816100-1cached
bench21 / 2- / 1- / 1105,100105,1002,04816100-1cached
bench61 / 2- / 1- / 1105,100105,1002,04816100scalar1cached
bench71 / 2- / 1- / 1105,100105,1002,04816100binary1cached
bench7b21 / 2- / 1- / 1105,100105,1002,04816100binary1cached
bench7b151 / 2- / 1- / 1105,100105,1002,04816100binary1cached
bench81 / 2- / 1- / 1105,100105,1002,04816100product1cached
bench14t11 / 2- / 1- / 1105,100105,1002,04816100turboquant1cached
bench14t151 / 2- / 1- / 1105,100105,1002,04816100turboquant1cached
bench14t21 / 2- / 1- / 1105,100105,1002,04816100turboquant1cached
bench14t41 / 2- / 1- / 1105,100105,1002,04816100turboquant1cached
bench121 / 2- / 1- / 1105,100105,1002,04816100-1cached

After the mutating rows bench2 held strawmANN 131,375 (+26,275), 131,375 of them indexed; Qdrant 131,375 (+26,275), 131,375 of them indexed. The table above is the state the throughput, latency and recall rows searched; this is what W11 left, and is that row's subject rather than theirs.

bench1 was read back straight after its row and dropped, with no settle between, so an engine still building it reports a snapshot taken mid-ingest. Its cells are not marked as a disagreement.

Per workload every metric of every row, engine beside engine

Metric down, engine across, so a comparison is two adjacent cells. Metrics a row did not measure are dropped rather than shown empty.

W0-upload transport floor: load

upload · collection=bench0 · client -p 2 -t 2 -c 1 (-p, -t, -c bfb default) · n=105,100
metricstrawmANNQdrant
wall clock6.2 s6.7 s1.09x
of which upload0.1 s0.7 s5.27x
of which index wait4.0 s4.0 s~equal
time to Green4.0 s4.0 s~equal
cpu9.1 s14.0 s1.55x
cpu, % of wall147%209%
waiting for a core3.4 ms1,192.3 ms348.43x
migrations11,6121,612.00x
faults min/maj13,124 / 046,982 / 128,012
peak RSS144.8 MiB756.0 MiB5.22x
disk written6.5 MiB37.5 MiB
disk read011.1 MiB

W0 d=4 floor: graph traversal with the distance taken out

closed-loop · collection=bench0 · client -p 1 -t 2 -c 1 (-t, -c bfb default) · n=50,000
metricstrawmANNQdrant
queries/second4,9884,187-
client p50198 µs236 µs
client p99232 µs286 µs
client p99.9274 µs334 µs
server p50112 µs134 µs
server p99122 µs168 µs
wall clock10.1 s12.0 s
queries sent50,00050,000
cpu7.5 s12.2 s
cpu, % of wall75%102%
waiting for a core3.3 ms3.0 ms
migrations0140
faults min/maj0 / 0306 / 0
peak RSS144.8 MiB754.7 MiB
disk written00
disk read00
strawmANN pass 1 -34% against two passes that agree: one pass set the spread on this row, so a band built from it is not a noise band d=4 floor: this measures graph traversal and heaps with the distance taken out, not request plumbing (findings 28: 76% of the server's CPU was HNSW search, 24% kernel; the RPC path is a small remainder)

W1 ingest throughput

upload · collection=bench1 · client -p 8 -t 8 -c 1 (-c bfb default) · n=105,100
metricstrawmANNQdrant
wall clock3.2 s4.5 s1.42x
of which upload1.1 s2.4 s2.28x
cpu2.1 s16.6 s8.00x
cpu, % of wall65%369%
waiting for a core1.2 ms7,140.0 ms5,921.03x
migrations04,550
faults min/maj226,098 / 0164,480 / 251,771
peak RSS1.1 GiB2.6 GiB2.43x
disk written821.1 MiB2.2 GiB
disk read0504.0 KiB

W2 index build time

upload · collection=bench2 · client -p 8 -t 8 -c 1 (-c bfb default) · n=105,100
metricstrawmANNQdrant
wall clock26.3 s27.5 s1.05x
of which upload1.1 s2.3 s2.18x
of which index wait23.1 s23.1 s~equal
time to Green23.1 s23.1 s~equal
cpu166.9 s142.8 s0.86x
cpu, % of wall635%519%
waiting for a core88.1 ms6,539.3 ms74.22x
migrations05,266
faults min/maj229,690 / 0261,153 / 321,753
peak RSS1.1 GiB4.2 GiB3.76x
disk written821.1 MiB3.9 GiB
disk read013.3 MiB

W3 search, fp32, single query 1.29x

ef=128 · closed-loop · collection=bench2 · client -p 1 -t 2 -c 1 (-t, -c bfb default) · n=50,000
metricstrawmANNQdrant
queries/second1,2869951.29x
recall@100.99840.9972~equal
client p50756 µs995 µs1.32x
client p991.39 ms1.42 ms~equal
client p99.91.74 ms1.55 ms0.89x
server p50666 µs882 µs1.32x
server p991.28 ms1.30 ms~equal
wall clock38.9 s50.3 s1.29x
queries sent50,00050,000
cpu35.6 s51.0 s1.43x
cpu, % of wall91%101%
waiting for a core0.9 ms4.1 ms4.38x
migrations0244
faults min/maj3 / 01,013 / 0
peak RSS1.1 GiB4.2 GiB3.76x
disk written00
disk read00

W4 search, saturating (closed loop) 0.82x

ef=128 · closed-loop · collection=bench2 · client -p 64 -t 16 -c 2 · n=50,000
metricstrawmANNQdrant
queries/second4,6585,6730.82x
recall@100.99840.9972~equal
client p5013.70 ms10.99 ms0.80x
client p9915.31 ms23.66 ms1.54x
client p99.922.16 ms35.93 ms1.62x
server p5013.58 ms10.47 ms0.77x
server p9915.16 ms18.62 ms1.23x
wall clock10.8 s8.9 s0.82x
queries sent50,00050,000
cpu77.4 s69.9 s0.90x
cpu, % of wall718%789%
waiting for a core3.9 ms80,158.3 ms20,763.27x
migrations06,963
faults min/maj144 / 05,016 / 0
peak RSS1.1 GiB4.2 GiB3.76x
disk written00
disk read00

W4-sat50 search, fixed rate at 50% of saturation (open loop) offered

ef=128 · open-loop · offered=2,327/s (50% of saturation, pinned reference 4,655 qps) · collection=bench2 · client -p n/a under --rps -t 16 -c 2 · n=200,000
metricstrawmANNQdrant
queries/second2,3272,327offered
recall@100.99840.9972~equal
client p50893 µs1.10 ms1.24x
client p991.57 ms1.68 ms1.07x
client p99.91.80 ms2.35 ms1.31x
server p50790 µs954 µs1.21x
server p991.46 ms1.50 ms1.02x
wall clock86.1 s86.1 s~equal
queries sent200,000200,000
cpu169.0 s225.2 s1.33x
cpu, % of wall196%262%
waiting for a core5.3 ms12,107.6 ms2,278.85x
migrations0423,631
faults min/maj8 / 03,625 / 0
peak RSS1.1 GiB4.2 GiB3.76x
disk written00
disk read00

W4-sat70 search, fixed rate at 70% of saturation (open loop) offered

ef=128 · open-loop · offered=3,258/s (70% of saturation, pinned reference 4,655 qps) · collection=bench2 · client -p n/a under --rps -t 16 -c 2 · n=200,000
metricstrawmANNQdrant
queries/second3,2583,258offered
recall@100.99840.9972~equal
client p501.01 ms1.18 ms1.16x
client p992.11 ms2.31 ms1.10x
client p99.92.46 ms2.79 ms1.13x
server p50906 µs1.01 ms1.11x
server p991.99 ms2.12 ms1.07x
wall clock61.5 s61.5 s~equal
queries sent200,000200,000
cpu199.2 s230.5 s1.16x
cpu, % of wall324%375%
waiting for a core7.2 ms41,776.5 ms5,776.95x
migrations0541,645
faults min/maj24 / 02,467 / 0
peak RSS1.1 GiB4.2 GiB3.76x
disk written00
disk read00

W4-sat90 search, fixed rate at 90% of saturation (open loop) offered

ef=128 · open-loop · offered=4,189/s (90% of saturation, pinned reference 4,655 qps) · collection=bench2 · client -p n/a under --rps -t 16 -c 2 · n=200,000
metricstrawmANNQdrant
queries/second4,1894,189offered
recall@100.99840.9972~equal
client p501.15 ms1.42 ms1.24x
client p992.53 ms3.03 ms1.20x
client p99.93.45 ms4.09 ms1.19x
server p501.04 ms1.21 ms1.17x
server p992.38 ms2.67 ms1.12x
wall clock47.9 s47.9 s~equal
queries sent200,000200,000
cpu222.7 s257.1 s1.15x
cpu, % of wall465%537%
waiting for a core15.2 ms134,814.7 ms8,869.18x
migrations0591,417
faults min/maj36 / 01,899 / 0
peak RSS1.1 GiB4.2 GiB3.76x
disk written00
disk read00

W5 search batched (16 distinct dataset queries per request) 0.78x

ef=128 · closed-loop · collection=bench2 · client -p 64 -t 16 -c 2 · n=50,000
metricstrawmANNQdrant
queries/second4,6495,9530.78x
recall@100.99840.9972~equal
client p50219.78 ms170.49 ms0.78x
client p99224.42 ms219.98 ms~equal
client p99.9229.72 ms281.22 ms1.22x
server p50219.13 ms168.82 ms0.77x
server p99223.70 ms200.57 ms0.90x
wall clock10.8 s8.4 s0.78x
queries sent50,00050,000
cpu76.4 s67.1 s0.88x
cpu, % of wall709%798%
waiting for a core5.4 ms91,452.0 ms16,993.16x
migrations01,018
faults min/maj1,244 / 018,963 / 0
peak RSS1.1 GiB4.2 GiB3.69x
disk written00
disk read00
per-batch latency (16 queries/request); queries: dataset, random-sample batched 16, so qps and rps differ by 16x; the ratio uses qps

W6-upload scalar quantization: load

upload · collection=bench6 · client -p 2 -t 2 -c 1 (-p, -t, -c bfb default) · n=105,100
metricstrawmANNQdrant
wall clock18.3 s22.3 s1.22x
of which upload1.0 s3.1 s3.04x
of which index wait15.1 s17.0 s1.13x
time to Green15.1 s17.0 s1.13x
cpu91.2 s72.4 s0.79x
cpu, % of wall500%324%
waiting for a core42.4 ms3,669.8 ms86.61x
migrations03,490
faults min/maj505,838 / 0398,415 / 338,627
peak RSS3.2 GiB6.4 GiB1.98x
disk written821.1 MiB4.3 GiB
disk read012.8 MiB

W6 quantized: scalar 1.18x

ef=128 · closed-loop · collection=bench6 · client -p 64 -t 16 -c 2 · n=50,000 · oversampling=12.8 · rescore=true
metricstrawmANNQdrant
queries/second10,8349,1711.18x
recall@100.99850.9973~equal
client p505.87 ms6.39 ms1.09x
client p996.37 ms17.32 ms2.72x
client p99.922.19 ms30.94 ms1.39x
server p505.77 ms5.17 ms0.90x
server p996.26 ms12.80 ms2.05x
wall clock4.7 s5.5 s1.18x
queries sent50,00050,000
cpu33.9 s42.4 s1.25x
cpu, % of wall729%773%
waiting for a core3.9 ms97,717.4 ms25,068.48x
migrations018,058
faults min/maj12 / 03,063 / 0
peak RSS3.2 GiB6.4 GiB1.98x
disk written00
disk read00

W6-ef32 SQ8 recall control, ef=32 (latency only) 1.47x

ef=32 · closed-loop · collection=bench6 · client -p 64 -t 16 -c 2 · n=100,000 · oversampling=3.2 · rescore=true
metricstrawmANNQdrant
queries/second31,68321,6241.47x
recall@100.99400.9884~equal
client p502.00 ms2.75 ms1.38x
client p992.18 ms6.26 ms2.87x
client p99.93.10 ms23.28 ms7.52x
server p501.88 ms2.10 ms1.12x
server p992.04 ms4.86 ms2.38x
wall clock3.2 s2.4 s0.73x
queries sent100,00050,000
cpu24.6 s17.6 s0.72x
cpu, % of wall762%750%
waiting for a core3.0 ms12,193.2 ms4,120.05x
migrations05,489
faults min/maj56 / 0188 / 0
peak RSS3.2 GiB6.4 GiB1.98x
disk written00
disk read00
strawmANN: -n 100000 (2x the table's 50000)

W6-ef64 SQ8 recall control, ef=64 (latency only) 1.25x

ef=64 · closed-loop · collection=bench6 · client -p 64 -t 16 -c 2 · n=50,000 · oversampling=6.4 · rescore=true
metricstrawmANNQdrant
queries/second18,62914,8601.25x
recall@100.99680.9947~equal
client p503.41 ms4.10 ms1.20x
client p993.70 ms8.29 ms2.24x
client p99.920.28 ms20.59 ms~equal
server p503.31 ms3.50 ms1.06x
server p993.58 ms6.71 ms1.88x
wall clock2.7 s3.4 s1.25x
queries sent50,00050,000
cpu20.3 s25.8 s1.27x
cpu, % of wall745%759%
waiting for a core1.9 ms14,235.4 ms7,677.36x
migrations05,334
faults min/maj12 / 0247 / 0
peak RSS3.2 GiB6.4 GiB1.98x
disk written00
disk read00

W6-ef128 SQ8 recall control, ef=128 (latency only) 1.12x

ef=128 · closed-loop · collection=bench6 · client -p 64 -t 16 -c 2 · n=50,000 · oversampling=12.8 · rescore=true
metricstrawmANNQdrant
queries/second10,8589,7281.12x
recall@100.99850.9973~equal
client p505.87 ms6.37 ms1.09x
client p996.37 ms11.13 ms1.75x
client p99.920.46 ms25.44 ms1.24x
server p505.77 ms5.89 ms1.02x
server p996.26 ms9.78 ms1.56x
wall clock4.6 s5.2 s1.12x
queries sent50,00050,000
cpu34.0 s40.3 s1.19x
cpu, % of wall732%779%
waiting for a core2.6 ms15,990.6 ms6,248.39x
migrations04,426
faults min/maj4 / 0301 / 0
peak RSS3.2 GiB6.4 GiB1.98x
disk written00
disk read00

W6-ef256 SQ8 recall control, ef=256 (latency only) 1.03x

ef=256 · closed-loop · collection=bench6 · client -p 64 -t 16 -c 2 · n=50,000 · oversampling=25.6 · rescore=true
metricstrawmANNQdrant
queries/second6,2486,0491.03x
recall@100.99920.9987~equal
client p5010.21 ms10.45 ms1.02x
client p9911.10 ms15.50 ms1.40x
client p99.920.61 ms27.25 ms1.32x
server p5010.11 ms10.09 ms~equal
server p9910.97 ms14.48 ms1.32x
wall clock8.0 s8.3 s1.03x
queries sent50,00050,000
cpu57.9 s65.8 s1.14x
cpu, % of wall720%792%
waiting for a core3.1 ms16,509.9 ms5,382.16x
migrations01,565
faults min/maj56 / 0639 / 0
peak RSS3.2 GiB6.4 GiB1.98x
disk written00
disk read00

W6-ef512 SQ8 recall control, ef=512 (latency only) parity

ef=512 · closed-loop · collection=bench6 · client -p 64 -t 16 -c 2 · n=50,000 · oversampling=51.2 · rescore=true
metricstrawmANNQdrant
queries/second3,5413,582parity
recall@100.99940.9994~equal
client p5018.02 ms17.81 ms~equal
client p9919.54 ms20.39 ms1.04x
client p99.927.05 ms31.94 ms1.18x
server p5017.91 ms17.38 ms0.97x
server p9919.41 ms19.98 ms1.03x
wall clock14.2 s14.0 s~equal
queries sent50,00050,000
cpu100.7 s111.4 s1.11x
cpu, % of wall711%796%
waiting for a core5.0 ms21,361.7 ms4,291.57x
migrations0398
faults min/maj2 / 01,788 / 0
peak RSS3.2 GiB6.4 GiB1.98x
disk written00
disk read00
within the ±2.8% band this dataset's noise floor puts on W6-ef512: no measured difference, not a small one

W7-upload binary quantization: load

upload · collection=bench7 · client -p 2 -t 2 -c 1 (-p, -t, -c bfb default) · n=105,100
metricstrawmANNQdrant
wall clock9.2 s16.3 s1.77x
of which upload1.0 s3.1 s3.06x
of which index wait6.0 s11.0 s1.83x
time to Green6.0 s11.0 s1.83x
cpu18.7 s38.9 s2.08x
cpu, % of wall204%239%
waiting for a core7.4 ms2,355.1 ms319.44x
migrations14,2154,215.00x
faults min/maj237,913 / 0344,131 / 430,030
peak RSS3.5 GiB10.1 GiB2.88x
disk written821.1 MiB4.7 GiB
disk read016.9 MiB

W7 quantized: binary + oversampling 1.53x

ef=128 · closed-loop · collection=bench7 · client -p 64 -t 16 -c 2 · n=100,000 · oversampling=12.8 · rescore=true
metricstrawmANNQdrant
queries/second25,18116,4811.53x
recall@100.98880.9858~equal
client p502.46 ms3.52 ms1.43x
client p993.42 ms9.82 ms2.87x
client p99.94.62 ms20.52 ms4.44x
server p502.37 ms1.79 ms0.76x
server p993.25 ms6.64 ms2.04x
wall clock4.0 s3.1 s0.76x
queries sent100,00050,000
cpu30.2 s23.6 s0.78x
cpu, % of wall748%768%
waiting for a core13.5 ms76,278.3 ms5,656.30x
migrations020,621
faults min/maj72 / 01,606 / 0
peak RSS3.5 GiB10.1 GiB2.88x
disk written00
disk read00
strawmANN: -n 100000 (2x the table's 50000)

W7-2bit-upload binary quantization, 2 bits: load

upload · collection=bench7b2 · client -p 2 -t 2 -c 1 (-p, -t, -c bfb default) · n=105,100
metricstrawmANNQdrant
wall clock12.2 s21.1 s1.73x
of which upload1.0 s3.0 s2.88x
of which index wait9.0 s16.0 s1.78x
time to Green9.0 s16.0 s1.78x
cpu25.7 s44.6 s1.74x
cpu, % of wall211%211%
waiting for a core10.0 ms1,297.8 ms129.83x
migrations03,462
faults min/maj246,078 / 0313,919 / 368,662
peak RSS5.6 GiB10.1 GiB1.78x
disk written821.1 MiB4.1 GiB
disk read013.8 MiB

W7-2bit quantized: binary quantization, 2 bits + oversampling 1.47x

ef=128 · closed-loop · collection=bench7b2 · client -p 64 -t 16 -c 2 · n=50,000 · oversampling=12.8 · rescore=true
metricstrawmANNQdrant
queries/second21,16814,4381.47x
recall@100.98490.9830~equal
client p502.99 ms4.05 ms1.36x
client p993.19 ms11.15 ms3.49x
client p99.919.70 ms18.91 ms0.96x
server p502.89 ms2.07 ms0.71x
server p993.09 ms7.65 ms2.48x
wall clock2.4 s3.5 s1.46x
queries sent50,00050,000
cpu17.7 s26.9 s1.52x
cpu, % of wall739%768%
waiting for a core1.2 ms87,039.8 ms72,522.05x
migrations022,365
faults min/maj0 / 02,579 / 0
peak RSS5.6 GiB10.1 GiB1.78x
disk written00
disk read00

W7-1p5bit-upload binary quantization, 1.5 bits: load

upload · collection=bench7b15 · client -p 2 -t 2 -c 1 (-p, -t, -c bfb default) · n=105,100
metricstrawmANNQdrant
wall clock12.2 s20.3 s1.66x
of which upload1.1 s3.1 s2.91x
of which index wait9.0 s15.0 s1.67x
time to Green9.0 s15.0 s1.67x
cpu23.6 s42.9 s1.82x
cpu, % of wall193%211%
waiting for a core9.2 ms1,413.8 ms154.04x
migrations03,434
faults min/maj241,963 / 0313,190 / 365,442
peak RSS5.6 GiB10.1 GiB1.78x
disk written821.1 MiB4.1 GiB
disk read013.6 MiB

W7-1p5bit quantized: binary quantization, 1.5 bits + oversampling

ef=128 · closed-loop · collection=bench7b15 · client -p 64 -t 16 -c 2 · n=50,000 · oversampling=12.8 · rescore=true
metricstrawmANNQdrant
queries/second22,82614,678-
recall@100.96930.9670
client p502.76 ms3.96 ms
client p992.96 ms10.89 ms
client p99.922.13 ms24.11 ms
server p502.67 ms2.03 ms
server p992.85 ms7.45 ms
wall clock2.2 s3.4 s
queries sent50,00050,000
cpu16.5 s26.4 s
cpu, % of wall739%767%
waiting for a core0.8 ms85,089.0 ms
migrations024,448
faults min/maj0 / 02,443 / 0
peak RSS5.6 GiB10.1 GiB
disk written00
disk read00
Qdrant pass 2 -14% against two passes that agree: one pass set the spread on this row, so a band built from it is not a noise band

W8-upload PQ: load

upload · collection=bench8 · client -p 2 -t 2 -c 1 (-p, -t, -c bfb default) · n=105,100
metricstrawmANNQdrant
wall clock216.9 s141.3 s0.65x
of which upload1.0 s2.8 s2.81x
of which index wait213.7 s136.4 s0.64x
time to Green213.7 s136.4 s0.64x
cpu1,672.3 s896.1 s0.54x
cpu, % of wall771%634%
waiting for a core493.6 ms2,043.8 ms4.14x
migrations016,721
faults min/maj461,881 / 0253,675 / 287,892
peak RSS5.4 GiB10.1 GiB1.86x
disk written821.1 MiB3.6 GiB
disk read013.5 MiB

W8 quantized: PQ 1.34x

ef=128 · closed-loop · collection=bench8 · client -p 64 -t 16 -c 2 · n=50,000 · oversampling=12.8 · rescore=true
metricstrawmANNQdrant
queries/second6,5074,8391.34x
recall@100.99800.9962~equal
client p509.79 ms12.88 ms1.32x
client p9910.65 ms26.27 ms2.47x
client p99.918.39 ms36.45 ms1.98x
server p509.70 ms12.38 ms1.28x
server p9910.54 ms21.86 ms2.07x
wall clock7.7 s10.4 s1.34x
queries sent50,00050,000
cpu55.3 s81.7 s1.48x
cpu, % of wall716%788%
waiting for a core2.9 ms97,256.2 ms33,080.68x
migrations08,224
faults min/maj0 / 05,774 / 0
peak RSS5.4 GiB10.1 GiB1.86x
disk written00
disk read00

W14-1bit-upload TurboQuant, 1 bit: load

upload · collection=bench14t1 · client -p 2 -t 2 -c 1 (-p, -t, -c bfb default) · n=105,100
metricstrawmANNQdrant
wall clock27.3 s25.7 s0.94x
of which upload1.0 s4.5 s4.38x
of which index wait24.1 s19.0 s0.79x
time to Green24.1 s19.0 s0.79x
cpu173.0 s67.8 s0.39x
cpu, % of wall635%263%
waiting for a core92.3 ms2,871.3 ms31.12x
migrations05,490
faults min/maj246,986 / 0321,067 / 379,300
peak RSS5.6 GiB10.1 GiB1.78x
disk written821.1 MiB4.2 GiB
disk read017.2 MiB

W14-1bit quantized: TurboQuant, 1 bit + oversampling 1.17x

ef=128 · closed-loop · collection=bench14t1 · client -p 64 -t 16 -c 2 · n=50,000 · oversampling=12.8 · rescore=true
metricstrawmANNQdrant
queries/second16,38613,9911.17x
recall@100.99820.9946~equal
client p503.87 ms4.09 ms1.06x
client p994.16 ms11.88 ms2.86x
client p99.918.45 ms22.08 ms1.20x
server p503.79 ms2.25 ms0.60x
server p994.05 ms8.44 ms2.08x
wall clock3.1 s3.6 s1.17x
queries sent50,00050,000
cpu22.6 s27.6 s1.22x
cpu, % of wall731%765%
waiting for a core1.0 ms90,490.1 ms90,021.31x
migrations022,467
faults min/maj0 / 02,573 / 0
peak RSS5.6 GiB10.1 GiB1.78x
disk written00
disk read00

W14-1p5bit-upload TurboQuant, 1.5 bits: load

upload · collection=bench14t15 · client -p 2 -t 2 -c 1 (-p, -t, -c bfb default) · n=105,100
metricstrawmANNQdrant
wall clock28.3 s28.1 s~equal
of which upload1.1 s5.8 s5.49x
of which index wait25.1 s20.1 s0.80x
time to Green25.1 s20.1 s0.80x
cpu176.7 s75.7 s0.43x
cpu, % of wall625%270%
waiting for a core98.0 ms3,280.1 ms33.47x
migrations05,247
faults min/maj253,226 / 0332,541 / 365,833
peak RSS5.6 GiB10.1 GiB1.78x
disk written821.1 MiB4.1 GiB
disk read016.0 MiB

W14-1p5bit quantized: TurboQuant, 1.5 bits + oversampling 1.04x

ef=128 · closed-loop · collection=bench14t15 · client -p 64 -t 16 -c 2 · n=50,000 · oversampling=12.8 · rescore=true
metricstrawmANNQdrant
queries/second13,35112,8301.04x
recall@100.99850.9934~equal
client p504.77 ms4.43 ms0.93x
client p995.11 ms13.33 ms2.61x
client p99.918.61 ms21.51 ms1.16x
server p504.68 ms2.75 ms0.59x
server p995.01 ms9.79 ms1.95x
wall clock3.8 s3.9 s1.04x
queries sent50,00050,000
cpu27.5 s30.2 s1.10x
cpu, % of wall726%768%
waiting for a core1.1 ms93,034.4 ms83,060.98x
migrations019,948
faults min/maj0 / 02,831 / 0
peak RSS5.6 GiB10.1 GiB1.78x
disk written00
disk read00

W14-2bit-upload TurboQuant, 2 bits: load

upload · collection=bench14t2 · client -p 2 -t 2 -c 1 (-p, -t, -c bfb default) · n=105,100
metricstrawmANNQdrant
wall clock28.2 s32.6 s1.15x
of which upload1.0 s5.4 s5.26x
of which index wait25.1 s25.1 s~equal
time to Green25.1 s25.1 s~equal
cpu173.8 s105.9 s0.61x
cpu, % of wall616%325%
waiting for a core94.6 ms3,606.2 ms38.14x
migrations05,569
faults min/maj263,458 / 0337,763 / 369,109
peak RSS5.6 GiB10.1 GiB1.78x
disk written821.1 MiB4.1 GiB
disk read015.3 MiB

W14-2bit quantized: TurboQuant, 2 bits + oversampling

ef=128 · closed-loop · collection=bench14t2 · client -p 64 -t 16 -c 2 · n=50,000 · oversampling=12.8 · rescore=true
metricstrawmANNQdrant
queries/second17,60213,260-
recall@100.99880.9975
client p503.60 ms4.31 ms
client p993.84 ms12.82 ms
client p99.921.17 ms20.39 ms
server p503.51 ms2.52 ms
server p993.74 ms8.99 ms
wall clock2.9 s3.8 s
queries sent50,00050,000
cpu21.1 s29.4 s
cpu, % of wall734%772%
waiting for a core1.0 ms91,222.8 ms
migrations023,244
faults min/maj0 / 02,644 / 0
peak RSS5.6 GiB10.1 GiB
disk written00
disk read00
Qdrant pass 2 -15% against two passes that agree: one pass set the spread on this row, so a band built from it is not a noise band

W14-4bit-upload TurboQuant, 4 bits: load

upload · collection=bench14t4 · client -p 2 -t 2 -c 1 (-p, -t, -c bfb default) · n=105,100
metricstrawmANNQdrant
wall clock30.3 s35.1 s1.16x
of which upload1.0 s6.5 s6.31x
of which index wait27.1 s26.1 s0.96x
time to Green27.1 s26.1 s0.96x
cpu177.1 s95.5 s0.54x
cpu, % of wall585%272%
waiting for a core98.9 ms4,046.0 ms40.92x
migrations06,720
faults min/maj296,243 / 0385,139 / 399,027
peak RSS5.6 GiB10.1 GiB1.78x
disk written821.1 MiB4.3 GiB
disk read013.7 MiB

W14-4bit quantized: TurboQuant, 4 bits + oversampling 1.02x

ef=128 · closed-loop · collection=bench14t4 · client -p 64 -t 16 -c 2 · n=50,000 · oversampling=12.8 · rescore=true
metricstrawmANNQdrant
queries/second12,51912,246~equal
recall@100.99840.9967~equal
client p505.08 ms4.71 ms0.93x
client p995.46 ms13.59 ms2.49x
client p99.921.95 ms24.53 ms1.12x
server p504.99 ms2.99 ms0.60x
server p995.36 ms9.86 ms1.84x
wall clock4.0 s4.1 s1.02x
queries sent50,00050,000
cpu29.4 s31.7 s1.08x
cpu, % of wall728%769%
waiting for a core1.4 ms93,865.0 ms68,462.16x
migrations019,310
faults min/maj0 / 02,939 / 0
peak RSS5.6 GiB10.1 GiB1.78x
disk written00
disk read00

W9 exact / brute force parity

exact · closed-loop · collection=bench2 · client -p 8 -t 2 -c 1 (-t, -c bfb default) · n=2,000
metricstrawmANNQdrant
queries/second7172parity
client p50108.80 ms112.97 ms1.04x
client p99156.20 ms128.28 ms0.82x
client p99.9178.24 ms137.30 ms0.77x
server p50107.86 ms111.69 ms1.04x
server p99155.18 ms127.12 ms0.82x
wall clock28.1 s27.9 s~equal
queries sent2,0002,000
cpu196.9 s219.3 s1.11x
cpu, % of wall701%786%
waiting for a core21.4 ms10,502.0 ms490.37x
migrations07,955
faults min/maj0 / 0749 / 0
peak RSS5.4 GiB10.1 GiB1.86x
disk written00
disk read00
within the ±3.3% band this dataset's noise floor puts on W9: no measured difference, not a small one brute force over the whole collection, no index involved

W10-ef32 recall control, ef=32 (latency only)

ef=32 · closed-loop · collection=bench2 · client -p 8 -t 2 -c 1 (-t, -c bfb default) · n=50,000
metricstrawmANNQdrant
queries/second12,02110,511-
recall@100.99410.9884
client p50656 µs708 µs
client p99971 µs1.39 ms
client p99.91.26 ms1.82 ms
server p50560 µs542 µs
server p99872 µs1.17 ms
wall clock4.2 s4.8 s
queries sent50,00050,000
cpu28.9 s27.8 s
cpu, % of wall689%580%
waiting for a core2.9 ms10,977.5 ms
migrations072,256
faults min/maj0 / 01,345 / 0
peak RSS5.4 GiB10.1 GiB
disk written00
disk read00
strawmANN pass 1 +10% against two passes that agree: one pass set the spread on this row, so a band built from it is not a noise band

W10-ef64 recall control, ef=64 (latency only) parity

ef=64 · closed-loop · collection=bench2 · client -p 8 -t 2 -c 1 (-t, -c bfb default) · n=50,000
metricstrawmANNQdrant
queries/second7,5157,152parity
recall@100.99680.9944~equal
client p501.05 ms1.02 ms0.98x
client p991.63 ms2.07 ms1.27x
client p99.91.86 ms2.61 ms1.41x
server p50950 µs837 µs0.88x
server p991.52 ms1.80 ms1.18x
wall clock6.7 s7.0 s1.05x
queries sent50,00050,000
cpu46.9 s43.0 s0.92x
cpu, % of wall701%612%
waiting for a core3.8 ms28,598.2 ms7,552.67x
migrations0127,646
faults min/maj0 / 01,051 / 0
peak RSS5.4 GiB10.1 GiB1.86x
disk written00
disk read00
within the ±17.2% band this dataset's noise floor puts on W10-ef64: no measured difference, not a small one

W10-ef128 recall control, ef=128 (latency only) parity

ef=128 · closed-loop · collection=bench2 · client -p 8 -t 2 -c 1 (-t, -c bfb default) · n=50,000
metricstrawmANNQdrant
queries/second4,6524,840parity
recall@100.99840.9972~equal
client p501.69 ms1.55 ms0.92x
client p992.75 ms3.02 ms1.10x
client p99.93.17 ms3.73 ms1.17x
server p501.58 ms1.32 ms0.83x
server p992.65 ms2.67 ms~equal
wall clock10.8 s10.4 s0.96x
queries sent50,00050,000
cpu76.3 s65.8 s0.86x
cpu, % of wall707%635%
waiting for a core6.0 ms41,026.0 ms6,842.95x
migrations0151,424
faults min/maj0 / 0309 / 0
peak RSS5.4 GiB10.1 GiB1.86x
disk written00
disk read00
within the ±16.2% band this dataset's noise floor puts on W10-ef128: no measured difference, not a small one

W10-ef256 recall control, ef=256 (latency only) parity

ef=256 · closed-loop · collection=bench2 · client -p 8 -t 2 -c 1 (-t, -c bfb default) · n=50,000
metricstrawmANNQdrant
queries/second2,8593,139parity
recall@100.99920.9987~equal
client p502.75 ms2.44 ms0.89x
client p994.61 ms4.48 ms0.97x
client p99.95.33 ms5.48 ms1.03x
server p502.64 ms2.18 ms0.83x
server p994.49 ms4.11 ms0.91x
wall clock17.5 s16.0 s0.91x
queries sent50,00050,000
cpu123.9 s105.2 s0.85x
cpu, % of wall707%659%
waiting for a core9.2 ms55,799.7 ms6,051.89x
migrations0174,169
faults min/maj4 / 0500 / 0
peak RSS5.4 GiB10.1 GiB1.86x
disk written00
disk read00
within the ±15.5% band this dataset's noise floor puts on W10-ef256: no measured difference, not a small one

W10-ef512 recall control, ef=512 (latency only) parity

ef=512 · closed-loop · collection=bench2 · client -p 8 -t 2 -c 1 (-t, -c bfb default) · n=50,000
metricstrawmANNQdrant
queries/second1,7311,957parity
recall@100.99960.9993~equal
client p504.52 ms3.98 ms0.88x
client p997.71 ms7.05 ms0.91x
client p99.98.86 ms8.31 ms0.94x
server p504.41 ms3.68 ms0.83x
server p997.60 ms6.63 ms0.87x
wall clock28.9 s25.6 s0.88x
queries sent50,00050,000
cpu204.1 s174.5 s0.86x
cpu, % of wall706%682%
waiting for a core14.2 ms77,540.7 ms5,454.64x
migrations0192,033
faults min/maj4 / 0979 / 0
peak RSS5.4 GiB10.1 GiB1.86x
disk written00
disk read00
within the ±16.2% band this dataset's noise floor puts on W10-ef512: no measured difference, not a small one

W12-upload filtered search: load 105,100 with payloads

upload · collection=bench12 · client -p 2 -t 2 -c 1 (-p, -t, -c bfb default) · n=105,100
metricstrawmANNQdrant
wall clock26.3 s27.7 s1.05x
of which upload1.1 s4.3 s4.05x
of which index wait23.1 s21.1 s0.91x
time to Green23.1 s21.1 s0.91x
cpu167.3 s142.6 s0.85x
cpu, % of wall636%515%
waiting for a core88.8 ms9,459.2 ms106.47x
migrations13,9073,907.00x
faults min/maj230,537 / 0216,135 / 352,935
peak RSS5.6 GiB10.1 GiB1.78x
disk written821.1 MiB3.7 GiB
disk read24.0 KiB20.1 MiB

W12-sel1 filtered search, one keyword (~1% of bench12) parity

ef=128 · closed-loop · collection=bench12 · client -p 64 -t 16 -c 2 · n=50,000
metricstrawmANNQdrant
queries/second5,5735,956parity
recall@101.00001.0000~equal
client p5011.46 ms10.31 ms0.90x
client p9912.17 ms23.38 ms1.92x
client p99.927.69 ms35.30 ms1.28x
server p5011.35 ms9.53 ms0.84x
server p9912.03 ms17.95 ms1.49x
wall clock9.0 s8.4 s0.94x
queries sent50,00050,000
cpu64.7 s66.1 s1.02x
cpu, % of wall718%783%
waiting for a core3.8 ms100,434.0 ms26,363.80x
migrations011,448
faults min/maj3 / 03,569 / 0
peak RSS5.6 GiB10.1 GiB1.78x
disk written00
disk read00
within the ±10.8% band this dataset's noise floor puts on W12-sel1: no measured difference, not a small one filtered search over a keyword payload index both engines were asked to build; whether each did is read back from the engine and refused beside the row when it did not. Recall is measured under the filter, against ground truth restricted to the matching set

W12-sel10 filtered search, any of 10 keywords (~10% of bench12) 1.25x

ef=128 · closed-loop · collection=bench12 · client -p 64 -t 16 -c 2 · n=50,000
metricstrawmANNQdrant
queries/second3,7012,9491.25x
recall@100.99890.9968~equal
client p5017.23 ms21.70 ms1.26x
client p9919.15 ms24.65 ms1.29x
client p99.928.35 ms34.13 ms1.20x
server p5017.13 ms21.17 ms1.24x
server p9919.01 ms24.19 ms1.27x
wall clock13.5 s17.0 s1.25x
queries sent50,00050,000
cpu96.2 s135.4 s1.41x
cpu, % of wall710%797%
waiting for a core3.0 ms23,208.0 ms7,752.21x
migrations0225
faults min/maj4 / 01,975 / 0
peak RSS5.6 GiB10.1 GiB1.78x
disk written00
disk read00
filtered search over a keyword payload index both engines were asked to build; whether each did is read back from the engine and refused beside the row when it did not. Recall is measured under the filter, against ground truth restricted to the matching set

W12-sel1-ef32 filtered recall control, one keyword, ef=32 (latency only) 0.91x

ef=32 · closed-loop · collection=bench12 · client -p 64 -t 16 -c 2 · n=50,000
metricstrawmANNQdrant
queries/second5,5676,0860.91x
recall@101.00001.0000~equal
client p5011.47 ms10.32 ms0.90x
client p9912.22 ms16.57 ms1.36x
client p99.921.70 ms29.99 ms1.38x
server p5011.35 ms9.84 ms0.87x
server p9912.07 ms15.35 ms1.27x
wall clock9.0 s8.3 s0.92x
queries sent50,00050,000
cpu64.8 s65.2 s~equal
cpu, % of wall718%789%
waiting for a core2.7 ms20,047.1 ms7,461.69x
migrations02,833
faults min/maj0 / 01,655 / 0
peak RSS5.6 GiB10.1 GiB1.78x
disk written00
disk read00

W12-sel1-ef64 filtered recall control, one keyword, ef=64 (latency only) 0.91x

ef=64 · closed-loop · collection=bench12 · client -p 64 -t 16 -c 2 · n=50,000
metricstrawmANNQdrant
queries/second5,5636,0810.91x
recall@101.00001.0000~equal
client p5011.47 ms10.32 ms0.90x
client p9912.19 ms16.63 ms1.36x
client p99.928.12 ms32.25 ms1.15x
server p5011.35 ms9.86 ms0.87x
server p9912.05 ms15.25 ms1.27x
wall clock9.0 s8.3 s0.92x
queries sent50,00050,000
cpu64.8 s65.3 s~equal
cpu, % of wall717%790%
waiting for a core3.7 ms19,925.6 ms5,406.72x
migrations02,746
faults min/maj12 / 0847 / 0
peak RSS5.6 GiB10.1 GiB1.78x
disk written00
disk read00

W12-sel1-ef128 filtered recall control, one keyword, ef=128 (latency only) parity

ef=128 · closed-loop · collection=bench12 · client -p 64 -t 16 -c 2 · n=50,000
metricstrawmANNQdrant
queries/second5,5666,075parity
recall@101.00001.0000~equal
client p5011.48 ms10.33 ms0.90x
client p9912.16 ms16.63 ms1.37x
client p99.919.89 ms29.17 ms1.47x
server p5011.37 ms9.86 ms0.87x
server p9912.02 ms15.36 ms1.28x
wall clock9.0 s8.3 s0.92x
queries sent50,00050,000
cpu64.8 s65.2 s~equal
cpu, % of wall718%788%
waiting for a core2.7 ms20,076.5 ms7,386.09x
migrations02,872
faults min/maj0 / 0551 / 0
peak RSS5.6 GiB10.1 GiB1.78x
disk written00
disk read00
within the ±10.8% band this dataset's noise floor puts on W12-sel1-ef128: no measured difference, not a small one

W12-sel1-ef256 filtered recall control, one keyword, ef=256 (latency only) parity

ef=256 · closed-loop · collection=bench12 · client -p 64 -t 16 -c 2 · n=50,000
metricstrawmANNQdrant
queries/second5,5676,070parity
recall@101.00001.0000~equal
client p5011.47 ms10.34 ms0.90x
client p9912.22 ms16.65 ms1.36x
client p99.925.88 ms28.27 ms1.09x
server p5011.36 ms9.84 ms0.87x
server p9912.07 ms15.53 ms1.29x
wall clock9.0 s8.3 s0.92x
queries sent50,00050,000
cpu64.8 s65.3 s~equal
cpu, % of wall718%789%
waiting for a core2.8 ms20,329.7 ms7,302.84x
migrations02,936
faults min/maj4 / 0747 / 0
peak RSS5.6 GiB10.1 GiB1.78x
disk written00
disk read00
within the ±11.5% band this dataset's noise floor puts on W12-sel1-ef256: no measured difference, not a small one

W12-sel1-ef512 filtered recall control, one keyword, ef=512 (latency only) parity

ef=512 · closed-loop · collection=bench12 · client -p 64 -t 16 -c 2 · n=50,000
metricstrawmANNQdrant
queries/second5,5516,061parity
recall@101.00001.0000~equal
client p5011.49 ms10.36 ms0.90x
client p9912.26 ms16.60 ms1.35x
client p99.918.52 ms26.28 ms1.42x
server p5011.38 ms9.86 ms0.87x
server p9912.12 ms15.49 ms1.28x
wall clock9.0 s8.3 s0.92x
queries sent50,00050,000
cpu64.9 s65.4 s~equal
cpu, % of wall718%789%
waiting for a core4.1 ms20,046.9 ms4,936.54x
migrations02,781
faults min/maj0 / 0861 / 0
peak RSS5.6 GiB10.1 GiB1.78x
disk written00
disk read00
within the ±11.7% band this dataset's noise floor puts on W12-sel1-ef512: no measured difference, not a small one

W12-sel10-ef32 filtered recall control, any of 10 keywords, ef=32 (latency only) 1.54x

ef=32 · closed-loop · collection=bench12 · client -p 64 -t 16 -c 2 · n=50,000
metricstrawmANNQdrant
queries/second9,5626,2251.54x
recall@100.99170.9818~equal
client p506.66 ms10.13 ms1.52x
client p997.41 ms14.42 ms1.95x
client p99.920.13 ms26.50 ms1.32x
server p506.56 ms9.83 ms1.50x
server p997.30 ms13.61 ms1.87x
wall clock5.3 s8.1 s1.53x
queries sent50,00050,000
cpu38.0 s64.0 s1.68x
cpu, % of wall722%792%
waiting for a core1.8 ms14,998.0 ms8,397.16x
migrations01,275
faults min/maj0 / 0764 / 0
peak RSS5.6 GiB10.1 GiB1.78x
disk written00
disk read00

W12-sel10-ef64 filtered recall control, any of 10 keywords, ef=64 (latency only) 1.35x

ef=64 · closed-loop · collection=bench12 · client -p 64 -t 16 -c 2 · n=50,000
metricstrawmANNQdrant
queries/second6,0484,4651.35x
recall@100.99680.9930~equal
client p5010.54 ms14.22 ms1.35x
client p9911.76 ms16.96 ms1.44x
client p99.922.91 ms27.92 ms1.22x
server p5010.44 ms13.89 ms1.33x
server p9911.64 ms16.54 ms1.42x
wall clock8.3 s11.2 s1.35x
queries sent50,00050,000
cpu59.5 s89.4 s1.50x
cpu, % of wall716%795%
waiting for a core2.7 ms17,598.1 ms6,445.36x
migrations0333
faults min/maj0 / 01,685 / 0
peak RSS5.6 GiB10.1 GiB1.78x
disk written00
disk read00

W12-sel10-ef128 filtered recall control, any of 10 keywords, ef=128 (latency only) 1.25x

ef=128 · closed-loop · collection=bench12 · client -p 64 -t 16 -c 2 · n=50,000
metricstrawmANNQdrant
queries/second3,7052,9571.25x
recall@100.99890.9968~equal
client p5017.22 ms21.59 ms1.25x
client p9919.15 ms24.69 ms1.29x
client p99.924.39 ms34.31 ms1.41x
server p5017.12 ms21.10 ms1.23x
server p9919.01 ms24.20 ms1.27x
wall clock13.5 s16.9 s1.25x
queries sent50,00050,000
cpu96.1 s135.0 s1.40x
cpu, % of wall710%797%
waiting for a core5.7 ms23,156.1 ms4,077.95x
migrations0284
faults min/maj0 / 03,332 / 0
peak RSS5.6 GiB10.1 GiB1.78x
disk written00
disk read00

W12-sel10-ef256 filtered recall control, any of 10 keywords, ef=256 (latency only) 1.18x

ef=256 · closed-loop · collection=bench12 · client -p 64 -t 16 -c 2 · n=50,000
metricstrawmANNQdrant
queries/second2,2311,8841.18x
recall@100.99970.9986~equal
client p5028.63 ms33.95 ms1.19x
client p9931.71 ms37.90 ms1.20x
client p99.933.11 ms41.08 ms1.24x
server p5028.53 ms33.44 ms1.17x
server p9931.57 ms37.45 ms1.19x
wall clock22.5 s26.6 s1.18x
queries sent50,00050,000
cpu158.5 s212.0 s1.34x
cpu, % of wall706%798%
waiting for a core5.1 ms32,264.0 ms6,323.57x
migrations0345
faults min/maj0 / 02,603 / 0
peak RSS5.6 GiB10.1 GiB1.78x
disk written00
disk read00

W12-sel10-ef512 filtered recall control, any of 10 keywords, ef=512 (latency only)

ef=512 · closed-loop · collection=bench12 · client -p 64 -t 16 -c 2 · n=50,000
metricstrawmANNQdrant
queries/second6171,150-
recall@101.00000.9994
client p50105.09 ms55.72 ms
client p99113.64 ms61.51 ms
client p99.9115.55 ms68.08 ms
server p50104.85 ms54.96 ms
server p99113.40 ms60.89 ms
wall clock81.1 s43.5 s
queries sent50,00050,000
cpu572.0 s347.6 s
cpu, % of wall705%799%
waiting for a core38.1 ms46,649.3 ms
migrations0730
faults min/maj0 / 07,761 / 0
peak RSS5.6 GiB10.1 GiB
disk written00
disk read00
Qdrant pass 1 -25% against two passes that agree: one pass set the spread on this row, so a band built from it is not a noise band

W13 scroll / pagination 1.12x

closed-loop · collection=bench2 · client -p 8 -t 2 -c 1 (-t, -c bfb default) · n=200,000
metricstrawmANNQdrant
queries/second56,85450,6971.12x
client p50128 µs146 µs1.14x
client p99204 µs284 µs1.39x
client p99.9237 µs432 µs1.82x
server p5011 µs28 µs2.60x
server p9915 µs97 µs6.32x
wall clock3.6 s4.1 s1.12x
queries sent200,000200,000
cpu5.3 s18.0 s3.42x
cpu, % of wall145%440%
waiting for a core3.0 ms2,068.1 ms687.23x
migrations0214,148
faults min/maj0 / 0328 / 0
peak RSS5.6 GiB10.1 GiB1.78x
disk written00
disk read00
-n 200000 (4x the table's 50000) strawmANN: 0.12 ms of the client's 0.13 ms p50 is not server time (12x), so 91% of this row is the load generator and the socket Qdrant: 0.12 ms of the client's 0.15 ms p50 is not server time (5x), so 81% of this row is the load generator and the socket 1.12x is 3.38x less work per query x 0.33x cores busy during the row (1.47 against 4.50) x 1.00x clock x 1.02x counted on-CPU share: the middle term is occupancy, not search speed

W11-steady mixed read/write below the rebuild threshold: search bench2 while 5,255 synthetic points append

ef=128 · closed-loop · collection=bench2 · client -p 8 -t 2 -c 1 (-t, -c bfb default) · n=100,000,000
metricstrawmANNQdrant
queries/second4,2013,884-
client p501.75 ms1.76 ms
client p996.01 ms4.69 ms
client p99.97.99 ms14.19 ms
server p501.64 ms1.46 ms
server p995.44 ms4.04 ms
wall clock33.5 s33.5 s
queries sent141,565134,909
cpu238.6 s224.5 s
cpu, % of wall712%670%
waiting for a core17,930.8 ms186,545.5 ms
migrations55439,330
faults min/maj35,060 / 0398,756 / 130,827
peak RSS5.6 GiB10.1 GiB
disk written41.3 MiB5.9 GiB
disk read038.4 MiB
strawmANN: qps over the 26.5 s of the append the search saw (4,262 over the whole search); append 198 points/s Qdrant: qps over the 26.5 s of the append the search saw (4,062 over the whole search); append 198 points/s search-during-write; no recall join

W11 mixed read/write: search bench2 while 21,020 synthetic points append (runs last)

ef=128 · closed-loop · collection=bench2 · client -p 8 -t 2 -c 1 (-t, -c bfb default) · n=100,000,000
metricstrawmANNQdrant
queries/second3,6982,695-
client p501.90 ms2.26 ms
client p997.01 ms9.47 ms
client p99.98.94 ms20.95 ms
server p501.79 ms1.86 ms
server p996.27 ms8.37 ms
wall clock88.8 s88.7 s
queries sent332,497251,951
cpu637.8 s606.9 s
cpu, % of wall718%685%
waiting for a core88,083.3 ms363,116.3 ms
migrations243528,552
faults min/maj129,726 / 01,559,118 / 624,754
peak RSS5.6 GiB16.9 GiB
disk written164.5 MiB22.7 GiB
disk read0141.9 MiB
strawmANN: qps over the 70.3 s of the append the search saw (3,777 over the whole search); append 299 points/s Qdrant: qps over the 70.3 s of the append the search saw (2,862 over the whole search); append 299 points/s Qdrant -19% across its passes, monotonically: the spread on this row is drift rather than noise, so the median is a trend's midpoint and not a repeatable measurement strawmANN pass 1 +10% against two passes that agree: one pass set the spread on this row, so a band built from it is not a noise band search-during-write; no recall join
Host discipline the §7.1 gate, per check, and ambient load per row

Ambient load per row

The §7.1 gate checks the machine once, at the start. Colour is the engine, as everywhere else; a hatched bar with a red edge is a row that had another process on the box while it ran, which the gate cannot see.

strawmANN gate pass

environment hash 373e8531fd3d1bf6
okAMD Ryzen AI 9 HX PRO 370 w/ Radeon 890M (24 logical)
okgovernor=performance
okboost disabled
oksmt=on
declared rather than required (§7.1 asks for SMT on or off, not
for off), and hashed, so these rows never share a chart with
SMT-off ones
cpu N and cpu N+12 share a core (12 pairs);
a --server-cpus or --client-cpus set holding both cpus of a
pair measures the engine on half the cores it names
okprofile=as-deployed (isolcpus=none nohz_full=none)
the scheduler is running as it ships, so these numbers describe a
deployment rather than the engine in isolation; they may not be
compared against an `isolated` run, and the environment hash
enforces that
okthp=madvise numa_nodes=1 numa_balancing=0
okperf_event_paranoid=-1
oktask_delayacct=1, so time blocked on a device is measurable
okperf at /usr/bin/perf, so `workloads.py run --perf` can attach
okcgroup io controller reaches the engines' own scope, so block-layer read/write operations are measurable
okzig=0.16.0
okmachine is quiescent (load 0.15 over 24 cores)
measurement profile: as-deployed

Qdrant gate pass

environment hash 373e8531fd3d1bf6
okAMD Ryzen AI 9 HX PRO 370 w/ Radeon 890M (24 logical)
okgovernor=performance
okboost disabled
oksmt=on
declared rather than required (§7.1 asks for SMT on or off, not
for off), and hashed, so these rows never share a chart with
SMT-off ones
cpu N and cpu N+12 share a core (12 pairs);
a --server-cpus or --client-cpus set holding both cpus of a
pair measures the engine on half the cores it names
okprofile=as-deployed (isolcpus=none nohz_full=none)
the scheduler is running as it ships, so these numbers describe a
deployment rather than the engine in isolation; they may not be
compared against an `isolated` run, and the environment hash
enforces that
okthp=madvise numa_nodes=1 numa_balancing=0
okperf_event_paranoid=-1
oktask_delayacct=1, so time blocked on a device is measurable
okperf at /usr/bin/perf, so `workloads.py run --perf` can attach
okcgroup io controller reaches the engines' own scope, so block-layer read/write operations are measurable
okzig=0.16.0
busy: Xorg(6%)
okmachine is quiescent: 0.09 cores of foreign load, under the 1.00 budget
measurement profile: as-deployed
What this does not establish

No Qdrant developer has used this tool. Nothing here has been run, checked against something already known, or disagreed with by anyone outside the project: every number has one author and one reviewer, and they are the same person. A result you can refute is more useful to us than one you accept.

It has never been pointed at a real Qdrant regression. The harness detects a known ISA slowdown and correctly reports no difference on a control row. That is internal consistency, not evidence it would flag a regression in your tree or stay quiet through a refactor. bench/harness/qdrant_ab.py exists to run two of your commits through it blind, and that experiment has not been done.

Part of the measured throughput gap is kernel width, not architecture. Read from a dev checkout: Qdrant's distance path tops out at four 256-bit accumulators and has no AVX-512, while these kernels use 512-bit ones on a machine that has them. That is a real difference and it is not the same claim as "the design is faster".

The engines are not equivalent, by construction. §1 removes sharding, replication, consensus, snapshots, sparse vectors, multivectors and disk-resident operation — permanently. Payload storage and filtering were in that list until 2026-09-03 and are now built (M7), so W12 measures a filtered search with a keyword index on both engines. Anything still unbuilt answers UNIMPLEMENTED naming the construct and reports n/a, never a silent degradation. A strawman that was not faster would mean it was badly built; the question is by how much, and where the model was wrong.

Reproducing this

Everything below runs from a clone. The engine has no dependencies; the analysis path is a uv project pinned by bench/uv.lock.

scripts/doctor.py                    # what can this machine measure?
bench/setup.py check                 # §7.1 host gate: governor, boost, isolation, idle
conformance/datasets/datasets.py fetch

# one engine at a time, §7.1
zig build -Doptimize=ReleaseFast
# --connections matters: W4 opens ~32 sockets (-t 16 -c 2) and a server with
# fewer closes the excess before the HTTP/2 preface, which the client reports
# only as "transport error".
./zig-out/bin/strawmann --port 6334 --connections 64
bench/harness/workloads.py run http://localhost:6334 strawmann --sink --report

# the other half of every number: recall, and the licence to compare at all
cd conformance
cargo run --release -- relevance --engine http://localhost:6334 --label strawmann \
  --base $DATA/h-and-m-2048-angular-filters/base.fbin --queries $DATA/h-and-m-2048-angular-filters/queries.fbin \
  --ground-truth $DATA/h-and-m-2048-angular-filters/gt/h-and-m-2048-angular-filters.cosine.k100.gt.json --metric cosine \
  --ef 32 64 128 256 512 --json ../bench/results/strawmann/recall.json
cargo run --release -- differ --strawmann http://localhost:6334 --qdrant http://localhost:6434 \
  --base $DATA/h-and-m-2048-angular-filters/base.fbin --queries $DATA/h-and-m-2048-angular-filters/queries.fbin \
  --ground-truth $DATA/h-and-m-2048-angular-filters/gt/h-and-m-2048-angular-filters.cosine.k100.gt.json \
  --json ../bench/results/strawmann/conformance.json

uv run --project bench bench/harness/report.py strawmann qdrant

Disagreements are the point. docs/spec.md is what all of this is measured against, docs/bugs.md lists the measurement bugs found so far (each produced a plausible wrong number rather than a failure), and docs/validation.md records what has and has not been checked.