NVIDIA / NVIDIA/cuvs

[Bug] cuVS CAGRA concurrent search performance gap between Python and C++ API

Open
#2,041 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Cuda
Stars
854
Forks
236
Avg merge
3d 3h
Merged PRs (30d)
62

Description

Summary

Simulating online search (concurrency = n, batch_size = 1) with cagra search python API.

Impact

Python users have no path to fan out concurrent searches; the safe alternative is multi-process, but each process duplicates the index+dataset on GPU and OOMs quickly. Result: Python tops out around ~600 QPS at bs=1, while cuvs-bench C++ achieves ~30K QPS at 90% recall on the same hardware (~50x gap).

Environment

Setup

Tried (but failed)

Calling cuvs.neighbors.cagra.search from multiple Python threads, each with its own cuvs.common.Resources(stream=stream.ptr), consistently segfaults inside pylibraft.common.device_ndarray.empty during output-buffer allocation. This is the natural Python equivalent of the std::async pattern in examples/cpp/src/cagra_persistent_example.cu, so concurrent submission to the persistent CAGRA kernel is unreachable from Python.

Steps to reproduce

import threading
import cupy as cp
import numpy as np
from cuvs.common import Resources
from cuvs.neighbors import cagra

rng = np.random.default_rng(0)
N, D, Q, K = 100_000, 2048, 8800, 10
base = cp.asarray(rng.random((N, D), dtype=np.float32))
queries = cp.asarray(rng.random((Q, D), dtype=np.float32))

idx = cagra.build(
    cagra.IndexParams(graph_degree=32, intermediate_graph_degree=64, build_algo="nn_descent"),
    base,
)
sp = cagra.SearchParams(itopk_size=64)
_ = cagra.search(sp, idx, queries, K)
cp.cuda.Device().synchronize()

def worker(a, b):
    stream = cp.cuda.Stream(non_blocking=True)
    res = Resources(stream=stream.ptr)
    cagra.search(sp, idx, queries[a:b], K, resources=res)
    res.sync()

threads = [threading.Thread(target=worker, args=(0, Q // 2)),
           threading.Thread(target=worker, args=(Q // 2, Q))]
for t in threads: t.start()
for t in threads: t.join()

Repo -

cuvs-search-bench

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the Python cagra.search path and the pylibraft.common.device_ndarray.empty failure described in the reproducer. Compare it with examples/cpp/src/cagra_persistent_example.cu and the cuvs-bench setup, then investigate safe concurrent submission and output allocation. Done means concurrent Python searches no longer segfault and the performance gap is characterized or resolved.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, python
Domain
backend, search
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.