Skip to content

Iterative CAGRA-Q - #1810

Open
irina-resh-nvda wants to merge 26 commits into
NVIDIA:mainfrom
irina-resh-nvda:iterative_cagra_q
Open

Iterative CAGRA-Q#1810
irina-resh-nvda wants to merge 26 commits into
NVIDIA:mainfrom
irina-resh-nvda:iterative_cagra_q

Conversation

@irina-resh-nvda

@irina-resh-nvda irina-resh-nvda commented Feb 16, 2026

Copy link
Copy Markdown
Contributor

Iterative cagra graph construction using CAGRA-Q search.

This PR improves the iterative CAGRA build method by enabling PQ compression: the dataset is compressed before the iterative search starts, and CAGRA-Q is used to iteratively update the KNN graph.

@copy-pr-bot

copy-pr-bot Bot commented Feb 16, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

… search

- Configurable growth-phase in-build search params (itopk_size, search_width,
  max_iterations) and internal/smem dtype; itopk auto-forced on the final
  full-size iteration.
- Decouple compression params used during iterative construction from the
  target index compression.
- Add shuffle_dataset option; fix out-of-bounds access from the in-place raft
  gather by switching to an out-of-place gather.
…around)

The shuffle_dataset path used an out-of-place gather into a temporary buffer to
work around an illegal memory access in raft's in-place gather overload when
n_rows * row_len exceeded 2^31 (32-bit index overflow).

That bug is now fixed upstream in raft (NVIDIA/raft#3059, closes #3055), which
the cuvs raft pin now includes. Revert to the in-place gather to drop the extra
full-size temporary allocation and copy.
@irina-resh-nvda
irina-resh-nvda marked this pull request as ready for review July 15, 2026 08:48
@irina-resh-nvda
irina-resh-nvda requested review from a team as code owners July 15, 2026 08:48
@aamijar aamijar changed the title Iterative cagra q Iterative graph build using CAGRA-Q search Jul 22, 2026
@aamijar aamijar changed the title Iterative graph build using CAGRA-Q search Iterative CAGRA-Q Jul 22, 2026
@aamijar

aamijar commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Hi @irina-resh-nvda, thanks for the contribution! I've added some commits to clean up some small things in this PR:

  1. Merge main into this branch and fix merge conflicts 278a4f3
  2. Run pre-commit run --all-files to fix style checker cc65291
  3. There were some unrelated .clangd and .gitignore changes I saw so I reverted that 25e6d7d
  4. There was an unrelated warning change in cuvs_bench so I reverted that 6bca275
  5. The tests/CMakeLists.txt has a duplicate file added so I removed that here 9d44b23
  6. There were some unrelated changes from auto to explicit return type which I reverted 73c9bbc
  7. Two commented out code lines were removed 23cf815

Comment thread cpp/tests/neighbors/ann_cagra.cuh Outdated
// {std::optional<bool>{std::nullopt}},
// {cuvs::neighbors::MergeStrategy::MERGE_STRATEGY_PHYSICAL,
// cuvs::neighbors::MergeStrategy::MERGE_STRATEGY_LOGICAL});
// inputs.insert(inputs.end(), inputs2.begin(), inputs2.end());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why has this test been commented out?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a leftover from my testing, i'll fix it

Comment thread cpp/tests/neighbors/ann_cagra.cuh Outdated
{16}, // k
{32}, // degree
{ // graph_build_algo::IVF_PQ,
// graph_build_algo::NN_DESCENT,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same question: what is the reason for the changes here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry, testing artefact, will fix

Comment thread cpp/tests/neighbors/ann_cagra.cuh Outdated
{true},
{false},
{0.995},
{0.01},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why has the recall changed to 1%?

Comment thread cpp/tests/neighbors/ann_cagra.cuh Outdated
// {std::optional<bool>{std::nullopt}},
// {cuvs::neighbors::MergeStrategy::MERGE_STRATEGY_PHYSICAL,
// cuvs::neighbors::MergeStrategy::MERGE_STRATEGY_LOGICAL});
// inputs.insert(inputs.end(), inputs2.begin(), inputs2.end());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same question: why was this commented out?

// Create a dataset with 1000 points
constexpr int64_t n_dataset = 1000;
// Create a dataset with 10000 points
constexpr int64_t n_dataset = 10000;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the reason this test file has been changed to use n_dataset = 10,000?

dev_ptr,
n_bytes,
cudaMemcpyDeviceToHost,
writeback_stream_));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should have a raft function that does this already.

