From a02ad188a5bb6a64bbfab8abb869a961390fc8c3 Mon Sep 17 00:00:00 2001 From: Chris Richardson Date: Mon, 11 May 2020 09:34:40 +0100 Subject: [PATCH 01/37] try oneapi mkl... not working [skip ci] --- spmv/Matrix.cpp | 159 ++++-------------------------------------------- spmv/Matrix.h | 8 +-- 2 files changed, 14 insertions(+), 153 deletions(-) diff --git a/spmv/Matrix.cpp b/spmv/Matrix.cpp index 25dce61..51a63e4 100644 --- a/spmv/Matrix.cpp +++ b/spmv/Matrix.cpp @@ -15,9 +15,7 @@ Matrix::Matrix(Eigen::SparseMatrix A, std::shared_ptr row_map) : _matA(A), _col_map(col_map), _row_map(row_map) { -#ifdef EIGEN_USE_MKL_ALL mkl_init(); -#endif } template @@ -29,137 +27,23 @@ Matrix::~Matrix() } //----------------------------------------------------------------------------- -#ifdef EIGEN_USE_MKL_ALL template <> void Matrix::mkl_init() { - sparse_status_t status = mkl_sparse_d_create_csr( - &A_mkl, SPARSE_INDEX_BASE_ZERO, _matA.rows(), _matA.cols(), - _matA.outerIndexPtr(), _matA.outerIndexPtr() + 1, _matA.innerIndexPtr(), - _matA.valuePtr()); - assert(status == SPARSE_STATUS_SUCCESS); - - status = mkl_sparse_optimize(A_mkl); - assert(status == SPARSE_STATUS_SUCCESS); - - if (status != SPARSE_STATUS_SUCCESS) - throw std::runtime_error("Could not create MKL matrix"); - - mat_desc.type = SPARSE_MATRIX_TYPE_GENERAL; - mat_desc.diag = SPARSE_DIAG_NON_UNIT; -} -//---------------------- -template <> -void Matrix>::mkl_init() -{ - sparse_status_t status = mkl_sparse_z_create_csr( - &A_mkl, SPARSE_INDEX_BASE_ZERO, _matA.rows(), _matA.cols(), - _matA.outerIndexPtr(), _matA.outerIndexPtr() + 1, _matA.innerIndexPtr(), - (MKL_Complex16*)_matA.valuePtr()); - assert(status == SPARSE_STATUS_SUCCESS); - - status = mkl_sparse_optimize(A_mkl); - assert(status == SPARSE_STATUS_SUCCESS); - - if (status != SPARSE_STATUS_SUCCESS) - throw std::runtime_error("Could not create MKL matrix"); - - mat_desc.type = SPARSE_MATRIX_TYPE_GENERAL; - mat_desc.diag = SPARSE_DIAG_NON_UNIT; -} -//---------------------- -template <> -void Matrix::mkl_init() -{ - sparse_status_t status = mkl_sparse_s_create_csr( - &A_mkl, SPARSE_INDEX_BASE_ZERO, _matA.rows(), _matA.cols(), - _matA.outerIndexPtr(), _matA.outerIndexPtr() + 1, _matA.innerIndexPtr(), - _matA.valuePtr()); - assert(status == SPARSE_STATUS_SUCCESS); - - status = mkl_sparse_optimize(A_mkl); - assert(status == SPARSE_STATUS_SUCCESS); - - if (status != SPARSE_STATUS_SUCCESS) - throw std::runtime_error("Could not create MKL matrix"); + mkl::sparse::matrixInit(&A_onemkl); - mat_desc.type = SPARSE_MATRIX_TYPE_GENERAL; - mat_desc.diag = SPARSE_DIAG_NON_UNIT; -} -//---------------------- -template <> -void Matrix>::mkl_init() -{ - sparse_status_t status = mkl_sparse_c_create_csr( - &A_mkl, SPARSE_INDEX_BASE_ZERO, _matA.rows(), _matA.cols(), - _matA.outerIndexPtr(), _matA.outerIndexPtr() + 1, _matA.innerIndexPtr(), - (MKL_Complex8*)_matA.valuePtr()); - assert(status == SPARSE_STATUS_SUCCESS); - - status = mkl_sparse_optimize(A_mkl); - assert(status == SPARSE_STATUS_SUCCESS); - - if (status != SPARSE_STATUS_SUCCESS) - throw std::runtime_error("Could not create MKL matrix"); - - mat_desc.type = SPARSE_MATRIX_TYPE_GENERAL; - mat_desc.diag = SPARSE_DIAG_NON_UNIT; -} -//---------------------- -template <> -Eigen::Matrix, Eigen::Dynamic, 1> - Matrix>::operator*( - const Eigen::Matrix, Eigen::Dynamic, 1>& b) const -{ - Eigen::Matrix, Eigen::Dynamic, 1> y(_matA.rows()); - const MKL_Complex16 one({1.0, 0.0}), zero({0.0, 0.0}); - mkl_sparse_z_mv(SPARSE_OPERATION_NON_TRANSPOSE, one, A_mkl, mat_desc, - (MKL_Complex16*)b.data(), zero, (MKL_Complex16*)y.data()); - return y; -} -//---------------------- -template <> -Eigen::Matrix, Eigen::Dynamic, 1> -Matrix>::transpmult( - const Eigen::Matrix, Eigen::Dynamic, 1>& b) const -{ - Eigen::Matrix, Eigen::Dynamic, 1> y(_matA.rows()); - const MKL_Complex16 one({1.0, 0.0}), zero({0.0, 0.0}); - mkl_sparse_z_mv(SPARSE_OPERATION_TRANSPOSE, one, A_mkl, mat_desc, - (MKL_Complex16*)b.data(), zero, (MKL_Complex16*)y.data()); - return y; -} -//---------------------- -template <> -Eigen::Matrix, Eigen::Dynamic, 1> - Matrix>::operator*( - const Eigen::Matrix, Eigen::Dynamic, 1>& b) const -{ - Eigen::Matrix, Eigen::Dynamic, 1> y(_matA.rows()); - const MKL_Complex8 one({1.0, 0.0}), zero({0.0, 0.0}); - mkl_sparse_c_mv(SPARSE_OPERATION_NON_TRANSPOSE, one, A_mkl, mat_desc, - (MKL_Complex8*)b.data(), zero, (MKL_Complex8*)y.data()); - return y; -} -//---------------------- -template <> -Eigen::Matrix, Eigen::Dynamic, 1> -Matrix>::transpmult( - const Eigen::Matrix, Eigen::Dynamic, 1>& b) const -{ - Eigen::Matrix, Eigen::Dynamic, 1> y(_matA.rows()); - const MKL_Complex8 one({1.0, 0.0}), zero({0.0, 0.0}); - mkl_sparse_c_mv(SPARSE_OPERATION_TRANSPOSE, one, A_mkl, mat_desc, - (MKL_Complex8*)b.data(), zero, (MKL_Complex8*)y.data()); - return y; + mkl::sparse::setCSRstructure(A_onemkl, _matA.rows(), _matA.cols(), + mkl::index_base::zero, _matA.outerIndexPtr(), + _matA.innerIndexPtr(), _matA.valuePtr()); } //---------------------- template <> Eigen::VectorXd Matrix::operator*(const Eigen::VectorXd& b) const { Eigen::VectorXd y(_matA.rows()); - mkl_sparse_d_mv(SPARSE_OPERATION_NON_TRANSPOSE, 1.0, A_mkl, mat_desc, - b.data(), 0.0, y.data()); + cl::sycl::queue q; + mkl::sparse::gemv(q, mkl::transpose::nontrans, 1.0, A_onemkl, + const_cast(b.data()), 0.0, y.data()); return y; } @@ -168,36 +52,15 @@ template <> Eigen::VectorXd Matrix::transpmult(const Eigen::VectorXd& b) const { Eigen::VectorXd y(_matA.cols()); - mkl_sparse_d_mv(SPARSE_OPERATION_TRANSPOSE, 1.0, A_mkl, mat_desc, b.data(), - 0.0, y.data()); - - return y; -} -//---------------------- -template <> -Eigen::VectorXf Matrix::operator*(const Eigen::VectorXf& b) const -{ - Eigen::VectorXf y(_matA.rows()); - mkl_sparse_s_mv(SPARSE_OPERATION_NON_TRANSPOSE, 1.0, A_mkl, mat_desc, - b.data(), 0.0, y.data()); + // mkl_sparse_s_mv(SPARSE_OPERATION_TRANSPOSE, 1.0, A_mkl, mat_desc, b.data(), + // 0.0, y.data()); return y; } -//--------------------- -template <> -Eigen::VectorXf Matrix::transpmult(const Eigen::VectorXf& b) const -{ - Eigen::VectorXf y(_matA.cols()); - mkl_sparse_s_mv(SPARSE_OPERATION_TRANSPOSE, 1.0, A_mkl, mat_desc, b.data(), - 0.0, y.data()); - - return y; -} -#endif //----------------------------------------------------------------------------- template -Eigen::Matrix Matrix:: -operator*(const Eigen::Matrix& b) const +Eigen::Matrix +Matrix::operator*(const Eigen::Matrix& b) const { return _matA * b; } diff --git a/spmv/Matrix.h b/spmv/Matrix.h index bccdf39..f7e3f66 100644 --- a/spmv/Matrix.h +++ b/spmv/Matrix.h @@ -5,6 +5,8 @@ #include #include +#include + #ifdef EIGEN_USE_MKL_ALL #include #endif @@ -61,12 +63,8 @@ class Matrix std::vector col_ghosts); private: -// MKL pointers to Eigen data -#ifdef EIGEN_USE_MKL_ALL - sparse_matrix_t A_mkl; - struct matrix_descr mat_desc; + mkl::sparse::matrixHandle_t A_onemkl; void mkl_init(); -#endif // Storage for Matrix Eigen::SparseMatrix _matA; From dec43eb41b4c32baa2b19bb0717d728237fa8ab3 Mon Sep 17 00:00:00 2001 From: Chris Richardson Date: Tue, 9 Jun 2020 14:35:14 +0100 Subject: [PATCH 02/37] Maybe even works! --- spmv/CMakeLists.txt | 3 ++- spmv/Matrix.cpp | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/spmv/CMakeLists.txt b/spmv/CMakeLists.txt index f62aeb1..be7a411 100644 --- a/spmv/CMakeLists.txt +++ b/spmv/CMakeLists.txt @@ -4,7 +4,7 @@ add_library(${PROJECT_NAME} SHARED L2GMap.cpp Matrix.cpp read_petsc.cpp cg.cpp) target_include_directories (${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) target_include_directories (${PROJECT_NAME} INTERFACE $) # Target libraries -target_link_libraries(${PROJECT_NAME} PUBLIC ${MPI_LIBRARIES}) +target_link_libraries(${PROJECT_NAME} PUBLIC ${MPI_LIBRARIES}) set_target_properties(${PROJECT_NAME} PROPERTIES PUBLIC_HEADER "spmv.h") set_target_properties(${PROJECT_NAME} PROPERTIES PRIVATE_HEADER "L2GMap.h;Matrix.h;read_petsc.h;cg.h") @@ -14,6 +14,7 @@ if(BLAS_FOUND) target_link_libraries(${PROJECT_NAME} PUBLIC ${BLAS_LIBRARIES}) endif() +target_link_libraries(${PROJECT_NAME} PUBLIC "mkl_sycl;mkl_intel_ilp64;mkl_tbb_thread;mkl_core;sycl;OpenCL;tbb;pthread;dl;m") install(TARGETS ${PROJECT_NAME} EXPORT libspmv diff --git a/spmv/Matrix.cpp b/spmv/Matrix.cpp index 1b1e3c0..344ab4c 100644 --- a/spmv/Matrix.cpp +++ b/spmv/Matrix.cpp @@ -301,7 +301,7 @@ Matrix Matrix::create_matrix( } // Explicit instantiation -template class spmv::Matrix; +// template class spmv::Matrix; template class spmv::Matrix; -template class spmv::Matrix>; -template class spmv::Matrix>; +// template class spmv::Matrix>; +// template class spmv::Matrix>; From 4dfecc99edce7aea819ed73be8f7633f69a7856f Mon Sep 17 00:00:00 2001 From: Chris Richardson Date: Tue, 9 Jun 2020 15:27:32 +0100 Subject: [PATCH 03/37] Fiddling around --- CMakeLists.txt | 12 ++---------- spmv/CMakeLists.txt | 5 ----- spmv/Matrix.cpp | 15 ++++++++------- spmv/Matrix.h | 5 +---- 4 files changed, 11 insertions(+), 26 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a4cde01..7d5fa3d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,18 +18,10 @@ set(CMAKE_SKIP_RPATH FALSE) set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") find_package(MPI REQUIRED) - -set(BLA_VENDOR Intel10_64lp) -find_package(BLAS) -if(BLAS_FOUND) - include_directories("/usr/include/mkl") -endif() - -find_package(Eigen3 REQUIRED) -include_directories(${EIGEN3_INCLUDE_DIR} ${MPI_INCLUDE_PATH}) +include_directories(${MPI_INCLUDE_PATH}) # Not sure why need to set -O3 and -DNDEBUG as should be set by Release build type -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=all -g -O3 -DNDEBUG -DEIGEN_MAX_ALIGN_BYTES=32") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O3 -DNDEBUG -fsycl -DMKL_ILP64") add_subdirectory(spmv) include_directories (${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/spmv/CMakeLists.txt b/spmv/CMakeLists.txt index be7a411..eb35497 100644 --- a/spmv/CMakeLists.txt +++ b/spmv/CMakeLists.txt @@ -9,11 +9,6 @@ target_link_libraries(${PROJECT_NAME} PUBLIC ${MPI_LIBRARIES}) set_target_properties(${PROJECT_NAME} PROPERTIES PUBLIC_HEADER "spmv.h") set_target_properties(${PROJECT_NAME} PROPERTIES PRIVATE_HEADER "L2GMap.h;Matrix.h;read_petsc.h;cg.h") -if(BLAS_FOUND) - target_compile_definitions(${PROJECT_NAME} PUBLIC EIGEN_USE_MKL_ALL) - target_link_libraries(${PROJECT_NAME} PUBLIC ${BLAS_LIBRARIES}) -endif() - target_link_libraries(${PROJECT_NAME} PUBLIC "mkl_sycl;mkl_intel_ilp64;mkl_tbb_thread;mkl_core;sycl;OpenCL;tbb;pthread;dl;m") install(TARGETS ${PROJECT_NAME} diff --git a/spmv/Matrix.cpp b/spmv/Matrix.cpp index 344ab4c..0b9d02f 100644 --- a/spmv/Matrix.cpp +++ b/spmv/Matrix.cpp @@ -16,6 +16,8 @@ Matrix::Matrix(Eigen::SparseMatrix A, std::shared_ptr row_map) : _matA(A), _col_map(col_map), _row_map(row_map) { + sycl::default_selector device_selector; + _q = sycl::queue(device_selector); mkl_init(); } @@ -42,10 +44,9 @@ template <> Eigen::VectorXd Matrix::operator*(const Eigen::VectorXd& b) const { Eigen::VectorXd y(_matA.rows()); - cl::sycl::queue q; - mkl::sparse::gemv(q, mkl::transpose::nontrans, 1.0, A_onemkl, - const_cast(b.data()), 0.0, y.data()); - + mkl::sparse::gemv(_q, mkl::transpose::nontrans, 1.0, A_onemkl, + const_cast(b.data()), 0.0, y.data()); + return y; } //--------------------- @@ -53,9 +54,9 @@ template <> Eigen::VectorXd Matrix::transpmult(const Eigen::VectorXd& b) const { Eigen::VectorXd y(_matA.cols()); - // mkl_sparse_s_mv(SPARSE_OPERATION_TRANSPOSE, 1.0, A_mkl, mat_desc, b.data(), - // 0.0, y.data()); - + cl::sycl::queue q; + mkl::sparse::gemv(q, mkl::transpose::trans, 1.0, A_onemkl, + const_cast(b.data()), 0.0, y.data()); return y; } //----------------------------------------------------------------------------- diff --git a/spmv/Matrix.h b/spmv/Matrix.h index f49b44e..6d3c634 100644 --- a/spmv/Matrix.h +++ b/spmv/Matrix.h @@ -8,10 +8,6 @@ #include -#ifdef EIGEN_USE_MKL_ALL -#include -#endif - #include #pragma once @@ -67,6 +63,7 @@ class Matrix std::vector col_ghosts); private: + mutable cl::sycl::queue _q; mkl::sparse::matrixHandle_t A_onemkl; void mkl_init(); From 28e9240c351f03ec8e67dce034a7c329d1e94a82 Mon Sep 17 00:00:00 2001 From: Chris Richardson Date: Wed, 10 Jun 2020 11:55:20 +0100 Subject: [PATCH 04/37] Add debug output --- spmv/Matrix.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/spmv/Matrix.cpp b/spmv/Matrix.cpp index 0b9d02f..6cad39e 100644 --- a/spmv/Matrix.cpp +++ b/spmv/Matrix.cpp @@ -18,17 +18,16 @@ Matrix::Matrix(Eigen::SparseMatrix A, { sycl::default_selector device_selector; _q = sycl::queue(device_selector); + std::cout << "Running on " + << _q.get_device().get_info() << "\n"; + mkl_init(); } template Matrix::~Matrix() { -#ifdef EIGEN_USE_MKL_ALL - mkl_sparse_destroy(A_mkl); -#endif } - //----------------------------------------------------------------------------- template <> void Matrix::mkl_init() From 153bd56a72ffa82ce56c0925f511ead85ab49d7a Mon Sep 17 00:00:00 2001 From: Chris Richardson Date: Wed, 10 Jun 2020 14:16:51 +0100 Subject: [PATCH 05/37] Update to latest onemkl --- spmv/Matrix.cpp | 5 +++-- spmv/Matrix.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/spmv/Matrix.cpp b/spmv/Matrix.cpp index 6cad39e..99af6ce 100644 --- a/spmv/Matrix.cpp +++ b/spmv/Matrix.cpp @@ -27,14 +27,15 @@ Matrix::Matrix(Eigen::SparseMatrix A, template Matrix::~Matrix() { + mkl::sparse::release_matrix_handle(&A_onemkl); } //----------------------------------------------------------------------------- template <> void Matrix::mkl_init() { - mkl::sparse::matrixInit(&A_onemkl); + mkl::sparse::init_matrix_handle(&A_onemkl); - mkl::sparse::setCSRstructure(A_onemkl, _matA.rows(), _matA.cols(), + mkl::sparse::set_csr_data(A_onemkl, _matA.rows(), _matA.cols(), mkl::index_base::zero, _matA.outerIndexPtr(), _matA.innerIndexPtr(), _matA.valuePtr()); } diff --git a/spmv/Matrix.h b/spmv/Matrix.h index 6d3c634..3311e9c 100644 --- a/spmv/Matrix.h +++ b/spmv/Matrix.h @@ -64,7 +64,7 @@ class Matrix private: mutable cl::sycl::queue _q; - mkl::sparse::matrixHandle_t A_onemkl; + mkl::sparse::matrix_handle_t A_onemkl; void mkl_init(); // Storage for Matrix From e42fb6b4b97d525b378cc2a136f7de6815bd9d2f Mon Sep 17 00:00:00 2001 From: igorbaratta Date: Fri, 23 Oct 2020 23:59:56 -0300 Subject: [PATCH 06/37] start adding support to sycl --- CMakeLists.txt | 6 +- spmv/CMakeLists.txt | 2 +- spmv/L2GMap.cpp | 6 +- spmv/L2GMap.h | 5 +- spmv/Matrix.cpp | 560 ++++++++++++++++++++++---------------------- spmv/Matrix.h | 69 +++--- spmv/Vector.h | 54 +++++ spmv/cg.cpp | 166 ++++++------- spmv/cg.h | 8 +- spmv/mpi_type.h | 1 + spmv/read_petsc.cpp | 522 ++++++++++++++++++++--------------------- spmv/read_petsc.h | 5 +- spmv/spmv.h | 4 +- 13 files changed, 731 insertions(+), 677 deletions(-) create mode 100644 spmv/Vector.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d5fa3d..1ea12e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ -# Require CMake 3.5 -cmake_minimum_required(VERSION 3.5) +# Require CMake 3.14 +cmake_minimum_required(VERSION 3.14) # Choose Release or Debug set(CMAKE_BUILD_TYPE Release) @@ -25,4 +25,4 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O3 -DNDEBUG -fsycl -DMKL_ILP64") add_subdirectory(spmv) include_directories (${CMAKE_CURRENT_SOURCE_DIR}) -add_subdirectory(demos) +# add_subdirectory(demos) diff --git a/spmv/CMakeLists.txt b/spmv/CMakeLists.txt index eb35497..349f167 100644 --- a/spmv/CMakeLists.txt +++ b/spmv/CMakeLists.txt @@ -7,7 +7,7 @@ target_include_directories (${PROJECT_NAME} INTERFACE $ +#include #include #include #include @@ -185,10 +186,7 @@ std::int32_t L2GMap::local_size() const return (_ranges[_mpi_rank + 1] - _ranges[_mpi_rank]); } //----------------------------------------------------------------------------- -std::int32_t L2GMap::num_ghosts() const -{ - return _ghosts.size(); -} +std::int32_t L2GMap::num_ghosts() const { return _ghosts.size(); } //----------------------------------------------------------------------------- std::int64_t L2GMap::global_size() const { return _ranges.back(); } //----------------------------------------------------------------------------- diff --git a/spmv/L2GMap.h b/spmv/L2GMap.h index c4ea45c..68969cd 100644 --- a/spmv/L2GMap.h +++ b/spmv/L2GMap.h @@ -1,8 +1,7 @@ // Copyright (C) 2020 Chris Richardson (chris@bpi.cam.ac.uk) // SPDX-License-Identifier: MIT -#include -#include +#include #include #include @@ -74,6 +73,8 @@ class L2GMap /// Access the ghost indices const std::vector& ghosts() const { return _ghosts; } + MPI_Comm comm() { return _neighbour_comm; } + private: // Ownership ranges for all processes on global comm std::vector _ranges; diff --git a/spmv/Matrix.cpp b/spmv/Matrix.cpp index 99af6ce..09a7002 100644 --- a/spmv/Matrix.cpp +++ b/spmv/Matrix.cpp @@ -10,12 +10,18 @@ using namespace spmv; -template -Matrix::Matrix(Eigen::SparseMatrix A, - std::shared_ptr col_map, - std::shared_ptr row_map) - : _matA(A), _col_map(col_map), _row_map(row_map) +template +Matrix::Matrix( + std::array shape, + std::shared_ptr> data, + std::shared_ptr> indptr, + std::shared_ptr> indices, + std::shared_ptr col_maxp, + std::shared_ptr row_map) + : _data(data), _indptr(indptr), _indices(indices), _shape(shape), + _col_map(col_map), _row_map(row_map) { + sycl::default_selector device_selector; _q = sycl::queue(device_selector); std::cout << "Running on " @@ -24,285 +30,279 @@ Matrix::Matrix(Eigen::SparseMatrix A, mkl_init(); } -template -Matrix::~Matrix() +template +Matrix::~Matrix() { - mkl::sparse::release_matrix_handle(&A_onemkl); + oneapi::mkl::sparse::release_matrix_handle(&A_onemkl); } //----------------------------------------------------------------------------- template <> -void Matrix::mkl_init() +void Matrix::mkl_init() { - mkl::sparse::init_matrix_handle(&A_onemkl); - - mkl::sparse::set_csr_data(A_onemkl, _matA.rows(), _matA.cols(), - mkl::index_base::zero, _matA.outerIndexPtr(), - _matA.innerIndexPtr(), _matA.valuePtr()); + oneapi::mkl::sparse::init_matrix_handle(&A_onemkl); + oneapi::mkl::sparse::set_csr_data(A_onemkl, _shape[0], _shape[1], + oneapi::mkl::index_base::zero, *_indptr, + *_indices, *_data); } //---------------------- -template <> -Eigen::VectorXd Matrix::operator*(const Eigen::VectorXd& b) const -{ - Eigen::VectorXd y(_matA.rows()); - mkl::sparse::gemv(_q, mkl::transpose::nontrans, 1.0, A_onemkl, - const_cast(b.data()), 0.0, y.data()); - - return y; -} -//--------------------- -template <> -Eigen::VectorXd Matrix::transpmult(const Eigen::VectorXd& b) const -{ - Eigen::VectorXd y(_matA.cols()); - cl::sycl::queue q; - mkl::sparse::gemv(q, mkl::transpose::trans, 1.0, A_onemkl, - const_cast(b.data()), 0.0, y.data()); - return y; -} -//----------------------------------------------------------------------------- -template -Eigen::Matrix -Matrix::operator*(const Eigen::Matrix& b) const -{ - return _matA * b; -} -//----------------------------------------------------------------------------- -template -Eigen::Matrix -Matrix::transpmult(const Eigen::Matrix& b) const -{ - return _matA.transpose() * b; -} -//----------------------------------------------------------------------------- -template -Matrix Matrix::create_matrix( - MPI_Comm comm, const Eigen::SparseMatrix mat, - std::int64_t nrows_local, std::int64_t ncols_local, - std::vector row_ghosts, std::vector col_ghosts) -{ - - int mpi_size, mpi_rank; - MPI_Comm_size(comm, &mpi_size); - MPI_Comm_rank(comm, &mpi_rank); - - std::vector row_ranges(mpi_size + 1, 0); - MPI_Allgather(&nrows_local, 1, MPI_INT64_T, row_ranges.data() + 1, 1, - MPI_INT64_T, comm); - for (int i = 0; i < mpi_size; ++i) - row_ranges[i + 1] += row_ranges[i]; - - // FIX: often same as rows? - std::vector col_ranges(mpi_size + 1, 0); - MPI_Allgather(&ncols_local, 1, MPI_INT64_T, col_ranges.data() + 1, 1, - MPI_INT64_T, comm); - for (int i = 0; i < mpi_size; ++i) - col_ranges[i + 1] += col_ranges[i]; - - // Locate owner process for each row - std::vector row_owner(row_ghosts.size()); - for (std::size_t i = 0; i < row_ghosts.size(); ++i) - { - auto it - = std::upper_bound(row_ranges.begin(), row_ranges.end(), row_ghosts[i]); - assert(it != row_ranges.end()); - row_owner[i] = it - row_ranges.begin() - 1; - assert(row_owner[i] != mpi_rank); - } - - // Create a neighbour comm, remap row_owner to neighbour number - std::set neighbour_set(row_owner.begin(), row_owner.end()); - std::vector dests(neighbour_set.begin(), neighbour_set.end()); - std::map proc_to_dest; - for (std::size_t i = 0; i < dests.size(); ++i) - proc_to_dest.insert({dests[i], i}); - for (auto& q : row_owner) - q = proc_to_dest[q]; - - // Get list of sources (may be different from dests, requires AlltoAll to - // find) - std::vector is_dest(mpi_size, 0); - for (int d : dests) - is_dest[d] = 1; - std::vector is_source(mpi_size, 0); - MPI_Alltoall(is_dest.data(), 1, MPI_CHAR, is_source.data(), 1, MPI_CHAR, - comm); - std::vector sources; - for (int i = 0; i < mpi_size; ++i) - if (is_source[i] == 1) - sources.push_back(i); - - MPI_Comm neighbour_comm; - MPI_Dist_graph_create_adjacent( - comm, sources.size(), sources.data(), MPI_UNWEIGHTED, dests.size(), - dests.data(), MPI_UNWEIGHTED, MPI_INFO_NULL, false, &neighbour_comm); - - // send all ghost rows to their owners, using global col idx. - const std::int32_t* Aouter = mat.outerIndexPtr(); - const std::int32_t* Ainner = mat.innerIndexPtr(); - const T* Aval = mat.valuePtr(); - - std::vector> p_to_index(dests.size()); - std::vector> p_to_val(dests.size()); - for (std::size_t i = 0; i < row_ghosts.size(); ++i) - { - const int p = row_owner[i]; - assert(p != -1); - p_to_index[p].push_back(row_ghosts[i]); - p_to_val[p].push_back(0.0); - p_to_index[p].push_back(Aouter[nrows_local + i + 1] - - Aouter[nrows_local + i]); - p_to_val[p].push_back(0.0); - - const std::int64_t local_offset = col_ranges[mpi_rank]; - for (int j = Aouter[nrows_local + i]; j < Aouter[nrows_local + i + 1]; ++j) - { - std::int64_t global_index; - if (Ainner[j] < ncols_local) - global_index = Ainner[j] + local_offset; - else - { - assert(Ainner[j] - ncols_local < (int)col_ghosts.size()); - global_index = col_ghosts[Ainner[j] - ncols_local]; - } - p_to_index[p].push_back(global_index); - p_to_val[p].push_back(Aval[j]); - } - } - - std::vector send_size(dests.size()); - std::vector send_index; - std::vector send_val; - std::vector send_offset = {0}; - for (std::size_t p = 0; p < dests.size(); ++p) - { - send_index.insert(send_index.end(), p_to_index[p].begin(), - p_to_index[p].end()); - send_val.insert(send_val.end(), p_to_val[p].begin(), p_to_val[p].end()); - assert(p_to_val[p].size() == p_to_index[p].size()); - send_size[p] = p_to_index[p].size(); - send_offset.push_back(send_index.size()); - } - - std::vector recv_size(sources.size()); - MPI_Neighbor_alltoall(send_size.data(), 1, MPI_INT, recv_size.data(), 1, - MPI_INT, neighbour_comm); - - std::vector recv_offset = {0}; - for (int r : recv_size) - recv_offset.push_back(recv_offset.back() + r); - - std::vector recv_index(recv_offset.back()); - std::vector recv_val(recv_offset.back()); - - MPI_Neighbor_alltoallv(send_index.data(), send_size.data(), - send_offset.data(), MPI_INT64_T, recv_index.data(), - recv_size.data(), recv_offset.data(), MPI_INT64_T, - neighbour_comm); - - MPI_Neighbor_alltoallv(send_val.data(), send_size.data(), send_offset.data(), - mpi_type(), recv_val.data(), recv_size.data(), - recv_offset.data(), mpi_type(), neighbour_comm); - - // Create new map from global column index to local - std::map col_ghost_map; - for (std::int64_t q : col_ghosts) - col_ghost_map.insert({q, -1}); - - // Add any new ghost columns - int pos = 0; - while (pos < (int)recv_index.size()) - { - // std::int64_t global_row = recv_index[pos]; - ++pos; - int nnz = recv_index[pos]; - ++pos; - for (int k = 0; k < nnz; ++k) - { - const std::int64_t recv_col = recv_index[pos]; - ++pos; - if (recv_col >= col_ranges[mpi_rank + 1] - or recv_col < col_ranges[mpi_rank]) - col_ghost_map.insert({recv_col, -1}); - } - } - - // Unique numbering of ghost cols - int c = ncols_local; - for (auto& q : col_ghost_map) - q.second = c++; - - std::vector> mat_data; - for (int row = 0; row < nrows_local; ++row) - for (int j = Aouter[row]; j < Aouter[row + 1]; ++j) - { - int col = Ainner[j]; - if (col >= ncols_local) - { - // Get remapped ghost column - std::int64_t global_col = col_ghosts[col - ncols_local]; - auto it = col_ghost_map.find(global_col); - assert(it != col_ghost_map.end()); - col = it->second; - assert(col >= ncols_local); - } - - assert(row >= 0 and row < nrows_local); - assert(col >= 0 and col < (int)(ncols_local + col_ghost_map.size())); - mat_data.push_back(Eigen::Triplet(row, col, Aval[j])); - } - - // Add received data - pos = 0; - while (pos < (int)recv_index.size()) - { - std::int64_t global_row = recv_index[pos]; - assert(global_row >= row_ranges[mpi_rank] - and global_row < row_ranges[mpi_rank + 1]); - std::int32_t row = global_row - row_ranges[mpi_rank]; - ++pos; - int nnz = recv_index[pos]; - ++pos; - for (int k = 0; k < nnz; ++k) - { - const std::int64_t global_col = recv_index[pos]; - const T val = recv_val[pos]; - ++pos; - int col; - if (global_col >= col_ranges[mpi_rank + 1] - or global_col < col_ranges[mpi_rank]) - { - auto it = col_ghost_map.find(global_col); - assert(it != col_ghost_map.end()); - col = it->second; - } - else - col = global_col - col_ranges[mpi_rank]; - assert(row >= 0 and row < nrows_local); - assert(col >= 0 and col < (int)(ncols_local + col_ghost_map.size())); - mat_data.push_back(Eigen::Triplet(row, col, val)); - } - } - - // Rebuild sparse matrix - std::vector new_col_ghosts; - for (auto& q : col_ghost_map) - new_col_ghosts.push_back(q.first); - - Eigen::SparseMatrix B( - nrows_local, ncols_local + new_col_ghosts.size()); - B.setFromTriplets(mat_data.begin(), mat_data.end()); - - std::shared_ptr col_map - = std::make_shared(comm, ncols_local, new_col_ghosts); - std::shared_ptr row_map = std::make_shared( - comm, nrows_local, std::vector()); - - spmv::Matrix b(B, col_map, row_map); - return b; -} - -// Explicit instantiation -// template class spmv::Matrix; -template class spmv::Matrix; -// template class spmv::Matrix>; -// template class spmv::Matrix>; +// //--------------------- +// template <> +// Eigen::VectorXd Matrix::transpmult(const Eigen::VectorXd& b) const +// { +// Eigen::VectorXd y(_matA.cols()); +// cl::sycl::queue q; +// mkl::sparse::gemv(q, mkl::transpose::trans, 1.0, A_onemkl, +// const_cast(b.data()), 0.0, y.data()); +// return y; +// } +// //----------------------------------------------------------------------------- +// template +// Eigen::Matrix +// Matrix::operator*(const Eigen::Matrix& b) const +// { +// return _matA * b; +// } +// //----------------------------------------------------------------------------- +// template +// Eigen::Matrix +// Matrix::transpmult(const Eigen::Matrix& b) const +// { +// return _matA.transpose() * b; +// } +// //----------------------------------------------------------------------------- +// template +// Matrix Matrix::create_matrix( +// MPI_Comm comm, const Eigen::SparseMatrix mat, +// std::int64_t nrows_local, std::int64_t ncols_local, +// std::vector row_ghosts, std::vector +// col_ghosts) +// { + +// int mpi_size, mpi_rank; +// MPI_Comm_size(comm, &mpi_size); +// MPI_Comm_rank(comm, &mpi_rank); + +// std::vector row_ranges(mpi_size + 1, 0); +// MPI_Allgather(&nrows_local, 1, MPI_INT64_T, row_ranges.data() + 1, 1, +// MPI_INT64_T, comm); +// for (int i = 0; i < mpi_size; ++i) +// row_ranges[i + 1] += row_ranges[i]; + +// // FIX: often same as rows? +// std::vector col_ranges(mpi_size + 1, 0); +// MPI_Allgather(&ncols_local, 1, MPI_INT64_T, col_ranges.data() + 1, 1, +// MPI_INT64_T, comm); +// for (int i = 0; i < mpi_size; ++i) +// col_ranges[i + 1] += col_ranges[i]; + +// // Locate owner process for each row +// std::vector row_owner(row_ghosts.size()); +// for (std::size_t i = 0; i < row_ghosts.size(); ++i) +// { +// auto it +// = std::upper_bound(row_ranges.begin(), row_ranges.end(), +// row_ghosts[i]); +// assert(it != row_ranges.end()); +// row_owner[i] = it - row_ranges.begin() - 1; +// assert(row_owner[i] != mpi_rank); +// } + +// // Create a neighbour comm, remap row_owner to neighbour number +// std::set neighbour_set(row_owner.begin(), row_owner.end()); +// std::vector dests(neighbour_set.begin(), neighbour_set.end()); +// std::map proc_to_dest; +// for (std::size_t i = 0; i < dests.size(); ++i) +// proc_to_dest.insert({dests[i], i}); +// for (auto& q : row_owner) +// q = proc_to_dest[q]; + +// // Get list of sources (may be different from dests, requires AlltoAll to +// // find) +// std::vector is_dest(mpi_size, 0); +// for (int d : dests) +// is_dest[d] = 1; +// std::vector is_source(mpi_size, 0); +// MPI_Alltoall(is_dest.data(), 1, MPI_CHAR, is_source.data(), 1, MPI_CHAR, +// comm); +// std::vector sources; +// for (int i = 0; i < mpi_size; ++i) +// if (is_source[i] == 1) +// sources.push_back(i); + +// MPI_Comm neighbour_comm; +// MPI_Dist_graph_create_adjacent( +// comm, sources.size(), sources.data(), MPI_UNWEIGHTED, dests.size(), +// dests.data(), MPI_UNWEIGHTED, MPI_INFO_NULL, false, &neighbour_comm); + +// // send all ghost rows to their owners, using global col idx. +// const std::int32_t* Aouter = mat.outerIndexPtr(); +// const std::int32_t* Ainner = mat.innerIndexPtr(); +// const T* Aval = mat.valuePtr(); + +// std::vector> p_to_index(dests.size()); +// std::vector> p_to_val(dests.size()); +// for (std::size_t i = 0; i < row_ghosts.size(); ++i) +// { +// const int p = row_owner[i]; +// assert(p != -1); +// p_to_index[p].push_back(row_ghosts[i]); +// p_to_val[p].push_back(0.0); +// p_to_index[p].push_back(Aouter[nrows_local + i + 1] +// - Aouter[nrows_local + i]); +// p_to_val[p].push_back(0.0); + +// const std::int64_t local_offset = col_ranges[mpi_rank]; +// for (int j = Aouter[nrows_local + i]; j < Aouter[nrows_local + i + 1]; +// ++j) +// { +// std::int64_t global_index; +// if (Ainner[j] < ncols_local) +// global_index = Ainner[j] + local_offset; +// else +// { +// assert(Ainner[j] - ncols_local < (int)col_ghosts.size()); +// global_index = col_ghosts[Ainner[j] - ncols_local]; +// } +// p_to_index[p].push_back(global_index); +// p_to_val[p].push_back(Aval[j]); +// } +// } + +// std::vector send_size(dests.size()); +// std::vector send_index; +// std::vector send_val; +// std::vector send_offset = {0}; +// for (std::size_t p = 0; p < dests.size(); ++p) +// { +// send_index.insert(send_index.end(), p_to_index[p].begin(), +// p_to_index[p].end()); +// send_val.insert(send_val.end(), p_to_val[p].begin(), p_to_val[p].end()); +// assert(p_to_val[p].size() == p_to_index[p].size()); +// send_size[p] = p_to_index[p].size(); +// send_offset.push_back(send_index.size()); +// } + +// std::vector recv_size(sources.size()); +// MPI_Neighbor_alltoall(send_size.data(), 1, MPI_INT, recv_size.data(), 1, +// MPI_INT, neighbour_comm); + +// std::vector recv_offset = {0}; +// for (int r : recv_size) +// recv_offset.push_back(recv_offset.back() + r); + +// std::vector recv_index(recv_offset.back()); +// std::vector recv_val(recv_offset.back()); + +// MPI_Neighbor_alltoallv(send_index.data(), send_size.data(), +// send_offset.data(), MPI_INT64_T, recv_index.data(), +// recv_size.data(), recv_offset.data(), MPI_INT64_T, +// neighbour_comm); + +// MPI_Neighbor_alltoallv(send_val.data(), send_size.data(), +// send_offset.data(), +// mpi_type(), recv_val.data(), recv_size.data(), +// recv_offset.data(), mpi_type(), neighbour_comm); + +// // Create new map from global column index to local +// std::map col_ghost_map; +// for (std::int64_t q : col_ghosts) +// col_ghost_map.insert({q, -1}); + +// // Add any new ghost columns +// int pos = 0; +// while (pos < (int)recv_index.size()) +// { +// // std::int64_t global_row = recv_index[pos]; +// ++pos; +// int nnz = recv_index[pos]; +// ++pos; +// for (int k = 0; k < nnz; ++k) +// { +// const std::int64_t recv_col = recv_index[pos]; +// ++pos; +// if (recv_col >= col_ranges[mpi_rank + 1] +// or recv_col < col_ranges[mpi_rank]) +// col_ghost_map.insert({recv_col, -1}); +// } +// } + +// // Unique numbering of ghost cols +// int c = ncols_local; +// for (auto& q : col_ghost_map) +// q.second = c++; + +// std::vector> mat_data; +// for (int row = 0; row < nrows_local; ++row) +// for (int j = Aouter[row]; j < Aouter[row + 1]; ++j) +// { +// int col = Ainner[j]; +// if (col >= ncols_local) +// { +// // Get remapped ghost column +// std::int64_t global_col = col_ghosts[col - ncols_local]; +// auto it = col_ghost_map.find(global_col); +// assert(it != col_ghost_map.end()); +// col = it->second; +// assert(col >= ncols_local); +// } + +// assert(row >= 0 and row < nrows_local); +// assert(col >= 0 and col < (int)(ncols_local + col_ghost_map.size())); +// mat_data.push_back(Eigen::Triplet(row, col, Aval[j])); +// } + +// // Add received data +// pos = 0; +// while (pos < (int)recv_index.size()) +// { +// std::int64_t global_row = recv_index[pos]; +// assert(global_row >= row_ranges[mpi_rank] +// and global_row < row_ranges[mpi_rank + 1]); +// std::int32_t row = global_row - row_ranges[mpi_rank]; +// ++pos; +// int nnz = recv_index[pos]; +// ++pos; +// for (int k = 0; k < nnz; ++k) +// { +// const std::int64_t global_col = recv_index[pos]; +// const T val = recv_val[pos]; +// ++pos; +// int col; +// if (global_col >= col_ranges[mpi_rank + 1] +// or global_col < col_ranges[mpi_rank]) +// { +// auto it = col_ghost_map.find(global_col); +// assert(it != col_ghost_map.end()); +// col = it->second; +// } +// else +// col = global_col - col_ranges[mpi_rank]; +// assert(row >= 0 and row < nrows_local); +// assert(col >= 0 and col < (int)(ncols_local + col_ghost_map.size())); +// mat_data.push_back(Eigen::Triplet(row, col, val)); +// } +// } + +// // Rebuild sparse matrix +// std::vector new_col_ghosts; +// for (auto& q : col_ghost_map) +// new_col_ghosts.push_back(q.first); + +// Eigen::SparseMatrix B( +// nrows_local, ncols_local + new_col_ghosts.size()); +// B.setFromTriplets(mat_data.begin(), mat_data.end()); + +// std::shared_ptr col_map +// = std::make_shared(comm, ncols_local, new_col_ghosts); +// std::shared_ptr row_map = std::make_shared( +// comm, nrows_local, std::vector()); + +// spmv::Matrix b(B, col_map, row_map); +// return b; +// } + +// // Explicit instantiation +// // template class spmv::Matrix; +// template class spmv::Matrix; +// // template class spmv::Matrix>; +// // template class spmv::Matrix>; diff --git a/spmv/Matrix.h b/spmv/Matrix.h index 3311e9c..1e83c40 100644 --- a/spmv/Matrix.h +++ b/spmv/Matrix.h @@ -1,14 +1,13 @@ -// Copyright (C) 2020 Chris Richardson (chris@bpi.cam.ac.uk) +// Copyright (C) 2020 Chris Richardson, Igor Baratta // SPDX-License-Identifier: MIT -#include -#include +#include #include -#include - #include - #include +#include + +#include "Vector.h" #pragma once @@ -18,14 +17,15 @@ namespace spmv class L2GMap; -template +template class Matrix { /// Matrix with row and column maps. public: - /// This constructor just copies in the data. To build a Matrix from more - /// general data, use `Matrix::create_matrix` instead. - Matrix(Eigen::SparseMatrix A, + Matrix(std::array shape, + std::shared_ptr> data, + std::shared_ptr> indptr, + std::shared_ptr> indices, std::shared_ptr col_map, std::shared_ptr row_map); @@ -33,12 +33,25 @@ class Matrix ~Matrix(); /// MatVec operator for A x - Eigen::Matrix - operator*(const Eigen::Matrix& b) const; + spmv::Vector operator*(spmv::Vector& b) const + { + std::shared_ptr> y( + cl::sycl::range<1>{_shape[0]}); + oneapi::mkl::sparse::gemv(_q, oneapi::mkl::transpose::nontrans, 1.0, + A_onemkl, b.getLocalData(), 0.0, *y); + return spmv::Vector(y, _row_map); + }; /// MatVec operator for A^T x - Eigen::Matrix - transpmult(const Eigen::Matrix& b) const; + spmv::Vector + transpmult(const cl::sycl::buffer& b) const + { + std::shared_ptr> y( + cl::sycl::range<1>{_shape[0]}); + oneapi::mkl::sparse::gemv(_q, oneapi::mkl::transpose::trans, 1.0, A_onemkl, + b.getLocalData(), 0.0, *y); + return spmv::Vector(y, _row_map); + }; /// Row mapping (local-to-global). Usually, there will not be ghost rows. std::shared_ptr row_map() const { return _row_map; } @@ -46,29 +59,17 @@ class Matrix /// Column mapping (local-to-global) std::shared_ptr col_map() const { return _col_map; } - /// Access the underlying local sparse matrix - Eigen::SparseMatrix& mat() { return _matA; } - const Eigen::SparseMatrix& mat() const { return _matA; } - - /// Create an `spmv::Matrix` from an Eigen::SparseMatrix and row and column - /// mappings, such that the resulting matrix has no row ghosts, but only - /// column ghosts. This is achieved by sending ghost rows to their owners, - /// where they are summed into existing rows. The column ghost mapping will - /// also change in this process. - static Matrix - create_matrix(MPI_Comm comm, - const Eigen::SparseMatrix mat, - std::int64_t nrows_local, std::int64_t ncols_local, - std::vector row_ghosts, - std::vector col_ghosts); - private: - mutable cl::sycl::queue _q; - mkl::sparse::matrix_handle_t A_onemkl; void mkl_init(); - // Storage for Matrix - Eigen::SparseMatrix _matA; + mutable cl::sycl::queue _q; + oneapi::mkl::sparse::matrix_handle_t A_onemkl; + + std::shared_ptr> _data; + std::shared_ptr> _indptr; + std::shared_ptr> _indices; + + std::array _shape; // Column and Row maps: usually _row_map will not have ghosts. std::shared_ptr _col_map; diff --git a/spmv/Vector.h b/spmv/Vector.h new file mode 100644 index 0000000..e73a052 --- /dev/null +++ b/spmv/Vector.h @@ -0,0 +1,54 @@ +#include +#include + +#include "L2GMap.h" +#include "mpi_type.h" + +namespace spmv +{ +template +class Vector +{ +public: + Vector(std::shared_ptr> data, + std::shared_ptr map) + : _data(data), _map(map) + { + DeviceSelector device_selector; + _q = sycl::queue(device_selector); + if (_map->local_size() != data->size()) + std::runtime_error("Size mismatch"); + }; + + std::int32_t local_size() const { return _map->local_size(); } + + cl::sycl::buffer& getLocalData() { return *_data; }; + + Vector& operator+=(const Vector& other) + { + oneapi::mkl::blas::axpy(_q, local_size(), 1.0, other.getLocalData(), 1, + *_data, 1); + } + + double dot(spmv::Vector& y) + { + cl::sycl::buffer res{1}; + oneapi::mkl::blas::dot(_q, _map->local_size(), *_data, 1, y.getLocalData(), + 1, res); + auto acc = res.template get_access(); + MPI_Comm comm = _map->comm(); + double local_sum = acc[0]; + double global_sum; + + auto data_type = spmv::mpi_type(); + MPI_Reduce(&local_sum, &global_sum, 1, data_type, MPI_SUM, 0, comm); + return global_sum; + }; + +private: + std::shared_ptr> _data; + std::shared_ptr _map; + mutable cl::sycl::queue _q; +}; +} // namespace spmv \ No newline at end of file diff --git a/spmv/cg.cpp b/spmv/cg.cpp index 4bc3eee..d4b9e21 100644 --- a/spmv/cg.cpp +++ b/spmv/cg.cpp @@ -1,83 +1,83 @@ -// Copyright (C) 2020 Chris Richardson (chris@bpi.cam.ac.uk) and Jeffrey Salmond -// SPDX-License-Identifier: MIT - -#include "cg.h" -#include "L2GMap.h" -#include "Matrix.h" -#include -#include - -//----------------------------------------------------------------------------- -std::tuple -spmv::cg(MPI_Comm comm, const spmv::Matrix& A, - const Eigen::Ref& b, int kmax, double rtol) -{ - int mpi_rank; - MPI_Comm_rank(comm, &mpi_rank); - - std::shared_ptr col_l2g = A.col_map(); - std::shared_ptr row_l2g = A.row_map(); - - // Check the row map is unghosted - if (row_l2g->num_ghosts() > 0) - throw std::runtime_error("spmv::cg - Error: A.row_map() has ghost entries"); - - int M = row_l2g->local_size(); - - if (b.rows() != M) - throw std::runtime_error("spmv::cg - Error: b.rows() != A.rows()"); - - // Residual vector - Eigen::VectorXd r(M); - Eigen::VectorXd y(M); - Eigen::VectorXd x(col_l2g->local_size() + col_l2g->num_ghosts()); - Eigen::VectorXd p(col_l2g->local_size() + col_l2g->num_ghosts()); - p.setZero(); - - // Assign to dense part of sparse vector - x.setZero(); - r = b; // b - A * x0 - p.head(M) = r; - - double rnorm = r.squaredNorm(); - double rnorm0; - MPI_Allreduce(&rnorm, &rnorm0, 1, MPI_DOUBLE, MPI_SUM, comm); - - // Iterations of CG - const double rtol2 = rtol * rtol; - double rnorm_old = rnorm0; - int k = 0; - while (k < kmax) - { - ++k; - - // y = A.p - col_l2g->update(p.data()); - y = A * p; - - // Calculate alpha = r.r/p.y - double pdoty = p.head(M).dot(y); - double pdoty_sum; - MPI_Allreduce(&pdoty, &pdoty_sum, 1, MPI_DOUBLE, MPI_SUM, comm); - double alpha = rnorm_old / pdoty_sum; - - // Update x and r - x.head(M) += alpha * p.head(M); - r -= alpha * y; - - // Update rnorm - rnorm = r.squaredNorm(); - double rnorm_new; - MPI_Allreduce(&rnorm, &rnorm_new, 1, MPI_DOUBLE, MPI_SUM, comm); - double beta = rnorm_new / rnorm_old; - rnorm_old = rnorm_new; - - // Update p - p.head(M) = p.head(M) * beta + r; - - if (rnorm_new / rnorm0 < rtol2) - break; - } - - return std::make_tuple(std::move(x), k); -} +// // Copyright (C) 2020 Chris Richardson (chris@bpi.cam.ac.uk) and Jeffrey Salmond +// // SPDX-License-Identifier: MIT + +// #include "cg.h" +// #include "L2GMap.h" +// #include "Matrix.h" +// #include +// #include + +// //----------------------------------------------------------------------------- +// std::tuple +// spmv::cg(MPI_Comm comm, const spmv::Matrix& A, +// const Eigen::Ref& b, int kmax, double rtol) +// { +// int mpi_rank; +// MPI_Comm_rank(comm, &mpi_rank); + +// std::shared_ptr col_l2g = A.col_map(); +// std::shared_ptr row_l2g = A.row_map(); + +// // Check the row map is unghosted +// if (row_l2g->num_ghosts() > 0) +// throw std::runtime_error("spmv::cg - Error: A.row_map() has ghost entries"); + +// int M = row_l2g->local_size(); + +// if (b.rows() != M) +// throw std::runtime_error("spmv::cg - Error: b.rows() != A.rows()"); + +// // Residual vector +// Eigen::VectorXd r(M); +// Eigen::VectorXd y(M); +// Eigen::VectorXd x(col_l2g->local_size() + col_l2g->num_ghosts()); +// Eigen::VectorXd p(col_l2g->local_size() + col_l2g->num_ghosts()); +// p.setZero(); + +// // Assign to dense part of sparse vector +// x.setZero(); +// r = b; // b - A * x0 +// p.head(M) = r; + +// double rnorm = r.squaredNorm(); +// double rnorm0; +// MPI_Allreduce(&rnorm, &rnorm0, 1, MPI_DOUBLE, MPI_SUM, comm); + +// // Iterations of CG +// const double rtol2 = rtol * rtol; +// double rnorm_old = rnorm0; +// int k = 0; +// while (k < kmax) +// { +// ++k; + +// // y = A.p +// col_l2g->update(p.data()); +// y = A * p; + +// // Calculate alpha = r.r/p.y +// double pdoty = p.head(M).dot(y); +// double pdoty_sum; +// MPI_Allreduce(&pdoty, &pdoty_sum, 1, MPI_DOUBLE, MPI_SUM, comm); +// double alpha = rnorm_old / pdoty_sum; + +// // Update x and r +// x.head(M) += alpha * p.head(M); +// r -= alpha * y; + +// // Update rnorm +// rnorm = r.squaredNorm(); +// double rnorm_new; +// MPI_Allreduce(&rnorm, &rnorm_new, 1, MPI_DOUBLE, MPI_SUM, comm); +// double beta = rnorm_new / rnorm_old; +// rnorm_old = rnorm_new; + +// // Update p +// p.head(M) = p.head(M) * beta + r; + +// if (rnorm_new / rnorm0 < rtol2) +// break; +// } + +// return std::make_tuple(std::move(x), k); +// } diff --git a/spmv/cg.h b/spmv/cg.h index d3b1761..b02601d 100644 --- a/spmv/cg.h +++ b/spmv/cg.h @@ -2,8 +2,6 @@ // SPDX-License-Identifier: MIT #pragma once -#include -#include #include #include @@ -24,8 +22,8 @@ class Matrix; /// /// @return tuple of result **x** and number of iterations /// -std::tuple cg(MPI_Comm comm, const Matrix& A, - const Eigen::Ref& b, - int max_its, double rtol); +std::tuple, int> +cg(MPI_Comm comm, const Matrix& A, + const cl::sycl::buffer& b, int max_its, double rtol); } // namespace spmv diff --git a/spmv/mpi_type.h b/spmv/mpi_type.h index 9a3d6cc..25862bb 100644 --- a/spmv/mpi_type.h +++ b/spmv/mpi_type.h @@ -1,6 +1,7 @@ // Copyright (C) 2020 Chris Richardson (chris@bpi.cam.ac.uk) // SPDX-License-Identifier: MIT +#include #include #pragma once diff --git a/spmv/read_petsc.cpp b/spmv/read_petsc.cpp index f480b26..383390d 100644 --- a/spmv/read_petsc.cpp +++ b/spmv/read_petsc.cpp @@ -1,261 +1,261 @@ -// Copyright (C) 2020 Chris Richardson (chris@bpi.cam.ac.uk) -// SPDX-License-Identifier: MIT - -#include "read_petsc.h" -#include "L2GMap.h" -#include -#include -#include -#include -#include - -// Divide size into N ~equal chunks -std::vector owner_ranges(int size, std::int64_t N) -{ - // Compute number of items per process and remainder - const std::int64_t n = N / size; - const std::int64_t r = N % size; - - // Compute local range - std::vector ranges; - for (int rank = 0; rank < (size + 1); ++rank) - { - if (rank < r) - ranges.push_back(rank * (n + 1)); - else - ranges.push_back(rank * n + r); - } - - return ranges; -} -//----------------------------------------------------------------------------- -spmv::Matrix spmv::read_petsc_binary(MPI_Comm comm, - std::string filename) -{ - Eigen::SparseMatrix A; - - int mpi_rank; - MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); - int mpi_size; - MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); - - std::map col_indices; - std::vector row_ranges, col_ranges; - std::int64_t ncols_local, nrows_local; - - std::ifstream file(filename.c_str(), - std::ios::in | std::ios::binary | std::ios::ate); - if (file.is_open()) - { - // Get first 4 ints from file - std::vector memblock(16); - file.seekg(0, std::ios::beg); - file.read(memblock.data(), 16); - - char* ptr = memblock.data(); - for (int i = 0; i < 4; ++i) - { - std::swap(*ptr, *(ptr + 3)); - std::swap(*(ptr + 1), *(ptr + 2)); - ptr += 4; - } - - std::int32_t* int_data = (std::int32_t*)(memblock.data()); - int id = int_data[0]; - if (id != 1211216) - throw std::runtime_error("Bad signature in PETSc Matrix file"); - - int nrows = int_data[1]; - int ncols = int_data[2]; - int nnz_tot = int_data[3]; - row_ranges = owner_ranges(mpi_size, nrows); - col_ranges = owner_ranges(mpi_size, ncols); - - if (mpi_rank == 0) - std::cout << "Read file: " << filename << ": " << nrows << "x" << ncols - << " = " << nnz_tot << "\n"; - - nrows_local = row_ranges[mpi_rank + 1] - row_ranges[mpi_rank]; - ncols_local = col_ranges[mpi_rank + 1] - col_ranges[mpi_rank]; - - // Reset memory block and read nnz per row for all rows - memblock.resize(nrows * 4); - ptr = memblock.data(); - file.read(memblock.data(), nrows * 4); - std::vector nnz(nrows); - std::int64_t nnz_sum = 0; - for (int i = 0; i < nrows; ++i) - { - std::swap(*ptr, *(ptr + 3)); - std::swap(*(ptr + 1), *(ptr + 2)); - nnz[i] = *((std::int32_t*)ptr); - nnz_sum += nnz[i]; - ptr += 4; - } - assert(nnz_sum == nnz_tot); - - // Get offset and size for data - std::int64_t nnz_offset = 0; - std::int64_t nnz_size = 0; - for (std::int64_t i = 0; i < row_ranges[mpi_rank]; ++i) - nnz_offset += nnz[i]; - for (std::int64_t i = row_ranges[mpi_rank]; i < row_ranges[mpi_rank + 1]; - ++i) - nnz_size += nnz[i]; - - std::streampos value_data_pos - = file.tellg() + (std::streampos)(nnz_tot * 4 + nnz_offset * 8); - - // Read col indices for each row - memblock.resize(nnz_size * 4); - ptr = memblock.data(); - file.seekg(nnz_offset * 4, std::ios::cur); - file.read(memblock.data(), nnz_size * 4); - - std::int32_t c = 0; - for (std::int64_t col = col_ranges[mpi_rank]; - col < col_ranges[mpi_rank + 1]; ++col) - { - col_indices.insert({col, c}); - ++c; - } - - // Map other columns - for (std::int64_t row = row_ranges[mpi_rank]; - row < row_ranges[mpi_rank + 1]; ++row) - { - for (std::int64_t j = 0; j < nnz[row]; ++j) - { - std::swap(*ptr, *(ptr + 3)); - std::swap(*(ptr + 1), *(ptr + 2)); - col_indices.insert({*((std::int32_t*)ptr), -1}); - ptr += 4; - } - } - // Ensure they are labelled in ascending order - for (auto& q : col_indices) - if (q.second == -1) - { - q.second = c; - ++c; - } - - A.resize(nrows_local, col_indices.size()); - - // Read values - std::vector valuedata(nnz_size * 8); - file.seekg(value_data_pos, std::ios::beg); - file.read(valuedata.data(), nnz_size * 8); - file.close(); - - // Pointer to values - char* vptr = valuedata.data(); - ptr = memblock.data(); - for (std::int64_t row = row_ranges[mpi_rank]; - row < row_ranges[mpi_rank + 1]; ++row) - { - for (std::int64_t j = 0; j < nnz[row]; ++j) - { - std::swap(*vptr, *(vptr + 7)); - std::swap(*(vptr + 1), *(vptr + 6)); - std::swap(*(vptr + 2), *(vptr + 5)); - std::swap(*(vptr + 3), *(vptr + 4)); - double val = *((double*)vptr); - vptr += 8; - - // Look up column local index - std::int32_t col = col_indices[*((std::int32_t*)ptr)]; - ptr += 4; - - A.insert(row - row_ranges[mpi_rank], col) = val; - } - } - } - else - throw std::runtime_error("Could not open file"); - - A.makeCompressed(); - - std::vector ghosts(col_indices.size() - ncols_local); - for (auto& q : col_indices) - if (q.first < col_ranges[mpi_rank] or q.first >= col_ranges[mpi_rank + 1]) - ghosts[q.second - ncols_local] = q.first; - - auto col_map = std::make_shared(comm, ncols_local, ghosts); - auto row_map = std::make_shared(comm, nrows_local, - std::vector()); - - return spmv::Matrix(A, col_map, row_map); -} -//----------------------------------------------------------------------------- -Eigen::VectorXd spmv::read_petsc_binary_vector(MPI_Comm comm, - std::string filename) -{ - Eigen::VectorXd vec; - - int mpi_rank; - MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); - int mpi_size; - MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); - - std::ifstream file(filename.c_str(), - std::ios::in | std::ios::binary | std::ios::ate); - if (file.is_open()) - { - // Get first 2 ints from file - std::vector memblock(8); - file.seekg(0, std::ios::beg); - file.read(memblock.data(), 8); - - char* ptr = memblock.data(); - for (int i = 0; i < 2; ++i) - { - std::swap(*ptr, *(ptr + 3)); - std::swap(*(ptr + 1), *(ptr + 2)); - ptr += 4; - } - - std::int32_t* int_data = (std::int32_t*)(memblock.data()); - int id = int_data[0]; - if (id != 1211214) - throw std::runtime_error("Bad signature in PETSc Vector file"); - - int nrows = int_data[1]; - std::vector ranges = owner_ranges(mpi_size, nrows); - - if (mpi_rank == 0) - std::cout << "Read vector file: " << filename << ": " << nrows << "\n"; - - std::int64_t nrows_local = ranges[mpi_rank + 1] - ranges[mpi_rank]; - - vec.resize(nrows_local); - - std::streampos value_data_pos - = file.tellg() + (std::streampos)(ranges[mpi_rank] * 8); - - // Read values - std::vector valuedata(nrows_local * 8); - file.seekg(value_data_pos, std::ios::beg); - file.read(valuedata.data(), nrows_local * 8); - file.close(); - - // Pointer to values - char* vptr = valuedata.data(); - - for (std::int64_t row = ranges[mpi_rank]; row < ranges[mpi_rank + 1]; ++row) - { - std::swap(*vptr, *(vptr + 7)); - std::swap(*(vptr + 1), *(vptr + 6)); - std::swap(*(vptr + 2), *(vptr + 5)); - std::swap(*(vptr + 3), *(vptr + 4)); - double val = *((double*)vptr); - vptr += 8; - vec[row - ranges[mpi_rank]] = val; - } - } - else - throw std::runtime_error("Could not open file"); - - return vec; -} -//----------------------------------------------------------------------------- +// // Copyright (C) 2020 Chris Richardson (chris@bpi.cam.ac.uk) +// // SPDX-License-Identifier: MIT + +// #include "read_petsc.h" +// #include "L2GMap.h" +// #include +// #include +// #include +// #include +// #include + +// // Divide size into N ~equal chunks +// std::vector owner_ranges(int size, std::int64_t N) +// { +// // Compute number of items per process and remainder +// const std::int64_t n = N / size; +// const std::int64_t r = N % size; + +// // Compute local range +// std::vector ranges; +// for (int rank = 0; rank < (size + 1); ++rank) +// { +// if (rank < r) +// ranges.push_back(rank * (n + 1)); +// else +// ranges.push_back(rank * n + r); +// } + +// return ranges; +// } +// //----------------------------------------------------------------------------- +// spmv::Matrix spmv::read_petsc_binary(MPI_Comm comm, +// std::string filename) +// { +// Eigen::SparseMatrix A; + +// int mpi_rank; +// MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); +// int mpi_size; +// MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + +// std::map col_indices; +// std::vector row_ranges, col_ranges; +// std::int64_t ncols_local, nrows_local; + +// std::ifstream file(filename.c_str(), +// std::ios::in | std::ios::binary | std::ios::ate); +// if (file.is_open()) +// { +// // Get first 4 ints from file +// std::vector memblock(16); +// file.seekg(0, std::ios::beg); +// file.read(memblock.data(), 16); + +// char* ptr = memblock.data(); +// for (int i = 0; i < 4; ++i) +// { +// std::swap(*ptr, *(ptr + 3)); +// std::swap(*(ptr + 1), *(ptr + 2)); +// ptr += 4; +// } + +// std::int32_t* int_data = (std::int32_t*)(memblock.data()); +// int id = int_data[0]; +// if (id != 1211216) +// throw std::runtime_error("Bad signature in PETSc Matrix file"); + +// int nrows = int_data[1]; +// int ncols = int_data[2]; +// int nnz_tot = int_data[3]; +// row_ranges = owner_ranges(mpi_size, nrows); +// col_ranges = owner_ranges(mpi_size, ncols); + +// if (mpi_rank == 0) +// std::cout << "Read file: " << filename << ": " << nrows << "x" << ncols +// << " = " << nnz_tot << "\n"; + +// nrows_local = row_ranges[mpi_rank + 1] - row_ranges[mpi_rank]; +// ncols_local = col_ranges[mpi_rank + 1] - col_ranges[mpi_rank]; + +// // Reset memory block and read nnz per row for all rows +// memblock.resize(nrows * 4); +// ptr = memblock.data(); +// file.read(memblock.data(), nrows * 4); +// std::vector nnz(nrows); +// std::int64_t nnz_sum = 0; +// for (int i = 0; i < nrows; ++i) +// { +// std::swap(*ptr, *(ptr + 3)); +// std::swap(*(ptr + 1), *(ptr + 2)); +// nnz[i] = *((std::int32_t*)ptr); +// nnz_sum += nnz[i]; +// ptr += 4; +// } +// assert(nnz_sum == nnz_tot); + +// // Get offset and size for data +// std::int64_t nnz_offset = 0; +// std::int64_t nnz_size = 0; +// for (std::int64_t i = 0; i < row_ranges[mpi_rank]; ++i) +// nnz_offset += nnz[i]; +// for (std::int64_t i = row_ranges[mpi_rank]; i < row_ranges[mpi_rank + 1]; +// ++i) +// nnz_size += nnz[i]; + +// std::streampos value_data_pos +// = file.tellg() + (std::streampos)(nnz_tot * 4 + nnz_offset * 8); + +// // Read col indices for each row +// memblock.resize(nnz_size * 4); +// ptr = memblock.data(); +// file.seekg(nnz_offset * 4, std::ios::cur); +// file.read(memblock.data(), nnz_size * 4); + +// std::int32_t c = 0; +// for (std::int64_t col = col_ranges[mpi_rank]; +// col < col_ranges[mpi_rank + 1]; ++col) +// { +// col_indices.insert({col, c}); +// ++c; +// } + +// // Map other columns +// for (std::int64_t row = row_ranges[mpi_rank]; +// row < row_ranges[mpi_rank + 1]; ++row) +// { +// for (std::int64_t j = 0; j < nnz[row]; ++j) +// { +// std::swap(*ptr, *(ptr + 3)); +// std::swap(*(ptr + 1), *(ptr + 2)); +// col_indices.insert({*((std::int32_t*)ptr), -1}); +// ptr += 4; +// } +// } +// // Ensure they are labelled in ascending order +// for (auto& q : col_indices) +// if (q.second == -1) +// { +// q.second = c; +// ++c; +// } + +// A.resize(nrows_local, col_indices.size()); + +// // Read values +// std::vector valuedata(nnz_size * 8); +// file.seekg(value_data_pos, std::ios::beg); +// file.read(valuedata.data(), nnz_size * 8); +// file.close(); + +// // Pointer to values +// char* vptr = valuedata.data(); +// ptr = memblock.data(); +// for (std::int64_t row = row_ranges[mpi_rank]; +// row < row_ranges[mpi_rank + 1]; ++row) +// { +// for (std::int64_t j = 0; j < nnz[row]; ++j) +// { +// std::swap(*vptr, *(vptr + 7)); +// std::swap(*(vptr + 1), *(vptr + 6)); +// std::swap(*(vptr + 2), *(vptr + 5)); +// std::swap(*(vptr + 3), *(vptr + 4)); +// double val = *((double*)vptr); +// vptr += 8; + +// // Look up column local index +// std::int32_t col = col_indices[*((std::int32_t*)ptr)]; +// ptr += 4; + +// A.insert(row - row_ranges[mpi_rank], col) = val; +// } +// } +// } +// else +// throw std::runtime_error("Could not open file"); + +// A.makeCompressed(); + +// std::vector ghosts(col_indices.size() - ncols_local); +// for (auto& q : col_indices) +// if (q.first < col_ranges[mpi_rank] or q.first >= col_ranges[mpi_rank + 1]) +// ghosts[q.second - ncols_local] = q.first; + +// auto col_map = std::make_shared(comm, ncols_local, ghosts); +// auto row_map = std::make_shared(comm, nrows_local, +// std::vector()); + +// return spmv::Matrix(A, col_map, row_map); +// } +// //----------------------------------------------------------------------------- +// Eigen::VectorXd spmv::read_petsc_binary_vector(MPI_Comm comm, +// std::string filename) +// { +// Eigen::VectorXd vec; + +// int mpi_rank; +// MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); +// int mpi_size; +// MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + +// std::ifstream file(filename.c_str(), +// std::ios::in | std::ios::binary | std::ios::ate); +// if (file.is_open()) +// { +// // Get first 2 ints from file +// std::vector memblock(8); +// file.seekg(0, std::ios::beg); +// file.read(memblock.data(), 8); + +// char* ptr = memblock.data(); +// for (int i = 0; i < 2; ++i) +// { +// std::swap(*ptr, *(ptr + 3)); +// std::swap(*(ptr + 1), *(ptr + 2)); +// ptr += 4; +// } + +// std::int32_t* int_data = (std::int32_t*)(memblock.data()); +// int id = int_data[0]; +// if (id != 1211214) +// throw std::runtime_error("Bad signature in PETSc Vector file"); + +// int nrows = int_data[1]; +// std::vector ranges = owner_ranges(mpi_size, nrows); + +// if (mpi_rank == 0) +// std::cout << "Read vector file: " << filename << ": " << nrows << "\n"; + +// std::int64_t nrows_local = ranges[mpi_rank + 1] - ranges[mpi_rank]; + +// vec.resize(nrows_local); + +// std::streampos value_data_pos +// = file.tellg() + (std::streampos)(ranges[mpi_rank] * 8); + +// // Read values +// std::vector valuedata(nrows_local * 8); +// file.seekg(value_data_pos, std::ios::beg); +// file.read(valuedata.data(), nrows_local * 8); +// file.close(); + +// // Pointer to values +// char* vptr = valuedata.data(); + +// for (std::int64_t row = ranges[mpi_rank]; row < ranges[mpi_rank + 1]; ++row) +// { +// std::swap(*vptr, *(vptr + 7)); +// std::swap(*(vptr + 1), *(vptr + 6)); +// std::swap(*(vptr + 2), *(vptr + 5)); +// std::swap(*(vptr + 3), *(vptr + 4)); +// double val = *((double*)vptr); +// vptr += 8; +// vec[row - ranges[mpi_rank]] = val; +// } +// } +// else +// throw std::runtime_error("Could not open file"); + +// return vec; +// } +// //----------------------------------------------------------------------------- diff --git a/spmv/read_petsc.h b/spmv/read_petsc.h index 6f58d46..bb5b509 100644 --- a/spmv/read_petsc.h +++ b/spmv/read_petsc.h @@ -1,12 +1,12 @@ // Copyright (C) 2020 Chris Richardson (chris@bpi.cam.ac.uk) // SPDX-License-Identifier: MIT -#include #include #include #include #include "Matrix.h" +#include "Vector.h" #pragma once @@ -20,7 +20,8 @@ class L2GMap; /// @param comm MPI Comm /// @param filename Filename /// @return spmv::Matrix Matrix -Matrix read_petsc_binary(MPI_Comm comm, std::string filename); +Matrix read_petsc_binary(MPI_Comm comm, + std::string filename); /// @brief Read a binary PETSc vector file and distribute. /// diff --git a/spmv/spmv.h b/spmv/spmv.h index 50acbcf..721e54c 100644 --- a/spmv/spmv.h +++ b/spmv/spmv.h @@ -3,5 +3,5 @@ #include "L2GMap.h" #include "Matrix.h" -#include "read_petsc.h" -#include "cg.h" +// #include "read_petsc.h" +// #include "cg.h" From 55a7d3abc2c3e205719e79739eb682c7cc9e6b83 Mon Sep 17 00:00:00 2001 From: igorbaratta Date: Sat, 24 Oct 2020 16:43:17 -0300 Subject: [PATCH 07/37] add Distributed vector --- CMakeLists.txt | 4 +- demos/CMakeLists.txt | 15 +- demos/vecnorm.cpp | 63 ++++++ spmv/Vector.h | 35 +++- spmv/read_petsc.cpp | 480 +++++++++++++++++++++---------------------- 5 files changed, 345 insertions(+), 252 deletions(-) create mode 100644 demos/vecnorm.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ea12e0..4fdcb42 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,8 +21,8 @@ find_package(MPI REQUIRED) include_directories(${MPI_INCLUDE_PATH}) # Not sure why need to set -O3 and -DNDEBUG as should be set by Release build type -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O3 -DNDEBUG -fsycl -DMKL_ILP64") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O3 -DNDEBUG -fsycl -DMKL_ILP64 -tbb") add_subdirectory(spmv) include_directories (${CMAKE_CURRENT_SOURCE_DIR}) -# add_subdirectory(demos) +add_subdirectory(demos) diff --git a/demos/CMakeLists.txt b/demos/CMakeLists.txt index 1d04284..98ce7aa 100644 --- a/demos/CMakeLists.txt +++ b/demos/CMakeLists.txt @@ -1,11 +1,14 @@ # Executables -add_executable(cgmain cgmain.cpp) -target_link_libraries(cgmain LINK_PUBLIC ${PROJECT_NAME}) +add_executable(vecnorm vecnorm.cpp) +target_link_libraries(vecnorm LINK_PUBLIC ${PROJECT_NAME}) -add_executable(matvecmain matvecmain.cpp CreateA.cpp) -target_link_libraries(matvecmain ${PROJECT_NAME}) +# add_executable(cgmain cgmain.cpp) +# target_link_libraries(cgmain LINK_PUBLIC ${PROJECT_NAME}) -add_executable(restrictmain restrictmain.cpp) -target_link_libraries(restrictmain ${PROJECT_NAME}) +# add_executable(matvecmain matvecmain.cpp CreateA.cpp) +# target_link_libraries(matvecmain ${PROJECT_NAME}) + +# add_executable(restrictmain restrictmain.cpp) +# target_link_libraries(restrictmain ${PROJECT_NAME}) diff --git a/demos/vecnorm.cpp b/demos/vecnorm.cpp new file mode 100644 index 0000000..b3cfcca --- /dev/null +++ b/demos/vecnorm.cpp @@ -0,0 +1,63 @@ +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +int main(int argc, char** argv) +{ + MPI_Init(&argc, &argv); + + int rank; + MPI_Comm comm{MPI_COMM_WORLD}; + MPI_Comm_rank(comm, &rank); + + constexpr std::size_t local_size = 1000; + constexpr std::size_t nghost = 10; + + std::vector v(local_size + nghost, 1); + std::vector ghosts(nghost); + std::iota(ghosts.begin(), ghosts.end(), (rank + 1) * local_size); + + auto map = std::make_shared(MPI_COMM_WORLD, local_size, ghosts); + auto data = std::make_shared>(v); + + spmv::Vector vec(data, map); + double norm = std::sqrt(vec.dot(vec)); + double ex_norm = std::sqrt((double)map->global_size()); + + if (rank == 0) + { + std::cout << std::setprecision(10); + std::cout << "Computed Norm: " << norm << std::endl; + std::cout << "Exact Norm: " << ex_norm << std::endl; + } + assert(fabs(norm - ex_norm) < 1e-5); + + vec += vec; + norm = std::sqrt(vec.dot(vec)); + if (rank == 0) + { + std::cout << std::endl; + std::cout << "Computed Norm: " << norm << std::endl; + std::cout << "Exact Norm: " << ex_norm * 2 << std::endl; + } + + spmv::Vector vec2 = vec + vec; + vec2 *= 0.5; + norm = std::sqrt(vec.dot(vec)); + if (rank == 0) + { + std::cout << std::endl; + std::cout << "Computed Norm: " << norm << std::endl; + std::cout << "Exact Norm: " << ex_norm * 2 << std::endl; + } + + return 0; +} \ No newline at end of file diff --git a/spmv/Vector.h b/spmv/Vector.h index e73a052..6f11df3 100644 --- a/spmv/Vector.h +++ b/spmv/Vector.h @@ -1,5 +1,9 @@ +// Copyright (C) 2020 Igor Baratta (ia397@cam.ac.uk) +// SPDX-License-Identifier: MIT + #include #include +#include #include "L2GMap.h" #include "mpi_type.h" @@ -17,7 +21,7 @@ class Vector { DeviceSelector device_selector; _q = sycl::queue(device_selector); - if (_map->local_size() != data->size()) + if (_map->local_size() != _data->get_size()) std::runtime_error("Size mismatch"); }; @@ -25,10 +29,33 @@ class Vector cl::sycl::buffer& getLocalData() { return *_data; }; - Vector& operator+=(const Vector& other) + /// Computes the product of a vector by a scalar. + Vector& operator*=(ScalarType alpha) + { + std::size_t ls = _map->local_size() + _map->num_ghosts(); + oneapi::mkl::blas::scal(_q, ls, alpha, *_data, 1); + return *this; + } + + Vector& operator+=(Vector& other) { oneapi::mkl::blas::axpy(_q, local_size(), 1.0, other.getLocalData(), 1, *_data, 1); + return *this; + } + + Vector& operator-=(Vector& other) + { + oneapi::mkl::blas::axpy(_q, local_size(), -1.0, other.getLocalData(), 1, + *_data, 1); + return *this; + } + + Vector& operator+(Vector& other) + { + auto buffer = std::make_shared>(*_data); + spmv::Vector out(buffer, _map); + return out += other; } double dot(spmv::Vector& y) @@ -39,10 +66,10 @@ class Vector auto acc = res.template get_access(); MPI_Comm comm = _map->comm(); double local_sum = acc[0]; - double global_sum; + double global_sum{-1.0}; auto data_type = spmv::mpi_type(); - MPI_Reduce(&local_sum, &global_sum, 1, data_type, MPI_SUM, 0, comm); + MPI_Allreduce(&local_sum, &global_sum, 1, data_type, MPI_SUM, comm); return global_sum; }; diff --git a/spmv/read_petsc.cpp b/spmv/read_petsc.cpp index 383390d..1f881c1 100644 --- a/spmv/read_petsc.cpp +++ b/spmv/read_petsc.cpp @@ -1,12 +1,12 @@ -// // Copyright (C) 2020 Chris Richardson (chris@bpi.cam.ac.uk) -// // SPDX-License-Identifier: MIT - -// #include "read_petsc.h" -// #include "L2GMap.h" -// #include -// #include -// #include -// #include +// // // Copyright (C) 2020 Chris Richardson (chris@bpi.cam.ac.uk) +// // // SPDX-License-Identifier: MIT + +// // #include "read_petsc.h" +// // #include "L2GMap.h" +// // #include +// // #include +// // #include +// // #include // #include // // Divide size into N ~equal chunks @@ -28,234 +28,234 @@ // return ranges; // } -// //----------------------------------------------------------------------------- -// spmv::Matrix spmv::read_petsc_binary(MPI_Comm comm, -// std::string filename) -// { -// Eigen::SparseMatrix A; - -// int mpi_rank; -// MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); -// int mpi_size; -// MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); - -// std::map col_indices; -// std::vector row_ranges, col_ranges; -// std::int64_t ncols_local, nrows_local; - -// std::ifstream file(filename.c_str(), -// std::ios::in | std::ios::binary | std::ios::ate); -// if (file.is_open()) -// { -// // Get first 4 ints from file -// std::vector memblock(16); -// file.seekg(0, std::ios::beg); -// file.read(memblock.data(), 16); - -// char* ptr = memblock.data(); -// for (int i = 0; i < 4; ++i) -// { -// std::swap(*ptr, *(ptr + 3)); -// std::swap(*(ptr + 1), *(ptr + 2)); -// ptr += 4; -// } - -// std::int32_t* int_data = (std::int32_t*)(memblock.data()); -// int id = int_data[0]; -// if (id != 1211216) -// throw std::runtime_error("Bad signature in PETSc Matrix file"); - -// int nrows = int_data[1]; -// int ncols = int_data[2]; -// int nnz_tot = int_data[3]; -// row_ranges = owner_ranges(mpi_size, nrows); -// col_ranges = owner_ranges(mpi_size, ncols); - -// if (mpi_rank == 0) -// std::cout << "Read file: " << filename << ": " << nrows << "x" << ncols -// << " = " << nnz_tot << "\n"; - -// nrows_local = row_ranges[mpi_rank + 1] - row_ranges[mpi_rank]; -// ncols_local = col_ranges[mpi_rank + 1] - col_ranges[mpi_rank]; - -// // Reset memory block and read nnz per row for all rows -// memblock.resize(nrows * 4); -// ptr = memblock.data(); -// file.read(memblock.data(), nrows * 4); -// std::vector nnz(nrows); -// std::int64_t nnz_sum = 0; -// for (int i = 0; i < nrows; ++i) -// { -// std::swap(*ptr, *(ptr + 3)); -// std::swap(*(ptr + 1), *(ptr + 2)); -// nnz[i] = *((std::int32_t*)ptr); -// nnz_sum += nnz[i]; -// ptr += 4; -// } -// assert(nnz_sum == nnz_tot); - -// // Get offset and size for data -// std::int64_t nnz_offset = 0; -// std::int64_t nnz_size = 0; -// for (std::int64_t i = 0; i < row_ranges[mpi_rank]; ++i) -// nnz_offset += nnz[i]; -// for (std::int64_t i = row_ranges[mpi_rank]; i < row_ranges[mpi_rank + 1]; -// ++i) -// nnz_size += nnz[i]; - -// std::streampos value_data_pos -// = file.tellg() + (std::streampos)(nnz_tot * 4 + nnz_offset * 8); - -// // Read col indices for each row -// memblock.resize(nnz_size * 4); -// ptr = memblock.data(); -// file.seekg(nnz_offset * 4, std::ios::cur); -// file.read(memblock.data(), nnz_size * 4); - -// std::int32_t c = 0; -// for (std::int64_t col = col_ranges[mpi_rank]; -// col < col_ranges[mpi_rank + 1]; ++col) -// { -// col_indices.insert({col, c}); -// ++c; -// } - -// // Map other columns -// for (std::int64_t row = row_ranges[mpi_rank]; -// row < row_ranges[mpi_rank + 1]; ++row) -// { -// for (std::int64_t j = 0; j < nnz[row]; ++j) -// { -// std::swap(*ptr, *(ptr + 3)); -// std::swap(*(ptr + 1), *(ptr + 2)); -// col_indices.insert({*((std::int32_t*)ptr), -1}); -// ptr += 4; -// } -// } -// // Ensure they are labelled in ascending order -// for (auto& q : col_indices) -// if (q.second == -1) -// { -// q.second = c; -// ++c; -// } - -// A.resize(nrows_local, col_indices.size()); - -// // Read values -// std::vector valuedata(nnz_size * 8); -// file.seekg(value_data_pos, std::ios::beg); -// file.read(valuedata.data(), nnz_size * 8); -// file.close(); - -// // Pointer to values -// char* vptr = valuedata.data(); -// ptr = memblock.data(); -// for (std::int64_t row = row_ranges[mpi_rank]; -// row < row_ranges[mpi_rank + 1]; ++row) -// { -// for (std::int64_t j = 0; j < nnz[row]; ++j) -// { -// std::swap(*vptr, *(vptr + 7)); -// std::swap(*(vptr + 1), *(vptr + 6)); -// std::swap(*(vptr + 2), *(vptr + 5)); -// std::swap(*(vptr + 3), *(vptr + 4)); -// double val = *((double*)vptr); -// vptr += 8; - -// // Look up column local index -// std::int32_t col = col_indices[*((std::int32_t*)ptr)]; -// ptr += 4; - -// A.insert(row - row_ranges[mpi_rank], col) = val; -// } -// } -// } -// else -// throw std::runtime_error("Could not open file"); - -// A.makeCompressed(); - -// std::vector ghosts(col_indices.size() - ncols_local); -// for (auto& q : col_indices) -// if (q.first < col_ranges[mpi_rank] or q.first >= col_ranges[mpi_rank + 1]) -// ghosts[q.second - ncols_local] = q.first; - -// auto col_map = std::make_shared(comm, ncols_local, ghosts); -// auto row_map = std::make_shared(comm, nrows_local, -// std::vector()); - -// return spmv::Matrix(A, col_map, row_map); -// } -// //----------------------------------------------------------------------------- -// Eigen::VectorXd spmv::read_petsc_binary_vector(MPI_Comm comm, -// std::string filename) -// { -// Eigen::VectorXd vec; - -// int mpi_rank; -// MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); -// int mpi_size; -// MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); - -// std::ifstream file(filename.c_str(), -// std::ios::in | std::ios::binary | std::ios::ate); -// if (file.is_open()) -// { -// // Get first 2 ints from file -// std::vector memblock(8); -// file.seekg(0, std::ios::beg); -// file.read(memblock.data(), 8); - -// char* ptr = memblock.data(); -// for (int i = 0; i < 2; ++i) -// { -// std::swap(*ptr, *(ptr + 3)); -// std::swap(*(ptr + 1), *(ptr + 2)); -// ptr += 4; -// } - -// std::int32_t* int_data = (std::int32_t*)(memblock.data()); -// int id = int_data[0]; -// if (id != 1211214) -// throw std::runtime_error("Bad signature in PETSc Vector file"); - -// int nrows = int_data[1]; -// std::vector ranges = owner_ranges(mpi_size, nrows); - -// if (mpi_rank == 0) -// std::cout << "Read vector file: " << filename << ": " << nrows << "\n"; - -// std::int64_t nrows_local = ranges[mpi_rank + 1] - ranges[mpi_rank]; - -// vec.resize(nrows_local); - -// std::streampos value_data_pos -// = file.tellg() + (std::streampos)(ranges[mpi_rank] * 8); - -// // Read values -// std::vector valuedata(nrows_local * 8); -// file.seekg(value_data_pos, std::ios::beg); -// file.read(valuedata.data(), nrows_local * 8); -// file.close(); - -// // Pointer to values -// char* vptr = valuedata.data(); - -// for (std::int64_t row = ranges[mpi_rank]; row < ranges[mpi_rank + 1]; ++row) -// { -// std::swap(*vptr, *(vptr + 7)); -// std::swap(*(vptr + 1), *(vptr + 6)); -// std::swap(*(vptr + 2), *(vptr + 5)); -// std::swap(*(vptr + 3), *(vptr + 4)); -// double val = *((double*)vptr); -// vptr += 8; -// vec[row - ranges[mpi_rank]] = val; -// } -// } -// else -// throw std::runtime_error("Could not open file"); - -// return vec; -// } -// //----------------------------------------------------------------------------- +// // //----------------------------------------------------------------------------- +// // spmv::Matrix spmv::read_petsc_binary(MPI_Comm comm, +// // std::string filename) +// // { +// // Eigen::SparseMatrix A; + +// // int mpi_rank; +// // MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); +// // int mpi_size; +// // MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + +// // std::map col_indices; +// // std::vector row_ranges, col_ranges; +// // std::int64_t ncols_local, nrows_local; + +// // std::ifstream file(filename.c_str(), +// // std::ios::in | std::ios::binary | std::ios::ate); +// // if (file.is_open()) +// // { +// // // Get first 4 ints from file +// // std::vector memblock(16); +// // file.seekg(0, std::ios::beg); +// // file.read(memblock.data(), 16); + +// // char* ptr = memblock.data(); +// // for (int i = 0; i < 4; ++i) +// // { +// // std::swap(*ptr, *(ptr + 3)); +// // std::swap(*(ptr + 1), *(ptr + 2)); +// // ptr += 4; +// // } + +// // std::int32_t* int_data = (std::int32_t*)(memblock.data()); +// // int id = int_data[0]; +// // if (id != 1211216) +// // throw std::runtime_error("Bad signature in PETSc Matrix file"); + +// // int nrows = int_data[1]; +// // int ncols = int_data[2]; +// // int nnz_tot = int_data[3]; +// // row_ranges = owner_ranges(mpi_size, nrows); +// // col_ranges = owner_ranges(mpi_size, ncols); + +// // if (mpi_rank == 0) +// // std::cout << "Read file: " << filename << ": " << nrows << "x" << ncols +// // << " = " << nnz_tot << "\n"; + +// // nrows_local = row_ranges[mpi_rank + 1] - row_ranges[mpi_rank]; +// // ncols_local = col_ranges[mpi_rank + 1] - col_ranges[mpi_rank]; + +// // // Reset memory block and read nnz per row for all rows +// // memblock.resize(nrows * 4); +// // ptr = memblock.data(); +// // file.read(memblock.data(), nrows * 4); +// // std::vector nnz(nrows); +// // std::int64_t nnz_sum = 0; +// // for (int i = 0; i < nrows; ++i) +// // { +// // std::swap(*ptr, *(ptr + 3)); +// // std::swap(*(ptr + 1), *(ptr + 2)); +// // nnz[i] = *((std::int32_t*)ptr); +// // nnz_sum += nnz[i]; +// // ptr += 4; +// // } +// // assert(nnz_sum == nnz_tot); + +// // // Get offset and size for data +// // std::int64_t nnz_offset = 0; +// // std::int64_t nnz_size = 0; +// // for (std::int64_t i = 0; i < row_ranges[mpi_rank]; ++i) +// // nnz_offset += nnz[i]; +// // for (std::int64_t i = row_ranges[mpi_rank]; i < row_ranges[mpi_rank + 1]; +// // ++i) +// // nnz_size += nnz[i]; + +// // std::streampos value_data_pos +// // = file.tellg() + (std::streampos)(nnz_tot * 4 + nnz_offset * 8); + +// // // Read col indices for each row +// // memblock.resize(nnz_size * 4); +// // ptr = memblock.data(); +// // file.seekg(nnz_offset * 4, std::ios::cur); +// // file.read(memblock.data(), nnz_size * 4); + +// // std::int32_t c = 0; +// // for (std::int64_t col = col_ranges[mpi_rank]; +// // col < col_ranges[mpi_rank + 1]; ++col) +// // { +// // col_indices.insert({col, c}); +// // ++c; +// // } + +// // // Map other columns +// // for (std::int64_t row = row_ranges[mpi_rank]; +// // row < row_ranges[mpi_rank + 1]; ++row) +// // { +// // for (std::int64_t j = 0; j < nnz[row]; ++j) +// // { +// // std::swap(*ptr, *(ptr + 3)); +// // std::swap(*(ptr + 1), *(ptr + 2)); +// // col_indices.insert({*((std::int32_t*)ptr), -1}); +// // ptr += 4; +// // } +// // } +// // // Ensure they are labelled in ascending order +// // for (auto& q : col_indices) +// // if (q.second == -1) +// // { +// // q.second = c; +// // ++c; +// // } + +// // A.resize(nrows_local, col_indices.size()); + +// // // Read values +// // std::vector valuedata(nnz_size * 8); +// // file.seekg(value_data_pos, std::ios::beg); +// // file.read(valuedata.data(), nnz_size * 8); +// // file.close(); + +// // // Pointer to values +// // char* vptr = valuedata.data(); +// // ptr = memblock.data(); +// // for (std::int64_t row = row_ranges[mpi_rank]; +// // row < row_ranges[mpi_rank + 1]; ++row) +// // { +// // for (std::int64_t j = 0; j < nnz[row]; ++j) +// // { +// // std::swap(*vptr, *(vptr + 7)); +// // std::swap(*(vptr + 1), *(vptr + 6)); +// // std::swap(*(vptr + 2), *(vptr + 5)); +// // std::swap(*(vptr + 3), *(vptr + 4)); +// // double val = *((double*)vptr); +// // vptr += 8; + +// // // Look up column local index +// // std::int32_t col = col_indices[*((std::int32_t*)ptr)]; +// // ptr += 4; + +// // A.insert(row - row_ranges[mpi_rank], col) = val; +// // } +// // } +// // } +// // else +// // throw std::runtime_error("Could not open file"); + +// // A.makeCompressed(); + +// // std::vector ghosts(col_indices.size() - ncols_local); +// // for (auto& q : col_indices) +// // if (q.first < col_ranges[mpi_rank] or q.first >= col_ranges[mpi_rank + 1]) +// // ghosts[q.second - ncols_local] = q.first; + +// // auto col_map = std::make_shared(comm, ncols_local, ghosts); +// // auto row_map = std::make_shared(comm, nrows_local, +// // std::vector()); + +// // return spmv::Matrix(A, col_map, row_map); +// // } +// // //----------------------------------------------------------------------------- +// // Eigen::VectorXd spmv::read_petsc_binary_vector(MPI_Comm comm, +// // std::string filename) +// // { +// // Eigen::VectorXd vec; + +// // int mpi_rank; +// // MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); +// // int mpi_size; +// // MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + +// // std::ifstream file(filename.c_str(), +// // std::ios::in | std::ios::binary | std::ios::ate); +// // if (file.is_open()) +// // { +// // // Get first 2 ints from file +// // std::vector memblock(8); +// // file.seekg(0, std::ios::beg); +// // file.read(memblock.data(), 8); + +// // char* ptr = memblock.data(); +// // for (int i = 0; i < 2; ++i) +// // { +// // std::swap(*ptr, *(ptr + 3)); +// // std::swap(*(ptr + 1), *(ptr + 2)); +// // ptr += 4; +// // } + +// // std::int32_t* int_data = (std::int32_t*)(memblock.data()); +// // int id = int_data[0]; +// // if (id != 1211214) +// // throw std::runtime_error("Bad signature in PETSc Vector file"); + +// // int nrows = int_data[1]; +// // std::vector ranges = owner_ranges(mpi_size, nrows); + +// // if (mpi_rank == 0) +// // std::cout << "Read vector file: " << filename << ": " << nrows << "\n"; + +// // std::int64_t nrows_local = ranges[mpi_rank + 1] - ranges[mpi_rank]; + +// // vec.resize(nrows_local); + +// // std::streampos value_data_pos +// // = file.tellg() + (std::streampos)(ranges[mpi_rank] * 8); + +// // // Read values +// // std::vector valuedata(nrows_local * 8); +// // file.seekg(value_data_pos, std::ios::beg); +// // file.read(valuedata.data(), nrows_local * 8); +// // file.close(); + +// // // Pointer to values +// // char* vptr = valuedata.data(); + +// // for (std::int64_t row = ranges[mpi_rank]; row < ranges[mpi_rank + 1]; ++row) +// // { +// // std::swap(*vptr, *(vptr + 7)); +// // std::swap(*(vptr + 1), *(vptr + 6)); +// // std::swap(*(vptr + 2), *(vptr + 5)); +// // std::swap(*(vptr + 3), *(vptr + 4)); +// // double val = *((double*)vptr); +// // vptr += 8; +// // vec[row - ranges[mpi_rank]] = val; +// // } +// // } +// // else +// // throw std::runtime_error("Could not open file"); + +// // return vec; +// // } +// // //----------------------------------------------------------------------------- From 27af3e7f9b201e62614bf69807260b62d8c0c605 Mon Sep 17 00:00:00 2001 From: igorbaratta Date: Sun, 25 Oct 2020 10:11:05 -0300 Subject: [PATCH 08/37] update demo --- demos/CMakeLists.txt | 6 +- demos/CreateA.h | 2 + demos/matvecmain.cpp | 40 +++--- demos/vecnorm.cpp | 4 +- spmv/L2GMap.h | 4 + spmv/Matrix.cpp | 319 +++++++------------------------------------ spmv/Matrix.h | 37 +++-- spmv/Vector.h | 14 ++ spmv/creation.h | 237 ++++++++++++++++++++++++++++++++ 9 files changed, 357 insertions(+), 306 deletions(-) create mode 100644 spmv/creation.h diff --git a/demos/CMakeLists.txt b/demos/CMakeLists.txt index 98ce7aa..d7cb691 100644 --- a/demos/CMakeLists.txt +++ b/demos/CMakeLists.txt @@ -4,11 +4,11 @@ add_executable(vecnorm vecnorm.cpp) target_link_libraries(vecnorm LINK_PUBLIC ${PROJECT_NAME}) +add_executable(matvecmain matvecmain.cpp CreateA.cpp) +target_link_libraries(matvecmain ${PROJECT_NAME}) + # add_executable(cgmain cgmain.cpp) # target_link_libraries(cgmain LINK_PUBLIC ${PROJECT_NAME}) -# add_executable(matvecmain matvecmain.cpp CreateA.cpp) -# target_link_libraries(matvecmain ${PROJECT_NAME}) - # add_executable(restrictmain restrictmain.cpp) # target_link_libraries(restrictmain ${PROJECT_NAME}) diff --git a/demos/CreateA.h b/demos/CreateA.h index 466b412..760d3d8 100644 --- a/demos/CreateA.h +++ b/demos/CreateA.h @@ -3,6 +3,8 @@ #pragma once +#include + #include #include #include diff --git a/demos/matvecmain.cpp b/demos/matvecmain.cpp index ea14bd6..ffaa83f 100644 --- a/demos/matvecmain.cpp +++ b/demos/matvecmain.cpp @@ -1,7 +1,8 @@ // Copyright (C) 2018-2020 Chris Richardson (chris@bpi.cam.ac.uk) // SPDX-License-Identifier: MIT -#include +#include + #include #include #include @@ -11,7 +12,8 @@ #include "CreateA.h" #include #include -#include +#include +// #include void matvec_main() { @@ -28,18 +30,18 @@ void matvec_main() // Either create a simple 1D stencil spmv::Matrix A = create_A(MPI_COMM_WORLD, 500000); - // Or read file created with "-ksp_view_mat binary" option - // spmv::Matrix A = spmv::read_petsc_binary(MPI_COMM_WORLD, "A4.dat"); - - std::shared_ptr l2g = A.col_map(); + std::shared_ptr l2g = A.col_map(); // Get local and global sizes std::int64_t M = A.row_map()->local_size(); std::int64_t N = l2g->global_size(); - Eigen::VectorXd b(M); + + // Create Distributed vector + std::vector b_data(M); + spmv::Vector b(b_data, l2g); auto timer_end = std::chrono::system_clock::now(); - // timings["0.MatCreate"] += (timer_end - timer_start); + timings["0.MatCreate"] += (timer_end - timer_start); timer_start = std::chrono::system_clock::now(); @@ -47,7 +49,7 @@ void matvec_main() std::cout << "Creating vector of size " << N << "\n"; // Vector with extra space for ghosts at end - Eigen::VectorXd psp(l2g->local_size() + l2g->num_ghosts()); + std::vector psp(l2g->local_size() + l2g->num_ghosts()); // Set up values in local range int r0 = l2g->global_offset(); @@ -57,6 +59,8 @@ void matvec_main() psp[i] = exp(-10 * pow(5 * (z - 0.5), 2.0)); } + spmv::Vector p(psp, l2g); + timer_end = std::chrono::system_clock::now(); timings["1.VecCreate"] += (timer_end - timer_start); @@ -70,24 +74,22 @@ void matvec_main() for (int i = 0; i < n_apply; ++i) { timer_start = std::chrono::system_clock::now(); - l2g->update(psp.data()); + // l2g->update(psp.data()); timer_end = std::chrono::system_clock::now(); timings["2.SparseUpdate"] += (timer_end - timer_start); timer_start = std::chrono::system_clock::now(); - q = A * psp; + b = A * p; timer_end = std::chrono::system_clock::now(); timings["3.SpMV"] += (timer_end - timer_start); - timer_start = std::chrono::system_clock::now(); - psp.head(M) = q; - timer_end = std::chrono::system_clock::now(); - timings["4.Copy"] += (timer_end - timer_start); + // timer_start = std::chrono::system_clock::now(); + // p = b; + // timer_end = std::chrono::system_clock::now(); + // timings["4.Copy"] += (timer_end - timer_start); } - double pnorm = psp.head(M).squaredNorm(); - double pnorm_sum; - MPI_Allreduce(&pnorm, &pnorm_sum, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + double pnorm = b.norm(); if (mpi_rank == 0) std::cout << "\nTimings (" << mpi_size @@ -116,7 +118,7 @@ void matvec_main() if (mpi_rank == 0) { std::cout << "----------------------------\n"; - std::cout << "norm = " << pnorm_sum << "\n"; + std::cout << "norm = " << pnorm << "\n"; } } diff --git a/demos/vecnorm.cpp b/demos/vecnorm.cpp index b3cfcca..79bbdad 100644 --- a/demos/vecnorm.cpp +++ b/demos/vecnorm.cpp @@ -34,7 +34,7 @@ int main(int argc, char** argv) if (rank == 0) { - std::cout << std::setprecision(10); + std::cout << std::setprecision(10) << std::endl; std::cout << "Computed Norm: " << norm << std::endl; std::cout << "Exact Norm: " << ex_norm << std::endl; } @@ -58,6 +58,8 @@ int main(int argc, char** argv) std::cout << "Computed Norm: " << norm << std::endl; std::cout << "Exact Norm: " << ex_norm * 2 << std::endl; } + + MPI_Finalize(); return 0; } \ No newline at end of file diff --git a/spmv/L2GMap.h b/spmv/L2GMap.h index 68969cd..c011b91 100644 --- a/spmv/L2GMap.h +++ b/spmv/L2GMap.h @@ -73,8 +73,12 @@ class L2GMap /// Access the ghost indices const std::vector& ghosts() const { return _ghosts; } + /// Return MPI communicator MPI_Comm comm() { return _neighbour_comm; } + /// Return MPI rank + std::int32_t rank() { return _mpi_rank; } + private: // Ownership ranges for all processes on global comm std::vector _ranges; diff --git a/spmv/Matrix.cpp b/spmv/Matrix.cpp index 09a7002..642f946 100644 --- a/spmv/Matrix.cpp +++ b/spmv/Matrix.cpp @@ -10,18 +10,17 @@ using namespace spmv; -template -Matrix::Matrix( +template +Matrix::Matrix( std::array shape, std::shared_ptr> data, - std::shared_ptr> indptr, - std::shared_ptr> indices, - std::shared_ptr col_maxp, + std::shared_ptr> indptr, + std::shared_ptr> indices, + std::shared_ptr col_map, std::shared_ptr row_map) : _data(data), _indptr(indptr), _indices(indices), _shape(shape), _col_map(col_map), _row_map(row_map) { - sycl::default_selector device_selector; _q = sycl::queue(device_selector); std::cout << "Running on " @@ -30,279 +29,59 @@ Matrix::Matrix( mkl_init(); } -template -Matrix::~Matrix() -{ - oneapi::mkl::sparse::release_matrix_handle(&A_onemkl); -} -//----------------------------------------------------------------------------- -template <> -void Matrix::mkl_init() +template +Matrix::Matrix(Eigen::SparseMatrix A, + std::shared_ptr col_map, + std::shared_ptr row_map) { - oneapi::mkl::sparse::init_matrix_handle(&A_onemkl); - oneapi::mkl::sparse::set_csr_data(A_onemkl, _shape[0], _shape[1], - oneapi::mkl::index_base::zero, *_indptr, - *_indices, *_data); -} -//---------------------- -// //--------------------- -// template <> -// Eigen::VectorXd Matrix::transpmult(const Eigen::VectorXd& b) const -// { -// Eigen::VectorXd y(_matA.cols()); -// cl::sycl::queue q; -// mkl::sparse::gemv(q, mkl::transpose::trans, 1.0, A_onemkl, -// const_cast(b.data()), 0.0, y.data()); -// return y; -// } -// //----------------------------------------------------------------------------- -// template -// Eigen::Matrix -// Matrix::operator*(const Eigen::Matrix& b) const -// { -// return _matA * b; -// } -// //----------------------------------------------------------------------------- -// template -// Eigen::Matrix -// Matrix::transpmult(const Eigen::Matrix& b) const -// { -// return _matA.transpose() * b; -// } -// //----------------------------------------------------------------------------- -// template -// Matrix Matrix::create_matrix( -// MPI_Comm comm, const Eigen::SparseMatrix mat, -// std::int64_t nrows_local, std::int64_t ncols_local, -// std::vector row_ghosts, std::vector -// col_ghosts) -// { - -// int mpi_size, mpi_rank; -// MPI_Comm_size(comm, &mpi_size); -// MPI_Comm_rank(comm, &mpi_rank); - -// std::vector row_ranges(mpi_size + 1, 0); -// MPI_Allgather(&nrows_local, 1, MPI_INT64_T, row_ranges.data() + 1, 1, -// MPI_INT64_T, comm); -// for (int i = 0; i < mpi_size; ++i) -// row_ranges[i + 1] += row_ranges[i]; - -// // FIX: often same as rows? -// std::vector col_ranges(mpi_size + 1, 0); -// MPI_Allgather(&ncols_local, 1, MPI_INT64_T, col_ranges.data() + 1, 1, -// MPI_INT64_T, comm); -// for (int i = 0; i < mpi_size; ++i) -// col_ranges[i + 1] += col_ranges[i]; - -// // Locate owner process for each row -// std::vector row_owner(row_ghosts.size()); -// for (std::size_t i = 0; i < row_ghosts.size(); ++i) -// { -// auto it -// = std::upper_bound(row_ranges.begin(), row_ranges.end(), -// row_ghosts[i]); -// assert(it != row_ranges.end()); -// row_owner[i] = it - row_ranges.begin() - 1; -// assert(row_owner[i] != mpi_rank); -// } - -// // Create a neighbour comm, remap row_owner to neighbour number -// std::set neighbour_set(row_owner.begin(), row_owner.end()); -// std::vector dests(neighbour_set.begin(), neighbour_set.end()); -// std::map proc_to_dest; -// for (std::size_t i = 0; i < dests.size(); ++i) -// proc_to_dest.insert({dests[i], i}); -// for (auto& q : row_owner) -// q = proc_to_dest[q]; - -// // Get list of sources (may be different from dests, requires AlltoAll to -// // find) -// std::vector is_dest(mpi_size, 0); -// for (int d : dests) -// is_dest[d] = 1; -// std::vector is_source(mpi_size, 0); -// MPI_Alltoall(is_dest.data(), 1, MPI_CHAR, is_source.data(), 1, MPI_CHAR, -// comm); -// std::vector sources; -// for (int i = 0; i < mpi_size; ++i) -// if (is_source[i] == 1) -// sources.push_back(i); - -// MPI_Comm neighbour_comm; -// MPI_Dist_graph_create_adjacent( -// comm, sources.size(), sources.data(), MPI_UNWEIGHTED, dests.size(), -// dests.data(), MPI_UNWEIGHTED, MPI_INFO_NULL, false, &neighbour_comm); - -// // send all ghost rows to their owners, using global col idx. -// const std::int32_t* Aouter = mat.outerIndexPtr(); -// const std::int32_t* Ainner = mat.innerIndexPtr(); -// const T* Aval = mat.valuePtr(); - -// std::vector> p_to_index(dests.size()); -// std::vector> p_to_val(dests.size()); -// for (std::size_t i = 0; i < row_ghosts.size(); ++i) -// { -// const int p = row_owner[i]; -// assert(p != -1); -// p_to_index[p].push_back(row_ghosts[i]); -// p_to_val[p].push_back(0.0); -// p_to_index[p].push_back(Aouter[nrows_local + i + 1] -// - Aouter[nrows_local + i]); -// p_to_val[p].push_back(0.0); - -// const std::int64_t local_offset = col_ranges[mpi_rank]; -// for (int j = Aouter[nrows_local + i]; j < Aouter[nrows_local + i + 1]; -// ++j) -// { -// std::int64_t global_index; -// if (Ainner[j] < ncols_local) -// global_index = Ainner[j] + local_offset; -// else -// { -// assert(Ainner[j] - ncols_local < (int)col_ghosts.size()); -// global_index = col_ghosts[Ainner[j] - ncols_local]; -// } -// p_to_index[p].push_back(global_index); -// p_to_val[p].push_back(Aval[j]); -// } -// } + _col_map = col_map; + _row_map = row_map; -// std::vector send_size(dests.size()); -// std::vector send_index; -// std::vector send_val; -// std::vector send_offset = {0}; -// for (std::size_t p = 0; p < dests.size(); ++p) -// { -// send_index.insert(send_index.end(), p_to_index[p].begin(), -// p_to_index[p].end()); -// send_val.insert(send_val.end(), p_to_val[p].begin(), p_to_val[p].end()); -// assert(p_to_val[p].size() == p_to_index[p].size()); -// send_size[p] = p_to_index[p].size(); -// send_offset.push_back(send_index.size()); -// } + _shape[0] = A.rows(); + _shape[1] = A.cols(); -// std::vector recv_size(sources.size()); -// MPI_Neighbor_alltoall(send_size.data(), 1, MPI_INT, recv_size.data(), 1, -// MPI_INT, neighbour_comm); - -// std::vector recv_offset = {0}; -// for (int r : recv_size) -// recv_offset.push_back(recv_offset.back() + r); - -// std::vector recv_index(recv_offset.back()); -// std::vector recv_val(recv_offset.back()); - -// MPI_Neighbor_alltoallv(send_index.data(), send_size.data(), -// send_offset.data(), MPI_INT64_T, recv_index.data(), -// recv_size.data(), recv_offset.data(), MPI_INT64_T, -// neighbour_comm); - -// MPI_Neighbor_alltoallv(send_val.data(), send_size.data(), -// send_offset.data(), -// mpi_type(), recv_val.data(), recv_size.data(), -// recv_offset.data(), mpi_type(), neighbour_comm); - -// // Create new map from global column index to local -// std::map col_ghost_map; -// for (std::int64_t q : col_ghosts) -// col_ghost_map.insert({q, -1}); - -// // Add any new ghost columns -// int pos = 0; -// while (pos < (int)recv_index.size()) -// { -// // std::int64_t global_row = recv_index[pos]; -// ++pos; -// int nnz = recv_index[pos]; -// ++pos; -// for (int k = 0; k < nnz; ++k) -// { -// const std::int64_t recv_col = recv_index[pos]; -// ++pos; -// if (recv_col >= col_ranges[mpi_rank + 1] -// or recv_col < col_ranges[mpi_rank]) -// col_ghost_map.insert({recv_col, -1}); -// } -// } + sycl::default_selector device_selector; + _q = sycl::queue(device_selector); + std::cout << "Running on " + << _q.get_device().get_info() << "\n"; -// // Unique numbering of ghost cols -// int c = ncols_local; -// for (auto& q : col_ghost_map) -// q.second = c++; + // Get indptr buffer + std::int32_t* Aouter = A.outerIndexPtr(); + std::vector indptr(A.rows()); + std::memcpy(Aouter, indptr.data(), sizeof(std::int32_t) * indptr.size()); + _indptr = std::make_shared>(indptr); -// std::vector> mat_data; -// for (int row = 0; row < nrows_local; ++row) -// for (int j = Aouter[row]; j < Aouter[row + 1]; ++j) -// { -// int col = Ainner[j]; -// if (col >= ncols_local) -// { -// // Get remapped ghost column -// std::int64_t global_col = col_ghosts[col - ncols_local]; -// auto it = col_ghost_map.find(global_col); -// assert(it != col_ghost_map.end()); -// col = it->second; -// assert(col >= ncols_local); -// } + // Get indices buffer + std::int32_t* Ainner = A.innerIndexPtr(); + std::vector indices(A.nonZeros()); + std::memcpy(Ainner, indices.data(), sizeof(std::int32_t) * indices.size()); + _indices = std::make_shared>(indices); -// assert(row >= 0 and row < nrows_local); -// assert(col >= 0 and col < (int)(ncols_local + col_ghost_map.size())); -// mat_data.push_back(Eigen::Triplet(row, col, Aval[j])); -// } + // Get data buffer + ScalarType* Aptr = A.valuePtr(); + std::vector data(A.nonZeros()); + std::memcpy(Aptr, data.data(), sizeof(ScalarType) * data.size()); + _data = std::make_shared>(data); -// // Add received data -// pos = 0; -// while (pos < (int)recv_index.size()) -// { -// std::int64_t global_row = recv_index[pos]; -// assert(global_row >= row_ranges[mpi_rank] -// and global_row < row_ranges[mpi_rank + 1]); -// std::int32_t row = global_row - row_ranges[mpi_rank]; -// ++pos; -// int nnz = recv_index[pos]; -// ++pos; -// for (int k = 0; k < nnz; ++k) -// { -// const std::int64_t global_col = recv_index[pos]; -// const T val = recv_val[pos]; -// ++pos; -// int col; -// if (global_col >= col_ranges[mpi_rank + 1] -// or global_col < col_ranges[mpi_rank]) -// { -// auto it = col_ghost_map.find(global_col); -// assert(it != col_ghost_map.end()); -// col = it->second; -// } -// else -// col = global_col - col_ranges[mpi_rank]; -// assert(row >= 0 and row < nrows_local); -// assert(col >= 0 and col < (int)(ncols_local + col_ghost_map.size())); -// mat_data.push_back(Eigen::Triplet(row, col, val)); -// } -// } + cl::sycl::buffer norm{1}; + oneapi::mkl::blas::nrm2(_q, A.nonZeros(), *_data, 1, norm); -// // Rebuild sparse matrix -// std::vector new_col_ghosts; -// for (auto& q : col_ghost_map) -// new_col_ghosts.push_back(q.first); + auto acc = norm.template get_access(); + double result = acc[0]; + std::cout << Aptr[1] << std::endl; -// Eigen::SparseMatrix B( -// nrows_local, ncols_local + new_col_ghosts.size()); -// B.setFromTriplets(mat_data.begin(), mat_data.end()); + mkl_init(); +} -// std::shared_ptr col_map -// = std::make_shared(comm, ncols_local, new_col_ghosts); -// std::shared_ptr row_map = std::make_shared( -// comm, nrows_local, std::vector()); +template +Matrix::~Matrix() +{ + oneapi::mkl::sparse::release_matrix_handle(&A_onemkl); +} -// spmv::Matrix b(B, col_map, row_map); -// return b; -// } -// // Explicit instantiation -// // template class spmv::Matrix; -// template class spmv::Matrix; -// // template class spmv::Matrix>; -// // template class spmv::Matrix>; +// Explicit instantiation +// template class spmv::Matrix; +template class spmv::Matrix; +// template class spmv::Matrix>; +// template class spmv::Matrix>; diff --git a/spmv/Matrix.h b/spmv/Matrix.h index 1e83c40..0543ee7 100644 --- a/spmv/Matrix.h +++ b/spmv/Matrix.h @@ -7,6 +7,8 @@ #include #include +#include + #include "Vector.h" #pragma once @@ -17,25 +19,29 @@ namespace spmv class L2GMap; -template +template class Matrix { /// Matrix with row and column maps. public: Matrix(std::array shape, std::shared_ptr> data, - std::shared_ptr> indptr, - std::shared_ptr> indices, + std::shared_ptr> indptr, + std::shared_ptr> indices, std::shared_ptr col_map, std::shared_ptr row_map); - /// Destructor (destroys MKL structs, if using MKL) + Matrix(Eigen::SparseMatrix A, + std::shared_ptr col_map, + std::shared_ptr row_map); + + /// Destructor (destroys MKL structs) ~Matrix(); /// MatVec operator for A x spmv::Vector operator*(spmv::Vector& b) const { - std::shared_ptr> y( + auto y = std::make_shared>( cl::sycl::range<1>{_shape[0]}); oneapi::mkl::sparse::gemv(_q, oneapi::mkl::transpose::nontrans, 1.0, A_onemkl, b.getLocalData(), 0.0, *y); @@ -43,10 +49,9 @@ class Matrix }; /// MatVec operator for A^T x - spmv::Vector - transpmult(const cl::sycl::buffer& b) const + spmv::Vector transpmult(spmv::Vector& b) const { - std::shared_ptr> y( + auto y = std::make_shared>( cl::sycl::range<1>{_shape[0]}); oneapi::mkl::sparse::gemv(_q, oneapi::mkl::transpose::trans, 1.0, A_onemkl, b.getLocalData(), 0.0, *y); @@ -54,20 +59,26 @@ class Matrix }; /// Row mapping (local-to-global). Usually, there will not be ghost rows. - std::shared_ptr row_map() const { return _row_map; } + std::shared_ptr row_map() const { return _row_map; } /// Column mapping (local-to-global) - std::shared_ptr col_map() const { return _col_map; } + std::shared_ptr col_map() const { return _col_map; } private: - void mkl_init(); + void mkl_init() + { + oneapi::mkl::sparse::init_matrix_handle(&A_onemkl); + oneapi::mkl::sparse::set_csr_data(A_onemkl, _shape[0], _shape[1], + oneapi::mkl::index_base::zero, *_indptr, + *_indices, *_data); + } mutable cl::sycl::queue _q; oneapi::mkl::sparse::matrix_handle_t A_onemkl; std::shared_ptr> _data; - std::shared_ptr> _indptr; - std::shared_ptr> _indices; + std::shared_ptr> _indptr; + std::shared_ptr> _indices; std::array _shape; diff --git a/spmv/Vector.h b/spmv/Vector.h index 6f11df3..eb3f7ca 100644 --- a/spmv/Vector.h +++ b/spmv/Vector.h @@ -1,6 +1,8 @@ // Copyright (C) 2020 Igor Baratta (ia397@cam.ac.uk) // SPDX-License-Identifier: MIT +#pragma once + #include #include #include @@ -21,10 +23,19 @@ class Vector { DeviceSelector device_selector; _q = sycl::queue(device_selector); + if (_map->local_size() != _data->get_size()) std::runtime_error("Size mismatch"); }; + Vector(std::vector& vec, std::shared_ptr map) + : _map(map) + { + DeviceSelector device_selector; + _q = sycl::queue(device_selector); + _data = std::make_shared>(vec); + } + std::int32_t local_size() const { return _map->local_size(); } cl::sycl::buffer& getLocalData() { return *_data; }; @@ -73,6 +84,9 @@ class Vector return global_sum; }; + /// Computes the vector 2 norm (Euclidean norm). + double norm() { return std::sqrt(this->dot(*this)); } + private: std::shared_ptr> _data; std::shared_ptr _map; diff --git a/spmv/creation.h b/spmv/creation.h new file mode 100644 index 0000000..79a9dc3 --- /dev/null +++ b/spmv/creation.h @@ -0,0 +1,237 @@ +// Copyright (C) 2020 Chris Richardson and Igor Baratta +// SPDX-License-Identifier: MIT + +#include + +#include "Matrix.h" + +namespace spmv +{ +template +spmv::Matrix +create_matrix(MPI_Comm comm, const Eigen::SparseMatrix mat, + std::int64_t nrows_local, std::int64_t ncols_local, + std::vector row_ghosts, + std::vector col_ghosts) +{ + + int mpi_size, mpi_rank; + MPI_Comm_size(comm, &mpi_size); + MPI_Comm_rank(comm, &mpi_rank); + + std::vector row_ranges(mpi_size + 1, 0); + MPI_Allgather(&nrows_local, 1, MPI_INT64_T, row_ranges.data() + 1, 1, + MPI_INT64_T, comm); + for (int i = 0; i < mpi_size; ++i) + row_ranges[i + 1] += row_ranges[i]; + + // FIX: often same as rows? + std::vector col_ranges(mpi_size + 1, 0); + MPI_Allgather(&ncols_local, 1, MPI_INT64_T, col_ranges.data() + 1, 1, + MPI_INT64_T, comm); + for (int i = 0; i < mpi_size; ++i) + col_ranges[i + 1] += col_ranges[i]; + + // Locate owner process for each row + std::vector row_owner(row_ghosts.size()); + for (std::size_t i = 0; i < row_ghosts.size(); ++i) + { + auto it + = std::upper_bound(row_ranges.begin(), row_ranges.end(), row_ghosts[i]); + assert(it != row_ranges.end()); + row_owner[i] = it - row_ranges.begin() - 1; + assert(row_owner[i] != mpi_rank); + } + + // Create a neighbour comm, remap row_owner to neighbour number + std::set neighbour_set(row_owner.begin(), row_owner.end()); + std::vector dests(neighbour_set.begin(), neighbour_set.end()); + std::map proc_to_dest; + for (std::size_t i = 0; i < dests.size(); ++i) + proc_to_dest.insert({dests[i], i}); + for (auto& q : row_owner) + q = proc_to_dest[q]; + + // Get list of sources (may be different from dests, requires AlltoAll to + // find) + std::vector is_dest(mpi_size, 0); + for (int d : dests) + is_dest[d] = 1; + std::vector is_source(mpi_size, 0); + MPI_Alltoall(is_dest.data(), 1, MPI_CHAR, is_source.data(), 1, MPI_CHAR, + comm); + std::vector sources; + for (int i = 0; i < mpi_size; ++i) + if (is_source[i] == 1) + sources.push_back(i); + + MPI_Comm neighbour_comm; + MPI_Dist_graph_create_adjacent( + comm, sources.size(), sources.data(), MPI_UNWEIGHTED, dests.size(), + dests.data(), MPI_UNWEIGHTED, MPI_INFO_NULL, false, &neighbour_comm); + + // send all ghost rows to their owners, using global col idx. + const std::int32_t* Aouter = mat.outerIndexPtr(); + const std::int32_t* Ainner = mat.innerIndexPtr(); + const T* Aval = mat.valuePtr(); + + std::vector> p_to_index(dests.size()); + std::vector> p_to_val(dests.size()); + for (std::size_t i = 0; i < row_ghosts.size(); ++i) + { + const int p = row_owner[i]; + assert(p != -1); + p_to_index[p].push_back(row_ghosts[i]); + p_to_val[p].push_back(0.0); + p_to_index[p].push_back(Aouter[nrows_local + i + 1] + - Aouter[nrows_local + i]); + p_to_val[p].push_back(0.0); + + const std::int64_t local_offset = col_ranges[mpi_rank]; + for (int j = Aouter[nrows_local + i]; j < Aouter[nrows_local + i + 1]; ++j) + { + std::int64_t global_index; + if (Ainner[j] < ncols_local) + global_index = Ainner[j] + local_offset; + else + { + assert(Ainner[j] - ncols_local < (int)col_ghosts.size()); + global_index = col_ghosts[Ainner[j] - ncols_local]; + } + p_to_index[p].push_back(global_index); + p_to_val[p].push_back(Aval[j]); + } + } + + std::vector send_size(dests.size()); + std::vector send_index; + std::vector send_val; + std::vector send_offset = {0}; + for (std::size_t p = 0; p < dests.size(); ++p) + { + send_index.insert(send_index.end(), p_to_index[p].begin(), + p_to_index[p].end()); + send_val.insert(send_val.end(), p_to_val[p].begin(), p_to_val[p].end()); + assert(p_to_val[p].size() == p_to_index[p].size()); + send_size[p] = p_to_index[p].size(); + send_offset.push_back(send_index.size()); + } + + std::vector recv_size(sources.size()); + MPI_Neighbor_alltoall(send_size.data(), 1, MPI_INT, recv_size.data(), 1, + MPI_INT, neighbour_comm); + + std::vector recv_offset = {0}; + for (int r : recv_size) + recv_offset.push_back(recv_offset.back() + r); + + std::vector recv_index(recv_offset.back()); + std::vector recv_val(recv_offset.back()); + + MPI_Neighbor_alltoallv(send_index.data(), send_size.data(), + send_offset.data(), MPI_INT64_T, recv_index.data(), + recv_size.data(), recv_offset.data(), MPI_INT64_T, + neighbour_comm); + + MPI_Neighbor_alltoallv(send_val.data(), send_size.data(), send_offset.data(), + mpi_type(), recv_val.data(), recv_size.data(), + recv_offset.data(), mpi_type(), neighbour_comm); + + // Create new map from global column index to local + std::map col_ghost_map; + for (std::int64_t q : col_ghosts) + col_ghost_map.insert({q, -1}); + + // Add any new ghost columns + int pos = 0; + while (pos < (int)recv_index.size()) + { + // std::int64_t global_row = recv_index[pos]; + ++pos; + int nnz = recv_index[pos]; + ++pos; + for (int k = 0; k < nnz; ++k) + { + const std::int64_t recv_col = recv_index[pos]; + ++pos; + if (recv_col >= col_ranges[mpi_rank + 1] + or recv_col < col_ranges[mpi_rank]) + col_ghost_map.insert({recv_col, -1}); + } + } + + // Unique numbering of ghost cols + int c = ncols_local; + for (auto& q : col_ghost_map) + q.second = c++; + + std::vector> mat_data; + for (int row = 0; row < nrows_local; ++row) + for (int j = Aouter[row]; j < Aouter[row + 1]; ++j) + { + int col = Ainner[j]; + if (col >= ncols_local) + { + // Get remapped ghost column + std::int64_t global_col = col_ghosts[col - ncols_local]; + auto it = col_ghost_map.find(global_col); + assert(it != col_ghost_map.end()); + col = it->second; + assert(col >= ncols_local); + } + + assert(row >= 0 and row < nrows_local); + assert(col >= 0 and col < (int)(ncols_local + col_ghost_map.size())); + mat_data.push_back(Eigen::Triplet(row, col, Aval[j])); + } + + // Add received data + pos = 0; + while (pos < (int)recv_index.size()) + { + std::int64_t global_row = recv_index[pos]; + assert(global_row >= row_ranges[mpi_rank] + and global_row < row_ranges[mpi_rank + 1]); + std::int32_t row = global_row - row_ranges[mpi_rank]; + ++pos; + int nnz = recv_index[pos]; + ++pos; + for (int k = 0; k < nnz; ++k) + { + const std::int64_t global_col = recv_index[pos]; + const T val = recv_val[pos]; + ++pos; + int col; + if (global_col >= col_ranges[mpi_rank + 1] + or global_col < col_ranges[mpi_rank]) + { + auto it = col_ghost_map.find(global_col); + assert(it != col_ghost_map.end()); + col = it->second; + } + else + col = global_col - col_ranges[mpi_rank]; + assert(row >= 0 and row < nrows_local); + assert(col >= 0 and col < (int)(ncols_local + col_ghost_map.size())); + mat_data.push_back(Eigen::Triplet(row, col, val)); + } + } + + // Rebuild sparse matrix + std::vector new_col_ghosts; + for (auto& q : col_ghost_map) + new_col_ghosts.push_back(q.first); + + Eigen::SparseMatrix B( + nrows_local, ncols_local + new_col_ghosts.size()); + B.setFromTriplets(mat_data.begin(), mat_data.end()); + + std::shared_ptr col_map + = std::make_shared(comm, ncols_local, new_col_ghosts); + std::shared_ptr row_map = std::make_shared( + comm, nrows_local, std::vector()); + + spmv::Matrix b(B, col_map, row_map); + return b; +} +} // namespace spmv \ No newline at end of file From d7861ad02f1aaed35de1c0439ba30581155aa1be Mon Sep 17 00:00:00 2001 From: igorbaratta Date: Sun, 25 Oct 2020 16:10:01 -0300 Subject: [PATCH 09/37] add new simple demo --- demos/CMakeLists.txt | 3 +++ demos/CreateA.cpp | 27 ++++++++++++++++++++- demos/CreateA.h | 1 - demos/diagonal.cpp | 56 ++++++++++++++++++++++++++++++++++++++++++++ demos/matvecmain.cpp | 12 ++++------ spmv/Matrix.cpp | 46 +++++++++--------------------------- spmv/Matrix.h | 11 +++++---- spmv/spmv.h | 1 + 8 files changed, 109 insertions(+), 48 deletions(-) create mode 100644 demos/diagonal.cpp diff --git a/demos/CMakeLists.txt b/demos/CMakeLists.txt index d7cb691..52f40c7 100644 --- a/demos/CMakeLists.txt +++ b/demos/CMakeLists.txt @@ -7,6 +7,9 @@ target_link_libraries(vecnorm LINK_PUBLIC ${PROJECT_NAME}) add_executable(matvecmain matvecmain.cpp CreateA.cpp) target_link_libraries(matvecmain ${PROJECT_NAME}) +add_executable(diagonal diagonal.cpp CreateA.cpp) +target_link_libraries(diagonal ${PROJECT_NAME}) + # add_executable(cgmain cgmain.cpp) # target_link_libraries(cgmain LINK_PUBLIC ${PROJECT_NAME}) diff --git a/demos/CreateA.cpp b/demos/CreateA.cpp index 1f2a56e..ebaa8da 100644 --- a/demos/CreateA.cpp +++ b/demos/CreateA.cpp @@ -107,6 +107,31 @@ spmv::Matrix create_A(MPI_Comm comm, int N) } Alocal.setFromTriplets(vals.begin(), vals.end()); - return spmv::Matrix(Alocal, col_l2g, row_l2g); + std::array shape; + shape[0] = M; + shape[1] = M + ghosts.size(); + + // Get indptr buffer + Aouter = Alocal.outerIndexPtr(); + std::vector indptr(A.rows()); + std::memcpy(Aouter, indptr.data(), sizeof(std::int32_t) * indptr.size()); + auto indptr_buff + = std::make_shared>(indptr); + + // Get indices buffer + Ainner = Alocal.innerIndexPtr(); + std::vector indices(A.nonZeros()); + std::memcpy(Ainner, indices.data(), sizeof(std::int32_t) * indices.size()); + auto indices_buff + = std::make_shared>(indices); + + // Get data buffer + double* Aptr = Alocal.valuePtr(); + std::vector data(A.nonZeros()); + std::memcpy(Aptr, data.data(), sizeof(double) * data.size()); + auto data_buff = std::make_shared>(data); + + return spmv::Matrix(shape, data_buff, indptr_buff, indices_buff, + col_l2g, row_l2g); } //----------------------------------------------------------------------------- diff --git a/demos/CreateA.h b/demos/CreateA.h index 760d3d8..2dce843 100644 --- a/demos/CreateA.h +++ b/demos/CreateA.h @@ -5,7 +5,6 @@ #include -#include #include #include #include diff --git a/demos/diagonal.cpp b/demos/diagonal.cpp new file mode 100644 index 0000000..b022b28 --- /dev/null +++ b/demos/diagonal.cpp @@ -0,0 +1,56 @@ +// Copyright (C) 2020 Igor Baratta +// SPDX-License-Identifier: MIT + +#include +#include + +#include +#include +#include + +#include + +// Create diagonal matrix and multiply by vector. +int main(int argc, char** argv) +{ + MPI_Init(&argc, &argv); + MPI_Comm comm = MPI_COMM_WORLD; + + int mpi_rank, mpi_size; + MPI_Comm_rank(comm, &mpi_rank); + MPI_Comm_size(comm, &mpi_size); + + // Problem data + std::size_t size = 1000; + double diag = 4.; + + // Create local to global map (diagonal matrix, no ghosts) + auto map + = std::make_shared(comm, size, std::vector()); + + // Create data csr matrix + std::vector data(size, diag); + std::vector indptr(size + 1, 1.); + std::iota(indptr.begin(), indptr.end(), 0); + std::vector indices(size, 1.); + std::iota(indices.begin(), indices.end(), 0); + + // Create Matrix + spmv::Matrix A(data, indptr, indices, map, map); + + // Create vector data + std::vector b_data(size, 1.); + spmv::Vector b(b_data, map); + + spmv::Vector c = A * b; + + double norm = c.norm(); + if (mpi_rank == 0) + { + std::cout << "Comp Norm: " << norm << std::endl; + std::cout << "Exct Norm: " << diag * std::sqrt((double)mpi_size * size) + << std::endl; + } + + return 0; +} \ No newline at end of file diff --git a/demos/matvecmain.cpp b/demos/matvecmain.cpp index ffaa83f..d384947 100644 --- a/demos/matvecmain.cpp +++ b/demos/matvecmain.cpp @@ -69,8 +69,6 @@ void matvec_main() if (mpi_rank == 0) std::cout << "Applying matrix " << n_apply << " times\n"; - // Temporary variable - Eigen::VectorXd q(M); for (int i = 0; i < n_apply; ++i) { timer_start = std::chrono::system_clock::now(); @@ -79,14 +77,14 @@ void matvec_main() timings["2.SparseUpdate"] += (timer_end - timer_start); timer_start = std::chrono::system_clock::now(); - b = A * p; + auto c = A * p; timer_end = std::chrono::system_clock::now(); timings["3.SpMV"] += (timer_end - timer_start); - // timer_start = std::chrono::system_clock::now(); - // p = b; - // timer_end = std::chrono::system_clock::now(); - // timings["4.Copy"] += (timer_end - timer_start); + timer_start = std::chrono::system_clock::now(); + b = c; + timer_end = std::chrono::system_clock::now(); + timings["4.Copy"] += (timer_end - timer_start); } double pnorm = b.norm(); diff --git a/spmv/Matrix.cpp b/spmv/Matrix.cpp index 642f946..60f9bfa 100644 --- a/spmv/Matrix.cpp +++ b/spmv/Matrix.cpp @@ -30,45 +30,22 @@ Matrix::Matrix( } template -Matrix::Matrix(Eigen::SparseMatrix A, +Matrix::Matrix(std::vector& data, + std::vector& row_ptr, + std::vector& col_ind, std::shared_ptr col_map, std::shared_ptr row_map) + : _col_map(col_map), _row_map(row_map) { - _col_map = col_map; - _row_map = row_map; - - _shape[0] = A.rows(); - _shape[1] = A.cols(); - sycl::default_selector device_selector; _q = sycl::queue(device_selector); - std::cout << "Running on " - << _q.get_device().get_info() << "\n"; - - // Get indptr buffer - std::int32_t* Aouter = A.outerIndexPtr(); - std::vector indptr(A.rows()); - std::memcpy(Aouter, indptr.data(), sizeof(std::int32_t) * indptr.size()); - _indptr = std::make_shared>(indptr); - // Get indices buffer - std::int32_t* Ainner = A.innerIndexPtr(); - std::vector indices(A.nonZeros()); - std::memcpy(Ainner, indices.data(), sizeof(std::int32_t) * indices.size()); - _indices = std::make_shared>(indices); - - // Get data buffer - ScalarType* Aptr = A.valuePtr(); - std::vector data(A.nonZeros()); - std::memcpy(Aptr, data.data(), sizeof(ScalarType) * data.size()); - _data = std::make_shared>(data); - - cl::sycl::buffer norm{1}; - oneapi::mkl::blas::nrm2(_q, A.nonZeros(), *_data, 1, norm); - - auto acc = norm.template get_access(); - double result = acc[0]; - std::cout << Aptr[1] << std::endl; + _data = std::make_shared>(data); + _indptr = std::make_shared>(row_ptr); + _indices = std::make_shared>(col_ind); + + _shape[0] = row_map->local_size() + row_map->num_ghosts(); + _shape[1] = col_map->local_size() + col_map->num_ghosts(); mkl_init(); } @@ -79,9 +56,8 @@ Matrix::~Matrix() oneapi::mkl::sparse::release_matrix_handle(&A_onemkl); } - // Explicit instantiation -// template class spmv::Matrix; +template class spmv::Matrix; template class spmv::Matrix; // template class spmv::Matrix>; // template class spmv::Matrix>; diff --git a/spmv/Matrix.h b/spmv/Matrix.h index 0543ee7..d83ca5f 100644 --- a/spmv/Matrix.h +++ b/spmv/Matrix.h @@ -26,12 +26,13 @@ class Matrix public: Matrix(std::array shape, std::shared_ptr> data, - std::shared_ptr> indptr, - std::shared_ptr> indices, + std::shared_ptr> row_ptr, + std::shared_ptr> col_ind, std::shared_ptr col_map, std::shared_ptr row_map); - Matrix(Eigen::SparseMatrix A, + Matrix(std::vector& data, std::vector& row_ptr, + std::vector& col_ind, std::shared_ptr col_map, std::shared_ptr row_map); @@ -41,8 +42,10 @@ class Matrix /// MatVec operator for A x spmv::Vector operator*(spmv::Vector& b) const { + std::size_t ls = _row_map->local_size() + _row_map->num_ghosts(); auto y = std::make_shared>( - cl::sycl::range<1>{_shape[0]}); + cl::sycl::range<1>{ls}); + oneapi::mkl::sparse::gemv(_q, oneapi::mkl::transpose::nontrans, 1.0, A_onemkl, b.getLocalData(), 0.0, *y); return spmv::Vector(y, _row_map); diff --git a/spmv/spmv.h b/spmv/spmv.h index 721e54c..a0f25fd 100644 --- a/spmv/spmv.h +++ b/spmv/spmv.h @@ -3,5 +3,6 @@ #include "L2GMap.h" #include "Matrix.h" +#include "Vector.h" // #include "read_petsc.h" // #include "cg.h" From fbededaeafbbace98721b676057344f030efbfcb Mon Sep 17 00:00:00 2001 From: igorbaratta Date: Sun, 25 Oct 2020 17:13:49 -0300 Subject: [PATCH 10/37] add more documentation --- demos/CreateA.cpp | 14 ++-------- demos/vecnorm.cpp | 2 -- spmv/Matrix.cpp | 68 ++++++++++++++++++++++++++++++++++++----------- spmv/Matrix.h | 55 +++++++++++++++----------------------- 4 files changed, 77 insertions(+), 62 deletions(-) diff --git a/demos/CreateA.cpp b/demos/CreateA.cpp index ebaa8da..2683c95 100644 --- a/demos/CreateA.cpp +++ b/demos/CreateA.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2018-2020 Chris Richardson (chris@bpi.cam.ac.uk) +// Copyright (C) 2018-2020 Chris Richardson, Igor Baratta // SPDX-License-Identifier: MIT #include "CreateA.h" @@ -107,31 +107,21 @@ spmv::Matrix create_A(MPI_Comm comm, int N) } Alocal.setFromTriplets(vals.begin(), vals.end()); - std::array shape; - shape[0] = M; - shape[1] = M + ghosts.size(); - // Get indptr buffer Aouter = Alocal.outerIndexPtr(); std::vector indptr(A.rows()); std::memcpy(Aouter, indptr.data(), sizeof(std::int32_t) * indptr.size()); - auto indptr_buff - = std::make_shared>(indptr); // Get indices buffer Ainner = Alocal.innerIndexPtr(); std::vector indices(A.nonZeros()); std::memcpy(Ainner, indices.data(), sizeof(std::int32_t) * indices.size()); - auto indices_buff - = std::make_shared>(indices); // Get data buffer double* Aptr = Alocal.valuePtr(); std::vector data(A.nonZeros()); std::memcpy(Aptr, data.data(), sizeof(double) * data.size()); - auto data_buff = std::make_shared>(data); - return spmv::Matrix(shape, data_buff, indptr_buff, indices_buff, - col_l2g, row_l2g); + return spmv::Matrix(data, indptr, indices, col_l2g, row_l2g); } //----------------------------------------------------------------------------- diff --git a/demos/vecnorm.cpp b/demos/vecnorm.cpp index 79bbdad..717bef5 100644 --- a/demos/vecnorm.cpp +++ b/demos/vecnorm.cpp @@ -58,8 +58,6 @@ int main(int argc, char** argv) std::cout << "Computed Norm: " << norm << std::endl; std::cout << "Exact Norm: " << ex_norm * 2 << std::endl; } - - MPI_Finalize(); return 0; } \ No newline at end of file diff --git a/spmv/Matrix.cpp b/spmv/Matrix.cpp index 60f9bfa..37473b2 100644 --- a/spmv/Matrix.cpp +++ b/spmv/Matrix.cpp @@ -1,34 +1,35 @@ -// Copyright (C) 2020 Chris Richardson (chris@bpi.cam.ac.uk) and Jeffrey Salmond +// Copyright (C) 2020 Chris Richardson (chris@bpi.cam.ac.uk), Jeffrey Salmond +// and Igor Baratta // SPDX-License-Identifier: MIT +#include + #include "Matrix.h" -#include "L2GMap.h" #include "mpi_type.h" -#include -#include -#include using namespace spmv; +//----------------------------------------------------------------------------- template Matrix::Matrix( - std::array shape, std::shared_ptr> data, std::shared_ptr> indptr, std::shared_ptr> indices, std::shared_ptr col_map, std::shared_ptr row_map) - : _data(data), _indptr(indptr), _indices(indices), _shape(shape), - _col_map(col_map), _row_map(row_map) + : _data(data), _indptr(indptr), _indices(indices), _col_map(col_map), + _row_map(row_map) { sycl::default_selector device_selector; _q = sycl::queue(device_selector); - std::cout << "Running on " - << _q.get_device().get_info() << "\n"; + + _shape[0] = row_map->local_size() + row_map->num_ghosts(); + _shape[1] = col_map->local_size() + col_map->num_ghosts(); mkl_init(); } +//----------------------------------------------------------------------------- template Matrix::Matrix(std::vector& data, std::vector& row_ptr, @@ -43,21 +44,58 @@ Matrix::Matrix(std::vector& data, _data = std::make_shared>(data); _indptr = std::make_shared>(row_ptr); _indices = std::make_shared>(col_ind); - + _shape[0] = row_map->local_size() + row_map->num_ghosts(); _shape[1] = col_map->local_size() + col_map->num_ghosts(); mkl_init(); } - +//----------------------------------------------------------------------------- +template +void Matrix::mult(spmv::Vector& x, + spmv::Vector& b) const +{ + oneapi::mkl::sparse::gemv(_q, oneapi::mkl::transpose::nontrans, 1.0, A_onemkl, + x.getLocalData(), 0.0, b.getLocalData()); +}; +//----------------------------------------------------------------------------- +template +void Matrix::transpmult(spmv::Vector& x, + spmv::Vector& b) const +{ + oneapi::mkl::sparse::gemv(_q, oneapi::mkl::transpose::trans, 1.0, A_onemkl, + x.getLocalData(), 0.0, b.getLocalData()); +}; +//----------------------------------------------------------------------------- +template +spmv::Vector +Matrix::operator*(spmv::Vector& x) const +{ + std::size_t ls = _row_map->local_size() + _row_map->num_ghosts(); + auto buffer = std::make_shared>( + cl::sycl::range<1>(ls)); + spmv::Vector b(buffer, _row_map); + this->mult(x, b); + return b; +}; +//----------------------------------------------------------------------------- template Matrix::~Matrix() { oneapi::mkl::sparse::release_matrix_handle(&A_onemkl); } - +//----------------------------------------------------------------------------- +template +void Matrix::mkl_init() +{ + oneapi::mkl::sparse::init_matrix_handle(&A_onemkl); + oneapi::mkl::sparse::set_csr_data(A_onemkl, _shape[0], _shape[1], + oneapi::mkl::index_base::zero, *_indptr, + *_indices, *_data); +} +//---------------------------------------------------------------------------- // Explicit instantiation template class spmv::Matrix; template class spmv::Matrix; -// template class spmv::Matrix>; -// template class spmv::Matrix>; +template class spmv::Matrix>; +template class spmv::Matrix>; diff --git a/spmv/Matrix.h b/spmv/Matrix.h index d83ca5f..0f22d10 100644 --- a/spmv/Matrix.h +++ b/spmv/Matrix.h @@ -2,13 +2,13 @@ // SPDX-License-Identifier: MIT #include + #include #include #include #include -#include - +#include "L2GMap.h" #include "Vector.h" #pragma once @@ -22,15 +22,16 @@ class L2GMap; template class Matrix { - /// Matrix with row and column maps. + /// CSR Matrix with row and column maps. public: - Matrix(std::array shape, - std::shared_ptr> data, + /// Create sparse matrix from buffer (data may be already on device memory) + Matrix(std::shared_ptr> data, std::shared_ptr> row_ptr, std::shared_ptr> col_ind, std::shared_ptr col_map, std::shared_ptr row_map); + /// Create sparse matrix from vectors (data is still on the host memory) Matrix(std::vector& data, std::vector& row_ptr, std::vector& col_ind, std::shared_ptr col_map, @@ -40,26 +41,14 @@ class Matrix ~Matrix(); /// MatVec operator for A x - spmv::Vector operator*(spmv::Vector& b) const - { - std::size_t ls = _row_map->local_size() + _row_map->num_ghosts(); - auto y = std::make_shared>( - cl::sycl::range<1>{ls}); - - oneapi::mkl::sparse::gemv(_q, oneapi::mkl::transpose::nontrans, 1.0, - A_onemkl, b.getLocalData(), 0.0, *y); - return spmv::Vector(y, _row_map); - }; - - /// MatVec operator for A^T x - spmv::Vector transpmult(spmv::Vector& b) const - { - auto y = std::make_shared>( - cl::sycl::range<1>{_shape[0]}); - oneapi::mkl::sparse::gemv(_q, oneapi::mkl::transpose::trans, 1.0, A_onemkl, - b.getLocalData(), 0.0, *y); - return spmv::Vector(y, _row_map); - }; + spmv::Vector operator*(spmv::Vector& x) const; + + /// MatVec operator for b = A x + void mult(spmv::Vector& x, spmv::Vector& b) const; + + /// MatVec operator for b = A^T x + void transpmult(spmv::Vector& x, + spmv::Vector& b) const; /// Row mapping (local-to-global). Usually, there will not be ghost rows. std::shared_ptr row_map() const { return _row_map; } @@ -68,24 +57,24 @@ class Matrix std::shared_ptr col_map() const { return _col_map; } private: - void mkl_init() - { - oneapi::mkl::sparse::init_matrix_handle(&A_onemkl); - oneapi::mkl::sparse::set_csr_data(A_onemkl, _shape[0], _shape[1], - oneapi::mkl::index_base::zero, *_indptr, - *_indices, *_data); - } + void mkl_init(); mutable cl::sycl::queue _q; oneapi::mkl::sparse::matrix_handle_t A_onemkl; + /// CSR format data buffer of the matrix std::shared_ptr> _data; + + /// CSR format row pointer buffer of the matrix std::shared_ptr> _indptr; + + /// CSR format column indices buffer of the matrix std::shared_ptr> _indices; + /// Shape of the local sparse matrix std::array _shape; - // Column and Row maps: usually _row_map will not have ghosts. + /// Column and Row maps: usually _row_map will not have ghosts. std::shared_ptr _col_map; std::shared_ptr _row_map; }; From a9c6768657b175f8a3af97bf25e51512c56049a0 Mon Sep 17 00:00:00 2001 From: igorbaratta Date: Sun, 25 Oct 2020 17:59:44 -0300 Subject: [PATCH 11/37] separate api and implementation --- spmv/CMakeLists.txt | 2 +- spmv/Matrix.h | 9 ++- spmv/Vector.cpp | 131 ++++++++++++++++++++++++++++++++++++++++++++ spmv/Vector.h | 69 ++++------------------- 4 files changed, 151 insertions(+), 60 deletions(-) create mode 100644 spmv/Vector.cpp diff --git a/spmv/CMakeLists.txt b/spmv/CMakeLists.txt index 349f167..72abea5 100644 --- a/spmv/CMakeLists.txt +++ b/spmv/CMakeLists.txt @@ -1,6 +1,6 @@ set(CMAKE_BUILD_WITH_INSTALL_RPATH ON) -add_library(${PROJECT_NAME} SHARED L2GMap.cpp Matrix.cpp read_petsc.cpp cg.cpp) +add_library(${PROJECT_NAME} SHARED L2GMap.cpp Matrix.cpp Vector.cpp read_petsc.cpp cg.cpp) target_include_directories (${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) target_include_directories (${PROJECT_NAME} INTERFACE $) # Target libraries diff --git a/spmv/Matrix.h b/spmv/Matrix.h index 0f22d10..ac3b5b1 100644 --- a/spmv/Matrix.h +++ b/spmv/Matrix.h @@ -24,14 +24,16 @@ class Matrix { /// CSR Matrix with row and column maps. public: - /// Create sparse matrix from buffer (data may be already on device memory) + /// Create distributed sparse matrix from buffers and local-to-global maps + /// (data might be on the device memory) Matrix(std::shared_ptr> data, std::shared_ptr> row_ptr, std::shared_ptr> col_ind, std::shared_ptr col_map, std::shared_ptr row_map); - /// Create sparse matrix from vectors (data is still on the host memory) + /// Create distributed sparse matrix from vectors and local-to-global maps + /// (data is still on the host memory) Matrix(std::vector& data, std::vector& row_ptr, std::vector& col_ind, std::shared_ptr col_map, @@ -56,6 +58,9 @@ class Matrix /// Column mapping (local-to-global) std::shared_ptr col_map() const { return _col_map; } + /// Set queue to submit work (indirectly defines the device in each rank) + void set_queue(cl::sycl::queue q) { _q = q; } + private: void mkl_init(); diff --git a/spmv/Vector.cpp b/spmv/Vector.cpp new file mode 100644 index 0000000..639867e --- /dev/null +++ b/spmv/Vector.cpp @@ -0,0 +1,131 @@ +// Copyright (C) 2020 Igor Baratta (ia397@cam.ac.uk) +// SPDX-License-Identifier: MIT + +#include + +#include "Vector.h" +#include "mpi_type.h" + +using namespace spmv; + +//----------------------------------------------------------------------------- +template +Vector::Vector( + std::shared_ptr> data, + std::shared_ptr map) + : _data(data), _map(map) +{ + cl::sycl::default_selector device_selector; + _q = sycl::queue(device_selector); + + std::size_t ls = _map->local_size() + _map->num_ghosts(); + if (ls != _data->get_size()) + std::runtime_error("Size mismatch"); +} + +//----------------------------------------------------------------------------- +template +Vector::Vector(std::vector& vec, + std::shared_ptr map) + : _map(map) +{ + cl::sycl::default_selector device_selector; + _q = sycl::queue(device_selector); + _data = std::make_shared>(vec); + + std::size_t ls = _map->local_size() + _map->num_ghosts(); + if (ls != _data->get_size()) + std::runtime_error("Size mismatch"); +} +//---------------------------------------------------------------------------- +template +Vector& Vector::operator*=(ScalarType alpha) +{ + std::size_t ls = _map->local_size() + _map->num_ghosts(); + oneapi::mkl::blas::scal(_q, ls, alpha, *_data, 1); + return *this; +} +//---------------------------------------------------------------------------- +template +Vector& Vector::operator+=(Vector& other) +{ + oneapi::mkl::blas::axpy(_q, local_size(), 1.0, other.getLocalData(), 1, + *_data, 1); + return *this; +} +//---------------------------------------------------------------------------- +template +Vector& Vector::operator-=(Vector& other) +{ + oneapi::mkl::blas::axpy(_q, local_size(), -1.0, other.getLocalData(), 1, + *_data, 1); + return *this; +} +//---------------------------------------------------------------------------- +template +Vector& Vector::operator+(Vector& other) +{ + auto buffer = std::make_shared>(*_data); + spmv::Vector out(buffer, _map); + return out += other; +} + +//---------------------------------------------------------------------------- +template +double Vector::dot(spmv::Vector& y) const +{ + cl::sycl::buffer res{1}; + oneapi::mkl::blas::dot(_q, _map->local_size(), *_data, 1, y.getLocalData(), 1, + res); + auto acc = res.template get_access(); + MPI_Comm comm = _map->comm(); + + double local_sum = acc[0]; + double global_sum{-1.0}; + + auto data_type = spmv::mpi_type(); + MPI_Allreduce(&local_sum, &global_sum, 1, data_type, MPI_SUM, comm); + return global_sum; +}; +//---------------------------------------------------------------------------- +template <> +double +Vector>::dot(spmv::Vector>& y) const +{ + cl::sycl::buffer, 1> res{1}; + oneapi::mkl::blas::dotc(_q, _map->local_size(), *_data, 1, y.getLocalData(), + 1, res); + auto acc = res.template get_access(); + MPI_Comm comm = _map->comm(); + + double local_sum = acc[0].real(); + double global_sum{-1.0}; + + auto data_type = spmv::mpi_type(); + MPI_Allreduce(&local_sum, &global_sum, 1, data_type, MPI_SUM, comm); + return global_sum; +}; +//---------------------------------------------------------------------------- +template <> +double +Vector>::dot(spmv::Vector>& y) const +{ + cl::sycl::buffer, 1> res{1}; + oneapi::mkl::blas::dotc(_q, _map->local_size(), *_data, 1, y.getLocalData(), + 1, res); + auto acc = res.template get_access(); + MPI_Comm comm = _map->comm(); + + double local_sum = acc[0].real(); + double global_sum{-1.0}; + + auto data_type = spmv::mpi_type(); + MPI_Allreduce(&local_sum, &global_sum, 1, data_type, MPI_SUM, comm); + return global_sum; +}; +//---------------------------------------------------------------------------- +// Explicit instantiation +template class spmv::Vector; +template class spmv::Vector; +template class spmv::Vector>; +template class spmv::Vector>; \ No newline at end of file diff --git a/spmv/Vector.h b/spmv/Vector.h index eb3f7ca..c03cf8c 100644 --- a/spmv/Vector.h +++ b/spmv/Vector.h @@ -12,77 +12,32 @@ namespace spmv { -template +template class Vector { public: + /// Create Distributed Vector using data buffers and local-to-global map (data + /// might be on device memory) Vector(std::shared_ptr> data, - std::shared_ptr map) - : _data(data), _map(map) - { - DeviceSelector device_selector; - _q = sycl::queue(device_selector); + std::shared_ptr map); - if (_map->local_size() != _data->get_size()) - std::runtime_error("Size mismatch"); - }; - - Vector(std::vector& vec, std::shared_ptr map) - : _map(map) - { - DeviceSelector device_selector; - _q = sycl::queue(device_selector); - _data = std::make_shared>(vec); - } + /// Create Distributed Vector using data on host and a local-to-global map + Vector(std::vector& vec, std::shared_ptr map); std::int32_t local_size() const { return _map->local_size(); } cl::sycl::buffer& getLocalData() { return *_data; }; - /// Computes the product of a vector by a scalar. - Vector& operator*=(ScalarType alpha) - { - std::size_t ls = _map->local_size() + _map->num_ghosts(); - oneapi::mkl::blas::scal(_q, ls, alpha, *_data, 1); - return *this; - } - - Vector& operator+=(Vector& other) - { - oneapi::mkl::blas::axpy(_q, local_size(), 1.0, other.getLocalData(), 1, - *_data, 1); - return *this; - } + /// Computes the product of the vector by a scalar. + Vector& operator*=(ScalarType alpha); - Vector& operator-=(Vector& other) - { - oneapi::mkl::blas::axpy(_q, local_size(), -1.0, other.getLocalData(), 1, - *_data, 1); - return *this; - } + Vector& operator+=(Vector& other); - Vector& operator+(Vector& other) - { - auto buffer = std::make_shared>(*_data); - spmv::Vector out(buffer, _map); - return out += other; - } + Vector& operator-=(Vector& other); - double dot(spmv::Vector& y) - { - cl::sycl::buffer res{1}; - oneapi::mkl::blas::dot(_q, _map->local_size(), *_data, 1, y.getLocalData(), - 1, res); - auto acc = res.template get_access(); - MPI_Comm comm = _map->comm(); - double local_sum = acc[0]; - double global_sum{-1.0}; + Vector& operator+(Vector& other); - auto data_type = spmv::mpi_type(); - MPI_Allreduce(&local_sum, &global_sum, 1, data_type, MPI_SUM, comm); - return global_sum; - }; + double dot(spmv::Vector& y) const; /// Computes the vector 2 norm (Euclidean norm). double norm() { return std::sqrt(this->dot(*this)); } From d8e4a993a9fd67d46c663a75dbba11a83ea92e0a Mon Sep 17 00:00:00 2001 From: igorbaratta Date: Sun, 25 Oct 2020 23:34:04 -0300 Subject: [PATCH 12/37] fix mat mult mkl --- demos/CreateA.cpp | 9 +++++---- demos/matvecmain.cpp | 17 ++++++++--------- spmv/Matrix.cpp | 7 +++++++ spmv/Vector.cpp | 1 + spmv/Vector.h | 1 - spmv/cg.h | 8 +++++--- 6 files changed, 26 insertions(+), 17 deletions(-) diff --git a/demos/CreateA.cpp b/demos/CreateA.cpp index 2683c95..4a84c77 100644 --- a/demos/CreateA.cpp +++ b/demos/CreateA.cpp @@ -106,21 +106,22 @@ spmv::Matrix create_A(MPI_Comm comm, int N) } } Alocal.setFromTriplets(vals.begin(), vals.end()); + Alocal.makeCompressed(); // Get indptr buffer Aouter = Alocal.outerIndexPtr(); - std::vector indptr(A.rows()); - std::memcpy(Aouter, indptr.data(), sizeof(std::int32_t) * indptr.size()); + std::vector indptr(A.rows() + 1); + std::memcpy(indptr.data(), Aouter, sizeof(std::int32_t) * indptr.size()); // Get indices buffer Ainner = Alocal.innerIndexPtr(); std::vector indices(A.nonZeros()); - std::memcpy(Ainner, indices.data(), sizeof(std::int32_t) * indices.size()); + std::memcpy(indices.data(), Ainner, sizeof(std::int32_t) * indices.size()); // Get data buffer double* Aptr = Alocal.valuePtr(); std::vector data(A.nonZeros()); - std::memcpy(Aptr, data.data(), sizeof(double) * data.size()); + std::memcpy(data.data(), Aptr, sizeof(double) * data.size()); return spmv::Matrix(data, indptr, indices, col_l2g, row_l2g); } diff --git a/demos/matvecmain.cpp b/demos/matvecmain.cpp index d384947..98007b5 100644 --- a/demos/matvecmain.cpp +++ b/demos/matvecmain.cpp @@ -13,7 +13,6 @@ #include #include #include -// #include void matvec_main() { @@ -36,10 +35,6 @@ void matvec_main() std::int64_t M = A.row_map()->local_size(); std::int64_t N = l2g->global_size(); - // Create Distributed vector - std::vector b_data(M); - spmv::Vector b(b_data, l2g); - auto timer_end = std::chrono::system_clock::now(); timings["0.MatCreate"] += (timer_end - timer_start); @@ -72,22 +67,26 @@ void matvec_main() for (int i = 0; i < n_apply; ++i) { timer_start = std::chrono::system_clock::now(); - // l2g->update(psp.data()); + { + auto p_buffer = p.getLocalData(); + auto pacc = p_buffer.get_access(); + l2g->update(static_cast(pacc.get_pointer())); + } timer_end = std::chrono::system_clock::now(); timings["2.SparseUpdate"] += (timer_end - timer_start); timer_start = std::chrono::system_clock::now(); - auto c = A * p; + A.mult(p, p); timer_end = std::chrono::system_clock::now(); timings["3.SpMV"] += (timer_end - timer_start); timer_start = std::chrono::system_clock::now(); - b = c; + auto c = p; timer_end = std::chrono::system_clock::now(); timings["4.Copy"] += (timer_end - timer_start); } - double pnorm = b.norm(); + double pnorm = p.norm(); if (mpi_rank == 0) std::cout << "\nTimings (" << mpi_size diff --git a/spmv/Matrix.cpp b/spmv/Matrix.cpp index 37473b2..393cfba 100644 --- a/spmv/Matrix.cpp +++ b/spmv/Matrix.cpp @@ -4,6 +4,8 @@ #include +#include "mkl_spblas_sycl.hpp" + #include "Matrix.h" #include "mpi_type.h" @@ -41,6 +43,9 @@ Matrix::Matrix(std::vector& data, sycl::default_selector device_selector; _q = sycl::queue(device_selector); + std::cout << "Running on " + << _q.get_device().get_info() << "\n"; + _data = std::make_shared>(data); _indptr = std::make_shared>(row_ptr); _indices = std::make_shared>(col_ind); @@ -92,6 +97,8 @@ void Matrix::mkl_init() oneapi::mkl::sparse::set_csr_data(A_onemkl, _shape[0], _shape[1], oneapi::mkl::index_base::zero, *_indptr, *_indices, *_data); + oneapi::mkl::sparse::optimize_gemv(_q, oneapi::mkl::transpose::nontrans, + A_onemkl); } //---------------------------------------------------------------------------- // Explicit instantiation diff --git a/spmv/Vector.cpp b/spmv/Vector.cpp index 639867e..664f9e2 100644 --- a/spmv/Vector.cpp +++ b/spmv/Vector.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2020 Igor Baratta (ia397@cam.ac.uk) // SPDX-License-Identifier: MIT +#include #include #include "Vector.h" diff --git a/spmv/Vector.h b/spmv/Vector.h index c03cf8c..2d8a7e7 100644 --- a/spmv/Vector.h +++ b/spmv/Vector.h @@ -5,7 +5,6 @@ #include #include -#include #include "L2GMap.h" #include "mpi_type.h" diff --git a/spmv/cg.h b/spmv/cg.h index b02601d..8cc83b5 100644 --- a/spmv/cg.h +++ b/spmv/cg.h @@ -11,6 +11,9 @@ namespace spmv template class Matrix; +template +class Vector; + /// @brief Solve **A.x=b** iteratively with Conjugate Gradient /// /// Input @@ -22,8 +25,7 @@ class Matrix; /// /// @return tuple of result **x** and number of iterations /// -std::tuple, int> -cg(MPI_Comm comm, const Matrix& A, - const cl::sycl::buffer& b, int max_its, double rtol); +std::tuple, int> cg(MPI_Comm comm, const Matrix& A, + Vector& b, int max_its, double rtol); } // namespace spmv From 3a60a6d89b1fc15bea3b8e1d0d5238c680a225d5 Mon Sep 17 00:00:00 2001 From: igorbaratta Date: Sun, 25 Oct 2020 23:43:37 -0300 Subject: [PATCH 13/37] try to fix tests --- .github/workflows/ccpp.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index ee993c4..b971931 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -9,8 +9,8 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Install Eigen3 - run: sudo apt install -y libmpich-dev libeigen3-dev + - name: Install Dependencies + run: sudo apt install -y libmpich-dev libeigen3-dev intel-basekit - name: cmake run: cmake . - name: make From 854b9b167986661b25d7a480d746ca300ed9d382 Mon Sep 17 00:00:00 2001 From: igorbaratta Date: Sun, 25 Oct 2020 23:47:19 -0300 Subject: [PATCH 14/37] add docker intel base kit --- .github/workflows/ccpp.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index b971931..8906da4 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -5,12 +5,12 @@ on: [push] jobs: build: - runs-on: ubuntu-latest + runs-on: intel/oneapi-basekit steps: - uses: actions/checkout@v2 - name: Install Dependencies - run: sudo apt install -y libmpich-dev libeigen3-dev intel-basekit + run: sudo apt install -y libmpich-dev libeigen3-dev - name: cmake run: cmake . - name: make From f8bf94acd60dbb877e1b1302862e36876a919d9a Mon Sep 17 00:00:00 2001 From: igorbaratta Date: Mon, 26 Oct 2020 09:51:53 -0300 Subject: [PATCH 15/37] use intel docker container --- .github/workflows/ccpp.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 8906da4..86a0bff 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -5,7 +5,8 @@ on: [push] jobs: build: - runs-on: intel/oneapi-basekit + runs-on: ubuntu-20.04 + container: intel/oneapi-basekit steps: - uses: actions/checkout@v2 From 060f84c86e9ae1ddf6c853e26d72a55c134786ce Mon Sep 17 00:00:00 2001 From: igorbaratta Date: Mon, 26 Oct 2020 10:32:12 -0300 Subject: [PATCH 16/37] revert some changes --- .github/workflows/ccpp.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 86a0bff..098ada1 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -6,7 +6,6 @@ jobs: build: runs-on: ubuntu-20.04 - container: intel/oneapi-basekit steps: - uses: actions/checkout@v2 From 677554e7219362646f9102a68eadce16a9526476 Mon Sep 17 00:00:00 2001 From: igorbaratta Date: Mon, 26 Oct 2020 10:43:12 -0300 Subject: [PATCH 17/37] install oneapi - github actions --- .github/workflows/ccpp.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 098ada1..7e89a74 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -10,7 +10,16 @@ jobs: steps: - uses: actions/checkout@v2 - name: Install Dependencies - run: sudo apt install -y libmpich-dev libeigen3-dev + run: | + sudo apt install -y libmpich-dev libeigen3-dev wget gnupg2 + wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB + sudo apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB + rm GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB + echo "deb https://apt.repos.intel.com/oneapi all main" | sudo tee /etc/apt/sources.list.d/oneAPI.list + sudo add-apt-repository "deb https://apt.repos.intel.com/oneapi all main" + sudo apt-get update + sudo apt-get install -y intel-basekit + - name: cmake run: cmake . - name: make From 3a9643d72b64f870550951f3b3b640465cd11be1 Mon Sep 17 00:00:00 2001 From: igorbaratta Date: Mon, 26 Oct 2020 11:48:36 -0300 Subject: [PATCH 18/37] use clang12 compiler --- .github/workflows/ccpp.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 7e89a74..ce6081b 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -21,7 +21,10 @@ jobs: sudo apt-get install -y intel-basekit - name: cmake - run: cmake . + run: | + source /opt/intel/oneapi/setvars.sh + export CXX=clang++ + cmake . - name: make run: make - name: Run with 2 processes From 30761f05628965b220e09c71dec3e1cf151b8fe6 Mon Sep 17 00:00:00 2001 From: igorbaratta Date: Mon, 26 Oct 2020 16:36:57 -0300 Subject: [PATCH 19/37] few improvements --- demos/CMakeLists.txt | 2 +- demos/diagonal.cpp | 54 +++++++++++++++++++++++++++++++++++++------- spmv/L2GMap.h | 2 +- spmv/Matrix.cpp | 3 --- spmv/Vector.h | 3 +++ 5 files changed, 51 insertions(+), 13 deletions(-) diff --git a/demos/CMakeLists.txt b/demos/CMakeLists.txt index 52f40c7..e9409d8 100644 --- a/demos/CMakeLists.txt +++ b/demos/CMakeLists.txt @@ -7,7 +7,7 @@ target_link_libraries(vecnorm LINK_PUBLIC ${PROJECT_NAME}) add_executable(matvecmain matvecmain.cpp CreateA.cpp) target_link_libraries(matvecmain ${PROJECT_NAME}) -add_executable(diagonal diagonal.cpp CreateA.cpp) +add_executable(diagonal diagonal.cpp) target_link_libraries(diagonal ${PROJECT_NAME}) # add_executable(cgmain cgmain.cpp) diff --git a/demos/diagonal.cpp b/demos/diagonal.cpp index b022b28..210f664 100644 --- a/demos/diagonal.cpp +++ b/demos/diagonal.cpp @@ -16,17 +16,20 @@ int main(int argc, char** argv) MPI_Init(&argc, &argv); MPI_Comm comm = MPI_COMM_WORLD; + // Problem data + std::size_t size = 50000; + std::size_t n_apply = 100; + double diag = 4.; + + // Keep list of timings + std::map> timings; + int mpi_rank, mpi_size; MPI_Comm_rank(comm, &mpi_rank); MPI_Comm_size(comm, &mpi_size); - // Problem data - std::size_t size = 1000; - double diag = 4.; - // Create local to global map (diagonal matrix, no ghosts) - auto map - = std::make_shared(comm, size, std::vector()); + auto map = std::make_shared(comm, size); // Create data csr matrix std::vector data(size, diag); @@ -42,12 +45,47 @@ int main(int argc, char** argv) std::vector b_data(size, 1.); spmv::Vector b(b_data, map); - spmv::Vector c = A * b; + if (mpi_rank == 0) + std::cout << "Applying matrix " << n_apply << " times\n"; + + std::vector c_data(size, 0.0); + spmv::Vector c(c_data, map); + + for (std::size_t i = 0; i < n_apply; i++) + { + auto timer_start = std::chrono::system_clock::now(); + c = A * b; + auto timer_end = std::chrono::system_clock::now(); + timings["1.Mult w/ Alloc"] += (timer_end - timer_start); + + timer_start = std::chrono::system_clock::now(); + A.mult(b, c); + timer_end = std::chrono::system_clock::now(); + timings["2.Mult w/o Alloc"] += (timer_end - timer_start); + } + + if (mpi_rank == 0) + std::cout << "\nTimings (" << mpi_size + << ")\n----------------------------\n"; + + for (auto q : timings) + { + double q_local = q.second.count(), q_max, q_min; + MPI_Reduce(&q_local, &q_max, 1, MPI_DOUBLE, MPI_MAX, 0, MPI_COMM_WORLD); + MPI_Reduce(&q_local, &q_min, 1, MPI_DOUBLE, MPI_MIN, 0, MPI_COMM_WORLD); + + if (mpi_rank == 0) + { + std::string pad(32 - q.first.size(), ' '); + std::cout << "[" << q.first << "]" << pad << q_min << '\t' << q_max + << "\n"; + } + } double norm = c.norm(); if (mpi_rank == 0) { - std::cout << "Comp Norm: " << norm << std::endl; + std::cout << "\nComp Norm: " << norm << std::endl; std::cout << "Exct Norm: " << diag * std::sqrt((double)mpi_size * size) << std::endl; } diff --git a/spmv/L2GMap.h b/spmv/L2GMap.h index c011b91..ac0cabd 100644 --- a/spmv/L2GMap.h +++ b/spmv/L2GMap.h @@ -26,7 +26,7 @@ class L2GMap /// @param ghosts Ghost indices, owned by other processes. /// Ghosts must be sorted in ascending order. L2GMap(MPI_Comm comm, std::int64_t local_size, - const std::vector& ghosts); + const std::vector& ghosts = {}); // Destructor destroys neighbour comm ~L2GMap(); diff --git a/spmv/Matrix.cpp b/spmv/Matrix.cpp index 393cfba..689e1c6 100644 --- a/spmv/Matrix.cpp +++ b/spmv/Matrix.cpp @@ -43,9 +43,6 @@ Matrix::Matrix(std::vector& data, sycl::default_selector device_selector; _q = sycl::queue(device_selector); - std::cout << "Running on " - << _q.get_device().get_info() << "\n"; - _data = std::make_shared>(data); _indptr = std::make_shared>(row_ptr); _indices = std::make_shared>(col_ind); diff --git a/spmv/Vector.h b/spmv/Vector.h index 2d8a7e7..355a4ba 100644 --- a/spmv/Vector.h +++ b/spmv/Vector.h @@ -23,6 +23,9 @@ class Vector /// Create Distributed Vector using data on host and a local-to-global map Vector(std::vector& vec, std::shared_ptr map); + /// Set queue to submit work (indirectly defines the device in each rank) + void set_queue(cl::sycl::queue q) { _q = q; } + std::int32_t local_size() const { return _map->local_size(); } cl::sycl::buffer& getLocalData() { return *_data; }; From c755b25215d929621a44412710478546d6937838 Mon Sep 17 00:00:00 2001 From: igorbaratta Date: Mon, 26 Oct 2020 23:18:55 -0300 Subject: [PATCH 20/37] reenable some functionalities --- demos/CMakeLists.txt | 16 +- demos/diagonal.cpp | 2 +- demos/petsc_mat_poisson | Bin 0 -> 92704 bytes demos/petsc_vec_poisson | Bin 0 -> 8720 bytes demos/restrictmain.cpp | 190 +++++++------- spmv/read_petsc.cpp | 541 +++++++++++++++++++++------------------- spmv/read_petsc.h | 6 +- 7 files changed, 391 insertions(+), 364 deletions(-) create mode 100644 demos/petsc_mat_poisson create mode 100644 demos/petsc_vec_poisson diff --git a/demos/CMakeLists.txt b/demos/CMakeLists.txt index e9409d8..80a1473 100644 --- a/demos/CMakeLists.txt +++ b/demos/CMakeLists.txt @@ -1,4 +1,3 @@ - # Executables add_executable(vecnorm vecnorm.cpp) @@ -10,8 +9,15 @@ target_link_libraries(matvecmain ${PROJECT_NAME}) add_executable(diagonal diagonal.cpp) target_link_libraries(diagonal ${PROJECT_NAME}) -# add_executable(cgmain cgmain.cpp) -# target_link_libraries(cgmain LINK_PUBLIC ${PROJECT_NAME}) +add_executable(cgmain cgmain.cpp) +target_link_libraries(cgmain LINK_PUBLIC ${PROJECT_NAME}) + +add_executable(restrictmain restrictmain.cpp) +target_link_libraries(restrictmain ${PROJECT_NAME}) + +# Copy files matrix and vector files to binary dir +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/petsc_mat_poisson + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) -# add_executable(restrictmain restrictmain.cpp) -# target_link_libraries(restrictmain ${PROJECT_NAME}) +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/petsc_vec_poisson + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) \ No newline at end of file diff --git a/demos/diagonal.cpp b/demos/diagonal.cpp index 210f664..7140f6d 100644 --- a/demos/diagonal.cpp +++ b/demos/diagonal.cpp @@ -31,7 +31,7 @@ int main(int argc, char** argv) // Create local to global map (diagonal matrix, no ghosts) auto map = std::make_shared(comm, size); - // Create data csr matrix + // Create diagonal csr matrix data std::vector data(size, diag); std::vector indptr(size + 1, 1.); std::iota(indptr.begin(), indptr.end(), 0); diff --git a/demos/petsc_mat_poisson b/demos/petsc_mat_poisson new file mode 100644 index 0000000000000000000000000000000000000000..94c46e39943e2e9839264059bbcef0baa58220f7 GIT binary patch literal 92704 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 HoIm~#6s(|I literal 0 HcmV?d00001 diff --git a/demos/restrictmain.cpp b/demos/restrictmain.cpp index 7e1addc..aa7f089 100644 --- a/demos/restrictmain.cpp +++ b/demos/restrictmain.cpp @@ -1,7 +1,8 @@ // Copyright (C) 2018-2020 Chris Richardson (chris@bpi.cam.ac.uk) // SPDX-License-Identifier: MIT -#include +#include + #include #include #include @@ -24,99 +25,100 @@ void restrict_main() auto timer_start = std::chrono::system_clock::now(); // Read in a PETSc binary format matrix - auto R = spmv::read_petsc_binary(MPI_COMM_WORLD, "R4.dat"); - auto q = spmv::read_petsc_binary_vector(MPI_COMM_WORLD, "b4.dat"); - - // Get local and global sizes - std::int64_t M = R.mat().rows(); - auto l2g = R.col_map(); - std::int64_t N = l2g->global_size(); - - std::cout << "Vector = " << q.size() << " " << M << "\n"; - - auto timer_end = std::chrono::system_clock::now(); - timings["0.PetscRead"] += (timer_end - timer_start); - - timer_start = std::chrono::system_clock::now(); - - if (mpi_rank == 0) - std::cout << "Creating vector of size " << N << "\n"; - - // Vector in "column space" with extra space for ghosts at end - Eigen::VectorXd psp(l2g->local_size() + l2g->num_ghosts()); - - timer_end = std::chrono::system_clock::now(); - timings["1.VecCreate"] += (timer_end - timer_start); - - // Apply matrix - if (mpi_rank == 0) - std::cout << "Applying matrix\n"; - - double pnorm_sum, qnorm_sum; - for (int i = 0; i < 10; ++i) - { - // Restrict - timer_start = std::chrono::system_clock::now(); - psp = R.transpmult(q); - - timer_end = std::chrono::system_clock::now(); - timings["3.SpMV"] += (timer_end - timer_start); - - timer_start = std::chrono::system_clock::now(); - l2g->reverse_update(psp.data()); - timer_end = std::chrono::system_clock::now(); - timings["2.SparseUpdate"] += (timer_end - timer_start); - - Eigen::Map p(psp.data(), l2g->local_size()); - double pnorm = p.squaredNorm(); - MPI_Allreduce(&pnorm, &pnorm_sum, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - - // Prolongate - timer_start = std::chrono::system_clock::now(); - l2g->update(psp.data()); - timer_end = std::chrono::system_clock::now(); - timings["2.SparseUpdate"] += (timer_end - timer_start); - - timer_start = std::chrono::system_clock::now(); - q = R * psp; - - timer_end = std::chrono::system_clock::now(); - timings["3.SpMV"] += (timer_end - timer_start); - - double qnorm = q.squaredNorm(); - MPI_Allreduce(&qnorm, &qnorm_sum, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - } - - if (mpi_rank == 0) - std::cout << "\nTimings (" << mpi_size - << ")\n----------------------------\n"; - - std::chrono::duration total_time - = std::chrono::duration::zero(); - for (auto q : timings) - total_time += q.second; - timings["Total"] = total_time; - - for (auto q : timings) - { - double q_local = q.second.count(), q_max, q_min; - MPI_Reduce(&q_local, &q_max, 1, MPI_DOUBLE, MPI_MAX, 0, MPI_COMM_WORLD); - MPI_Reduce(&q_local, &q_min, 1, MPI_DOUBLE, MPI_MIN, 0, MPI_COMM_WORLD); - - if (mpi_rank == 0) - { - std::string pad(16 - q.first.size(), ' '); - std::cout << "[" << q.first << "]" << pad << q_min << '\t' << q_max - << "\n"; - } - } - - if (mpi_rank == 0) - { - std::cout << "----------------------------\n"; - std::cout << "norm q = " << qnorm_sum << "\n"; - std::cout << "norm p = " << pnorm_sum << "\n"; - } + auto R = spmv::read_petsc_binary(MPI_COMM_WORLD, "binaryoutput"); + +// auto q = spmv::read_petsc_binary_vector(MPI_COMM_WORLD, "b4.dat"); + + // // Get local and global sizes + // std::int64_t M = R.mat().rows(); + // auto l2g = R.col_map(); + // std::int64_t N = l2g->global_size(); + + // std::cout << "Vector = " << q.size() << " " << M << "\n"; + + // auto timer_end = std::chrono::system_clock::now(); + // timings["0.PetscRead"] += (timer_end - timer_start); + + // timer_start = std::chrono::system_clock::now(); + + // if (mpi_rank == 0) + // std::cout << "Creating vector of size " << N << "\n"; + + // // Vector in "column space" with extra space for ghosts at end + // Eigen::VectorXd psp(l2g->local_size() + l2g->num_ghosts()); + + // timer_end = std::chrono::system_clock::now(); + // timings["1.VecCreate"] += (timer_end - timer_start); + + // // Apply matrix + // if (mpi_rank == 0) + // std::cout << "Applying matrix\n"; + + // double pnorm_sum, qnorm_sum; + // for (int i = 0; i < 10; ++i) + // { + // // Restrict + // timer_start = std::chrono::system_clock::now(); + // psp = R.transpmult(q); + + // timer_end = std::chrono::system_clock::now(); + // timings["3.SpMV"] += (timer_end - timer_start); + + // timer_start = std::chrono::system_clock::now(); + // l2g->reverse_update(psp.data()); + // timer_end = std::chrono::system_clock::now(); + // timings["2.SparseUpdate"] += (timer_end - timer_start); + + // Eigen::Map p(psp.data(), l2g->local_size()); + // double pnorm = p.squaredNorm(); + // MPI_Allreduce(&pnorm, &pnorm_sum, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + + // // Prolongate + // timer_start = std::chrono::system_clock::now(); + // l2g->update(psp.data()); + // timer_end = std::chrono::system_clock::now(); + // timings["2.SparseUpdate"] += (timer_end - timer_start); + + // timer_start = std::chrono::system_clock::now(); + // q = R * psp; + + // timer_end = std::chrono::system_clock::now(); + // timings["3.SpMV"] += (timer_end - timer_start); + + // double qnorm = q.squaredNorm(); + // MPI_Allreduce(&qnorm, &qnorm_sum, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + // } + + // if (mpi_rank == 0) + // std::cout << "\nTimings (" << mpi_size + // << ")\n----------------------------\n"; + + // std::chrono::duration total_time + // = std::chrono::duration::zero(); + // for (auto q : timings) + // total_time += q.second; + // timings["Total"] = total_time; + + // for (auto q : timings) + // { + // double q_local = q.second.count(), q_max, q_min; + // MPI_Reduce(&q_local, &q_max, 1, MPI_DOUBLE, MPI_MAX, 0, MPI_COMM_WORLD); + // MPI_Reduce(&q_local, &q_min, 1, MPI_DOUBLE, MPI_MIN, 0, MPI_COMM_WORLD); + + // if (mpi_rank == 0) + // { + // std::string pad(16 - q.first.size(), ' '); + // std::cout << "[" << q.first << "]" << pad << q_min << '\t' << q_max + // << "\n"; + // } + // } + + // if (mpi_rank == 0) + // { + // std::cout << "----------------------------\n"; + // std::cout << "norm q = " << qnorm_sum << "\n"; + // std::cout << "norm p = " << pnorm_sum << "\n"; + // } } //----------------------------------------------------------------------------- int main(int argc, char** argv) diff --git a/spmv/read_petsc.cpp b/spmv/read_petsc.cpp index 1f881c1..5ff5b16 100644 --- a/spmv/read_petsc.cpp +++ b/spmv/read_petsc.cpp @@ -1,261 +1,280 @@ -// // // Copyright (C) 2020 Chris Richardson (chris@bpi.cam.ac.uk) -// // // SPDX-License-Identifier: MIT - -// // #include "read_petsc.h" -// // #include "L2GMap.h" -// // #include -// // #include -// // #include -// // #include -// #include - -// // Divide size into N ~equal chunks -// std::vector owner_ranges(int size, std::int64_t N) -// { -// // Compute number of items per process and remainder -// const std::int64_t n = N / size; -// const std::int64_t r = N % size; - -// // Compute local range -// std::vector ranges; -// for (int rank = 0; rank < (size + 1); ++rank) -// { -// if (rank < r) -// ranges.push_back(rank * (n + 1)); -// else -// ranges.push_back(rank * n + r); -// } - -// return ranges; -// } -// // //----------------------------------------------------------------------------- -// // spmv::Matrix spmv::read_petsc_binary(MPI_Comm comm, -// // std::string filename) -// // { -// // Eigen::SparseMatrix A; - -// // int mpi_rank; -// // MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); -// // int mpi_size; -// // MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); - -// // std::map col_indices; -// // std::vector row_ranges, col_ranges; -// // std::int64_t ncols_local, nrows_local; - -// // std::ifstream file(filename.c_str(), -// // std::ios::in | std::ios::binary | std::ios::ate); -// // if (file.is_open()) -// // { -// // // Get first 4 ints from file -// // std::vector memblock(16); -// // file.seekg(0, std::ios::beg); -// // file.read(memblock.data(), 16); - -// // char* ptr = memblock.data(); -// // for (int i = 0; i < 4; ++i) -// // { -// // std::swap(*ptr, *(ptr + 3)); -// // std::swap(*(ptr + 1), *(ptr + 2)); -// // ptr += 4; -// // } - -// // std::int32_t* int_data = (std::int32_t*)(memblock.data()); -// // int id = int_data[0]; -// // if (id != 1211216) -// // throw std::runtime_error("Bad signature in PETSc Matrix file"); - -// // int nrows = int_data[1]; -// // int ncols = int_data[2]; -// // int nnz_tot = int_data[3]; -// // row_ranges = owner_ranges(mpi_size, nrows); -// // col_ranges = owner_ranges(mpi_size, ncols); - -// // if (mpi_rank == 0) -// // std::cout << "Read file: " << filename << ": " << nrows << "x" << ncols -// // << " = " << nnz_tot << "\n"; - -// // nrows_local = row_ranges[mpi_rank + 1] - row_ranges[mpi_rank]; -// // ncols_local = col_ranges[mpi_rank + 1] - col_ranges[mpi_rank]; - -// // // Reset memory block and read nnz per row for all rows -// // memblock.resize(nrows * 4); -// // ptr = memblock.data(); -// // file.read(memblock.data(), nrows * 4); -// // std::vector nnz(nrows); -// // std::int64_t nnz_sum = 0; -// // for (int i = 0; i < nrows; ++i) -// // { -// // std::swap(*ptr, *(ptr + 3)); -// // std::swap(*(ptr + 1), *(ptr + 2)); -// // nnz[i] = *((std::int32_t*)ptr); -// // nnz_sum += nnz[i]; -// // ptr += 4; -// // } -// // assert(nnz_sum == nnz_tot); - -// // // Get offset and size for data -// // std::int64_t nnz_offset = 0; -// // std::int64_t nnz_size = 0; -// // for (std::int64_t i = 0; i < row_ranges[mpi_rank]; ++i) -// // nnz_offset += nnz[i]; -// // for (std::int64_t i = row_ranges[mpi_rank]; i < row_ranges[mpi_rank + 1]; -// // ++i) -// // nnz_size += nnz[i]; - -// // std::streampos value_data_pos -// // = file.tellg() + (std::streampos)(nnz_tot * 4 + nnz_offset * 8); - -// // // Read col indices for each row -// // memblock.resize(nnz_size * 4); -// // ptr = memblock.data(); -// // file.seekg(nnz_offset * 4, std::ios::cur); -// // file.read(memblock.data(), nnz_size * 4); - -// // std::int32_t c = 0; -// // for (std::int64_t col = col_ranges[mpi_rank]; -// // col < col_ranges[mpi_rank + 1]; ++col) -// // { -// // col_indices.insert({col, c}); -// // ++c; -// // } - -// // // Map other columns -// // for (std::int64_t row = row_ranges[mpi_rank]; -// // row < row_ranges[mpi_rank + 1]; ++row) -// // { -// // for (std::int64_t j = 0; j < nnz[row]; ++j) -// // { -// // std::swap(*ptr, *(ptr + 3)); -// // std::swap(*(ptr + 1), *(ptr + 2)); -// // col_indices.insert({*((std::int32_t*)ptr), -1}); -// // ptr += 4; -// // } -// // } -// // // Ensure they are labelled in ascending order -// // for (auto& q : col_indices) -// // if (q.second == -1) -// // { -// // q.second = c; -// // ++c; -// // } - -// // A.resize(nrows_local, col_indices.size()); - -// // // Read values -// // std::vector valuedata(nnz_size * 8); -// // file.seekg(value_data_pos, std::ios::beg); -// // file.read(valuedata.data(), nnz_size * 8); -// // file.close(); - -// // // Pointer to values -// // char* vptr = valuedata.data(); -// // ptr = memblock.data(); -// // for (std::int64_t row = row_ranges[mpi_rank]; -// // row < row_ranges[mpi_rank + 1]; ++row) -// // { -// // for (std::int64_t j = 0; j < nnz[row]; ++j) -// // { -// // std::swap(*vptr, *(vptr + 7)); -// // std::swap(*(vptr + 1), *(vptr + 6)); -// // std::swap(*(vptr + 2), *(vptr + 5)); -// // std::swap(*(vptr + 3), *(vptr + 4)); -// // double val = *((double*)vptr); -// // vptr += 8; - -// // // Look up column local index -// // std::int32_t col = col_indices[*((std::int32_t*)ptr)]; -// // ptr += 4; - -// // A.insert(row - row_ranges[mpi_rank], col) = val; -// // } -// // } -// // } -// // else -// // throw std::runtime_error("Could not open file"); - -// // A.makeCompressed(); - -// // std::vector ghosts(col_indices.size() - ncols_local); -// // for (auto& q : col_indices) -// // if (q.first < col_ranges[mpi_rank] or q.first >= col_ranges[mpi_rank + 1]) -// // ghosts[q.second - ncols_local] = q.first; - -// // auto col_map = std::make_shared(comm, ncols_local, ghosts); -// // auto row_map = std::make_shared(comm, nrows_local, -// // std::vector()); - -// // return spmv::Matrix(A, col_map, row_map); -// // } -// // //----------------------------------------------------------------------------- -// // Eigen::VectorXd spmv::read_petsc_binary_vector(MPI_Comm comm, -// // std::string filename) -// // { -// // Eigen::VectorXd vec; - -// // int mpi_rank; -// // MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); -// // int mpi_size; -// // MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); - -// // std::ifstream file(filename.c_str(), -// // std::ios::in | std::ios::binary | std::ios::ate); -// // if (file.is_open()) -// // { -// // // Get first 2 ints from file -// // std::vector memblock(8); -// // file.seekg(0, std::ios::beg); -// // file.read(memblock.data(), 8); - -// // char* ptr = memblock.data(); -// // for (int i = 0; i < 2; ++i) -// // { -// // std::swap(*ptr, *(ptr + 3)); -// // std::swap(*(ptr + 1), *(ptr + 2)); -// // ptr += 4; -// // } - -// // std::int32_t* int_data = (std::int32_t*)(memblock.data()); -// // int id = int_data[0]; -// // if (id != 1211214) -// // throw std::runtime_error("Bad signature in PETSc Vector file"); - -// // int nrows = int_data[1]; -// // std::vector ranges = owner_ranges(mpi_size, nrows); - -// // if (mpi_rank == 0) -// // std::cout << "Read vector file: " << filename << ": " << nrows << "\n"; - -// // std::int64_t nrows_local = ranges[mpi_rank + 1] - ranges[mpi_rank]; - -// // vec.resize(nrows_local); - -// // std::streampos value_data_pos -// // = file.tellg() + (std::streampos)(ranges[mpi_rank] * 8); - -// // // Read values -// // std::vector valuedata(nrows_local * 8); -// // file.seekg(value_data_pos, std::ios::beg); -// // file.read(valuedata.data(), nrows_local * 8); -// // file.close(); - -// // // Pointer to values -// // char* vptr = valuedata.data(); - -// // for (std::int64_t row = ranges[mpi_rank]; row < ranges[mpi_rank + 1]; ++row) -// // { -// // std::swap(*vptr, *(vptr + 7)); -// // std::swap(*(vptr + 1), *(vptr + 6)); -// // std::swap(*(vptr + 2), *(vptr + 5)); -// // std::swap(*(vptr + 3), *(vptr + 4)); -// // double val = *((double*)vptr); -// // vptr += 8; -// // vec[row - ranges[mpi_rank]] = val; -// // } -// // } -// // else -// // throw std::runtime_error("Could not open file"); - -// // return vec; -// // } -// // //----------------------------------------------------------------------------- +// Copyright (C) 2020 Chris Richardson (chris@bpi.cam.ac.uk) +// SPDX-License-Identifier: MIT + +#include + +#include +#include +#include +#include +#include +#include + +#include "L2GMap.h" +#include "read_petsc.h" + +// Divide size into N ~equal chunks +std::vector owner_ranges(int size, std::int64_t N) +{ + // Compute number of items per process and remainder + const std::int64_t n = N / size; + const std::int64_t r = N % size; + + // Compute local range + std::vector ranges; + for (int rank = 0; rank < (size + 1); ++rank) + { + if (rank < r) + ranges.push_back(rank * (n + 1)); + else + ranges.push_back(rank * n + r); + } + + return ranges; +} +//----------------------------------------------------------------------------- +spmv::Matrix spmv::read_petsc_binary(MPI_Comm comm, + std::string filename) +{ + Eigen::SparseMatrix A; + + int mpi_rank; + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + int mpi_size; + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + + std::map col_indices; + std::vector row_ranges, col_ranges; + std::int64_t ncols_local, nrows_local; + + std::ifstream file(filename.c_str(), + std::ios::in | std::ios::binary | std::ios::ate); + if (file.is_open()) + { + // Get first 4 ints from file + std::vector memblock(16); + file.seekg(0, std::ios::beg); + file.read(memblock.data(), 16); + + char* ptr = memblock.data(); + for (int i = 0; i < 4; ++i) + { + std::swap(*ptr, *(ptr + 3)); + std::swap(*(ptr + 1), *(ptr + 2)); + ptr += 4; + } + + std::int32_t* int_data = (std::int32_t*)(memblock.data()); + int id = int_data[0]; + if (id != 1211216) + throw std::runtime_error("Bad signature in PETSc Matrix file"); + + int nrows = int_data[1]; + int ncols = int_data[2]; + int nnz_tot = int_data[3]; + row_ranges = owner_ranges(mpi_size, nrows); + col_ranges = owner_ranges(mpi_size, ncols); + + if (mpi_rank == 0) + std::cout << "Read file: " << filename << ": " << nrows << "x" << ncols + << " = " << nnz_tot << "\n"; + + nrows_local = row_ranges[mpi_rank + 1] - row_ranges[mpi_rank]; + ncols_local = col_ranges[mpi_rank + 1] - col_ranges[mpi_rank]; + + // Reset memory block and read nnz per row for all rows + memblock.resize(nrows * 4); + ptr = memblock.data(); + file.read(memblock.data(), nrows * 4); + std::vector nnz(nrows); + std::int64_t nnz_sum = 0; + for (int i = 0; i < nrows; ++i) + { + std::swap(*ptr, *(ptr + 3)); + std::swap(*(ptr + 1), *(ptr + 2)); + nnz[i] = *((std::int32_t*)ptr); + nnz_sum += nnz[i]; + ptr += 4; + } + assert(nnz_sum == nnz_tot); + + // Get offset and size for data + std::int64_t nnz_offset = 0; + std::int64_t nnz_size = 0; + for (std::int64_t i = 0; i < row_ranges[mpi_rank]; ++i) + nnz_offset += nnz[i]; + for (std::int64_t i = row_ranges[mpi_rank]; i < row_ranges[mpi_rank + 1]; + ++i) + nnz_size += nnz[i]; + + std::streampos value_data_pos + = file.tellg() + (std::streampos)(nnz_tot * 4 + nnz_offset * 8); + + // Read col indices for each row + memblock.resize(nnz_size * 4); + ptr = memblock.data(); + file.seekg(nnz_offset * 4, std::ios::cur); + file.read(memblock.data(), nnz_size * 4); + + std::int32_t c = 0; + for (std::int64_t col = col_ranges[mpi_rank]; + col < col_ranges[mpi_rank + 1]; ++col) + { + col_indices.insert({col, c}); + ++c; + } + + // Map other columns + for (std::int64_t row = row_ranges[mpi_rank]; + row < row_ranges[mpi_rank + 1]; ++row) + { + for (std::int64_t j = 0; j < nnz[row]; ++j) + { + std::swap(*ptr, *(ptr + 3)); + std::swap(*(ptr + 1), *(ptr + 2)); + col_indices.insert({*((std::int32_t*)ptr), -1}); + ptr += 4; + } + } + // Ensure they are labelled in ascending order + for (auto& q : col_indices) + if (q.second == -1) + { + q.second = c; + ++c; + } + + A.resize(nrows_local, col_indices.size()); + + // Read values + std::vector valuedata(nnz_size * 8); + file.seekg(value_data_pos, std::ios::beg); + file.read(valuedata.data(), nnz_size * 8); + file.close(); + + // Pointer to values + char* vptr = valuedata.data(); + ptr = memblock.data(); + for (std::int64_t row = row_ranges[mpi_rank]; + row < row_ranges[mpi_rank + 1]; ++row) + { + for (std::int64_t j = 0; j < nnz[row]; ++j) + { + std::swap(*vptr, *(vptr + 7)); + std::swap(*(vptr + 1), *(vptr + 6)); + std::swap(*(vptr + 2), *(vptr + 5)); + std::swap(*(vptr + 3), *(vptr + 4)); + double val = *((double*)vptr); + vptr += 8; + + // Look up column local index + std::int32_t col = col_indices[*((std::int32_t*)ptr)]; + ptr += 4; + + A.insert(row - row_ranges[mpi_rank], col) = val; + } + } + } + else + throw std::runtime_error("Could not open file"); + + A.makeCompressed(); + + std::vector ghosts(col_indices.size() - ncols_local); + for (auto& q : col_indices) + if (q.first < col_ranges[mpi_rank] or q.first >= col_ranges[mpi_rank + 1]) + ghosts[q.second - ncols_local] = q.first; + + auto col_map = std::make_shared(comm, ncols_local, ghosts); + auto row_map = std::make_shared(comm, nrows_local); + + // Get indptr buffer + std::int32_t* Aouter = A.outerIndexPtr(); + std::vector indptr(A.rows() + 1); + std::memcpy(indptr.data(), Aouter, sizeof(std::int32_t) * indptr.size()); + + // Get indices buffer + std::int32_t* Ainner = A.innerIndexPtr(); + std::vector indices(A.nonZeros()); + std::memcpy(indices.data(), Ainner, sizeof(std::int32_t) * indices.size()); + + // Get data buffer + double* Aptr = A.valuePtr(); + std::vector data(A.nonZeros()); + std::memcpy(data.data(), Aptr, sizeof(double) * data.size()); + + return spmv::Matrix(data, indptr, indices, col_map, row_map); +} +//----------------------------------------------------------------------------- +std::vector spmv::read_petsc_binary_vector(MPI_Comm comm, + std::string filename) +{ + std::vector vec; + + int mpi_rank; + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + int mpi_size; + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + + std::ifstream file(filename.c_str(), + std::ios::in | std::ios::binary | std::ios::ate); + if (file.is_open()) + { + // Get first 2 ints from file + std::vector memblock(8); + file.seekg(0, std::ios::beg); + file.read(memblock.data(), 8); + + char* ptr = memblock.data(); + for (int i = 0; i < 2; ++i) + { + std::swap(*ptr, *(ptr + 3)); + std::swap(*(ptr + 1), *(ptr + 2)); + ptr += 4; + } + + std::int32_t* int_data = (std::int32_t*)(memblock.data()); + int id = int_data[0]; + if (id != 1211214) + throw std::runtime_error("Bad signature in PETSc Vector file"); + + int nrows = int_data[1]; + std::vector ranges = owner_ranges(mpi_size, nrows); + + if (mpi_rank == 0) + std::cout << "Read vector file: " << filename << ": " << nrows << "\n"; + + std::int64_t nrows_local = ranges[mpi_rank + 1] - ranges[mpi_rank]; + + vec.resize(nrows_local); + + std::streampos value_data_pos + = file.tellg() + (std::streampos)(ranges[mpi_rank] * 8); + + // Read values + std::vector valuedata(nrows_local * 8); + file.seekg(value_data_pos, std::ios::beg); + file.read(valuedata.data(), nrows_local * 8); + file.close(); + + // Pointer to values + char* vptr = valuedata.data(); + + for (std::int64_t row = ranges[mpi_rank]; row < ranges[mpi_rank + 1]; + ++row) + { + std::swap(*vptr, *(vptr + 7)); + std::swap(*(vptr + 1), *(vptr + 6)); + std::swap(*(vptr + 2), *(vptr + 5)); + std::swap(*(vptr + 3), *(vptr + 4)); + double val = *((double*)vptr); + vptr += 8; + vec[row - ranges[mpi_rank]] = val; + } + } + else + throw std::runtime_error("Could not open file"); + + return vec; +} +//----------------------------------------------------------------------------- diff --git a/spmv/read_petsc.h b/spmv/read_petsc.h index bb5b509..cf023eb 100644 --- a/spmv/read_petsc.h +++ b/spmv/read_petsc.h @@ -20,8 +20,7 @@ class L2GMap; /// @param comm MPI Comm /// @param filename Filename /// @return spmv::Matrix Matrix -Matrix read_petsc_binary(MPI_Comm comm, - std::string filename); +Matrix read_petsc_binary(MPI_Comm comm, std::string filename); /// @brief Read a binary PETSc vector file and distribute. /// @@ -29,5 +28,6 @@ Matrix read_petsc_binary(MPI_Comm comm, /// @param comm MPI Communicator /// @param filename Filename /// @return Vector of values -Eigen::VectorXd read_petsc_binary_vector(MPI_Comm comm, std::string filename); +std::vector read_petsc_binary_vector(MPI_Comm comm, std::string filename); + } // namespace spmv From 6b5ed9b362b7781b77c6ee2cdd84187971de3f92 Mon Sep 17 00:00:00 2001 From: igorbaratta Date: Tue, 27 Oct 2020 15:21:32 -0300 Subject: [PATCH 21/37] fix vector addition and multiplication --- demos/cgmain.cpp | 30 +++++------ demos/diagonal.cpp | 2 +- demos/matvecmain.cpp | 2 +- demos/vecnorm.cpp | 10 ++-- spmv/Matrix.cpp | 4 +- spmv/Vector.cpp | 116 ++++++++++++++++++++++++++++++++++++------- spmv/Vector.h | 36 +++++++++++--- spmv/creation.h | 1 + spmv/spmv.h | 4 +- 9 files changed, 154 insertions(+), 51 deletions(-) diff --git a/demos/cgmain.cpp b/demos/cgmain.cpp index 861cc2e..967de92 100644 --- a/demos/cgmain.cpp +++ b/demos/cgmain.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2018-2020 Chris Richardson (chris@bpi.cam.ac.uk) // SPDX-License-Identifier: MIT +#include #include #include @@ -34,12 +35,15 @@ int cg_main(int argc, char** argv) else throw std::runtime_error("Use with filename"); - auto A - = spmv::read_petsc_binary(MPI_COMM_WORLD, "petsc_mat" + argv1 + ".dat"); - std::shared_ptr l2g = A.col_map(); + auto A = spmv::read_petsc_binary(MPI_COMM_WORLD, "petsc_mat_" + argv1); + std::shared_ptr l2g = A.col_map(); + + auto b_data + = spmv::read_petsc_binary_vector(MPI_COMM_WORLD, "petsc_vec_" + argv1); + std::int32_t ls = l2g->local_size() + l2g->num_ghosts(); + b_data.resize(ls); + spmv::Vector b(b_data, l2g); - auto b = spmv::read_petsc_binary_vector(MPI_COMM_WORLD, - "petsc_vec" + argv1 + ".dat"); // Get local and global sizes std::int64_t N = l2g->global_size(); @@ -61,21 +65,17 @@ int cg_main(int argc, char** argv) MPI_Pcontrol(0); // Get norm on local part of vector - double xnorm = x.head(l2g->local_size()).squaredNorm(); - double xnorm_sum; - MPI_Allreduce(&xnorm, &xnorm_sum, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + double xnorm = x.norm(); // Test result - l2g->update(x.data()); - Eigen::VectorXd r = A * x - b; - double rnorm = r.squaredNorm(); - double rnorm_sum; - MPI_Allreduce(&rnorm, &rnorm_sum, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + x.update(); + auto r = A * x - b; + double rnom = r.norm(); if (mpi_rank == 0) { - std::cout << "r.norm = " << std::sqrt(rnorm_sum) << "\n"; - std::cout << "x.norm = " << std::sqrt(xnorm_sum) << " in " << num_its + std::cout << "r.norm = " << std::sqrt(rnom) << "\n"; + std::cout << "x.norm = " << std::sqrt(xnorm) << " in " << num_its << " iterations\n"; std::cout << "\nTimings (" << mpi_size << ")\n----------------------------\n"; diff --git a/demos/diagonal.cpp b/demos/diagonal.cpp index 7140f6d..dde6fc8 100644 --- a/demos/diagonal.cpp +++ b/demos/diagonal.cpp @@ -46,7 +46,7 @@ int main(int argc, char** argv) spmv::Vector b(b_data, map); if (mpi_rank == 0) - std::cout << "Applying matrix " << n_apply << " times\n"; + std::cout << "Applying diagonal matrix to vector " << n_apply << " times\n"; std::vector c_data(size, 0.0); spmv::Vector c(c_data, map); diff --git a/demos/matvecmain.cpp b/demos/matvecmain.cpp index 98007b5..bb5935b 100644 --- a/demos/matvecmain.cpp +++ b/demos/matvecmain.cpp @@ -68,7 +68,7 @@ void matvec_main() { timer_start = std::chrono::system_clock::now(); { - auto p_buffer = p.getLocalData(); + auto p_buffer = p.get_local_buffer(); auto pacc = p_buffer.get_access(); l2g->update(static_cast(pacc.get_pointer())); } diff --git a/demos/vecnorm.cpp b/demos/vecnorm.cpp index 717bef5..4c23bde 100644 --- a/demos/vecnorm.cpp +++ b/demos/vecnorm.cpp @@ -29,7 +29,7 @@ int main(int argc, char** argv) auto data = std::make_shared>(v); spmv::Vector vec(data, map); - double norm = std::sqrt(vec.dot(vec)); + double norm = vec.norm(); double ex_norm = std::sqrt((double)map->global_size()); if (rank == 0) @@ -41,7 +41,7 @@ int main(int argc, char** argv) assert(fabs(norm - ex_norm) < 1e-5); vec += vec; - norm = std::sqrt(vec.dot(vec)); + norm = vec.norm(); if (rank == 0) { std::cout << std::endl; @@ -49,14 +49,14 @@ int main(int argc, char** argv) std::cout << "Exact Norm: " << ex_norm * 2 << std::endl; } - spmv::Vector vec2 = vec + vec; + spmv::Vector vec2 = vec + (vec * 2.); vec2 *= 0.5; - norm = std::sqrt(vec.dot(vec)); + norm = vec2.norm(); if (rank == 0) { std::cout << std::endl; std::cout << "Computed Norm: " << norm << std::endl; - std::cout << "Exact Norm: " << ex_norm * 2 << std::endl; + std::cout << "Exact Norm: " << 3 * ex_norm << std::endl; } return 0; diff --git a/spmv/Matrix.cpp b/spmv/Matrix.cpp index 689e1c6..5234e74 100644 --- a/spmv/Matrix.cpp +++ b/spmv/Matrix.cpp @@ -58,7 +58,7 @@ void Matrix::mult(spmv::Vector& x, spmv::Vector& b) const { oneapi::mkl::sparse::gemv(_q, oneapi::mkl::transpose::nontrans, 1.0, A_onemkl, - x.getLocalData(), 0.0, b.getLocalData()); + x.get_local_buffer(), 0.0, b.get_local_buffer()); }; //----------------------------------------------------------------------------- template @@ -66,7 +66,7 @@ void Matrix::transpmult(spmv::Vector& x, spmv::Vector& b) const { oneapi::mkl::sparse::gemv(_q, oneapi::mkl::transpose::trans, 1.0, A_onemkl, - x.getLocalData(), 0.0, b.getLocalData()); + x.get_local_buffer(), 0.0, b.get_local_buffer()); }; //----------------------------------------------------------------------------- template diff --git a/spmv/Vector.cpp b/spmv/Vector.cpp index 664f9e2..f574aeb 100644 --- a/spmv/Vector.cpp +++ b/spmv/Vector.cpp @@ -9,6 +9,9 @@ using namespace spmv; +template +class SetZero; + //----------------------------------------------------------------------------- template Vector::Vector( @@ -23,7 +26,6 @@ Vector::Vector( if (ls != _data->get_size()) std::runtime_error("Size mismatch"); } - //----------------------------------------------------------------------------- template Vector::Vector(std::vector& vec, @@ -38,6 +40,37 @@ Vector::Vector(std::vector& vec, if (ls != _data->get_size()) std::runtime_error("Size mismatch"); } +//----------------------------------------------------------------------------- +template +Vector Vector::duplicate() const +{ + std::size_t ls = _map->local_size() + _map->num_ghosts(); + auto buffer = std::make_shared>( + cl::sycl::range<1>{ls}); + return spmv::Vector(buffer, _map); +} +//----------------------------------------------------------------------------- +template +Vector Vector::copy() const +{ + std::size_t ls = _map->local_size() + _map->num_ghosts(); + auto buffer = std::make_shared>( + cl::sycl::range<1>{ls}); + oneapi::mkl::blas::copy(_q, ls, *_data, 1, *buffer, 1); + return spmv::Vector(buffer, _map); +} +//---------------------------------------------------------------------------- +template +void Vector::set_zero() +{ + _q.submit([&](cl::sycl::handler& cgh) { + std::size_t ls = _map->local_size() + _map->num_ghosts(); + auto acc + = _data->template get_access(cgh); + cgh.parallel_for>( + cl::sycl::range<1>{ls}, [=](cl::sycl::id<1> i) { acc[i] = 0.; }); + }); +} //---------------------------------------------------------------------------- template Vector& Vector::operator*=(ScalarType alpha) @@ -48,36 +81,75 @@ Vector& Vector::operator*=(ScalarType alpha) } //---------------------------------------------------------------------------- template +Vector Vector::operator*(ScalarType alpha) const +{ + auto out = this->copy(); + out *= alpha; + return out; +} +//---------------------------------------------------------------------------- +template Vector& Vector::operator+=(Vector& other) { - oneapi::mkl::blas::axpy(_q, local_size(), 1.0, other.getLocalData(), 1, + oneapi::mkl::blas::axpy(_q, local_size(), 1.0, other.get_local_buffer(), 1, + *_data, 1); + return *this; +} +//---------------------------------------------------------------------------- +template +Vector& Vector::operator+=(Vector&& other) +{ + oneapi::mkl::blas::axpy(_q, local_size(), 1.0, other.get_local_buffer(), 1, *_data, 1); return *this; } //---------------------------------------------------------------------------- template +Vector Vector::operator+(Vector& other) const +{ + auto out = this->copy(); + out += other; + return out; +} +//---------------------------------------------------------------------------- +template +Vector Vector::operator+(Vector&& other) const +{ + auto out = this->copy(); + out += other; + return out; +} +//---------------------------------------------------------------------------- +template Vector& Vector::operator-=(Vector& other) { - oneapi::mkl::blas::axpy(_q, local_size(), -1.0, other.getLocalData(), 1, + oneapi::mkl::blas::axpy(_q, local_size(), -1.0, other.get_local_buffer(), 1, *_data, 1); return *this; } //---------------------------------------------------------------------------- template -Vector& Vector::operator+(Vector& other) +Vector& Vector::operator-=(Vector&& other) { - auto buffer = std::make_shared>(*_data); - spmv::Vector out(buffer, _map); - return out += other; + oneapi::mkl::blas::axpy(_q, local_size(), -1.0, other.get_local_buffer(), 1, + *_data, 1); + return *this; } - //---------------------------------------------------------------------------- template -double Vector::dot(spmv::Vector& y) const +Vector Vector::operator-(Vector& other) const +{ + auto out = this->copy(); + out -= other; + return out; +} +//---------------------------------------------------------------------------- +template +double Vector::dot(spmv::Vector& y) { cl::sycl::buffer res{1}; - oneapi::mkl::blas::dot(_q, _map->local_size(), *_data, 1, y.getLocalData(), 1, - res); + oneapi::mkl::blas::dot(_q, _map->local_size(), *_data, 1, + y.get_local_buffer(), 1, res); auto acc = res.template get_access(); MPI_Comm comm = _map->comm(); @@ -90,12 +162,11 @@ double Vector::dot(spmv::Vector& y) const }; //---------------------------------------------------------------------------- template <> -double -Vector>::dot(spmv::Vector>& y) const +double Vector>::dot(spmv::Vector>& y) { cl::sycl::buffer, 1> res{1}; - oneapi::mkl::blas::dotc(_q, _map->local_size(), *_data, 1, y.getLocalData(), - 1, res); + oneapi::mkl::blas::dotc(_q, _map->local_size(), *_data, 1, + y.get_local_buffer(), 1, res); auto acc = res.template get_access(); MPI_Comm comm = _map->comm(); @@ -108,12 +179,11 @@ Vector>::dot(spmv::Vector>& y) const }; //---------------------------------------------------------------------------- template <> -double -Vector>::dot(spmv::Vector>& y) const +double Vector>::dot(spmv::Vector>& y) { cl::sycl::buffer, 1> res{1}; - oneapi::mkl::blas::dotc(_q, _map->local_size(), *_data, 1, y.getLocalData(), - 1, res); + oneapi::mkl::blas::dotc(_q, _map->local_size(), *_data, 1, + y.get_local_buffer(), 1, res); auto acc = res.template get_access(); MPI_Comm comm = _map->comm(); @@ -125,6 +195,14 @@ Vector>::dot(spmv::Vector>& y) const return global_sum; }; //---------------------------------------------------------------------------- +template +void Vector::update() +{ + auto p_buffer = this->get_local_buffer(); + auto pacc = p_buffer.template get_access(); + _map->update(static_cast(pacc.get_pointer())); +} +//---------------------------------------------------------------------------- // Explicit instantiation template class spmv::Vector; template class spmv::Vector; diff --git a/spmv/Vector.h b/spmv/Vector.h index 355a4ba..40ffae5 100644 --- a/spmv/Vector.h +++ b/spmv/Vector.h @@ -16,7 +16,7 @@ class Vector { public: /// Create Distributed Vector using data buffers and local-to-global map (data - /// might be on device memory) + /// might be already on device memory) Vector(std::shared_ptr> data, std::shared_ptr map); @@ -28,22 +28,46 @@ class Vector std::int32_t local_size() const { return _map->local_size(); } - cl::sycl::buffer& getLocalData() { return *_data; }; + cl::sycl::buffer& get_local_buffer() { return *_data; }; /// Computes the product of the vector by a scalar. Vector& operator*=(ScalarType alpha); - Vector& operator+=(Vector& other); + Vector& operator+=(Vector& other); + Vector& operator+=(Vector&& other); + Vector& operator-=(Vector& other); + Vector& operator-=(Vector&& other); - Vector& operator-=(Vector& other); + /// Computes the product of the vector by a scalar. + Vector operator*(ScalarType alpha) const; + + /// Applies binary sum operator to each element of tow Vectors (a = b + c) + Vector operator+(Vector& other) const; + + /// Applies binary sum operator to each element of tow Vectors (a = b + c) + Vector operator+(Vector&& other) const; + + /// Applies substraction operator to each element of tow Vectors (a = b - c) + Vector operator-(Vector& other) const; - Vector& operator+(Vector& other); + /// Creates a new vector of the same type and dimension as this. + Vector duplicate() const; - double dot(spmv::Vector& y) const; + /// Creates a new vector and copy the content of the current vector. + Vector copy() const; + + /// Sets all elements of this vector to zero. + void set_zero(); + + /// Computes the dot product. + double dot(spmv::Vector& y); /// Computes the vector 2 norm (Euclidean norm). double norm() { return std::sqrt(this->dot(*this)); } + /// Updates ghosts values, from global representation to local. + void update(); + private: std::shared_ptr> _data; std::shared_ptr _map; diff --git a/spmv/creation.h b/spmv/creation.h index 79a9dc3..67154ba 100644 --- a/spmv/creation.h +++ b/spmv/creation.h @@ -2,6 +2,7 @@ // SPDX-License-Identifier: MIT #include +#include #include "Matrix.h" diff --git a/spmv/spmv.h b/spmv/spmv.h index a0f25fd..ef9d600 100644 --- a/spmv/spmv.h +++ b/spmv/spmv.h @@ -4,5 +4,5 @@ #include "L2GMap.h" #include "Matrix.h" #include "Vector.h" -// #include "read_petsc.h" -// #include "cg.h" +#include "read_petsc.h" +#include "cg.h" From 064f6a9d4b7da4d4a970c5f53a56002a5ae7f4da Mon Sep 17 00:00:00 2001 From: igorbaratta Date: Tue, 27 Oct 2020 15:59:07 -0300 Subject: [PATCH 22/37] fix cg --- spmv/cg.cpp | 168 ++++++++++++++++++++++++++-------------------------- 1 file changed, 85 insertions(+), 83 deletions(-) diff --git a/spmv/cg.cpp b/spmv/cg.cpp index d4b9e21..1e9508b 100644 --- a/spmv/cg.cpp +++ b/spmv/cg.cpp @@ -1,83 +1,85 @@ -// // Copyright (C) 2020 Chris Richardson (chris@bpi.cam.ac.uk) and Jeffrey Salmond -// // SPDX-License-Identifier: MIT - -// #include "cg.h" -// #include "L2GMap.h" -// #include "Matrix.h" -// #include -// #include - -// //----------------------------------------------------------------------------- -// std::tuple -// spmv::cg(MPI_Comm comm, const spmv::Matrix& A, -// const Eigen::Ref& b, int kmax, double rtol) -// { -// int mpi_rank; -// MPI_Comm_rank(comm, &mpi_rank); - -// std::shared_ptr col_l2g = A.col_map(); -// std::shared_ptr row_l2g = A.row_map(); - -// // Check the row map is unghosted -// if (row_l2g->num_ghosts() > 0) -// throw std::runtime_error("spmv::cg - Error: A.row_map() has ghost entries"); - -// int M = row_l2g->local_size(); - -// if (b.rows() != M) -// throw std::runtime_error("spmv::cg - Error: b.rows() != A.rows()"); - -// // Residual vector -// Eigen::VectorXd r(M); -// Eigen::VectorXd y(M); -// Eigen::VectorXd x(col_l2g->local_size() + col_l2g->num_ghosts()); -// Eigen::VectorXd p(col_l2g->local_size() + col_l2g->num_ghosts()); -// p.setZero(); - -// // Assign to dense part of sparse vector -// x.setZero(); -// r = b; // b - A * x0 -// p.head(M) = r; - -// double rnorm = r.squaredNorm(); -// double rnorm0; -// MPI_Allreduce(&rnorm, &rnorm0, 1, MPI_DOUBLE, MPI_SUM, comm); - -// // Iterations of CG -// const double rtol2 = rtol * rtol; -// double rnorm_old = rnorm0; -// int k = 0; -// while (k < kmax) -// { -// ++k; - -// // y = A.p -// col_l2g->update(p.data()); -// y = A * p; - -// // Calculate alpha = r.r/p.y -// double pdoty = p.head(M).dot(y); -// double pdoty_sum; -// MPI_Allreduce(&pdoty, &pdoty_sum, 1, MPI_DOUBLE, MPI_SUM, comm); -// double alpha = rnorm_old / pdoty_sum; - -// // Update x and r -// x.head(M) += alpha * p.head(M); -// r -= alpha * y; - -// // Update rnorm -// rnorm = r.squaredNorm(); -// double rnorm_new; -// MPI_Allreduce(&rnorm, &rnorm_new, 1, MPI_DOUBLE, MPI_SUM, comm); -// double beta = rnorm_new / rnorm_old; -// rnorm_old = rnorm_new; - -// // Update p -// p.head(M) = p.head(M) * beta + r; - -// if (rnorm_new / rnorm0 < rtol2) -// break; -// } - -// return std::make_tuple(std::move(x), k); -// } +// Copyright (C) 2020 Chris Richardson (chris@bpi.cam.ac.uk) and Jeffrey Salmond +// SPDX-License-Identifier: MIT + +#include + +#include "cg.h" +#include +#include + +#include "L2GMap.h" +#include "Matrix.h" +#include "Vector.h" + +//----------------------------------------------------------------------------- +std::tuple, int> spmv::cg(MPI_Comm comm, + const spmv::Matrix& A, + spmv::Vector& b, + int max_its, double rtol) +{ + int mpi_rank; + MPI_Comm_rank(comm, &mpi_rank); + + std::shared_ptr col_l2g = A.col_map(); + std::shared_ptr row_l2g = A.row_map(); + + // Check the row map is unghosted + if (row_l2g->num_ghosts() > 0) + throw std::runtime_error("spmv::cg - Error: A.row_map() has ghost entries"); + + int M = row_l2g->local_size(); + + if (b.local_size() != M) + throw std::runtime_error("spmv::cg - Error: b.rows() != A.rows()"); + + // Residual vector + auto y = b.duplicate(); + auto x = b.duplicate(); + + x.set_zero(); + + // Assign to dense part of sparse vector + // TODO: Create copy assignment - Default creates shallow copy due to + // shared_ptr. + auto r = b.copy(); // b - A * x0 + auto p = r.copy(); + + double rnorm = r.norm(); + double rnorm0 = rnorm; + + // Iterations of CG + const double rtol2 = rtol * rtol; + double rnorm_old = rnorm; + int k = 0; + while (k < max_its) + { + ++k; + + // y = A.p + p.update(); + y = A * p; + + // Calculate alpha = r.r/p.y + double pdoty = p.dot(y); + double alpha = rnorm_old / pdoty; + + // Update x and r + x += p * alpha; + r -= y * alpha; + + // Update rnorm + rnorm = r.norm(); + double beta = rnorm / rnorm_old; + rnorm_old = rnorm; + + // Update p + p = p * beta + r; + + std::cout << rnorm << std::endl; + + if (rnorm / rnorm0 < rtol2) + break; + } + + return std::make_tuple(std::move(x), k); +} From 5138837b8b6697f085b9466201524cbb5b232ff3 Mon Sep 17 00:00:00 2001 From: igorbaratta Date: Tue, 27 Oct 2020 17:13:26 -0300 Subject: [PATCH 23/37] fix cg norm --- spmv/cg.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/spmv/cg.cpp b/spmv/cg.cpp index 1e9508b..3e6bf0e 100644 --- a/spmv/cg.cpp +++ b/spmv/cg.cpp @@ -44,7 +44,7 @@ std::tuple, int> spmv::cg(MPI_Comm comm, auto r = b.copy(); // b - A * x0 auto p = r.copy(); - double rnorm = r.norm(); + double rnorm = r.dot(r); double rnorm0 = rnorm; // Iterations of CG @@ -57,7 +57,7 @@ std::tuple, int> spmv::cg(MPI_Comm comm, // y = A.p p.update(); - y = A * p; + A.mult(p, y); // Calculate alpha = r.r/p.y double pdoty = p.dot(y); @@ -68,15 +68,13 @@ std::tuple, int> spmv::cg(MPI_Comm comm, r -= y * alpha; // Update rnorm - rnorm = r.norm(); + rnorm = r.dot(r); double beta = rnorm / rnorm_old; rnorm_old = rnorm; // Update p p = p * beta + r; - std::cout << rnorm << std::endl; - if (rnorm / rnorm0 < rtol2) break; } From 96692fe333cd8ea62d6156c2d2cfdf1526a26450 Mon Sep 17 00:00:00 2001 From: igorbaratta Date: Tue, 27 Oct 2020 17:38:46 -0300 Subject: [PATCH 24/37] change default to cpu instead of host --- demos/matvecmain.cpp | 6 +----- spmv/Matrix.cpp | 4 ++-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/demos/matvecmain.cpp b/demos/matvecmain.cpp index bb5935b..6b4a4b2 100644 --- a/demos/matvecmain.cpp +++ b/demos/matvecmain.cpp @@ -67,11 +67,7 @@ void matvec_main() for (int i = 0; i < n_apply; ++i) { timer_start = std::chrono::system_clock::now(); - { - auto p_buffer = p.get_local_buffer(); - auto pacc = p_buffer.get_access(); - l2g->update(static_cast(pacc.get_pointer())); - } + p.update(); timer_end = std::chrono::system_clock::now(); timings["2.SparseUpdate"] += (timer_end - timer_start); diff --git a/spmv/Matrix.cpp b/spmv/Matrix.cpp index 5234e74..e84a0a8 100644 --- a/spmv/Matrix.cpp +++ b/spmv/Matrix.cpp @@ -22,7 +22,7 @@ Matrix::Matrix( : _data(data), _indptr(indptr), _indices(indices), _col_map(col_map), _row_map(row_map) { - sycl::default_selector device_selector; + sycl::cpu_selector device_selector; _q = sycl::queue(device_selector); _shape[0] = row_map->local_size() + row_map->num_ghosts(); @@ -40,7 +40,7 @@ Matrix::Matrix(std::vector& data, std::shared_ptr row_map) : _col_map(col_map), _row_map(row_map) { - sycl::default_selector device_selector; + sycl::cpu_selector device_selector; _q = sycl::queue(device_selector); _data = std::make_shared>(data); From e0017460db4856b57a3ad13755f096b4931eb22f Mon Sep 17 00:00:00 2001 From: igorbaratta Date: Tue, 27 Oct 2020 18:07:23 -0300 Subject: [PATCH 25/37] try to fix ci --- .github/workflows/ccpp.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index ce6081b..99e3d89 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -22,7 +22,7 @@ jobs: - name: cmake run: | - source /opt/intel/oneapi/setvars.sh + . /opt/intel/oneapi/setvars.sh export CXX=clang++ cmake . - name: make From 5d6a2f403f09d8f7f90de40b83c35c456cd43da0 Mon Sep 17 00:00:00 2001 From: igorbaratta Date: Tue, 27 Oct 2020 19:51:41 -0300 Subject: [PATCH 26/37] use github ci --- .github/workflows/ccpp.yml | 19 +++++-------------- CMakeLists.txt | 4 ++-- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 99e3d89..032be2a 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -6,26 +6,17 @@ jobs: build: runs-on: ubuntu-20.04 + container: intel/oneapi-basekit steps: - uses: actions/checkout@v2 - name: Install Dependencies - run: | - sudo apt install -y libmpich-dev libeigen3-dev wget gnupg2 - wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB - sudo apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB - rm GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB - echo "deb https://apt.repos.intel.com/oneapi all main" | sudo tee /etc/apt/sources.list.d/oneAPI.list - sudo add-apt-repository "deb https://apt.repos.intel.com/oneapi all main" - sudo apt-get update - sudo apt-get install -y intel-basekit + run: sudo apt install -y libeigen3-dev wget gnupg2 - name: cmake - run: | - . /opt/intel/oneapi/setvars.sh - export CXX=clang++ - cmake . + run: CXX=clang++ cmake . + - name: make run: make - name: Run with 2 processes - run: ./demos/matvecmain && OMP_NUM_THREADS=1 mpirun -n 2 ./demos/matvecmain + run: ./demos/matvecmain && mpirun -n 2 ./demos/matvecmain diff --git a/CMakeLists.txt b/CMakeLists.txt index 4fdcb42..7e4fad5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ -# Require CMake 3.14 -cmake_minimum_required(VERSION 3.14) +# Require CMake 3.10 +cmake_minimum_required(VERSION 3.10) # Choose Release or Debug set(CMAKE_BUILD_TYPE Release) From a14e80c6b24402fbeb5ded146e9a0e8bff6532ad Mon Sep 17 00:00:00 2001 From: igorbaratta Date: Tue, 27 Oct 2020 20:06:20 -0300 Subject: [PATCH 27/37] do not use sudo --- .github/workflows/ccpp.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 032be2a..141fa6d 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -11,7 +11,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Install Dependencies - run: sudo apt install -y libeigen3-dev wget gnupg2 + run: apt update && apt install -y libeigen3-dev - name: cmake run: CXX=clang++ cmake . From f2c128a2ba10e7ace89753c7598e96f0a5afe229 Mon Sep 17 00:00:00 2001 From: igorbaratta Date: Tue, 27 Oct 2020 20:24:41 -0300 Subject: [PATCH 28/37] try setting onemkl dir --- .github/workflows/ccpp.yml | 8 +++++--- CMakeLists.txt | 3 +++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 141fa6d..c780df6 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -8,14 +8,16 @@ jobs: runs-on: ubuntu-20.04 container: intel/oneapi-basekit + env: + CXX: clang++ + ONE_MKL_DIR: /opt/intel/oneapi/mkl/2021.1-beta09/ + steps: - uses: actions/checkout@v2 - name: Install Dependencies run: apt update && apt install -y libeigen3-dev - - name: cmake - run: CXX=clang++ cmake . - + run: cmake . - name: make run: make - name: Run with 2 processes diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e4fad5..b2e1fb9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,9 @@ set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") find_package(MPI REQUIRED) include_directories(${MPI_INCLUDE_PATH}) +find_package(BLAS REQUIRED) +include_directories($ENV{ONE_MKL_DIR}) + # Not sure why need to set -O3 and -DNDEBUG as should be set by Release build type set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O3 -DNDEBUG -fsycl -DMKL_ILP64 -tbb") From c176bde90b2fdb16f61ef749dddb35d00a67de5f Mon Sep 17 00:00:00 2001 From: igorbaratta Date: Tue, 27 Oct 2020 20:26:23 -0300 Subject: [PATCH 29/37] make a symbolic link to eigen headers --- .github/workflows/ccpp.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index c780df6..ef412d6 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -15,7 +15,9 @@ jobs: steps: - uses: actions/checkout@v2 - name: Install Dependencies - run: apt update && apt install -y libeigen3-dev + run: | + apt update && apt install -y libeigen3-dev + ln -s /usr/include/eigen3/Eigen /usr/include/Eigen - name: cmake run: cmake . - name: make From 86acd87df92cc307f461ce7454bca66c066d6069 Mon Sep 17 00:00:00 2001 From: igorbaratta Date: Tue, 27 Oct 2020 22:12:13 -0300 Subject: [PATCH 30/37] minor fixes --- .github/workflows/ccpp.yml | 6 ++++-- spmv/Matrix.cpp | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index ef412d6..c8f0b2c 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -19,8 +19,10 @@ jobs: apt update && apt install -y libeigen3-dev ln -s /usr/include/eigen3/Eigen /usr/include/Eigen - name: cmake - run: cmake . + run: echo $ONE_MKL_DIR && cmake . - name: make run: make - name: Run with 2 processes - run: ./demos/matvecmain && mpirun -n 2 ./demos/matvecmain + run: | + ./demos/matvecmain && mpirun -n 2 ./demos/matvecmain + ./demos/vecnorm && mpirun -n 2 ./demos/vecnorm diff --git a/spmv/Matrix.cpp b/spmv/Matrix.cpp index e84a0a8..f1773ad 100644 --- a/spmv/Matrix.cpp +++ b/spmv/Matrix.cpp @@ -4,7 +4,7 @@ #include -#include "mkl_spblas_sycl.hpp" +#include "mkl_sycl.hpp" #include "Matrix.h" #include "mpi_type.h" From a1fa1e90adf791275e6ba411059aaa91c2dd7ee9 Mon Sep 17 00:00:00 2001 From: igorbaratta Date: Tue, 27 Oct 2020 22:24:27 -0300 Subject: [PATCH 31/37] bump oneapi version --- .github/workflows/ccpp.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index c8f0b2c..8665fa2 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -10,7 +10,7 @@ jobs: env: CXX: clang++ - ONE_MKL_DIR: /opt/intel/oneapi/mkl/2021.1-beta09/ + ONE_MKL_DIR: /opt/intel/oneapi/mkl/2021.1-beta10/ steps: - uses: actions/checkout@v2 From a77b0460474f7e1da325c3d017deff143bea5e19 Mon Sep 17 00:00:00 2001 From: igorbaratta Date: Tue, 27 Oct 2020 23:26:17 -0300 Subject: [PATCH 32/37] use oneapi 1.0 --- demos/diagonal.cpp | 1 - spmv/Matrix.cpp | 2 +- spmv/Matrix.h | 2 +- spmv/Vector.cpp | 2 +- 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/demos/diagonal.cpp b/demos/diagonal.cpp index dde6fc8..dac1a9b 100644 --- a/demos/diagonal.cpp +++ b/demos/diagonal.cpp @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MIT #include -#include #include #include diff --git a/spmv/Matrix.cpp b/spmv/Matrix.cpp index f1773ad..8f15857 100644 --- a/spmv/Matrix.cpp +++ b/spmv/Matrix.cpp @@ -4,7 +4,7 @@ #include -#include "mkl_sycl.hpp" +#include "oneapi/mkl.hpp" #include "Matrix.h" #include "mpi_type.h" diff --git a/spmv/Matrix.h b/spmv/Matrix.h index ac3b5b1..3cb4784 100644 --- a/spmv/Matrix.h +++ b/spmv/Matrix.h @@ -4,8 +4,8 @@ #include #include -#include #include +#include #include #include "L2GMap.h" diff --git a/spmv/Vector.cpp b/spmv/Vector.cpp index f574aeb..def1766 100644 --- a/spmv/Vector.cpp +++ b/spmv/Vector.cpp @@ -1,8 +1,8 @@ // Copyright (C) 2020 Igor Baratta (ia397@cam.ac.uk) // SPDX-License-Identifier: MIT -#include #include +#include #include "Vector.h" #include "mpi_type.h" From 36393fa7f32c6a040eaea22a43804103571f02da Mon Sep 17 00:00:00 2001 From: igorbaratta Date: Wed, 28 Oct 2020 09:01:30 -0300 Subject: [PATCH 33/37] formating --- demos/diagonal.cpp | 2 +- demos/vecnorm.cpp | 2 +- spmv/Vector.cpp | 2 +- spmv/Vector.h | 2 +- spmv/creation.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/demos/diagonal.cpp b/demos/diagonal.cpp index dac1a9b..9ee9269 100644 --- a/demos/diagonal.cpp +++ b/demos/diagonal.cpp @@ -90,4 +90,4 @@ int main(int argc, char** argv) } return 0; -} \ No newline at end of file +} diff --git a/demos/vecnorm.cpp b/demos/vecnorm.cpp index 4c23bde..77dc01a 100644 --- a/demos/vecnorm.cpp +++ b/demos/vecnorm.cpp @@ -60,4 +60,4 @@ int main(int argc, char** argv) } return 0; -} \ No newline at end of file +} diff --git a/spmv/Vector.cpp b/spmv/Vector.cpp index def1766..29a7f07 100644 --- a/spmv/Vector.cpp +++ b/spmv/Vector.cpp @@ -207,4 +207,4 @@ void Vector::update() template class spmv::Vector; template class spmv::Vector; template class spmv::Vector>; -template class spmv::Vector>; \ No newline at end of file +template class spmv::Vector>; diff --git a/spmv/Vector.h b/spmv/Vector.h index 40ffae5..95565f4 100644 --- a/spmv/Vector.h +++ b/spmv/Vector.h @@ -73,4 +73,4 @@ class Vector std::shared_ptr _map; mutable cl::sycl::queue _q; }; -} // namespace spmv \ No newline at end of file +} // namespace spmv diff --git a/spmv/creation.h b/spmv/creation.h index 67154ba..cdafbc6 100644 --- a/spmv/creation.h +++ b/spmv/creation.h @@ -235,4 +235,4 @@ create_matrix(MPI_Comm comm, const Eigen::SparseMatrix mat, spmv::Matrix b(B, col_map, row_map); return b; } -} // namespace spmv \ No newline at end of file +} // namespace spmv From d37416123e4299e27475a33b575ae5c9e13d224d Mon Sep 17 00:00:00 2001 From: igorbaratta Date: Mon, 9 Nov 2020 14:30:58 -0300 Subject: [PATCH 34/37] remove eigen --- demos/CreateA.cpp | 103 ++++----- demos/cgmain.cpp | 2 - demos/matvecmain.cpp | 1 - demos/restrictmain.cpp | 132 ------------ spmv/creation.h | 476 ++++++++++++++++++++--------------------- spmv/read_petsc.cpp | 60 ++---- spmv/utils.h | 73 +++++++ 7 files changed, 366 insertions(+), 481 deletions(-) delete mode 100644 demos/restrictmain.cpp create mode 100644 spmv/utils.h diff --git a/demos/CreateA.cpp b/demos/CreateA.cpp index 4a84c77..d9a585b 100644 --- a/demos/CreateA.cpp +++ b/demos/CreateA.cpp @@ -2,31 +2,13 @@ // SPDX-License-Identifier: MIT #include "CreateA.h" -#include + #include #include #include -//----------------------------------------------------------------------------- -// Divide size into N ~equal chunks -std::vector owner_ranges(std::int64_t size, std::int64_t N) -{ - // Compute number of items per process and remainder - const std::int64_t n = N / size; - const std::int64_t r = N % size; - - // Compute local range - std::vector ranges; - for (int rank = 0; rank < (size + 1); ++rank) - { - if (rank < r) - ranges.push_back(rank * (n + 1)); - else - ranges.push_back(rank * n + r); - } +#include - return ranges; -} //----------------------------------------------------------------------------- spmv::Matrix create_A(MPI_Comm comm, int N) { @@ -36,15 +18,16 @@ spmv::Matrix create_A(MPI_Comm comm, int N) MPI_Comm_size(comm, &mpi_size); // Make a square Matrix divided evenly across cores - std::vector ranges = owner_ranges(mpi_size, N); + std::vector ranges = spmv::owner_ranges(mpi_size, N); std::int64_t r0 = ranges[mpi_rank]; std::int64_t r1 = ranges[mpi_rank + 1]; int M = r1 - r0; - // Local part of the matrix - // Must be RowMajor and compressed - Eigen::SparseMatrix A(M, N); + // Local part of the matrix, COO format + std::vector coo_data; + std::vector coo_row; + std::vector coo_col; // Set up A // Add entries on all local rows @@ -57,29 +40,46 @@ spmv::Matrix create_A(MPI_Comm comm, int N) // Special case for very first and last global rows if (c0 == 0) { - A.insert(i, c0) = 1.0 - gamma; - A.insert(i, c0 + 1) = gamma; + coo_data.push_back(1.0 - gamma); + coo_row.push_back(i); + coo_col.push_back(c0); + + coo_data.push_back(gamma); + coo_row.push_back(i); + coo_col.push_back(c0 + 1); } else if (c0 == (N - 1)) { - A.insert(i, c0 - 1) = gamma; - A.insert(i, c0) = 1.0 - gamma; + coo_data.push_back(gamma); + coo_row.push_back(i); + coo_col.push_back(c0 - 1); + + coo_data.push_back(1.0 - gamma); + coo_row.push_back(i); + coo_col.push_back(c0); } else { - A.insert(i, c0 - 1) = gamma; - A.insert(i, c0) = 1.0 - 2.0 * gamma; - A.insert(i, c0 + 1) = gamma; + coo_data.push_back(1.0 - gamma); + coo_row.push_back(i); + coo_col.push_back(c0); + + coo_data.push_back(1.0 - 2.0 * gamma); + coo_row.push_back(i); + coo_col.push_back(c0); + + coo_data.push_back(gamma); + coo_row.push_back(i); + coo_col.push_back(c0 + 1); } } - A.makeCompressed(); // Remap columns to local indexing std::set ghost_indices; - std::int32_t nnz = A.outerIndexPtr()[M]; + std::int32_t nnz = coo_col.size(); for (std::int32_t i = 0; i < nnz; ++i) { - std::int32_t global_index = A.innerIndexPtr()[i]; + std::int32_t global_index = coo_col[i]; if (global_index < r0 or global_index >= r1) ghost_indices.insert(global_index); } @@ -90,38 +90,13 @@ spmv::Matrix create_A(MPI_Comm comm, int N) = std::make_shared(comm, M, std::vector()); // Rebuild A using local indices - Eigen::SparseMatrix Alocal(M, M + ghosts.size()); - std::vector> vals; - std::int32_t* Aouter = A.outerIndexPtr(); - std::int32_t* Ainner = A.innerIndexPtr(); - double* Aval = A.valuePtr(); - - for (std::int32_t row = 0; row < M; ++row) + for (auto& col : coo_col) { - for (std::int32_t j = Aouter[row]; j < Aouter[row + 1]; ++j) - { - std::int32_t col = col_l2g->global_to_local(Ainner[j]); - double val = Aval[j]; - vals.push_back(Eigen::Triplet(row, col, val)); - } + col = col_l2g->global_to_local(col); } - Alocal.setFromTriplets(vals.begin(), vals.end()); - Alocal.makeCompressed(); - - // Get indptr buffer - Aouter = Alocal.outerIndexPtr(); - std::vector indptr(A.rows() + 1); - std::memcpy(indptr.data(), Aouter, sizeof(std::int32_t) * indptr.size()); - - // Get indices buffer - Ainner = Alocal.innerIndexPtr(); - std::vector indices(A.nonZeros()); - std::memcpy(indices.data(), Ainner, sizeof(std::int32_t) * indices.size()); - - // Get data buffer - double* Aptr = Alocal.valuePtr(); - std::vector data(A.nonZeros()); - std::memcpy(data.data(), Aptr, sizeof(double) * data.size()); + auto [data, indptr, indices] = spmv::coo_to_csr( + row_l2g->local_size(), col_l2g->local_size() + col_l2g->num_ghosts(), + coo_data.size(), coo_row, coo_col, coo_data); return spmv::Matrix(data, indptr, indices, col_l2g, row_l2g); } diff --git a/demos/cgmain.cpp b/demos/cgmain.cpp index 967de92..e8158b9 100644 --- a/demos/cgmain.cpp +++ b/demos/cgmain.cpp @@ -2,8 +2,6 @@ // SPDX-License-Identifier: MIT #include -#include -#include #include #include #include diff --git a/demos/matvecmain.cpp b/demos/matvecmain.cpp index 6b4a4b2..60099b1 100644 --- a/demos/matvecmain.cpp +++ b/demos/matvecmain.cpp @@ -3,7 +3,6 @@ #include -#include #include #include #include diff --git a/demos/restrictmain.cpp b/demos/restrictmain.cpp deleted file mode 100644 index aa7f089..0000000 --- a/demos/restrictmain.cpp +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (C) 2018-2020 Chris Richardson (chris@bpi.cam.ac.uk) -// SPDX-License-Identifier: MIT - -#include - -#include -#include -#include -#include -#include - -#include "CreateA.h" -#include -#include - -void restrict_main() -{ - int mpi_rank; - MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); - int mpi_size; - MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); - - // Keep list of timings - std::map> timings; - - auto timer_start = std::chrono::system_clock::now(); - // Read in a PETSc binary format matrix - auto R = spmv::read_petsc_binary(MPI_COMM_WORLD, "binaryoutput"); - -// auto q = spmv::read_petsc_binary_vector(MPI_COMM_WORLD, "b4.dat"); - - // // Get local and global sizes - // std::int64_t M = R.mat().rows(); - // auto l2g = R.col_map(); - // std::int64_t N = l2g->global_size(); - - // std::cout << "Vector = " << q.size() << " " << M << "\n"; - - // auto timer_end = std::chrono::system_clock::now(); - // timings["0.PetscRead"] += (timer_end - timer_start); - - // timer_start = std::chrono::system_clock::now(); - - // if (mpi_rank == 0) - // std::cout << "Creating vector of size " << N << "\n"; - - // // Vector in "column space" with extra space for ghosts at end - // Eigen::VectorXd psp(l2g->local_size() + l2g->num_ghosts()); - - // timer_end = std::chrono::system_clock::now(); - // timings["1.VecCreate"] += (timer_end - timer_start); - - // // Apply matrix - // if (mpi_rank == 0) - // std::cout << "Applying matrix\n"; - - // double pnorm_sum, qnorm_sum; - // for (int i = 0; i < 10; ++i) - // { - // // Restrict - // timer_start = std::chrono::system_clock::now(); - // psp = R.transpmult(q); - - // timer_end = std::chrono::system_clock::now(); - // timings["3.SpMV"] += (timer_end - timer_start); - - // timer_start = std::chrono::system_clock::now(); - // l2g->reverse_update(psp.data()); - // timer_end = std::chrono::system_clock::now(); - // timings["2.SparseUpdate"] += (timer_end - timer_start); - - // Eigen::Map p(psp.data(), l2g->local_size()); - // double pnorm = p.squaredNorm(); - // MPI_Allreduce(&pnorm, &pnorm_sum, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - - // // Prolongate - // timer_start = std::chrono::system_clock::now(); - // l2g->update(psp.data()); - // timer_end = std::chrono::system_clock::now(); - // timings["2.SparseUpdate"] += (timer_end - timer_start); - - // timer_start = std::chrono::system_clock::now(); - // q = R * psp; - - // timer_end = std::chrono::system_clock::now(); - // timings["3.SpMV"] += (timer_end - timer_start); - - // double qnorm = q.squaredNorm(); - // MPI_Allreduce(&qnorm, &qnorm_sum, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - // } - - // if (mpi_rank == 0) - // std::cout << "\nTimings (" << mpi_size - // << ")\n----------------------------\n"; - - // std::chrono::duration total_time - // = std::chrono::duration::zero(); - // for (auto q : timings) - // total_time += q.second; - // timings["Total"] = total_time; - - // for (auto q : timings) - // { - // double q_local = q.second.count(), q_max, q_min; - // MPI_Reduce(&q_local, &q_max, 1, MPI_DOUBLE, MPI_MAX, 0, MPI_COMM_WORLD); - // MPI_Reduce(&q_local, &q_min, 1, MPI_DOUBLE, MPI_MIN, 0, MPI_COMM_WORLD); - - // if (mpi_rank == 0) - // { - // std::string pad(16 - q.first.size(), ' '); - // std::cout << "[" << q.first << "]" << pad << q_min << '\t' << q_max - // << "\n"; - // } - // } - - // if (mpi_rank == 0) - // { - // std::cout << "----------------------------\n"; - // std::cout << "norm q = " << qnorm_sum << "\n"; - // std::cout << "norm p = " << pnorm_sum << "\n"; - // } -} -//----------------------------------------------------------------------------- -int main(int argc, char** argv) -{ - MPI_Init(&argc, &argv); - - restrict_main(); - - MPI_Finalize(); - return 0; -} diff --git a/spmv/creation.h b/spmv/creation.h index cdafbc6..0e5d3f8 100644 --- a/spmv/creation.h +++ b/spmv/creation.h @@ -1,238 +1,238 @@ -// Copyright (C) 2020 Chris Richardson and Igor Baratta -// SPDX-License-Identifier: MIT - -#include -#include - -#include "Matrix.h" - -namespace spmv -{ -template -spmv::Matrix -create_matrix(MPI_Comm comm, const Eigen::SparseMatrix mat, - std::int64_t nrows_local, std::int64_t ncols_local, - std::vector row_ghosts, - std::vector col_ghosts) -{ - - int mpi_size, mpi_rank; - MPI_Comm_size(comm, &mpi_size); - MPI_Comm_rank(comm, &mpi_rank); - - std::vector row_ranges(mpi_size + 1, 0); - MPI_Allgather(&nrows_local, 1, MPI_INT64_T, row_ranges.data() + 1, 1, - MPI_INT64_T, comm); - for (int i = 0; i < mpi_size; ++i) - row_ranges[i + 1] += row_ranges[i]; - - // FIX: often same as rows? - std::vector col_ranges(mpi_size + 1, 0); - MPI_Allgather(&ncols_local, 1, MPI_INT64_T, col_ranges.data() + 1, 1, - MPI_INT64_T, comm); - for (int i = 0; i < mpi_size; ++i) - col_ranges[i + 1] += col_ranges[i]; - - // Locate owner process for each row - std::vector row_owner(row_ghosts.size()); - for (std::size_t i = 0; i < row_ghosts.size(); ++i) - { - auto it - = std::upper_bound(row_ranges.begin(), row_ranges.end(), row_ghosts[i]); - assert(it != row_ranges.end()); - row_owner[i] = it - row_ranges.begin() - 1; - assert(row_owner[i] != mpi_rank); - } - - // Create a neighbour comm, remap row_owner to neighbour number - std::set neighbour_set(row_owner.begin(), row_owner.end()); - std::vector dests(neighbour_set.begin(), neighbour_set.end()); - std::map proc_to_dest; - for (std::size_t i = 0; i < dests.size(); ++i) - proc_to_dest.insert({dests[i], i}); - for (auto& q : row_owner) - q = proc_to_dest[q]; - - // Get list of sources (may be different from dests, requires AlltoAll to - // find) - std::vector is_dest(mpi_size, 0); - for (int d : dests) - is_dest[d] = 1; - std::vector is_source(mpi_size, 0); - MPI_Alltoall(is_dest.data(), 1, MPI_CHAR, is_source.data(), 1, MPI_CHAR, - comm); - std::vector sources; - for (int i = 0; i < mpi_size; ++i) - if (is_source[i] == 1) - sources.push_back(i); - - MPI_Comm neighbour_comm; - MPI_Dist_graph_create_adjacent( - comm, sources.size(), sources.data(), MPI_UNWEIGHTED, dests.size(), - dests.data(), MPI_UNWEIGHTED, MPI_INFO_NULL, false, &neighbour_comm); - - // send all ghost rows to their owners, using global col idx. - const std::int32_t* Aouter = mat.outerIndexPtr(); - const std::int32_t* Ainner = mat.innerIndexPtr(); - const T* Aval = mat.valuePtr(); - - std::vector> p_to_index(dests.size()); - std::vector> p_to_val(dests.size()); - for (std::size_t i = 0; i < row_ghosts.size(); ++i) - { - const int p = row_owner[i]; - assert(p != -1); - p_to_index[p].push_back(row_ghosts[i]); - p_to_val[p].push_back(0.0); - p_to_index[p].push_back(Aouter[nrows_local + i + 1] - - Aouter[nrows_local + i]); - p_to_val[p].push_back(0.0); - - const std::int64_t local_offset = col_ranges[mpi_rank]; - for (int j = Aouter[nrows_local + i]; j < Aouter[nrows_local + i + 1]; ++j) - { - std::int64_t global_index; - if (Ainner[j] < ncols_local) - global_index = Ainner[j] + local_offset; - else - { - assert(Ainner[j] - ncols_local < (int)col_ghosts.size()); - global_index = col_ghosts[Ainner[j] - ncols_local]; - } - p_to_index[p].push_back(global_index); - p_to_val[p].push_back(Aval[j]); - } - } - - std::vector send_size(dests.size()); - std::vector send_index; - std::vector send_val; - std::vector send_offset = {0}; - for (std::size_t p = 0; p < dests.size(); ++p) - { - send_index.insert(send_index.end(), p_to_index[p].begin(), - p_to_index[p].end()); - send_val.insert(send_val.end(), p_to_val[p].begin(), p_to_val[p].end()); - assert(p_to_val[p].size() == p_to_index[p].size()); - send_size[p] = p_to_index[p].size(); - send_offset.push_back(send_index.size()); - } - - std::vector recv_size(sources.size()); - MPI_Neighbor_alltoall(send_size.data(), 1, MPI_INT, recv_size.data(), 1, - MPI_INT, neighbour_comm); - - std::vector recv_offset = {0}; - for (int r : recv_size) - recv_offset.push_back(recv_offset.back() + r); - - std::vector recv_index(recv_offset.back()); - std::vector recv_val(recv_offset.back()); - - MPI_Neighbor_alltoallv(send_index.data(), send_size.data(), - send_offset.data(), MPI_INT64_T, recv_index.data(), - recv_size.data(), recv_offset.data(), MPI_INT64_T, - neighbour_comm); - - MPI_Neighbor_alltoallv(send_val.data(), send_size.data(), send_offset.data(), - mpi_type(), recv_val.data(), recv_size.data(), - recv_offset.data(), mpi_type(), neighbour_comm); - - // Create new map from global column index to local - std::map col_ghost_map; - for (std::int64_t q : col_ghosts) - col_ghost_map.insert({q, -1}); - - // Add any new ghost columns - int pos = 0; - while (pos < (int)recv_index.size()) - { - // std::int64_t global_row = recv_index[pos]; - ++pos; - int nnz = recv_index[pos]; - ++pos; - for (int k = 0; k < nnz; ++k) - { - const std::int64_t recv_col = recv_index[pos]; - ++pos; - if (recv_col >= col_ranges[mpi_rank + 1] - or recv_col < col_ranges[mpi_rank]) - col_ghost_map.insert({recv_col, -1}); - } - } - - // Unique numbering of ghost cols - int c = ncols_local; - for (auto& q : col_ghost_map) - q.second = c++; - - std::vector> mat_data; - for (int row = 0; row < nrows_local; ++row) - for (int j = Aouter[row]; j < Aouter[row + 1]; ++j) - { - int col = Ainner[j]; - if (col >= ncols_local) - { - // Get remapped ghost column - std::int64_t global_col = col_ghosts[col - ncols_local]; - auto it = col_ghost_map.find(global_col); - assert(it != col_ghost_map.end()); - col = it->second; - assert(col >= ncols_local); - } - - assert(row >= 0 and row < nrows_local); - assert(col >= 0 and col < (int)(ncols_local + col_ghost_map.size())); - mat_data.push_back(Eigen::Triplet(row, col, Aval[j])); - } - - // Add received data - pos = 0; - while (pos < (int)recv_index.size()) - { - std::int64_t global_row = recv_index[pos]; - assert(global_row >= row_ranges[mpi_rank] - and global_row < row_ranges[mpi_rank + 1]); - std::int32_t row = global_row - row_ranges[mpi_rank]; - ++pos; - int nnz = recv_index[pos]; - ++pos; - for (int k = 0; k < nnz; ++k) - { - const std::int64_t global_col = recv_index[pos]; - const T val = recv_val[pos]; - ++pos; - int col; - if (global_col >= col_ranges[mpi_rank + 1] - or global_col < col_ranges[mpi_rank]) - { - auto it = col_ghost_map.find(global_col); - assert(it != col_ghost_map.end()); - col = it->second; - } - else - col = global_col - col_ranges[mpi_rank]; - assert(row >= 0 and row < nrows_local); - assert(col >= 0 and col < (int)(ncols_local + col_ghost_map.size())); - mat_data.push_back(Eigen::Triplet(row, col, val)); - } - } - - // Rebuild sparse matrix - std::vector new_col_ghosts; - for (auto& q : col_ghost_map) - new_col_ghosts.push_back(q.first); - - Eigen::SparseMatrix B( - nrows_local, ncols_local + new_col_ghosts.size()); - B.setFromTriplets(mat_data.begin(), mat_data.end()); - - std::shared_ptr col_map - = std::make_shared(comm, ncols_local, new_col_ghosts); - std::shared_ptr row_map = std::make_shared( - comm, nrows_local, std::vector()); - - spmv::Matrix b(B, col_map, row_map); - return b; -} -} // namespace spmv +// // Copyright (C) 2020 Chris Richardson and Igor Baratta +// // SPDX-License-Identifier: MIT + +// #include +// #include + +// #include "Matrix.h" + +// namespace spmv +// { +// template +// spmv::Matrix +// create_matrix(MPI_Comm comm, const Eigen::SparseMatrix mat, +// std::int64_t nrows_local, std::int64_t ncols_local, +// std::vector row_ghosts, +// std::vector col_ghosts) +// { + +// int mpi_size, mpi_rank; +// MPI_Comm_size(comm, &mpi_size); +// MPI_Comm_rank(comm, &mpi_rank); + +// std::vector row_ranges(mpi_size + 1, 0); +// MPI_Allgather(&nrows_local, 1, MPI_INT64_T, row_ranges.data() + 1, 1, +// MPI_INT64_T, comm); +// for (int i = 0; i < mpi_size; ++i) +// row_ranges[i + 1] += row_ranges[i]; + +// // FIX: often same as rows? +// std::vector col_ranges(mpi_size + 1, 0); +// MPI_Allgather(&ncols_local, 1, MPI_INT64_T, col_ranges.data() + 1, 1, +// MPI_INT64_T, comm); +// for (int i = 0; i < mpi_size; ++i) +// col_ranges[i + 1] += col_ranges[i]; + +// // Locate owner process for each row +// std::vector row_owner(row_ghosts.size()); +// for (std::size_t i = 0; i < row_ghosts.size(); ++i) +// { +// auto it +// = std::upper_bound(row_ranges.begin(), row_ranges.end(), row_ghosts[i]); +// assert(it != row_ranges.end()); +// row_owner[i] = it - row_ranges.begin() - 1; +// assert(row_owner[i] != mpi_rank); +// } + +// // Create a neighbour comm, remap row_owner to neighbour number +// std::set neighbour_set(row_owner.begin(), row_owner.end()); +// std::vector dests(neighbour_set.begin(), neighbour_set.end()); +// std::map proc_to_dest; +// for (std::size_t i = 0; i < dests.size(); ++i) +// proc_to_dest.insert({dests[i], i}); +// for (auto& q : row_owner) +// q = proc_to_dest[q]; + +// // Get list of sources (may be different from dests, requires AlltoAll to +// // find) +// std::vector is_dest(mpi_size, 0); +// for (int d : dests) +// is_dest[d] = 1; +// std::vector is_source(mpi_size, 0); +// MPI_Alltoall(is_dest.data(), 1, MPI_CHAR, is_source.data(), 1, MPI_CHAR, +// comm); +// std::vector sources; +// for (int i = 0; i < mpi_size; ++i) +// if (is_source[i] == 1) +// sources.push_back(i); + +// MPI_Comm neighbour_comm; +// MPI_Dist_graph_create_adjacent( +// comm, sources.size(), sources.data(), MPI_UNWEIGHTED, dests.size(), +// dests.data(), MPI_UNWEIGHTED, MPI_INFO_NULL, false, &neighbour_comm); + +// // send all ghost rows to their owners, using global col idx. +// const std::int32_t* Aouter = mat.outerIndexPtr(); +// const std::int32_t* Ainner = mat.innerIndexPtr(); +// const T* Aval = mat.valuePtr(); + +// std::vector> p_to_index(dests.size()); +// std::vector> p_to_val(dests.size()); +// for (std::size_t i = 0; i < row_ghosts.size(); ++i) +// { +// const int p = row_owner[i]; +// assert(p != -1); +// p_to_index[p].push_back(row_ghosts[i]); +// p_to_val[p].push_back(0.0); +// p_to_index[p].push_back(Aouter[nrows_local + i + 1] +// - Aouter[nrows_local + i]); +// p_to_val[p].push_back(0.0); + +// const std::int64_t local_offset = col_ranges[mpi_rank]; +// for (int j = Aouter[nrows_local + i]; j < Aouter[nrows_local + i + 1]; ++j) +// { +// std::int64_t global_index; +// if (Ainner[j] < ncols_local) +// global_index = Ainner[j] + local_offset; +// else +// { +// assert(Ainner[j] - ncols_local < (int)col_ghosts.size()); +// global_index = col_ghosts[Ainner[j] - ncols_local]; +// } +// p_to_index[p].push_back(global_index); +// p_to_val[p].push_back(Aval[j]); +// } +// } + +// std::vector send_size(dests.size()); +// std::vector send_index; +// std::vector send_val; +// std::vector send_offset = {0}; +// for (std::size_t p = 0; p < dests.size(); ++p) +// { +// send_index.insert(send_index.end(), p_to_index[p].begin(), +// p_to_index[p].end()); +// send_val.insert(send_val.end(), p_to_val[p].begin(), p_to_val[p].end()); +// assert(p_to_val[p].size() == p_to_index[p].size()); +// send_size[p] = p_to_index[p].size(); +// send_offset.push_back(send_index.size()); +// } + +// std::vector recv_size(sources.size()); +// MPI_Neighbor_alltoall(send_size.data(), 1, MPI_INT, recv_size.data(), 1, +// MPI_INT, neighbour_comm); + +// std::vector recv_offset = {0}; +// for (int r : recv_size) +// recv_offset.push_back(recv_offset.back() + r); + +// std::vector recv_index(recv_offset.back()); +// std::vector recv_val(recv_offset.back()); + +// MPI_Neighbor_alltoallv(send_index.data(), send_size.data(), +// send_offset.data(), MPI_INT64_T, recv_index.data(), +// recv_size.data(), recv_offset.data(), MPI_INT64_T, +// neighbour_comm); + +// MPI_Neighbor_alltoallv(send_val.data(), send_size.data(), send_offset.data(), +// mpi_type(), recv_val.data(), recv_size.data(), +// recv_offset.data(), mpi_type(), neighbour_comm); + +// // Create new map from global column index to local +// std::map col_ghost_map; +// for (std::int64_t q : col_ghosts) +// col_ghost_map.insert({q, -1}); + +// // Add any new ghost columns +// int pos = 0; +// while (pos < (int)recv_index.size()) +// { +// // std::int64_t global_row = recv_index[pos]; +// ++pos; +// int nnz = recv_index[pos]; +// ++pos; +// for (int k = 0; k < nnz; ++k) +// { +// const std::int64_t recv_col = recv_index[pos]; +// ++pos; +// if (recv_col >= col_ranges[mpi_rank + 1] +// or recv_col < col_ranges[mpi_rank]) +// col_ghost_map.insert({recv_col, -1}); +// } +// } + +// // Unique numbering of ghost cols +// int c = ncols_local; +// for (auto& q : col_ghost_map) +// q.second = c++; + +// std::vector> mat_data; +// for (int row = 0; row < nrows_local; ++row) +// for (int j = Aouter[row]; j < Aouter[row + 1]; ++j) +// { +// int col = Ainner[j]; +// if (col >= ncols_local) +// { +// // Get remapped ghost column +// std::int64_t global_col = col_ghosts[col - ncols_local]; +// auto it = col_ghost_map.find(global_col); +// assert(it != col_ghost_map.end()); +// col = it->second; +// assert(col >= ncols_local); +// } + +// assert(row >= 0 and row < nrows_local); +// assert(col >= 0 and col < (int)(ncols_local + col_ghost_map.size())); +// mat_data.push_back(Eigen::Triplet(row, col, Aval[j])); +// } + +// // Add received data +// pos = 0; +// while (pos < (int)recv_index.size()) +// { +// std::int64_t global_row = recv_index[pos]; +// assert(global_row >= row_ranges[mpi_rank] +// and global_row < row_ranges[mpi_rank + 1]); +// std::int32_t row = global_row - row_ranges[mpi_rank]; +// ++pos; +// int nnz = recv_index[pos]; +// ++pos; +// for (int k = 0; k < nnz; ++k) +// { +// const std::int64_t global_col = recv_index[pos]; +// const T val = recv_val[pos]; +// ++pos; +// int col; +// if (global_col >= col_ranges[mpi_rank + 1] +// or global_col < col_ranges[mpi_rank]) +// { +// auto it = col_ghost_map.find(global_col); +// assert(it != col_ghost_map.end()); +// col = it->second; +// } +// else +// col = global_col - col_ranges[mpi_rank]; +// assert(row >= 0 and row < nrows_local); +// assert(col >= 0 and col < (int)(ncols_local + col_ghost_map.size())); +// mat_data.push_back(Eigen::Triplet(row, col, val)); +// } +// } + +// // Rebuild sparse matrix +// std::vector new_col_ghosts; +// for (auto& q : col_ghost_map) +// new_col_ghosts.push_back(q.first); + +// Eigen::SparseMatrix B( +// nrows_local, ncols_local + new_col_ghosts.size()); +// B.setFromTriplets(mat_data.begin(), mat_data.end()); + +// std::shared_ptr col_map +// = std::make_shared(comm, ncols_local, new_col_ghosts); +// std::shared_ptr row_map = std::make_shared( +// comm, nrows_local, std::vector()); + +// spmv::Matrix b(B, col_map, row_map); +// return b; +// } +// } // namespace spmv diff --git a/spmv/read_petsc.cpp b/spmv/read_petsc.cpp index 5ff5b16..e621019 100644 --- a/spmv/read_petsc.cpp +++ b/spmv/read_petsc.cpp @@ -3,7 +3,6 @@ #include -#include #include #include #include @@ -12,31 +11,16 @@ #include "L2GMap.h" #include "read_petsc.h" +#include "utils.h" -// Divide size into N ~equal chunks -std::vector owner_ranges(int size, std::int64_t N) -{ - // Compute number of items per process and remainder - const std::int64_t n = N / size; - const std::int64_t r = N % size; - - // Compute local range - std::vector ranges; - for (int rank = 0; rank < (size + 1); ++rank) - { - if (rank < r) - ranges.push_back(rank * (n + 1)); - else - ranges.push_back(rank * n + r); - } - - return ranges; -} //----------------------------------------------------------------------------- spmv::Matrix spmv::read_petsc_binary(MPI_Comm comm, std::string filename) { - Eigen::SparseMatrix A; + // COO data structure + std::vector coo_data; + std::vector coo_row; + std::vector coo_col; int mpi_rank; MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); @@ -144,8 +128,6 @@ spmv::Matrix spmv::read_petsc_binary(MPI_Comm comm, ++c; } - A.resize(nrows_local, col_indices.size()); - // Read values std::vector valuedata(nnz_size * 8); file.seekg(value_data_pos, std::ios::beg); @@ -170,16 +152,15 @@ spmv::Matrix spmv::read_petsc_binary(MPI_Comm comm, // Look up column local index std::int32_t col = col_indices[*((std::int32_t*)ptr)]; ptr += 4; - - A.insert(row - row_ranges[mpi_rank], col) = val; + coo_data.push_back(val); + coo_row.push_back(row - row_ranges[mpi_rank]); + coo_col.push_back(col); } } } else throw std::runtime_error("Could not open file"); - A.makeCompressed(); - std::vector ghosts(col_indices.size() - ncols_local); for (auto& q : col_indices) if (q.first < col_ranges[mpi_rank] or q.first >= col_ranges[mpi_rank + 1]) @@ -188,26 +169,18 @@ spmv::Matrix spmv::read_petsc_binary(MPI_Comm comm, auto col_map = std::make_shared(comm, ncols_local, ghosts); auto row_map = std::make_shared(comm, nrows_local); - // Get indptr buffer - std::int32_t* Aouter = A.outerIndexPtr(); - std::vector indptr(A.rows() + 1); - std::memcpy(indptr.data(), Aouter, sizeof(std::int32_t) * indptr.size()); - - // Get indices buffer - std::int32_t* Ainner = A.innerIndexPtr(); - std::vector indices(A.nonZeros()); - std::memcpy(indices.data(), Ainner, sizeof(std::int32_t) * indices.size()); + auto [data, indptr, indices] + = coo_to_csr(nrows_local, col_indices.size(), coo_data.size(), + coo_row, coo_col, coo_data); - // Get data buffer - double* Aptr = A.valuePtr(); - std::vector data(A.nonZeros()); - std::memcpy(data.data(), Aptr, sizeof(double) * data.size()); + for (std::int32_t i = 0; i < 20; i++) + std::cout << indptr[i] << " "; - return spmv::Matrix(data, indptr, indices, col_map, row_map); + return spmv::Matrix(data, indptr, indices, col_map, row_map); } //----------------------------------------------------------------------------- std::vector spmv::read_petsc_binary_vector(MPI_Comm comm, - std::string filename) + std::string filename) { std::vector vec; @@ -260,8 +233,7 @@ std::vector spmv::read_petsc_binary_vector(MPI_Comm comm, // Pointer to values char* vptr = valuedata.data(); - for (std::int64_t row = ranges[mpi_rank]; row < ranges[mpi_rank + 1]; - ++row) + for (std::int64_t row = ranges[mpi_rank]; row < ranges[mpi_rank + 1]; ++row) { std::swap(*vptr, *(vptr + 7)); std::swap(*(vptr + 1), *(vptr + 6)); diff --git a/spmv/utils.h b/spmv/utils.h new file mode 100644 index 0000000..1f2bb2e --- /dev/null +++ b/spmv/utils.h @@ -0,0 +1,73 @@ +// Copyright (C) 2020 Igor Baratta (ia397@cam.ac.uk) +// SPDX-License-Identifier: MIT + +#include +#include +#include + +namespace spmv +{ + +// Divide size into N ~equal chunks +std::vector owner_ranges(int size, std::int64_t N) +{ + // Compute number of items per process and remainder + const std::int64_t n = N / size; + const std::int64_t r = N % size; + + // Compute local range + std::vector ranges; + for (int rank = 0; rank < (size + 1); ++rank) + { + if (rank < r) + ranges.push_back(rank * (n + 1)); + else + ranges.push_back(rank * n + r); + } + + return ranges; +} + +/// Simple csr data sctructure used for structured binding in C++ 17 +template +struct csr_data +{ + std::vector data; + std::vector indptr; + std::vector indices; +}; + +template +csr_data +coo_to_csr(const std::int32_t nrows, const std::int32_t ncols, + const std::int32_t nnz, std::vector coo_row, + std::vector coo_col, std::vector coo_data) +{ + std::vector data(nnz); + std::vector indptr(nrows + 1); + std::vector indices(nnz); + + // Compute number of non-zero entries per row of A + std::vector nnz_row(nrows); + for (std::int32_t i = 0; i < nnz; i++) + nnz_row[coo_row[i]]++; + + std::exclusive_scan(nnz_row.begin(), nnz_row.end(), indptr.begin(), 0); + indptr[nrows] = nnz; + + std::fill(nnz_row.begin(), nnz_row.end(), 0); + for (std::int32_t i = 0; i < nnz; i++) + { + std::int32_t row = coo_row[i]; + std::int32_t pos = nnz_row[row] + indptr[row]; + + data[pos] = coo_data[i]; + indices[pos] = coo_col[i]; + + nnz_row[row]++; + } + + return {data, indptr, indices}; +} + +} // namespace spmv \ No newline at end of file From cde16d042651becbf1ccf828fe62c85e6221652d Mon Sep 17 00:00:00 2001 From: igorbaratta Date: Mon, 9 Nov 2020 14:44:45 -0300 Subject: [PATCH 35/37] remove demo --- demos/CMakeLists.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/demos/CMakeLists.txt b/demos/CMakeLists.txt index 80a1473..1d06fb4 100644 --- a/demos/CMakeLists.txt +++ b/demos/CMakeLists.txt @@ -12,9 +12,6 @@ target_link_libraries(diagonal ${PROJECT_NAME}) add_executable(cgmain cgmain.cpp) target_link_libraries(cgmain LINK_PUBLIC ${PROJECT_NAME}) -add_executable(restrictmain restrictmain.cpp) -target_link_libraries(restrictmain ${PROJECT_NAME}) - # Copy files matrix and vector files to binary dir file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/petsc_mat_poisson DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) From 4a0e212a1b7598c4407e75f0b6137f2cd2e69e4e Mon Sep 17 00:00:00 2001 From: igorbaratta Date: Mon, 9 Nov 2020 15:30:52 -0300 Subject: [PATCH 36/37] keep removing eigen --- demos/CreateA.cpp | 14 ++++++++++---- spmv/read_petsc.cpp | 5 +---- spmv/utils.h | 2 ++ 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/demos/CreateA.cpp b/demos/CreateA.cpp index d9a585b..5c4fbdf 100644 --- a/demos/CreateA.cpp +++ b/demos/CreateA.cpp @@ -40,34 +40,41 @@ spmv::Matrix create_A(MPI_Comm comm, int N) // Special case for very first and last global rows if (c0 == 0) { + // A.insert(i, c0) = 1.0 - gamma; coo_data.push_back(1.0 - gamma); coo_row.push_back(i); coo_col.push_back(c0); + // A.insert(i, c0 + 1) = gamma; coo_data.push_back(gamma); coo_row.push_back(i); coo_col.push_back(c0 + 1); } else if (c0 == (N - 1)) { + // A.insert(i, c0 - 1) = gamma; coo_data.push_back(gamma); coo_row.push_back(i); coo_col.push_back(c0 - 1); + // A.insert(i, c0) = 1.0 - gamma; coo_data.push_back(1.0 - gamma); coo_row.push_back(i); coo_col.push_back(c0); } else { - coo_data.push_back(1.0 - gamma); + // A.insert(i, c0 - 1) = gamma; + coo_data.push_back(gamma); coo_row.push_back(i); - coo_col.push_back(c0); + coo_col.push_back(c0 - 1); + // A.insert(i, c0) = 1.0 - 2.0 * gamma; coo_data.push_back(1.0 - 2.0 * gamma); coo_row.push_back(i); coo_col.push_back(c0); + // A.insert(i, c0 + 1) = gamma; coo_data.push_back(gamma); coo_row.push_back(i); coo_col.push_back(c0 + 1); @@ -91,9 +98,8 @@ spmv::Matrix create_A(MPI_Comm comm, int N) // Rebuild A using local indices for (auto& col : coo_col) - { col = col_l2g->global_to_local(col); - } + auto [data, indptr, indices] = spmv::coo_to_csr( row_l2g->local_size(), col_l2g->local_size() + col_l2g->num_ghosts(), coo_data.size(), coo_row, coo_col, coo_data); diff --git a/spmv/read_petsc.cpp b/spmv/read_petsc.cpp index e621019..357790c 100644 --- a/spmv/read_petsc.cpp +++ b/spmv/read_petsc.cpp @@ -173,10 +173,7 @@ spmv::Matrix spmv::read_petsc_binary(MPI_Comm comm, = coo_to_csr(nrows_local, col_indices.size(), coo_data.size(), coo_row, coo_col, coo_data); - for (std::int32_t i = 0; i < 20; i++) - std::cout << indptr[i] << " "; - - return spmv::Matrix(data, indptr, indices, col_map, row_map); + return spmv::Matrix(data, indptr, indices, col_map, row_map); } //----------------------------------------------------------------------------- std::vector spmv::read_petsc_binary_vector(MPI_Comm comm, diff --git a/spmv/utils.h b/spmv/utils.h index 1f2bb2e..f523976 100644 --- a/spmv/utils.h +++ b/spmv/utils.h @@ -1,6 +1,7 @@ // Copyright (C) 2020 Igor Baratta (ia397@cam.ac.uk) // SPDX-License-Identifier: MIT +#include #include #include #include @@ -37,6 +38,7 @@ struct csr_data std::vector indices; }; +// TODO: Parallel Kernel template csr_data coo_to_csr(const std::int32_t nrows, const std::int32_t ncols, From 323f8485d8399026c46439177fb30b2cd8de68c3 Mon Sep 17 00:00:00 2001 From: igorbaratta Date: Mon, 9 Nov 2020 16:04:48 -0300 Subject: [PATCH 37/37] fix for gcc<9.3 --- spmv/utils.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/spmv/utils.h b/spmv/utils.h index f523976..5ff8026 100644 --- a/spmv/utils.h +++ b/spmv/utils.h @@ -1,8 +1,8 @@ // Copyright (C) 2020 Igor Baratta (ia397@cam.ac.uk) // SPDX-License-Identifier: MIT -#include #include +#include #include #include @@ -54,7 +54,11 @@ coo_to_csr(const std::int32_t nrows, const std::int32_t ncols, for (std::int32_t i = 0; i < nnz; i++) nnz_row[coo_row[i]]++; - std::exclusive_scan(nnz_row.begin(), nnz_row.end(), indptr.begin(), 0); + std::partial_sum(nnz_row.begin(), nnz_row.end(), indptr.begin() + 1, + std::plus()); + // std::exclusive_scan(nnz_row.begin(), nnz_row.end(), indptr.begin(), 0); + + indptr[0] = 0; indptr[nrows] = nnz; std::fill(nnz_row.begin(), nnz_row.end(), 0);