From 2a8621c4a7a59ba5fd95123eb30f5ba735eef1b8 Mon Sep 17 00:00:00 2001 From: Eduard Valeyev Date: Wed, 24 Jul 2024 08:44:18 -0400 Subject: [PATCH] introduced ttg::matrix::Triplet (replacement for Eigen::Triplet) to enable moves --- examples/spmm/spmm.cc | 11 +++-- examples/spmm/spmm_cuda.cc | 12 +++-- examples/ttg_matrix.h | 97 ++++++++++++++++++++++++++------------ 3 files changed, 79 insertions(+), 41 deletions(-) diff --git a/examples/spmm/spmm.cc b/examples/spmm/spmm.cc index 7cf656e4e..c09e908fb 100644 --- a/examples/spmm/spmm.cc +++ b/examples/spmm/spmm.cc @@ -29,6 +29,7 @@ #endif #include "ttg.h" +#include "../ttg_matrix.h" using namespace ttg; @@ -103,7 +104,7 @@ using blk_t = double; template using SpMatrix = Eigen::SparseMatrix; template -using SpMatrixTriplet = Eigen::Triplet; // {row,col,value} +using SpMatrixTriplet = ttg::matrix::Triplet; // {row,col,value} #if defined(BLOCK_SPARSE_GEMM) && defined(BTAS_IS_USABLE) @@ -990,7 +991,7 @@ static void initSpRmat(const std::function &)> &keymap, const c boost::minstd_rand gen(seed); boost::rmat_iterator> rmat_it(gen, N, E, a, b, c, d); - using triplet_t = Eigen::Triplet; + using triplet_t = ttg::matrix::Triplet; std::vector A_elements; for (int i = 0; i < N; i++) { nnz++; @@ -1026,7 +1027,7 @@ static void initSpHardCoded(const std::function &)> &keymap, Sp C.resize(m, n); // We initialize the same matrices on all the ranks, but we will use only the local part // following the keymap - using triplet_t = Eigen::Triplet; + using triplet_t = ttg::matrix::Triplet; std::vector A_elements; A_elements.emplace_back(0, 1, 12.3); A_elements.emplace_back(0, 2, 10.7); @@ -1073,7 +1074,7 @@ static void initBlSpHardCoded(const std::function &)> &keymap, int rank = ttg::default_execution_context().rank(); - using triplet_t = Eigen::Triplet; + using triplet_t = ttg::matrix::Triplet; std::vector A_elements; std::vector Aref_elements; #if defined(BTAS_IS_USABLE) @@ -1239,7 +1240,7 @@ static void initBlSpRandom(const std::function &)> &keymap, siz std::mt19937 genv(seed + 1); std::uniform_int_distribution<> dist(minTs, maxTs); // randomly pick any value in the range minTs, maxTs - using triplet_t = Eigen::Triplet; + using triplet_t = ttg::matrix::Triplet; std::vector A_elements; std::vector B_elements; std::vector Aref_elements; diff --git a/examples/spmm/spmm_cuda.cc b/examples/spmm/spmm_cuda.cc index 9dcf5928e..6597c0921 100644 --- a/examples/spmm/spmm_cuda.cc +++ b/examples/spmm/spmm_cuda.cc @@ -54,6 +54,8 @@ using namespace ttg; #include #endif +#include "../ttg_matrix.h" + #if defined(BLOCK_SPARSE_GEMM) && defined(BTAS_IS_USABLE) template @@ -399,7 +401,7 @@ using blk_t = double; template using SpMatrix = Eigen::SparseMatrix; template -using SpMatrixTriplet = Eigen::Triplet; // {row,col,value} +using SpMatrixTriplet = ttg::matrix::Triplet; // {row,col,value} #if defined(BLOCK_SPARSE_GEMM) && defined(BTAS_IS_USABLE) @@ -1197,7 +1199,7 @@ static void initSpRmat(const std::function &)> &keymap, const c boost::minstd_rand gen(seed); boost::rmat_iterator> rmat_it(gen, N, E, a, b, c, d); - using triplet_t = Eigen::Triplet; + using triplet_t = ttg::matrix::Triplet; std::vector A_elements; for (int i = 0; i < N; i++) { nnz++; @@ -1232,7 +1234,7 @@ static void initSpHardCoded(const std::function &)> &keymap, Sp C.resize(m, n); // We initialize the same matrices on all the ranks, but we will use only the local part // following the keymap - using triplet_t = Eigen::Triplet; + using triplet_t = ttg::matrix::Triplet; std::vector A_elements; A_elements.emplace_back(0, 1, 12.3); A_elements.emplace_back(0, 2, 10.7); @@ -1279,7 +1281,7 @@ static void initBlSpHardCoded(const std::function &)> &keymap, int rank = ttg::default_execution_context().rank(); - using triplet_t = Eigen::Triplet; + using triplet_t = ttg::matrix::Triplet; std::vector A_elements; std::vector Aref_elements; #if defined(BTAS_IS_USABLE) @@ -1446,7 +1448,7 @@ static void initBlSpRandom(const std::function &)> &keymap, siz std::mt19937 genv(seed + 1); std::uniform_int_distribution<> dist(minTs, maxTs); // randomly pick any value in the range minTs, maxTs - using triplet_t = Eigen::Triplet; + using triplet_t = ttg::matrix::Triplet; std::vector A_elements; std::vector B_elements; std::vector Aref_elements; diff --git a/examples/ttg_matrix.h b/examples/ttg_matrix.h index 3478e2aa4..ce563cb4a 100644 --- a/examples/ttg_matrix.h +++ b/examples/ttg_matrix.h @@ -8,11 +8,46 @@ #include #include "ttg/serialization/std/vector.h" +#include "ttg/util/multiindex.h" + +#include namespace ttg { namespace matrix { + /// element of a sparse matrix = {row index, col index, value} + + /// movable replacement for Eigen::Triplet + template::StorageIndex > + class Triplet { + public: + Triplet() = default; + Triplet(const Triplet&) = default; + Triplet(Triplet&&) = default; + Triplet& operator=(const Triplet&) = default; + Triplet& operator=(Triplet&&) = default; + + Triplet(StorageIndex r, const StorageIndex c, const Value& v) + : m_row(r), m_col(c), m_value(v) + {} + Triplet(StorageIndex r, const StorageIndex c, Value&& v = Value{}) + : m_row(r), m_col(c), m_value(std::move(v)) + {} + + /** \returns the row index of the element */ + const StorageIndex& row() const { return m_row; } + + /** \returns the column index of the element */ + const StorageIndex& col() const { return m_col; } + + /** \returns the value of the element */ + const Value& value() const { return m_value; } + protected: + StorageIndex m_row = -1, m_col = -1; + Value m_value; + }; + // matrix shape = maps {column,row} index to {row,column} indices class Shape : public std::vector> { using base_t = std::vector>; @@ -192,22 +227,22 @@ namespace ttg { } // compute shape of an existing SpMatrix on rank 0 - template + template class ReadShape : public TT>, ReadShape, ttg::typelist> { public: using baseT = typename ReadShape::ttT; static constexpr const int owner = 0; // where data resides - ReadShape(const char *label, const SpMatrix &matrix, Edge &in, Edge &out) + ReadShape(const char *label, const Eigen::SparseMatrix &matrix, Edge &in, Edge &out) : baseT(edges(in), edges(out), std::string("read_spmatrix_shape(") + label + ")", {"ctl"}, {std::string("shape[") + label + "]"}, /* keymap */ []() { return owner; }) , matrix_(matrix) {} - void op(std::tuple> &out) { ::sendv<0>(Shape(matrix_), out); } + void op(std::tuple> &out) { ttg::sendv<0>(Shape(matrix_), out); } private: - const SpMatrix &matrix_; + const Eigen::SparseMatrix &matrix_; }; // flow data from an existing SpMatrix on rank 0 @@ -217,38 +252,38 @@ namespace ttg { // but will only be efficient if can do random access (slow with CSC format used by Eigen matrices) // - this could be generalized to read efficiently from a distributed data structure // Use Read_SpMatrix if need to read all data from a data structure localized on 1 process - template - class Read : public TT, std::tuple, Blk>>, Read, ttg::typelist> { + template + class Read : public TT, std::tuple, Blk>>, Read, ttg::typelist> { public: - using baseT = TT, std::tuple, Blk>>, Read, void>; + using baseT = TT, std::tuple, Blk>>, Read, void>; static constexpr const int owner = 0; // where data resides - Read(const char *label, const SpMatrix &matrix, Edge, void> &in, Edge, Blk> &out) + Read(const char *label, const Eigen::SparseMatrix &matrix, Edge, void> &in, Edge, Blk> &out) : baseT(edges(in), edges(out), std::string("read_spmatrix(") + label + ")", {"ctl[ij]"}, {std::string(label) + "[ij]"}, /* keymap */ [](auto key) { return owner; }) , matrix_(matrix) {} - void op(const Key<2> &key, std::tuple, Blk>> &out) { + void op(const MultiIndex<2> &key, std::tuple, Blk>> &out) { // random access in CSC format is inefficient, this is only to demonstrate the way to go for hash-based storage // for whatever reason coeffRef does not work on a const SpMatrix& - ::send<0>(key, static_cast(const_cast &>(matrix_).coeffRef(key[0], key[1])), out); + ttg::send<0>(key, static_cast(const_cast &>(matrix_).coeffRef(key[0], key[1])), out); } private: - const SpMatrix &matrix_; + const Eigen::SparseMatrix &matrix_; }; // WriteShape commits shape to an existing SpMatrix on rank 0 and sends it on // since SpMatrix supports random inserts there is no need to commit the shape into the matrix, other than get the // dimensions - template + template class WriteShape : public TT>, WriteShape, ttg::typelist> { public: using baseT = typename WriteShape::ttT; static constexpr const int owner = 0; // where data resides - WriteShape(const char *label, SpMatrix &matrix, Edge &in, Edge &out) + WriteShape(const char *label, Eigen::SparseMatrix &matrix, Edge &in, Edge &out) : baseT(edges(in), edges(out), std::string("write_spmatrix_shape(") + label + ")", {std::string("shape_in[") + label + "]"}, {std::string("shape_out[") + label + "]"}, /* keymap */ []() { return owner; }) @@ -256,28 +291,28 @@ namespace ttg { void op(typename baseT::input_values_tuple_type &&ins, std::tuple> &out) { const auto &shape = baseT::template get<0>(ins); - ::ttg::trace("Resizing ", static_cast(&matrix_)); + ttg::trace("Resizing ", static_cast(&matrix_)); matrix_.resize(shape.nrows(), shape.ncols()); - ::sendv<0>(shape, out); + ttg::sendv<0>(shape, out); } private: - SpMatrix &matrix_; + Eigen::SparseMatrix &matrix_; }; // flow (move?) data into an existing SpMatrix on rank 0 - template - class Write : public TT, std::tuple<>, Write, Blk, ttg::typelist> { + template + class Write : public TT, std::tuple<>, Write, ttg::typelist> { public: using baseT = typename Write::ttT; - Write(const char *label, SpMatrix &matrix, Edge, Blk> &data_in, Edge, void> &ctl_in) + Write(const char *label, Eigen::SparseMatrix &matrix, Edge, Blk> &data_in, Edge, void> &ctl_in) : baseT(edges(data_in, ctl_in), edges(), std::string("write_spmatrix(") + label + ")", {std::string(label) + "[ij]", std::string("ctl[ij]")}, {}, /* keymap */ [](auto key) { return 0; }) , matrix_(matrix) {} - void op(const Key<2> &key, typename baseT::input_values_tuple_type &&elem, std::tuple<> &) { + void op(const MultiIndex<2> &key, typename baseT::input_values_tuple_type &&elem, std::tuple<> &) { std::lock_guard lock(mtx_); ttg::trace("rank =", default_execution_context().rank(), "/ thread_id =", reinterpret_cast(pthread_self()), @@ -309,8 +344,8 @@ namespace ttg { private: std::mutex mtx_; - SpMatrix &matrix_; - std::vector> values_; + Eigen::SparseMatrix &matrix_; + std::vector> values_; mutable std::shared_ptr> completion_status_; }; @@ -325,28 +360,28 @@ namespace ttg { /* keymap */ []() { return owner; }) {} void op(typename baseT::input_values_tuple_type &&ins, std::tuple> &out) { - ::sendv<0>(Shape::add(baseT::template get<0>(ins), baseT::template get<1>(ins)), out); + ttg::sendv<0>(Shape::add(baseT::template get<0>(ins), baseT::template get<1>(ins)), out); } }; // pushes all blocks given by the shape - class Push : public TT, void>>, Push, ttg::typelist> { + class Push : public TT, void>>, Push, ttg::typelist> { public: using baseT = typename Push::ttT; static constexpr const int owner = 0; // where data resides - Push(const char *label, Edge &in, Edge, void> &out) + Push(const char *label, Edge &in, Edge, void> &out) : baseT(edges(in), edges(out), std::string("push_spmatrix(") + label + ")", {std::string("shape[") + label + "]"}, {"ctl[ij]"}, /* keymap */ []() { return owner; }) {} - void op(typename baseT::input_values_tuple_type &&ins, std::tuple, void>> &out) { + void op(typename baseT::input_values_tuple_type &&ins, std::tuple, void>> &out) { const auto &shape = baseT::get<0>(ins); if (shape.type() == Shape::Type::col2row) { long colidx = 0; for (const auto &col : shape) { for (const auto rowidx : col) { - ::sendk<0>(Key<2>({rowidx, colidx}), out); + ttg::sendk<0>(MultiIndex<2>({rowidx, colidx}), out); } ++colidx; } @@ -354,7 +389,7 @@ namespace ttg { long rowidx = 0; for (const auto &row : shape) { for (const auto colidx : row) { - ::sendk<0>(Key<2>({rowidx, colidx}), out); + ttg::sendk<0>(MultiIndex<2>({rowidx, colidx}), out); } ++rowidx; } @@ -372,9 +407,9 @@ namespace ttg { class Matrix { public: using shape_t = matrix::Shape; - using data_edge_t = Edge, T>; + using data_edge_t = Edge, T>; using shape_edge_t = Edge; - using ctl_edge_t = Edge, void>; + using ctl_edge_t = Edge, void>; Matrix() = default; @@ -403,7 +438,7 @@ namespace ttg { /// @return an std::future object indicating the status; @c destination_matrix is ready if calling has_value() /// on the return value of this function is true. /// @note up to the user to ensure completion before reading destination_matrix - auto operator>>(SpMatrix &destination_matrix) { + auto operator>>(Eigen::SparseMatrix &destination_matrix) { // shape writer writes shape to destination_matrix ttg_register_ptr(world_, std::make_shared>("Matrix.WriteShape", destination_matrix, shape_edge_, shape_writer_push_edge_));