diff --git a/resolve/LinSolverDirectRocSolverRf.cpp b/resolve/LinSolverDirectRocSolverRf.cpp index 694bd244a..e22060ba1 100644 --- a/resolve/LinSolverDirectRocSolverRf.cpp +++ b/resolve/LinSolverDirectRocSolverRf.cpp @@ -41,6 +41,14 @@ namespace ReSolve delete L_csr_; delete U_csr_; + + // setup() creates the combined factor matrix and the rocSOLVER refactorization + // info object; release them here so they are not leaked on teardown. + delete M_; + if (infoM_ != nullptr) + { + rocsolver_destroy_rfinfo(infoM_); + } } /** @@ -71,6 +79,13 @@ namespace ReSolve index_type n = A_->getNumRows(); // set matrix info + // setup() may be called more than once; destroy any previously created + // info object first so it is not leaked. + if (infoM_ != nullptr) + { + rocsolver_destroy_rfinfo(infoM_); + infoM_ = nullptr; + } rocsolver_create_rfinfo(&infoM_, workspace_->getRocblasHandle()); // Combine factors L and U into matrix M_ @@ -335,6 +350,9 @@ namespace ReSolve index_type* U_row = U->getRowData(memory::HOST); index_type* U_col = U->getColData(memory::HOST); index_type M_nnz = (L->getNnz() + U->getNnz() - n); + // combineFactors() is called from setup(), which may run more than once; + // release any matrix from a previous call before allocating a new one. + delete M_; M_ = new matrix::Csr(n, n, M_nnz); M_->allocateMatrixData(memory::HOST); index_type* M_row = M_->getRowData(memory::HOST); diff --git a/resolve/LinSolverDirectRocSparseILU0.cpp b/resolve/LinSolverDirectRocSparseILU0.cpp index 982499bb9..c7c56eceb 100644 --- a/resolve/LinSolverDirectRocSparseILU0.cpp +++ b/resolve/LinSolverDirectRocSparseILU0.cpp @@ -17,6 +17,33 @@ namespace ReSolve { mem_.deleteOnDevice(d_aux1_); mem_.deleteOnDevice(d_ILU_vals_); + + if (buffer_ != nullptr) + { + mem_.deleteOnDevice(buffer_); + buffer_ = nullptr; + } + + if (info_A_ != nullptr) + { + rocsparse_destroy_mat_info(info_A_); + info_A_ = nullptr; + } + if (descr_U_ != nullptr) + { + rocsparse_destroy_mat_descr(descr_U_); + descr_U_ = nullptr; + } + if (descr_L_ != nullptr) + { + rocsparse_destroy_mat_descr(descr_L_); + descr_L_ = nullptr; + } + if (descr_A_ != nullptr) + { + rocsparse_destroy_mat_descr(descr_A_); + descr_A_ = nullptr; + } } int LinSolverDirectRocSparseILU0::setup(matrix::Sparse* A, diff --git a/tests/lsan.supp b/tests/lsan.supp new file mode 100644 index 000000000..966c755ce --- /dev/null +++ b/tests/lsan.supp @@ -0,0 +1,13 @@ +# LeakSanitizer suppressions for ReSolve HIP/ROCm builds. +# +# These leaks originate inside the AMD ROCm runtime libraries (HSA runtime and +# the HIP runtime), not in ReSolve. They are one-time allocations made during +# runtime initialization that live for the entire process lifetime and are +# reclaimed by the OS at exit. They are not fixable from within ReSolve. +# +# See ORNL/ReSolve#388. +leak:libhsa-runtime64.so +leak:libamdhip64.so +leak:librocsparse.so +leak:librocblas.so +leak:librocsolver.so diff --git a/tests/unit/matrix/SparseTests.hpp b/tests/unit/matrix/SparseTests.hpp index 28ed73c4b..fadbe8ea4 100644 --- a/tests/unit/matrix/SparseTests.hpp +++ b/tests/unit/matrix/SparseTests.hpp @@ -240,6 +240,13 @@ namespace ReSolve // Clean up allocated memory delete[] val_data; + // In the device case h_val_data is a scratch host buffer allocated + // above; on host it aliases the matrix-owned data and must not be freed. + if (memspace_ != memory::HOST) + { + delete[] h_val_data; + } + if (A.destroyMatrixData(memspace_) != 0) { std::cout << "Failed to destroy matrix data.\n";