-
Notifications
You must be signed in to change notification settings - Fork 226
Bug fix: barrier determinism #1856
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -115,14 +115,15 @@ void my_cusparsespmv_preprocess(cusparseHandle_t handle, | |
| } | ||
| #endif | ||
|
|
||
| static cusparseSpMVAlg_t get_spmv_alg([[maybe_unused]] int num_rows) | ||
| static cusparseSpMVAlg_t get_spmv_alg(int num_rows, int num_cols) | ||
| { | ||
| // ALG2 has a bug in cuSPARSE < 13.0 where beta=1 accumulate mode ignores existing y values. | ||
| // ALG1 uses a deterministic row-split algorithm, while ALG2 uses a merge-based | ||
| // algorithm that may be faster but can use atomics. ALG1 is safe for reproducibility. | ||
| // ALG2 provides deterministic (bit-wise) results but older ALG2 has a bug with matrices that have | ||
| // a single row or column, so fall back to ALG1 for those on cuSPARSE < 13.0.0. | ||
| constexpr int cusparse_version = | ||
| CUSPARSE_VER_MAJOR * 1000 + CUSPARSE_VER_MINOR * 100 + CUSPARSE_VER_PATCH; | ||
| if (cusparse_version < 13000) { return CUSPARSE_SPMV_CSR_ALG1; } | ||
| if ((num_rows <= 1 || num_cols <= 1) && cusparse_version < 13000) { | ||
| return CUSPARSE_SPMV_CSR_ALG1; | ||
|
Comment on lines
+124
to
+125
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift Add unit coverage for algorithm selection. Add gtest coverage for zero, one, and larger matrix dimensions. Cover pre-13.0 and 13.0-or-newer selection. Exercise both normal and transpose SpMV paths. As per coding guidelines: 🤖 Prompt for AI AgentsSource: Coding guidelines 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift 🔎 Supported by static analysis🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- changed file excerpt ---'
sed -n '1,230p' cpp/src/barrier/cusparse_view.cu
printf '%s\n' '--- relevant guide ---'
rg -n -A80 -B10 'CUDA / GPU|unit test|cuSPARSE|cusparse' .github/.coderabbit_review_guide.md
printf '%s\n' '--- version and runtime bindings ---'
rg -n -A8 -B8 'CUSPARSE_VER_|cusparseGetVersion|cusparse_version|get_spmv_alg|CUSPARSE_SPMV_CSR_ALG' cpp/src cpp/include
printf '%s\n' '--- focused diff ---'
git diff --unified=25 -- cpp/src/barrier/cusparse_view.cuRepository: NVIDIA/cuopt Length of output: 50368 🤖 get_repo_knowledge executed:
Length of output: 47780 🏁 Script executed: #!/bin/bash
set -eu
sed -n '1,230p' cpp/src/barrier/cusparse_view.cu
printf '\n--- guide ---\n'
rg -n -A80 -B10 'CUDA / GPU|unit test|cuSPARSE|cusparse' .github/.coderabbit_review_guide.md
printf '\n--- bindings ---\n'
rg -n -A8 -B8 'CUSPARSE_VER_|cusparseGetVersion|cusparse_version|get_spmv_alg|CUSPARSE_SPMV_CSR_ALG' cpp/src cpp/include
printf '\n--- diff ---\n'
git diff --unified=25 -- cpp/src/barrier/cusparse_view.cuRepository: NVIDIA/cuopt Length of output: 50368 🌐 Web query:
💡 Result: The file cpp/src/barrier/cusparse_view.cu is part of the NVIDIA cuOpt source code, which utilizes the cuSPARSE library for sparse matrix operations [1][2]. In this context, CUSPARSE_VER_MAJOR and related macros (such as CUSPARSE_VER_MINOR, CUSPARSE_VER_PATCH, and CUSPARSE_VERSION) are standard constants provided by the cuSPARSE library headers [3][4]. These macros are used within cuOpt source files like cusparse_view.cu to manage compatibility, conditionally compile code, or enable specific features based on the version of the cuSPARSE library available at build time [5][6][7]. For example, cuOpt uses these versions to: 1. Guard or enable experimental features, such as SpMVOp APIs, by verifying the cuSPARSE runtime version [7][8]. 2. Manage conditional logic for descriptor or buffer creation, especially when handling mixed-precision or specialized sparse matrix operations across different library versions [6][7]. The constant CUSPARSE_VER_MAJOR represents the major version number of the installed cuSPARSE library [9][10]. Developers typically use it alongside other version constants to ensure the application compiles against a compatible cuSPARSE runtime [5][11]. While cusparse_view.cu is a specific implementation file in cuOpt [1], it relies on these standard cuSPARSE definitions to interact with the library's runtime interface [9][7]. Citations:
Base
🤖 Prompt for AI Agents
Comment on lines
+118
to
+125
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift 🔎 Supported by static analysis🤖 get_repo_knowledge executed:
Length of output: 26597 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- changed files ---'
git diff --stat
printf '%s\n' '--- relevant diff ---'
git diff -- cpp/src/barrier/cusparse_view.cu cpp/src/barrier/cusparse_view.hpp
printf '%s\n' '--- guide references ---'
rg -n -A35 -B5 'CUDA / GPU|cusparse|determin|SpMV' .github/.coderabbit_review_guide.md
printf '%s\n' '--- declarations and call sites ---'
rg -n -A8 -B8 'get_spmv_alg|cusparse_view_t::cusparse_view_t|cusparse_view_t\(' cpp/src/barrier/cusparse_view.cu cpp/src/barrier/cusparse_view.hppRepository: NVIDIA/cuopt Length of output: 15121 🏁 Script executed: #!/bin/bash
set -eu
git diff --stat
git diff -- cpp/src/barrier/cusparse_view.cu cpp/src/barrier/cusparse_view.hpp
sed -n '1,220p' cpp/src/barrier/cusparse_view.cu
sed -n '1,100p' cpp/src/barrier/cusparse_view.hppRepository: NVIDIA/cuopt Length of output: 12655 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- cusparse_view constructor call sites ---'
rg -n -A6 -B6 'cusparse_view_t<|make_unique<.*cusparse_view|make_shared<.*cusparse_view|cusparse_view_t[ (]' cpp --glob '*.{cu,cpp,hpp,cuh}'
printf '%s\n' '--- deterministic and algorithm-selection references ---'
rg -n -A8 -B8 'deterministic|determinism|CUSPARSE_SPMV_CSR_ALG[12]|get_spmv_alg' cpp/src cpp/tests --glob '*.{cu,cpp,hpp,cuh}'
printf '%s\n' '--- related cuSPARSE view implementation ---'
rg -n -A12 -B8 'class cusparse_view_t|cusparse_view_t\(' cpp --glob '*cusparse_view*'
printf '%s\n' '--- repository state and parent availability ---'
git status --short
git rev-parse --show-toplevel
git rev-parse HEAD
git rev-parse HEAD^Repository: NVIDIA/cuopt Length of output: 50369 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- commit diff for the reviewed files ---'
git diff --unified=25 HEAD^ HEAD -- cpp/src/barrier/cusparse_view.cu cpp/src/barrier/cusparse_view.hpp
printf '%s\n' '--- barrier view references ---'
rg -n 'cusparse_view_t' cpp/src cpp/include cpp/tests --glob '*.{cu,cpp,hpp,cuh}' | head -n 120
printf '%s\n' '--- deterministic fields and barrier construction ---'
rg -n -A8 -B8 'barrier::cusparse_view_t|cusparse_view_t<.*>\s+[A-Za-z_]|deterministic.*cusparse|cusparse.*determin' cpp/src --glob '*.{cu,cpp,hpp,cuh}' | head -n 240Repository: NVIDIA/cuopt Length of output: 34870 Restore deterministic-mode state in the SpMV selector. On cuSPARSE versions below 13, the previous selector used 📍 Affects 2 files
🤖 Prompt for AI Agents |
||
| } | ||
| return CUSPARSE_SPMV_CSR_ALG2; | ||
| } | ||
|
|
||
|
|
@@ -131,9 +132,10 @@ void cusparse_view_t<i_t, f_t>::init_spmv_buffer_and_preprocess(cusparseSpMatDes | |
| cusparseDnVecDescr_t x, | ||
| cusparseDnVecDescr_t y, | ||
| rmm::device_buffer& buffer, | ||
| i_t rows) | ||
| i_t rows, | ||
| i_t cols) | ||
| { | ||
| const auto spmv_alg = get_spmv_alg(rows); | ||
| const auto spmv_alg = get_spmv_alg(rows, cols); | ||
| size_t buffer_size_spmv = 0; | ||
| RAFT_CUSPARSE_TRY( | ||
| raft::sparse::detail::cusparsespmv_buffersize(handle_ptr_->get_cusparse_handle(), | ||
|
|
@@ -186,7 +188,7 @@ cusparse_view_t<i_t, f_t>::cusparse_view_t(raft::handle_t const* handle_ptr, | |
| csr_matrix_t<i_t, f_t> A_csr(A.m, A.n, 1); | ||
| A.to_compressed_row(A_csr); | ||
| rows_ = A_csr.m; | ||
| i_t cols = A_csr.n; | ||
| cols_ = A_csr.n; | ||
| i_t nnz = A_csr.x.size(); | ||
| const std::vector<i_t>& offsets = A_csr.row_start; | ||
| const std::vector<i_t>& indices = A_csr.j; | ||
|
|
@@ -202,7 +204,7 @@ cusparse_view_t<i_t, f_t>::cusparse_view_t(raft::handle_t const* handle_ptr, | |
|
|
||
| cusparseCreateCsr(&A_, | ||
| rows_, | ||
| cols, | ||
| cols_, | ||
| nnz, | ||
| A_offsets_.data(), | ||
| A_indices_.data(), | ||
|
|
@@ -213,7 +215,7 @@ cusparse_view_t<i_t, f_t>::cusparse_view_t(raft::handle_t const* handle_ptr, | |
| CUDA_R_64F); | ||
|
|
||
| cusparseCreateCsr(&A_T_, | ||
| cols, | ||
| cols_, | ||
| rows_, | ||
| nnz, | ||
| A_T_offsets_.data(), | ||
|
|
@@ -227,13 +229,13 @@ cusparse_view_t<i_t, f_t>::cusparse_view_t(raft::handle_t const* handle_ptr, | |
| // Tmp just to init the buffer size and preprocess | ||
| cusparseDnVecDescr_t x; | ||
| cusparseDnVecDescr_t y; | ||
| rmm::device_uvector<f_t> d_x(cols, handle_ptr_->get_stream()); | ||
| rmm::device_uvector<f_t> d_x(cols_, handle_ptr_->get_stream()); | ||
| rmm::device_uvector<f_t> d_y(rows_, handle_ptr_->get_stream()); | ||
| RAFT_CUSPARSE_TRY(raft::sparse::detail::cusparsecreatednvec(&x, d_x.size(), d_x.data())); | ||
| RAFT_CUSPARSE_TRY(raft::sparse::detail::cusparsecreatednvec(&y, d_y.size(), d_y.data())); | ||
|
|
||
| init_spmv_buffer_and_preprocess(A_, x, y, spmv_buffer_, rows_); | ||
| init_spmv_buffer_and_preprocess(A_T_, y, x, spmv_buffer_transpose_, A_T_offsets_.size() - 1); | ||
| init_spmv_buffer_and_preprocess(A_, x, y, spmv_buffer_, rows_, cols_); | ||
| init_spmv_buffer_and_preprocess(A_T_, y, x, spmv_buffer_transpose_, cols_, rows_); | ||
|
|
||
| RAFT_CUSPARSE_TRY(cusparseDestroyDnVec(x)); | ||
| RAFT_CUSPARSE_TRY(cusparseDestroyDnVec(y)); | ||
|
|
@@ -302,7 +304,7 @@ void cusparse_view_t<i_t, f_t>::spmv(f_t alpha, | |
| x, | ||
| d_beta->data(), | ||
| y, | ||
| get_spmv_alg(rows_), | ||
| get_spmv_alg(rows_, cols_), | ||
| (f_t*)spmv_buffer_.data(), | ||
| handle_ptr_->get_stream()); | ||
| } | ||
|
|
@@ -357,7 +359,7 @@ void cusparse_view_t<i_t, f_t>::transpose_spmv(f_t alpha, | |
| x, | ||
| d_beta->data(), | ||
| y, | ||
| get_spmv_alg(A_T_offsets_.size() - 1), | ||
| get_spmv_alg(cols_, rows_), | ||
| (f_t*)spmv_buffer_transpose_.data(), | ||
| handle_ptr_->get_stream()); | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
🔎 Supported by static analysis
🤖 get_repo_knowledge executed:
get_repo_knowledge NVIDIA/cuopt /tmp/coderabbit-repo-knowledge/nvidia-cuopt-f5e5051e/learnings /tmp/coderabbit-repo-knowledge/nvidia-cuopt-f5e5051e/conventionsLength of output: 36773
🏁 Script executed:
Repository: NVIDIA/cuopt
Length of output: 50369
🏁 Script executed:
Repository: NVIDIA/cuopt
Length of output: 150
🏁 Script executed:
Repository: NVIDIA/cuopt
Length of output: 13284
🏁 Script executed:
Repository: NVIDIA/cuopt
Length of output: 27216
🏁 Script executed:
Repository: NVIDIA/cuopt
Length of output: 33527
Preserve deterministic-mode algorithm selection. The previous
get_spmv_algselectedCUSPARSE_SPMV_CSR_ALG2only whendeterministic_was enabled and otherwise selectedALG1on cuSPARSE versions below 13. The new helper removesdeterministic_, so all non-singleton matrices useALG2regardless of--cudss-deterministic. Pass the mode through and keep the row/column workaround separate.🤖 Prompt for AI Agents