Repository navigation
perf(hnsw): compact outgoing adjacency - #444
Conversation
Signed-off-by: Jim Ezesinachi <ezesinachijim@gmail.com>
Opt-in Benchmark Results: similarity/hnsw_compact_adjacency_graphfirst-time benchmark: candidate vs control |
Opt-in Memory Benchmark Resultssimilarity/hnsw_compact_adjacency_graph_memoryWhole HNSW structural-memory candidate, The candidate replaces only each per-layer outgoing Papaya
This compares steady, post-build structural memory. It excludes vector payload and does not measure concurrent peak memory, persistence, deletion, or whole-DB overhead. Do not extrapolate directly to Cohere 10M. similarity/hnsw_counter_shards_memoryDetected CPUs: 4; default counter shards: 4; architecture: x86_64. Median of 3 fresh processes per scenario/variant. All variants share one collector. Control uses default sharding; candidates use one/two shards only for per-node collections. Index-wide collections retain default sharding. Values are jemalloc deltas from a baseline retaining the input vectors. Active/resident columns are control / one shard / two shards. Resident is jemalloc resident, not process RSS. Fixtures use cosine distance and serial insertion.
Expected savings cover live per-node counters only, using 128-byte padding on x86_64/ARM64. Retired collections, allocator size classes, and reclamation timing can change the measured delta; this prediction is not whole-index accounting. A negative expectation on a small-CPU machine means the candidate uses more shards than the default.
|
Test Results427 tests 427 ✅ 11m 33s ⏱️ Results for commit 922bf4b. ♻️ This comment has been updated with latest results. |
Benchmark Results |
Signed-off-by: Jim Ezesinachi <ezesinachijim@gmail.com>
Signed-off-by: Jim Ezesinachi <ezesinachijim@gmail.com>
Signed-off-by: Jim Ezesinachi <ezesinachijim@gmail.com>
Opt-in Benchmark Results: similarity/hnsw_distance_reusePR base vs PR branch |
Opt-in Benchmark Results: similarity/hnsw_insert_distance_reusePR base vs PR branch |
Per-layer outgoing HNSW neighbor sets allocate a Papaya table, counters, and separate entries for small, bounded lists. Store these lists as immutable
ArcSwap<Vec<NodeId>>snapshots to reduce structural memory and improve traversal locality.The existing
NodeandHNSWare generic over edge storage, so HashSet control and compact candidate share insertion, search, filtering, deletion, and persistence algorithms. Compact writes use compare-and-swap; pruning recomputes selection if another writer changes the snapshot. Backlinks, outer layer maps, graph-layer sets, embeddings, and IDs retain their existing representations.DB builds use compact adjacency by default.
--features bench-control-adjacencyselects the HashSet control for fallback and ghz A/B builds. The previousbench-compact-adjacencyflag remains accepted for candidate commands. The persistedTempNode/TempHNSWshape is retained, allowing either representation to restore the other's snapshots.Criterion and fresh-process memory A/B targets remain registered under
bench-experiments; the existing labelled workflow discovers them and posts their reports.Measured results
Same-run Criterion estimates for deterministic 768-dimensional cosine fixtures:
Construction and incremental insertion timings include index destruction; they do not isolate insertion cost.
Structural allocation, median of three fresh processes, M=16/M0=32/efConstruction=200, shared collectors and one per-node counter shard:
Memory deltas exclude unchanged embedding payload. Post-drop allocation checks passed. These measurements do not establish whole-DB peak memory or that Cohere 10M fits within 56 GiB. End-to-end ghz c1 results for this final shared implementation are still pending.
Validation
bench-experiments.