// use memcpy instead of raft::copy to avoid strange behavior with HMM/ATS memory

If there is a problem here, we should try to root fix that in raft.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think this change is indeed some kind of diff artefact

host_view_.data_handle() + src_row_offset * host_view_.extent(1),
n_bytes,
cudaMemcpyHostToDevice,
prefetch_stream_));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as before: let's try to use the raft copy function.

cudaPointerAttributes attr;
RAFT_CUDA_TRY(cudaPointerGetAttributes(&attr, ptr));
return attr.hostPointer != nullptr;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should already have utilities somewhere to do check if a pointer is host or device accessible, either within in raft or cuvs.
I can try to find those functions for you.

* @tparam IdxT The type of the index
*/
template <typename T, typename IdxT>
class batched_device_view_from_host {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we use batch_load_iterator for the same purpose?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like a merge/diff view artifact. I think @mfoerste4 has added this new class earlier in his refactoring and I asked exactly the same question. There was seemingly a good reason for it, but I forgot it :) @mfoerste4 could you please remind?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bumping this, if we don't need this utility we can remove a bunch of code from this PR from this file utils.hpp and delete the test_batched_device_view_from_host.cu test file.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this seems to be a merge issue. The class and test do not exist on main anymore.

@irina-resh-nvda

Copy link
Copy Markdown
Contributor Author

the new main merge introduced some crashes, im investigating

@achirkin achirkin left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, a few suggestions here, mainly about the use of raft resources and helper utilities in cuvs.

Comment thread cpp/src/neighbors/detail/cagra/cagra_build.cuh Outdated
Comment thread cpp/src/neighbors/detail/cagra/cagra_build.cuh Outdated
{
auto stream = raft::resource::get_cuda_stream(res);

auto dev_knn_graph = raft::make_device_matrix<IdxT, int64_t>(res, curr_query_size, curr_topk);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How big the curr_query_size here - is it bounded?
Consider using raft::resource::get_workspace_resource_ref(res) or raft::resource::get_large_workspace_resource_ref(res) depending on the answer to correctly track this as a temporary allocation.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's bounded by the dataset size, so i will use get_large_workspace_resource_ref as you suggested

Comment on lines +2154 to +2155
dev_output_graph =
raft::make_device_matrix<IdxT, int64_t>(res, curr_query_size, next_graph_degree);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same question about being bounded and using the workspace resource here.
Also, do you allocate it multiple times (i.e. by calling it multiple times)?

  • if no: maybe use the return semantics here for clarity (instead of passing the output variable by reference)?
  • if yes: it would make sense to first clear the variable, and then assign a new one - to avoid two large arrays being allocated at the same time (increasing the memory footprint of the whole thing). Perhaps, doing this outside of the search_and_optimize function and changing the function to return the new graph would make sense in this case too.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same N-limited boundedness. Will change to return, and release the old graph before allocating the new one to reduce peak memory use

* @tparam IdxT The type of the index
*/
template <typename T, typename IdxT>
class batched_device_view_from_host {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like a merge/diff view artifact. I think @mfoerste4 has added this new class earlier in his refactoring and I asked exactly the same question. There was seemingly a good reason for it, but I forgot it :) @mfoerste4 could you please remind?

@irina-resh-nvda
irina-resh-nvda requested review from a team as code owners August 10, 2026 13:01
…emporaries in iterative build (~2.7x faster build)
@aamijar

aamijar commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

It looks like a lot of files were edited to change the copyright header? I think we should revert those.
Update I fixed it in these commits:
355d240
8cd4191

This commit 6ad9234 reverted minor diff in a test file.

We should look through the merge conflicts due to Datasets API and resolve them.
Fyi a few cagra-q fixes are being worked on here #2413

This reverts commit d9c6bfd.
@copy-pr-bot

copy-pr-bot Bot commented Aug 10, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature request New feature or request non-breaking Introduces a non-breaking change

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

7 participants