Skip to content

feat(gpu_hnsw): re-vendor faiss GPU tree (nq-chunked visited bitmap, OOM fix)#10

Merged
devin-ai-integration[bot] merged 1 commit into
gpu-hnsw-faissfrom
devin/gpu-hnsw-oom-chunk-revendor
Jul 20, 2026
Merged

feat(gpu_hnsw): re-vendor faiss GPU tree (nq-chunked visited bitmap, OOM fix)#10
devin-ai-integration[bot] merged 1 commit into
gpu-hnsw-faissfrom
devin/gpu-hnsw-oom-chunk-revendor

Conversation

@devin-ai-integration

Copy link
Copy Markdown

Summary

Re-vendors the faiss GPU HNSW OOM fix (6si/faiss#9) into knowhere's in-tree thirdparty/faiss, byte-identical to 6si/faiss@devin/gpu-hnsw-oom-chunk, and adds a chunking-parity unit test.

The bug: GPU HNSW search scratch is grow-only per pool slot. The visited bitmap is nq * ceil(N/32) * 4 bytes and is never released, so high search concurrency (one bitmap per concurrent slot) on large segments exhausts device VRAM — 16 concurrent batch=512 searches on a ~538M-row segment grew the pool to ~97 of ~98 GB and OOM'd everything after (v90 Blackwell validation).

The fix (vendored): the layer-0 search processes queries in nq-chunks so the bitmap is bounded regardless of batch size / concurrency; GpuHnswSearchScratch::ensure() sizes the bitmap for one chunk. gpu_hnsw_bitmap_chunk(nq, N) derives the per-launch query count from a VRAM cap (default 256 MiB; env-tunable via GPU_HNSW_BITMAP_MB / GPU_HNSW_BITMAP_BYTES). Chunking is result-invariant (queries independent; per-query buffers indexed by chunk-local block index against caller-offset base pointers), and small segments still run a single pass. See 6si/faiss#9 for the full mechanism.

Test — tests/ut/test_gpu_search.cc [gpu_hnsw_chunk_parity]: runs each search twice and asserts element-for-element identical ids/distances:

unsetenv("GPU_HNSW_BITMAP_BYTES");            // default cap => chunk == nq (single pass)
base = gpu_idx.Search(q, json, bitset);
setenv("GPU_HNSW_BITMAP_BYTES", ~2*per_query) // force many chunks
chunked = gpu_idx.Search(q, json, bitset);
REQUIRE(chunked.ids == base.ids && chunked.dist ≈ base.dist);

Sections cover L2/IP/COSINE × {fp32 unfiltered, int8 unfiltered (DP4A: distinct int8 layer-0 vs fp32 upper-layer query offsets), fp32 filtered ~30% (two-tier beam + per-chunk worklist reset), fp32 filtered ~99% (up-front brute-force fallback)}.

Only thirdparty/faiss/faiss/gpu/impl/{GpuHnswTypes.h,GpuHnswTypes.cu,GpuHnswSearch.cuh} and the test change; no public API / index-registration changes.

Related PRs

Link to Devin session: https://6sense.devinenterprise.com/sessions/55dab0bd33c346df99b5818b30059342
Requested by: @premal

…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>
@premal premal self-assigned this Jul 20, 2026
@devin-ai-integration

Copy link
Copy Markdown
Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@devin-ai-integration
devin-ai-integration Bot merged commit f712669 into gpu-hnsw-faiss Jul 20, 2026
devin-ai-integration Bot added a commit to 6si/milvus that referenced this pull request Jul 20, 2026
…mmit

Repoint from the pre-merge feature-branch SHA 2b52090d to f7126691, the merge commit of 6si/knowhere#10 on gpu-hnsw-faiss, so the pin references the permanent integration branch rather than a feature branch.

Signed-off-by: premal <premal@6sense.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
devin-ai-integration Bot added a commit that referenced this pull request Jul 21, 2026
Mirror the two Devin Review fixes from faiss PR #10 into thirdparty/faiss so
the built libknowhere matches:
- upload the filter bitset in GpuIndexHNSW::searchImpl_ before gpu_hnsw_search
  (the standard search() path selected the filtered kernel on a sticky-param
  bitset but never allocated/uploaded the device buffer -> illegal access).
- guard extract_hnsw_layers against reading nb_neighbors(1) for a degenerate
  layer-0-only index (max_level==0), which would be an out-of-bounds read of
  cum_nneighbor_per_level[2].

Signed-off-by: premal <premal@6sense.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant