Skip to content

[QST] CAGRA self-search QPS seems low — is this expected on L4 with SINGLE_CTA/search_width=1? #2488

Description

@marcelo-cjl

What is your question?

I benchmarked CAGRA native cosine search with a small self-search program and measured a QPS that seems lower than I expected from the cuVS ANN benchmarks. Is ~43.5k QPS a reasonable number for these parameters on an L4, or is something off? And which parameters would have the biggest impact on QPS?

Update (2026-08-26): The original reproducer used raw, unnormalized Cohere vectors with L2Expanded. I corrected the benchmark to use native cuVS CosineExpanded for both index construction and search, and updated the measurements below. The script still passes the input vectors to cuVS unchanged and does not pre-normalize them.

Reproduction

Minimal reproducer (self-contained script that builds cuVS from source and runs a tiny C++ benchmark using cuvs::neighbors::cagra::build / cuvs::neighbors::cagra::search):

https://github.com/marcelo-cjl/cuvs/blob/33ac4cfef430934cf4f4c583f942d0b429736133/cpp/bench/cuvs_cagra_self_search/cuvs_cagra_self_search.sh

Environment:

  • Machine: AWS g6.4xlarge
  • GPU: NVIDIA L4 23 GB
  • Driver: 560.35.05
  • cuVS: built from source at commit 33ac4cfe (Release, -DBUILD_TESTS=OFF -DBUILD_C_LIBRARY=OFF -DBUILD_CAGRA_HNSWLIB=OFF -DBUILD_MG_ALGOS=OFF -DCUVS_COMPILE_DYNAMIC_ONLY=ON, CMAKE_CUDA_ARCHITECTURES=native)

Dataset: VectorDBBench Cohere Medium, converted to .fbin (1,000,000 rows x 768 dims, float). This is a self-search workload: the same training file is used to build the index and as the query input. self_recall_at_1 is the fraction of queries where the top-1 label equals the query's own row id.

Index / search parameters:

Parameter Value
dtype float
metric CosineExpanded
graph_degree 64
intermediate_graph_degree 128
topk 1
itopk_size 32
search_width 1
max_iterations 0
search_algo SINGLE_CTA

Observed results from two searches against the same rebuilt cosine index:

run stage rows dim search_ms qps self_recall_at_1
1 search 1,000,000 768 22,993.9 43,489.8 0.995099
2 search 1,000,000 768 22,996.2 43,485.5 0.995099

search_ms is measured with CUDA events around a single cuvs::neighbors::cagra::search call (1M queries in one batch); qps = rows * 1000 / search_ms.

Expected behavior

I was expecting higher throughput based on the cuVS ANN benchmarks. Specifically:

  1. Is ~43.5k QPS reasonable for native CosineExpanded, SINGLE_CTA, search_width=1, topk=1, 1M x 768 float on an L4, or does it indicate a configuration problem?
  2. Which knobs have the biggest impact on QPS (e.g., multi-CTA search algorithm, larger search_width/itopk_size, half precision, query batch size)?
  3. Is there an official way to run this exact native-cosine workload through cuvs-bench so I can compare against a reference number?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions