feat: GPU_HNSW / GPU_HNSW_SQ index using faiss::gpu::GpuIndexHNSW — native FP32/FP16/BF16/INT8#2
feat: GPU_HNSW / GPU_HNSW_SQ index using faiss::gpu::GpuIndexHNSW — native FP32/FP16/BF16/INT8#2devin-ai-integration[bot] wants to merge 40 commits into
Conversation
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
|
Successfully scanned changes introduced in a pull request into Internal scan identifier:
See all issues found during this scan in the OX Security Application. Detailed information
3 aggregations
|
GPU_HNSW (and GPU_HNSW_SQ) index type via vendored faiss GpuIndexHNSW: IndexNode wiring, index-type registration, faiss_gpu_hnsw CUDA target, and recall/cosine/topk/serialize tests. Clean feature-only commit on current main; dead cooperative-distance code excluded. Signed-off-by: Devin AI <devin-ai-integration[bot]@users.noreply.github.com>
45139ad to
8e24da1
Compare
Mirror the 6si/faiss GPU HNSW review fixes into the vendored copy: - default overflow_factor to 2 in internal GpuHnswSearchParams - propagate config_.device into the scratch pool (no hardcoded device 0) - make setSearchParams sticky (no consume-once race) - query device shared-memory opt-in limit and opt the kernel into >48KiB dynamic shared memory instead of assuming a 48KiB cap - synchronize before the stack-local entry-point buffer is destroyed Signed-off-by: premal <premal@6sense.com> Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- keep Count()/Dim() working after the CPU copy is freed by capturing n_rows/dim before reset and overriding Count()/Dim() (previously returned -1, making the loaded segment look empty) - make HasRawData()/GetVectorByIds() and StaticHasRawData() consistent: GPU_HNSW frees the CPU copy so it exposes no CPU-reconstructable raw data (return false / not_implemented once uploaded) - set gsp.overflow_factor=2 in the search path so the overflow candidate queue stays enabled (recall) - publish gpu_index_ through an atomic gpu_ready_ flag (release/acquire) to remove the unsynchronized double-checked read - harden the filtered-search guard to reject on bitset.data()!=nullptr instead of count() (which defaults to 0) - correct the class comment: GPU_HNSW is registered for F32 and INT8 only - add Count()/Dim() regression assertions to the GPU HNSW search test Signed-off-by: premal <premal@6sense.com> Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Signed-off-by: premal <premal@6sense.com> Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…n record The overflow candidate queue was never functional (overflow_insert had no call site; d_overflow_count only zeroed+read). Removed from the kernel in 6si/faiss#1 and 6si/knowhere#2. Update the design doc to describe a plain parallel beam search and add a decision record explaining the removal. Signed-off-by: premal <premal@6sense.com> Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Mirror of 6si/faiss#1: the overflow candidate queue was never wired in (overflow_insert had no call site; d_overflow_count only zeroed+read), so it only wasted scratch VRAM + a memset per search. Remove the overflow machinery from the vendored faiss GPU kernel and drop the explicit gsp.overflow_factor=2 in faiss_hnsw.cc. Recall is tuned via ef. Signed-off-by: premal <premal@6sense.com> Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
GPU_HNSW_SQ was exposed by Milvus (constant, param spec, tests, GPU routing) but had no Knowhere backend, so creating it hit no impl. Add a thin GpuHnswSQIndexNode subclass of GpuHnswIndexNode that only overrides Type(); the GPU search path is identical (a CPU-built HNSW/HNSW_SQ index uploaded to GpuIndexHNSW). Register it for VECTOR_FLOAT and VECTOR_INT8, add the INDEX_GPU_HNSW_SQ constant + index-table entries, and accept the GPU_HNSW_SQ binset key in Deserialize's alias path. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: premal <premal@6sense.com> Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Sync of 6si/faiss@467593eae (byte-identical vendored copy): - searchImpl_ event-based stream sync before reading host queries (zilliztech#15) - cudaSetDevice() before cudaFree in scratch/index destructors (zilliztech#19/zilliztech#20) - clear error when search_width exceeds shared-memory budget (zilliztech#18) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: premal <premal@6sense.com> Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Mirror the faiss native fp16/bf16 device-storage change into the vendored faiss copy (byte-identical to 6si/faiss) and register fp16/bf16 for both GPU_HNSW and GPU_HNSW_SQ: - index_table.h: add VECTOR_FLOAT16 / VECTOR_BFLOAT16 legal-type rows for both GPU index types. - faiss_hnsw.cc: add fp16/bf16 KNOWHERE_REGISTER_GLOBAL (feature::FP16|GPU, feature::BF16|GPU) and RegisterStaticFunc entries for both nodes; update the class comment to describe native 2-byte fp16/bf16 device storage with per-element up-conversion to fp32 in the kernel. - test_gpu_search.cc: add GPU HNSW FP16/BF16 deserialize+search UTs (CPU HNSW_SQ QT_fp16/QT_bf16 build -> GPU load -> recall vs brute force). Compile-verified only; GPU-runtime validation pending capacity. Signed-off-by: premal <premal@6sense.com> Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
… type Add INT8 path to gpu_hnsw_search() that dispatches to layer0_beam_search_kernel_int8 when sc.d_queries_i8 is populated. Upper-layer search still uses fp32 queries (d_queries) for the greedy entry-point descent through sparse upper layers.
V5-C1: Remove +128 query shift in searchHostInt8. upload_int8_dataset already reverses FAISS's +128 bias (codes[i]-128), so GPU stores original signed user values. Queries arrive as the same signed int8 values — no shift needed. The +128 shift was causing (q+128)*d instead of q*d. V5-C2: Gate DP4A dispatch on idx.use_ip in GpuHnswSearch.cuh. The DP4A kernel only computes dot products; L2 now falls through to the existing fp32 generic kernel. V5-H1: Replace throw on dim%4!=0 with fp32 fallback via searchHost(). V5-L1: Fix misleading comments describing the encoding.
…l merge) Re-vendor faiss/gpu from 6si/faiss (devin/gpu-hnsw-int8-dp4a-unify) so the vendored copy stops diverging from upstream faiss. This pulls in: - the single <DataT,QueryT,USE_DP4A> layer-0 kernel (replaces the separate serial int8 kernel + serial fp32 kernel with one parallel bitonic-merge kernel that also handles native int8 DP4A); - staging padded to next_pow2(search_width*2*M) so non-power-of-two 2*M no longer hard-fails GPU search; - ef-clamp warning and corrected int8/negated-distance header docs. Also: - document the fp32-Flat/unsigned-SQ8 transient-peak under-count in StaticEstimateLoadResource (2x is correct for the compact int8 path production uses; a per-DataType estimator is the proper fix); - add a non-power-of-two 2*M UT covering both the fp32 and int8 DP4A parallel-merge paths (cosine, dim divisible by 4). Signed-off-by: premal <premal@6sense.com> Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Code Review — Delta (INT8 DP4A + Padded Staging)
|
| Finding | Status |
|---|---|
| C1 (lazy-upload metric detection) | ❌ Not fixed |
| I1 (single-threaded merge) | ✅ Fixed — parallel bitonic merge |
| I2 (stale "+128 shift" docstrings) | |
| I3 (duplicated upper-layer logic) | ✅ Fixed — unified template |
| I4 (maxMemoryCost under-counting) | 📄 Documented — detailed limitation comment added |
Full review: static analysis only (no CUDA/GPU available for compile/test verification).
Re-vendors faiss gpu-hnsw-faiss@81c9ff25 GpuHnswSearchKernel.cuh. Corrects the parallel_merge_into_result diagonal binary search (staging[mid] vs result[pos-mid-1], not result[pos-mid]) that caused ~4% recall and a UINT32_MAX-sentinel CUDA illegal memory access on int8/COSINE search. Validated on CPU vs std::merge (200k cases, 0 failures). All 7 vendored faiss/gpu files remain byte-identical to faiss. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
… tests Re-vendor faiss GpuHnswSearchKernel.cuh (faiss gpu-hnsw-faiss @46235ee3): guard ep/parent/result node ids < N before graph/dataset indexing (fixes v82 fp16 P1 OOB in layer0_beam_search_kernel<__half,float,false>). Add independently-taggable per-dtype GPU HNSW search tests (nb=4000, dim=64, M=16, ef=200 -- same config as the failing fp16 P1 case), each covering L2/IP/COSINE so a CUDA context crash in one instantiation does not hide the others: - [gpu_hnsw_dtype_fp32] flat -> <float,float,false> (config control) - [gpu_hnsw_dtype_fp16] HNSW_SQ fp16 -> <__half,float,false> - [gpu_hnsw_dtype_bf16] HNSW_SQ bf16 -> <__nv_bfloat16,float,false> - [gpu_hnsw_dtype_sq8] HNSW_SQ sq8 -> decoded <float,float,false> - [gpu_hnsw_dtype_int8] native int8 (IP/COSINE take DP4A, dim%4==0) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: premal <premal@6sense.com> Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Re-vendor faiss GpuHnswSearchKernel.cuh (faiss gpu-hnsw-faiss @81e4cc69): split the bitonic compare-exchange into read -> __syncthreads -> write -> __syncthreads phases, removing the cross-warp read/write hazard that produced the v82 fp16 P1 OOB. Vendored file byte-identical to faiss. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: premal <premal@6sense.com> Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Code Review — Delta 2 (Bitonic Sort Race Fix + Recall Tests)Bug fixes correctly mirror faiss PRThe vendored kernel changes are identical to 6si/faiss#1: two-phase barrier bitonic sort fix,
|
…OSINE re-negation; re-vendor faiss Source fixes (src/index/hnsw/faiss_hnsw.cc): - GPU_HNSW_SQ deserialize: alias the incoming payload under this node's own Type() (INDEX_GPU_HNSW_SQ) so the base loader's GetByName(Type()) finds it; the previous hardcoded INDEX_GPU_HNSW alias made every GPU_HNSW_SQ segment unqueryable while leaving base GPU_HNSW behavior intact. - Lazy GPU upload now reuses UploadCpuIndexToGpuLocked() (made const) instead of deriving the metric from the query config, so IP/COSINE/L2 is detected from the FAISS index even when the query omits metric_type. - Remove the IP/COSINE sign-flip loops after searchHost()/searchHostInt8(): faiss now returns true similarity on copy-out, so re-negating would invert it. - Correct the stale native-int8 comments (no +128 shift; signed int8 uploaded verbatim, DP4A kernel). Re-vendored faiss GPU tree (thirdparty/faiss, byte-identical to faiss 48ab2cb7): GpuIndexHNSW.h, impl/GpuHnswSearch.cuh, impl/GpuHnswSearchKernel.cuh, impl/GpuHnswTypes.cu. Tests (tests/ut/test_gpu_search.cc): - [gpu_hnsw_sq_alias] load a CPU HNSW_SQ index into the GPU_HNSW_SQ node. - [gpu_hnsw_ip_sign] IP/COSINE distances are true similarity (sign+magnitude vs recomputed neighbor similarity; descending order). - [gpu_hnsw_k_valid] all k slots are real neighbors (no sentinel) with ef>=k. Signed-off-by: premal <premal@6sense.com> Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…lute floor The [gpu_hnsw_compare] 'Varying ef comparison' section asserted gpu_recall >= 0.5f for every ef, but at ef=16 (~= k) HNSW recall is legitimately low on both engines (CPU HNSW itself scores ~0.41, GPU ~0.47). The absolute floor was meaningless in that regime and the section already computes cpu_recall but never used it. Assert GPU tracks the CPU oracle within a small tolerance instead, which is the correct invariant for a GPU-vs-CPU comparison test and catches real regressions at every ef. Signed-off-by: premal <premal@6sense.com> Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Code Review — Delta 3 (C1 fix, distance convention, SQ alias, recall parity)✅ C1 (Critical) — FINALLY FIXEDThe lazy-upload path in New Issue — Important (lower severity than C1)[I1] Post-processing still reads Distance Convention Change — CorrectKnowhere no longer negates IP/cosine distances (faiss now returns true similarity). Sign flip removed from post-processing. Cosine post-scaling math correct for both fp32 and int8 paths. Sentinel handling is metric-appropriate. GPU_HNSW_SQ Aliasing — Correct
New Recall Parity Tests — Well-Designed
Previously-Flagged Items — All Addressed
No new critical issues. The C1 fix removes the last blocking item. |
…nfig I1: GpuHnswIndexNode::Search() detected COSINE from hnsw_cfg.metric_type to decide fp32 query normalization and int8 1/||q|| distance scaling. A search config that omits metric_type defaults to L2, so a cosine index would skip normalization and silently return wrong scores. Derive the metric from the built GPU index via the new GpuIndexHNSW::isCosine() accessor (captured at upload time from the FAISS index type), matching the index-side detection already used on the upload path. Re-vendor the faiss GPU tree (byte-identical to 6si/faiss@24be1b66): - mutex-guarded, monotonic cudaFuncSetAttribute smem configuration (TOCTOU fix) - entry_point bounds validation in extract_hnsw_layers - GpuIndexHNSW isCosine()/useInnerProduct() accessors Add a regression test that searches a COSINE index with metric_type omitted from the config and asserts identical results to the explicit-COSINE search. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Signed-off-by: premal <premal@6sense.com> Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Code Review — Delta 4 (I1 fix — index-derived metric in post-processing + regression test)✅ I1 (Important) — FULLY FIXEDThe post-processing in With C1 fixed in delta 3 (lazy-upload now calls Regression Test — Well-Designed"Test GPU HNSW Cosine Metric Omitted From Search Config" builds a cosine index, searches with Minor: the test only covers the fp32 path, not int8 DP4A — but both use the same No New Critical or Important IssuesNo merge blockers remain on the knowhere side. All previously-flagged items from our review series are now resolved:
|
…lags) Byte-identical re-vendor of 6si/faiss@a43d3afe: reset() now clears is_cosine_/use_ip_ so a reused GpuIndexHNSW can't inherit a stale cosine/IP interpretation. Verified with cmp against the faiss source. Signed-off-by: premal <premal@6sense.com> Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The faiss_gpu_hnsw OBJECT library is the only place the faiss GPU sources are compiled in the knowhere build: FAISS_SRCS does not glob faiss/gpu/*, and the vendored thirdparty/faiss/faiss/gpu/CMakeLists.txt (faiss_gpu_objs) is never add_subdirectory()'d. Comment-only; no compiled objects change. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: premal <premal@6sense.com> Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Code Review — Delta 5 (reset() fix + CMake GPU source documentation)✅ M1 from Delta 4 — FIXED
CMake Comment Block — Good DocumentationThe new comment block in the faiss CMakeLists explains the GPU source compilation architecture clearly:
This is valuable for future maintainers. No issues. No new issues. All previously-flagged items remain resolved. |
Re-vendor the faiss GPU tree with CPU-parity filtered search and wire the delete/TTL/partition BitsetView through GpuHnswIndexNode::Search() instead of rejecting a non-empty bitset. - faiss thirdparty: byte-identical copy of the filtered-search kernel, GPU brute-force header (GpuHnswBruteForce.cuh, added to gpu/CMakeLists.txt), host launcher and scratch types. - Search(): remove the blanket filtered-search rejection; pass bitset ptr/nbits/filtered-count and disable_fallback_brute_force into faiss for both native int8 and fp32 paths. Still reject id-remapped / id-offset bitsets (has_out_ids()/id_offset()!=0) since the kernel tests by raw node id (== row offset == bit index), and guard a bitset shorter than ntotal. Snapshot/reload concurrency, CPU-index release after upload, and cosine/int8 post-scaling preserved. - bitsetview.h: add id_offset() accessor for the shape guard. - tests: gpu_hnsw_id_mapping (blocking G-ID proof: node id == row offset == bitset index, via unfiltered self-query and filtered self-query) and gpu_hnsw_filtered_recall (no returned id filtered; recall vs brute force across delete ratios 0.1-0.99). Signed-off-by: premal <premal@6sense.com> Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…edge cases; vendor ensure_filter device fix Signed-off-by: premal <premal@6sense.com> Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
feat(gpu_hnsw): GPU-side filtered search (deletes/TTL/partition bitset)
Delta 6 Review — knowhere PR #2 (filtered search wiring + tests merged in)The filtered search wiring from PR #8 has been folded into PR #2. Reviewed the delta against our previous PR #8 review. Previously-Flagged Items — Most Fixed! ✅
Vendoring ✅All faiss PR #7 additions present in knowhere tree. New Issues (all minor)
VerdictApproved. Great progress on test coverage — the CPU-HNSW parity gate with 0.05 tolerance and the expanded ratio sweep (including 0.0/0.3/0.7) are exactly what was needed. Ready for GPU runtime validation. Full review at $M/reports/review-knowhere-pr2-delta6.md |
…stance, H1) Re-vendors faiss gpu-hnsw-faiss tip f22116e8 (merge of faiss PR #8): the layer-0 neighbor expansion is now warp-per-candidate cooperative distance (32 lanes stride one vector, warp-reduce) instead of thread-per-candidate, coalescing the dominant dataset loads. Measured on the L40S build box (counter deltas transfer to Blackwell): sectors/request 12.1 -> 3.10 (3.9x), throughput 1.57x int8-DP4A / 1.85x fp32, recall identical to baseline (7/7, max delta -0.0025), compute-sanitizer clean (memcheck/racecheck/initcheck). No public API or semantic change. Signed-off-by: premal <premal@6sense.com> Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
feat(gpu_hnsw): re-vendor faiss GPU tree (warp-cooperative layer-0 distance, H1)
…OOM fix) Re-vendors the faiss GPU HNSW fix that bounds the grow-only visited bitmap by processing queries in nq-chunks (byte-identical to 6si/faiss devin/gpu-hnsw-oom-chunk). The bitmap was nq * ceil(N/32) * 4 bytes per scratch slot and never released, so high search concurrency on large segments exhausted device VRAM. Chunking caps it regardless of batch size / concurrency; small segments still run a single pass. Adds tests/ut/test_gpu_search.cc [gpu_hnsw_chunk_parity]: runs each search twice (default cap => single pass, vs GPU_HNSW_BITMAP_BYTES forced tiny => many chunks) and asserts identical ids/distances across fp32 & int8-DP4A, unfiltered, mid-ratio filtered, and up-front-BF (99%) paths for L2/IP/COSINE. Signed-off-by: premal <premal@6sense.com> Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
feat(gpu_hnsw): re-vendor faiss GPU tree (nq-chunked visited bitmap, OOM fix)
Summary
GPU HNSW index implementation using a vendored FAISS
GpuIndexHNSWbackend. Accepts CPU-built HNSW/HNSW_SQ indexes at load time, uploads vectors and graph to GPU VRAM, frees the CPU copy, and runs a parallel beam search entirely on GPU with per-segment CUDA streams. Recall is tuned viaef.Registered index types & precisions:
GPU_HNSWandGPU_HNSW_SQ, each for fp32, fp16, bf16, and int8.GPU_HNSW_SQis a thin alias —GpuHnswSQIndexNodesubclassesGpuHnswIndexNodeand only overridesType(); the GPU search and load paths are identical.Registrations (both index types) now cover all four precisions:
Native low-precision storage: fp16/bf16/int8 stay in their on-disk layout on the device (2/2/1 bytes/element) and are up-converted to fp32 per element inside the search kernel — mirroring the pre-existing INT8 path. The vendored FAISS copy (
thirdparty/faiss/faiss/gpu/impl/GpuHnsw*.{h,cuh}) is kept byte-identical to 6si/faiss#1: aGpuHnswDatasetTypeenum drives kernel dispatch andupload_halfwidth_dataset()copies the raw 2-byte codes verbatim. TheIndexNodeDataMockWrapper<fp16|bf16>converts fp16/bf16 query inputs to the node's fp32-facing interface, while the stored dataset stays native low-precision.Load-path fix (mmap/file) — fixes the production querynode OOM: the eager GPU upload must run on both deserialization entrypoints. Milvus loads sealed segments through the mmap/file path (
VectorMemIndex::LoadFromFile → index_.DeserializeFromFile()), notDeserialize(BinarySet).GpuHnswIndexNodepreviously only overrodeDeserialize(BinarySet), soDeserializeFromFilefell through to the base CPU loader and the upload never ran: the CPU-built HNSW stayed resident in host RAM (fp32-expanded for int8/fp16/bf16 inputs, ~5.9 GiB/segment for mpd_v2) while VRAM sat idle, OOMKilling querynodes during the load storm before any search could trigger the lazy-upload fallback. Fix factors the upload/unpublish into helpers and calls them from both entrypoints:GpuHnswSQIndexNodeinherits the fix. New[gpu_hnsw_p1]test loads viaDeserializeFromFile(enable_mmap true/false) and assertsSize()==0before any search (i.e.indexes[0]freed) — fails pre-fix and cannot be masked by the first-search lazy upload.Architecture (unchanged core):
GpuHnswIndexNodewrapsfaiss::gpu::GpuIndexHNSW; accepts CPU-serialized HNSW/HNSW_SQ atDeserialize()(binset key aliased fromGPU_HNSW_SQ/HNSW_SQ/HNSW) and atDeserializeFromFile()(raw faiss index bytes / mmap). CPU copy freed after upload;Count()/Dim()captured before the free.StandardGpuResourcessingleton (GetSharedGpuResources());StaticEstimateLoadResourcereturnsmemoryCost=0;GetGpuConstructionMutex()serializes construction;gpu_ready_publishes the built index for the lock-free search fast path; per-segmentcudaStreamNonBlockingstreams.Tests: added
Test GPU HNSW FP16 DeserializationandTest GPU HNSW BF16 Deserialization(CPU HNSW_SQQT_fp16/QT_bf16build → GPU load → recall vs brute force; floors 0.9 / 0.85), plus the[gpu_hnsw_p1]regression sections (cosine-norm parity, reload lifetime, load accounting, and the new DeserializeFromFile upload/free assertion). Guarded byKNOWHERE_WITH_CUVS, so they compile/run only on GPU builds (no silent no-op pass on CPU builds).Kernel: 1-thread-per-distance, 128 concurrent candidates/block,
num_parents == 0stagnation break. The earlier non-functional "OCQ" overflow queue was removed here and in faiss#1 (decision recorddocs/design-docs/design_docs/20260711-gpu-hnsw-ocq-removal.mdin 6si/milvus#6); use a largereffor higher recall.Filtered search:
Search()rejects a non-empty bitset withinvalid_args(delete/TTL/partition). No in-node CPU fallback (copy freed after upload); GPU-side bitset filtering is a documented follow-up. Scoped to append-mostly / immutable collections for now.Verification: compile-verified via the GPU build. The DeserializeFromFile fix is validated by the
[gpu_hnsw_p1]unit test and a live single-segment + full mpd_v2 load re-run (VRAM growth + host-anon-returns-to-baseline + zero OOMKills) — in progress. The prior perf numbers (8× g7e.2xlarge, mpd_v2 569M, GPU 3.3–4.5× CPU vec/s, R@1 0.892) predate this change and covered fp32/int8; native fp16/bf16 correctness is validated by the GPU unit/recall gates and the sealed-segment cluster e2e (see Performance below); a matched fp16/bf16 throughput run is a follow-up.Performance (CPU-HNSW vs GPU)
Benchmarked on the same dataset and harness (collection
mpd_v2, 569.9M rows, INT8 COSINE;run_eval_jobs.py,--sample-size 2048 --continuous-iterations 30). Best cell = batch 512, 8 parallel × 4 workers (32 concurrency):Throughput figures are from the
gpu-hnsw-v89image (this beam-search kernel; fp32/int8 COSINE). v89 is 10–24% faster than v83 at all matched batch-512 cells (4×1 +11%, 4×4 +11%, 8×1 +24%, 8×4 +14%), so the filtered-search path does not regress unfiltered throughput. Native fp16/bf16 throughput is a follow-up; correctness across fp32/fp16/bf16/int8 × L2/IP/COSINE (and filtered deletes/TTL/partition at CPU parity) is covered by the unit/recall/sanitizer gates and the sealed-segment cluster e2e.Related PRs: 6si/faiss#1 (FAISS kernel), 6si/milvus#6 (Milvus integration).
Link to Devin session: https://6sense.devinenterprise.com/sessions/d39aba56b8a3467cbbf231ab631a06ed
Link to Devin session: https://6sense.devinenterprise.com/sessions/55dab0bd33c346df99b5818b30059342
Requested by: @premal