diff --git a/examples/floyd-warshall/floyd_warshall.cc b/examples/floyd-warshall/floyd_warshall.cc index d6de4b424a..8e7c6b8906 100644 --- a/examples/floyd-warshall/floyd_warshall.cc +++ b/examples/floyd-warshall/floyd_warshall.cc @@ -95,8 +95,7 @@ std::ostream& operator<<(std::ostream& s, const Control& ctl) { class Initiator : public TT, Out, Out, Out>, Initiator> { - using baseT = - TT, Out, Out, Out>, Initiator>; + using baseT = typename Initiator::ttT; public: Initiator(const std::string& name) : baseT(name, {}, {"outA", "outB", "outC", "outD"}) {} @@ -128,11 +127,8 @@ class Initiator : public TT, Out class FuncA : public TT, Out, Out, Out, Out, Out>, - FuncA, Control> { - using baseT = TT, Out, Out, Out, - Out, Out>, - FuncA, Control>; + FuncA, std::tuple> { + using baseT = typename FuncA::ttT; double* adjacency_matrix_ttg; int problem_size; int blocking_factor; @@ -224,10 +220,8 @@ class FuncB : public TT< Key, std::tuple, Out, Out, Out, Out>, - FuncB, Control, Control> { - using baseT = - TT, Out, Out, Out, Out>, - FuncB, Control, Control>; + FuncB, std::tuple> { + using baseT = typename FuncB::ttT; double* adjacency_matrix_ttg; int problem_size; int blocking_factor; @@ -317,10 +311,8 @@ class FuncC : public TT< Key, std::tuple, Out, Out, Out, Out>, - FuncC, Control, Control> { - using baseT = - TT, Out, Out, Out, Out>, - FuncC, Control, Control>; + FuncC, std::tuple> { + using baseT = typename FuncC::ttT; double* adjacency_matrix_ttg; int problem_size; int blocking_factor; @@ -407,9 +399,8 @@ class FuncC }; class FuncD : public TT, Out, Out, Out>, - FuncD, Control, Control, Control> { - using baseT = TT, Out, Out, Out>, FuncD, - Control, Control, Control>; + FuncD, std::tuple> { + using baseT = typename FuncD::ttT; double* adjacency_matrix_ttg; int problem_size; int blocking_factor; diff --git a/examples/floyd-warshall/floyd_warshall_df.cc b/examples/floyd-warshall/floyd_warshall_df.cc index 7bb203ce22..7a533d4a95 100644 --- a/examples/floyd-warshall/floyd_warshall_df.cc +++ b/examples/floyd-warshall/floyd_warshall_df.cc @@ -154,8 +154,8 @@ class Initiator : public TT -class Finalizer : public TT, Finalizer, BlockMatrix> { - using baseT = TT, Finalizer, BlockMatrix>; +class Finalizer : public TT, Finalizer, std::tuple>> { + using baseT = typename Finalizer::ttT; Matrix* result_matrix_ttg; int problem_size; int blocking_factor; @@ -236,12 +236,8 @@ class FuncA : public TT>, Out>, Out>, Out>, Out>, Out>, Out>>, - FuncA, BlockMatrix> { - using baseT = TT< - Key, - std::tuple>, Out>, Out>, Out>, - Out>, Out>, Out>>, - FuncA, BlockMatrix>; + FuncA, std::tuple>> { + using baseT = typename FuncA::ttT; Matrix* adjacency_matrix_ttg; int problem_size; int blocking_factor; @@ -339,11 +335,8 @@ template class FuncB : public TT>, Out>, Out>, Out>, Out>, Out>>, - FuncB, BlockMatrix, const BlockMatrix> { - using baseT = TT>, Out>, Out>, - Out>, Out>, Out>>, - FuncB, BlockMatrix, const BlockMatrix>; + FuncB, std::tuple, const BlockMatrix>> { + using baseT = typename FuncB::ttT; Matrix* adjacency_matrix_ttg; int problem_size; int blocking_factor; @@ -432,11 +425,8 @@ template class FuncC : public TT>, Out>, Out>, Out>, Out>, Out>>, - FuncC, BlockMatrix, const BlockMatrix> { - using baseT = TT>, Out>, Out>, - Out>, Out>, Out>>, - FuncC, BlockMatrix, const BlockMatrix>; + FuncC, std::tuple, const BlockMatrix>> { + using baseT = typename FuncC::ttT; Matrix* adjacency_matrix_ttg; int problem_size; int blocking_factor; @@ -524,11 +514,8 @@ template class FuncD : public TT>, Out>, Out>, Out>, Out>>, - FuncD, BlockMatrix, const BlockMatrix, const BlockMatrix> { - using baseT = TT>, Out>, Out>, - Out>, Out>>, - FuncD, BlockMatrix, const BlockMatrix, const BlockMatrix>; + FuncD, std::tuple, const BlockMatrix, const BlockMatrix>> { + using baseT = typename FuncD::ttT; Matrix* adjacency_matrix_ttg; int problem_size; int blocking_factor; diff --git a/examples/ge/ge.cc b/examples/ge/ge.cc index c25b63a724..414436a97b 100644 --- a/examples/ge/ge.cc +++ b/examples/ge/ge.cc @@ -130,8 +130,7 @@ std::ostream& operator<<(std::ostream& s, const Integer& intVal) { class Initiator : public TT, Out, Out, Out>, Initiator> { - using baseT = - TT, Out, Out, Out>, Initiator>; + using baseT = typename Initiator::ttT; public: Initiator(const std::string& name) : baseT(name, {}, {"outA", "outB", "outC", "outD"}) {} @@ -160,8 +159,8 @@ class Initiator } }; -class FuncA : public TT, Out, Out>, FuncA, Control> { - using baseT = TT, Out, Out>, FuncA, Control>; +class FuncA : public TT, Out, Out>, FuncA, std::tuple> { + using baseT = typename FuncA::ttT; double* adjacency_matrix_ttg; int problem_size; int blocking_factor; @@ -240,8 +239,8 @@ class FuncA : public TT, Out, Ou } }; -class FuncB : public TT>, FuncB, Control, Control> { - using baseT = TT>, FuncB, Control, Control>; +class FuncB : public TT>, FuncB, std::tuple> { + using baseT = typename FuncB::ttT; double* adjacency_matrix_ttg; int problem_size; int blocking_factor; @@ -312,8 +311,8 @@ class FuncB : public TT>, FuncB, Control, Cont } }; -class FuncC : public TT>, FuncC, Control, Control> { - using baseT = TT>, FuncC, Control, Control>; +class FuncC : public TT>, FuncC, std::tuple> { + using baseT = typename FuncC::ttT; double* adjacency_matrix_ttg; int problem_size; int blocking_factor; @@ -385,9 +384,8 @@ class FuncC : public TT>, FuncC, Control, Cont }; class FuncD : public TT, Out, Out, Out>, - FuncD, Control, Control, Control, Control> { - using baseT = TT, Out, Out, Out>, FuncD, - Control, Control, Control, Control>; + FuncD, std::tuple> { + using baseT = typename FuncD::ttT; double* adjacency_matrix_ttg; int problem_size; int blocking_factor; diff --git a/examples/ge/ge_df.cc b/examples/ge/ge_df.cc index 3bb4bd588e..ca01afdd13 100644 --- a/examples/ge/ge_df.cc +++ b/examples/ge/ge_df.cc @@ -136,10 +136,7 @@ class Initiator : public TT>, Out>, Out>, Out>>, Initiator> { - using baseT = TT>, Out>, Out>, - Out>>, - Initiator>; + using baseT = typename Initiator::ttT; Matrix* adjacency_matrix_ttg; @@ -179,8 +176,8 @@ class Initiator : public TT -class Finalizer : public TT, Finalizer, BlockMatrix> { - using baseT = TT, Finalizer, BlockMatrix>; +class Finalizer : public TT, Finalizer, std::tuple>> { + using baseT = typename Finalizer::ttT; Matrix* result_matrix_ttg; int problem_size; int blocking_factor; @@ -256,11 +253,8 @@ template class FuncA : public TT>, Out>, Out>, Out>>, - FuncA, BlockMatrix> { - using baseT = TT>, Out>, Out>, - Out>>, - FuncA, BlockMatrix>; + FuncA, std::tuple>> { + using baseT = typename FuncA::ttT; Matrix* adjacency_matrix_ttg; int problem_size; int blocking_factor; @@ -346,10 +340,9 @@ class FuncA : public TT -class FuncB : public TT>, Out>>, FuncB, BlockMatrix, - BlockMatrix> { - using baseT = - TT>, Out>>, FuncB, BlockMatrix, BlockMatrix>; +class FuncB : public TT>, Out>>, FuncB, + std::tuple, BlockMatrix>> { + using baseT = typename FuncB::ttT; Matrix* adjacency_matrix_ttg; int problem_size; int blocking_factor; @@ -427,10 +420,9 @@ class FuncB : public TT>, Out -class FuncC : public TT>, Out>>, FuncC, BlockMatrix, - BlockMatrix> { - using baseT = - TT>, Out>>, FuncC, BlockMatrix, BlockMatrix>; +class FuncC : public TT>, Out>>, FuncC, + std::tuple, BlockMatrix>> { + using baseT = typename FuncC::ttT; Matrix* adjacency_matrix_ttg; int problem_size; int blocking_factor; @@ -512,11 +504,8 @@ template class FuncD : public TT>, Out>, Out>, Out>>, - FuncD, BlockMatrix, BlockMatrix, BlockMatrix, BlockMatrix> { - using baseT = TT>, Out>, Out>, - Out>>, - FuncD, BlockMatrix, BlockMatrix, BlockMatrix, BlockMatrix>; + FuncD, std::tuple, BlockMatrix, BlockMatrix, BlockMatrix>> { + using baseT = typename FuncD::ttT; Matrix* adjacency_matrix_ttg; int problem_size; int blocking_factor; diff --git a/examples/madness/madness-1d/madness-1d.cc b/examples/madness/madness-1d/madness-1d.cc index 2626f80d49..fae5c8e82a 100644 --- a/examples/madness/madness-1d/madness-1d.cc +++ b/examples/madness/madness-1d/madness-1d.cc @@ -10,7 +10,7 @@ #include #include -#include "ttg/madness/ttg.h" +#include "ttg.h" #include "Vector.h" #include "Matrix.h" @@ -309,8 +309,8 @@ std::ostream& operator<<(std::ostream&s, const Control& ctl) { return s; } -class Printer : public TT, Printer, Node> { - using baseT = TT, Printer, Node>; +class Printer : public TT, Printer, std::tuple> { + using baseT = typename Printer::ttT; public: Printer(const std::string& name) : baseT(name, {"input"}, {}) {} @@ -325,8 +325,8 @@ class Printer : public TT, Printer, Node> { }; -class GaxpyOp : public TT, Out, Out>, GaxpyOp, Node, Node> { - using baseT = TT, Out, Out>, GaxpyOp, Node, Node>; +class GaxpyOp : public TT, Out, Out>, GaxpyOp, std::tuple> { + using baseT = typename GaxpyOp::ttT; double alpha; double beta; @@ -369,8 +369,8 @@ class GaxpyOp : public TT, Out, Out, Out, Out>, BinaryOp, Node, Node> { - using baseT = TT, Out, Out>, BinaryOp, Node, Node>; +class BinaryOp : public TT, Out, Out>, BinaryOp, std::tuple> { + using baseT = typename BinaryOp::ttT; using funcT = Vector (*)(const Vector &, const Vector&); funcT func; @@ -430,8 +430,8 @@ class BinaryOp : public TT, Out, Out, Out, Out>, Diff_prologue, Node> { - using baseT = TT, Out, Out>, Diff_prologue, Node>; +class Diff_prologue : public TT, Out, Out>, Diff_prologue, std::tuple> { + using baseT = typename Diff_prologue::ttT; public: @@ -452,8 +452,8 @@ class Diff_prologue : public TT, Out, } }; -class Diff_doIt : public TT, Out, Out, Out>, Diff_doIt, Node, Node, Node> { - using baseT = TT, Out, Out, Out>, Diff_doIt, Node, Node, Node>; +class Diff_doIt : public TT, Out, Out, Out>, Diff_doIt, std::tuple> { + using baseT = typename Diff_doIt::ttT; Vector unfilter(const Vector &inputVector, int k, const Matrix * hg) const { Vector inputVector_copy(inputVector); @@ -530,8 +530,8 @@ class Diff_doIt : public TT, Out, Out< }; -class Compress_prologue : public TT, Out, Out>, Compress_prologue, Node> { - using baseT = TT, Out, Out>, Compress_prologue, Node>; +class Compress_prologue : public TT, Out, Out>, Compress_prologue, std::tuple> { + using baseT = typename Compress_prologue::ttT; public: Compress_prologue(const std::string &name) @@ -564,8 +564,8 @@ class Compress_prologue : public TT, Out, Out, Out>, Compress_doIt, Node, Node> { - using baseT = TT, Out, Out>, Compress_doIt, Node, Node>; +class Compress_doIt : public TT, Out, Out>, Compress_doIt, std::tuple> { + using baseT = typename Compress_doIt::ttT; public: Compress_doIt(const std::string &name) @@ -607,8 +607,8 @@ class Compress_doIt : public TT, Out, }; -class Reconstruct_prologue : public TT>, Reconstruct_prologue, Node> { - using baseT = TT>, Reconstruct_prologue, Node>; +class Reconstruct_prologue : public TT>, Reconstruct_prologue, std::tuple> { + using baseT = typename Reconstruct_prologue::ttT; public: Reconstruct_prologue(const std::string &name) @@ -633,8 +633,8 @@ class Reconstruct_prologue : public TT>, Recons }; -class Reconstruct_doIt : public TT, Out>, Reconstruct_doIt, Vector, Node> { - using baseT = TT, Out>, Reconstruct_doIt, Vector, Node>; +class Reconstruct_doIt : public TT, Out>, Reconstruct_doIt, std::tuple> { + using baseT = typename Reconstruct_doIt::ttT; public: Reconstruct_doIt(const std::string &name) @@ -672,8 +672,8 @@ class Reconstruct_doIt : public TT, Out, Out>, Project, Control> { - using baseT = TT, Out>, Project, Control>; +class Project : public TT, Out>, Project, std::tuple> { + using baseT = typename Project::ttT; public: using funcT = double(*)(double); @@ -733,7 +733,7 @@ class Project : public TT, Out>, Pro }; class Producer : public TT>, Producer> { - using baseT = TT>, Producer>; + using baseT = typename Producer::ttT; public: Producer(const std::string &name) : baseT(name, {}, {"output"}) {} @@ -753,7 +753,7 @@ class Producer : public TT>, Producer> { // EXAMPLE 1 class Everything : public TT, Everything> { - using baseT = TT, Everything>; + using baseT = Everything::ttT; Producer producer; Project project; diff --git a/examples/madness/mrattg_streaming.cc b/examples/madness/mrattg_streaming.cc index bceb52b5ef..dfa4e92a3b 100644 --- a/examples/madness/mrattg_streaming.cc +++ b/examples/madness/mrattg_streaming.cc @@ -366,7 +366,7 @@ namespace detail { using compress_out_type = std::tuple>; using compress_in_type = std::tuple; template - using compmake_tt_type = ttg::TT, compress_out_type, Rin, Rin>; + using compmake_tt_type = ttg::TT, compress_out_type, std::tuple>; }; template struct tree_types{ @@ -375,7 +375,7 @@ namespace detail { using compress_out_type = std::tuple>; using compress_in_type = std::tuple; template - using compmake_tt_type = ttg::TT, compress_out_type, Rin, Rin, Rin, Rin>; + using compmake_tt_type = ttg::TT, compress_out_type, std::tuple>; }; template struct tree_types{ @@ -384,7 +384,7 @@ namespace detail { using compress_out_type = std::tuple>; using compress_in_type = std::tuple; template - using compmake_tt_type = ttg::TT, compress_out_type, Rin, Rin, Rin, Rin, Rin, Rin, Rin, Rin>; + using compmake_tt_type = ttg::TT, compress_out_type, std::tuple>; }; }; @@ -413,16 +413,10 @@ void send_leaves_up(const Key& key, } } -template -void reduce_leaves(const Key& key, const FunctionReconstructedNodeWrap& node, std::tuple>& out) { - //std::cout << "Reduce_leaves " << node.key.childindex() << " " << node.neighbor_sum[node.key.childindex()] << std::endl; - std::get<0>(out).send(key, node); -} - // With data streaming up the tree run compression template void do_compress(const Key& key, - const FunctionReconstructedNodeWrap &in, + const std::array, 1< &ins, std::tuple, cnodeOut> &out) { //const typename ::detail::tree_types::compress_in_type& in, //typename ::detail::tree_types::compress_out_type& out) { @@ -435,9 +429,9 @@ void do_compress(const Key& key, FixedTensor s; //auto ins = ::mra::tuple_to_array_of_ptrs_const(in); /// Ugh ... cannot get const to match for (size_t i : range(Key::num_children)) { - s(child_slices[i]) = in.get().neighbor_coeffs[i]; - result.get().is_leaf[i] = in.get().is_neighbor_leaf[i]; - sumsq += in.get().neighbor_sum[i]; // Accumulate sumsq from child difference coeffs + s(child_slices[i]) = ins[i].get().coeffs; //in.get().neighbor_coeffs[i]; + result.get().is_leaf[i] = ins[i].get().is_leaf; //in.get().is_neighbor_leaf[i]; + sumsq += ins[i].get().sum; //in.get().neighbor_sum[i]; // Accumulate sumsq from child difference coeffs //if (in.neighbor_sum[i] > 10000) //std::cout << i << " " << in.neighbor_sum[i] << " " << sumsq << std::endl; @@ -478,11 +472,10 @@ std::string int2bitstring(size_t i, size_t width) { /// Make a composite operator that implements compression for a single function template auto make_compress(rnodeEdge& in, cnodeEdge& out, const std::string& name = "compress") { - rnodeEdge children1("children1"), children2("children2"); + rnodeEdge children1("children1"); return std::make_tuple(ttg::make_tt(&send_leaves_up, edges(in), edges(children1, out), "send_leaves_up", {"input"}, {"children1", "output"}), - ttg::make_tt(&reduce_leaves, edges(children1), edges(children2), "reduce_leaves", {"children1"}, {"children2"}), - ttg::make_tt(&do_compress, edges(children2), edges(children1,out), "do_compress", {"children2"}, {"recur","output"})); + ttg::make_tt(&do_compress, edges(children1), edges(children1,out), "do_compress", {"children2"}, {"recur","output"})); } template @@ -687,16 +680,10 @@ void test1() { auto compress = make_compress(a, b); auto &reduce_leaves_op = std::get<1>(compress); - reduce_leaves_op->template set_input_reducer<0>([](FunctionReconstructedNodeWrap &node, + reduce_leaves_op->template set_input_reducer<0>([](std::array, 1< &nodes, const FunctionReconstructedNodeWrap &another) { - //Update self values into the array. - node.get().neighbor_coeffs[node.get().key.childindex()] = node.get().coeffs; - node.get().is_neighbor_leaf[node.get().key.childindex()] = node.get().is_leaf; - node.get().neighbor_sum[node.get().key.childindex()] = node.get().sum; - node.get().neighbor_coeffs[another.get().key.childindex()] = another.get().coeffs; - node.get().is_neighbor_leaf[another.get().key.childindex()] = another.get().is_leaf; - node.get().neighbor_sum[another.get().key.childindex()] = another.get().sum; + nodes[another.get().key.childindex()] = another; }); reduce_leaves_op->template set_static_argstream_size<0>(1 << NDIM); @@ -712,7 +699,6 @@ void test1() { ops.push_back(std::move(p1)); ops.push_back(std::move(std::get<0>(compress))); ops.push_back(std::move(std::get<1>(compress))); - ops.push_back(std::move(std::get<2>(compress))); ops.push_back(std::move(recon)); ops.push_back(std::move(printer)); ops.push_back(std::move(printer2)); @@ -775,19 +761,12 @@ void test2(size_t nfunc, T thresh = 1e-6) { auto compress = make_compress(a, b); std::get<0>(compress)->set_keymap(pmap); std::get<1>(compress)->set_keymap(pmap); - std::get<2>(compress)->set_keymap(pmap); auto &reduce_leaves_op = std::get<1>(compress); - reduce_leaves_op->template set_input_reducer<0>([](FunctionReconstructedNodeWrap &node, + reduce_leaves_op->template set_input_reducer<0>([](std::array, 1< &nodes, const FunctionReconstructedNodeWrap &another) { - //Update self values into the array. - node.get().neighbor_coeffs[node.get().key.childindex()] = node.get().coeffs; - node.get().is_neighbor_leaf[node.get().key.childindex()] = node.get().is_leaf; - node.get().neighbor_sum[node.get().key.childindex()] = node.get().sum; - node.get().neighbor_coeffs[another.get().key.childindex()] = another.get().coeffs; - node.get().is_neighbor_leaf[another.get().key.childindex()] = another.get().is_leaf; - node.get().neighbor_sum[another.get().key.childindex()] = another.get().sum; + nodes[another.get().key.childindex()] = another; }); reduce_leaves_op->template set_static_argstream_size<0>(1 << NDIM); @@ -804,7 +783,6 @@ void test2(size_t nfunc, T thresh = 1e-6) { ops.push_back(std::move(p1)); ops.push_back(std::move(std::get<0>(compress))); ops.push_back(std::move(std::get<1>(compress))); - ops.push_back(std::move(std::get<2>(compress))); ops.push_back(std::move(recon)); ops.push_back(std::move(printer)); ops.push_back(std::move(printer2)); diff --git a/examples/mrafunctionnode.h b/examples/mrafunctionnode.h index 7c9eb177c1..aea95cc7ec 100644 --- a/examples/mrafunctionnode.h +++ b/examples/mrafunctionnode.h @@ -174,10 +174,6 @@ namespace mra { FunctionReconstructedNode(const Key& key) : key(key), sum(0.0), is_leaf(false) {} T normf() const {return (is_leaf ? coeffs.normf() : 0.0);} bool has_children() const {return !is_leaf;} - //Can't make it a vector to keep the class as POD. - std::array, 1 << NDIM> neighbor_coeffs; - std::array is_neighbor_leaf; - std::array neighbor_sum; }; template diff --git a/examples/randomaccess/randomaccess.cc b/examples/randomaccess/randomaccess.cc index bded70c022..96a90e17fc 100644 --- a/examples/randomaccess/randomaccess.cc +++ b/examples/randomaccess/randomaccess.cc @@ -12,6 +12,7 @@ #define CHUNKBIG (32*CHUNK) #include "ttg.h" +#include "ttg/serialization.h" using namespace ttg; typedef struct params { diff --git a/examples/spmm/spmm.cc b/examples/spmm/spmm.cc index 8da592ae4f..c4e297ab4b 100644 --- a/examples/spmm/spmm.cc +++ b/examples/spmm/spmm.cc @@ -188,9 +188,9 @@ inline int tile2rank(int i, int j, int P, int Q) { // flow data from an existing SpMatrix on rank 0 template &)>> -class Read_SpMatrix : public TT, std::tuple, Blk>>, Read_SpMatrix, void> { +class Read_SpMatrix : public TT, std::tuple, Blk>>, Read_SpMatrix, std::tuple> { public: - using baseT = TT, std::tuple, Blk>>, Read_SpMatrix, void>; + using baseT = typename Read_SpMatrix::ttT; Read_SpMatrix(const char *label, const SpMatrix &matrix, Edge> &ctl, Edge, Blk> &out, Keymap &keymap) @@ -214,9 +214,9 @@ class Read_SpMatrix : public TT, std::tuple, Blk>>, Read_SpMat // flow (move?) data into an existing SpMatrix on rank 0 template -class Write_SpMatrix : public TT, std::tuple<>, Write_SpMatrix, Blk> { +class Write_SpMatrix : public TT, std::tuple<>, Write_SpMatrix, std::tuple> { public: - using baseT = TT, std::tuple<>, Write_SpMatrix, Blk>; + using baseT = typename Write_SpMatrix::ttT; template Write_SpMatrix(SpMatrix &matrix, Edge, Blk> &in, Keymap &&keymap) @@ -286,9 +286,9 @@ class SpMM { } /// Locally broadcast A[i][k] to all {i,j,k} such that B[j][k] exists - class LocalBcastA : public TT, std::tuple, Blk>>, LocalBcastA, Blk> { + class LocalBcastA : public TT, std::tuple, Blk>>, LocalBcastA, std::tuple> { public: - using baseT = TT, std::tuple, Blk>>, LocalBcastA, Blk>; + using baseT = typename LocalBcastA::ttT; LocalBcastA(Edge, Blk> &a, Edge, Blk> &a_ijk, const std::vector> &b_rowidx_to_colidx, Keymap keymap) @@ -321,9 +321,9 @@ class SpMM { }; // class LocalBcastA /// broadcast A[i][k] to all procs where B[j][k] - class BcastA : public TT, std::tuple, Blk>>, BcastA, Blk> { + class BcastA : public TT, std::tuple, Blk>>, BcastA, std::tuple> { public: - using baseT = TT, std::tuple, Blk>>, BcastA, Blk>; + using baseT = typename BcastA::ttT; BcastA(Edge, Blk> &a, Edge, Blk> &a_ikp, const std::vector> &b_rowidx_to_colidx, Keymap keymap) @@ -356,9 +356,9 @@ class SpMM { }; // class BcastA /// broadcast B[k][j] to all {i,j,k} such that A[i][k] exists - class LocalBcastB : public TT, std::tuple, Blk>>, LocalBcastB, Blk> { + class LocalBcastB : public TT, std::tuple, Blk>>, LocalBcastB, std::tuple> { public: - using baseT = TT, std::tuple, Blk>>, LocalBcastB, Blk>; + using baseT = typename LocalBcastB::ttT; LocalBcastB(Edge, Blk> &b, Edge, Blk> &b_ijk, const std::vector> &a_colidx_to_rowidx, Keymap keymap) @@ -391,9 +391,9 @@ class SpMM { }; // class BcastA /// broadcast B[k][j] to all {i,j,k} such that A[i][k] exists - class BcastB : public TT, std::tuple, Blk>>, BcastB, Blk> { + class BcastB : public TT, std::tuple, Blk>>, BcastB, std::tuple> { public: - using baseT = TT, std::tuple, Blk>>, BcastB, Blk>; + using baseT = typename BcastB::ttT; BcastB(Edge, Blk> &b, Edge, Blk> &b_kjp, const std::vector> &a_colidx_to_rowidx, Keymap keymap) @@ -426,9 +426,9 @@ class SpMM { /// multiply task has 3 input flows: a_ijk, b_ijk, and c_ijk, c_ijk contains the running total class MultiplyAdd - : public TT, std::tuple, Blk>, Out, Blk>>, MultiplyAdd, const Blk, const Blk, Blk> { + : public TT, std::tuple, Blk>, Out, Blk>>, MultiplyAdd, std::tuple> { public: - using baseT = TT, std::tuple, Blk>, Out, Blk>>, MultiplyAdd, const Blk, const Blk, Blk>; + using baseT = typename MultiplyAdd::ttT; MultiplyAdd(Edge, Blk> &a_ijk, Edge, Blk> &b_ijk, Edge, Blk> &c_ijk, Edge, Blk> &c, const std::vector> &a_rowidx_to_colidx, @@ -604,7 +604,7 @@ class SpMM { }; class Control : public TT>>, Control> { - using baseT = TT>>, Control>; + using baseT = typename Control::ttT; int P; int Q; diff --git a/examples/t9/t9.cc b/examples/t9/t9.cc index d1d8bc52cd..5d543a683b 100644 --- a/examples/t9/t9.cc +++ b/examples/t9/t9.cc @@ -280,8 +280,8 @@ auto make_reconstruct(const nodeEdge& in, nodeEdge& out, const std::string& name } // cannot easily replace this with make_tt due to persistent state -class Norm2 : public TT, Norm2, Node> { - using baseT = TT, Norm2, Node>; +class Norm2 : public TT, Norm2, std::tuple> { + using baseT = typename Norm2::ttT; double sumsq; std::mutex charon; diff --git a/examples/t9/t9_streaming.cc b/examples/t9/t9_streaming.cc index 5fbe1f00f2..4978289fee 100644 --- a/examples/t9/t9_streaming.cc +++ b/examples/t9/t9_streaming.cc @@ -292,8 +292,8 @@ auto make_reconstruct(const nodeEdge& in, nodeEdge& out, const std::string& name } // cannot easily replace this with wrapper due to persistent state -class Norm2 : public TT, Norm2, Node> { - using baseT = TT, Norm2, Node>; +class Norm2 : public TT, Norm2, std::tuple> { + using baseT = typename Norm2::ttT; double sumsq; std::mutex charon; diff --git a/examples/test/test.cc b/examples/test/test.cc index 467396ba71..ac610e4368 100644 --- a/examples/test/test.cc +++ b/examples/test/test.cc @@ -3,6 +3,9 @@ #include "ttg.h" +#include "ttg/serialization.h" +#include "ttg/serialization/std/vector.h" + /* TODO: Get rid of using statement */ using namespace ttg; @@ -12,8 +15,8 @@ using keyT = uint64_t; #include "ttg.h" -class A : public TT, Out>, A, const int> { - using baseT = TT, Out>, A, const int>; +class A : public TT, Out>, A, std::tuple> { + using baseT = typename A::ttT; public: A(const std::string &name) : baseT(name, {"inputA"}, {"resultA", "iterateA"}) {} @@ -50,7 +53,7 @@ class A : public TT, Out>, A, const i }; class Producer : public TT>, Producer> { - using baseT = TT>, Producer>; + using baseT = typename Producer::ttT; public: Producer(const std::string &name) : baseT(name, {}, {"output"}) {} @@ -66,8 +69,8 @@ class Producer : public TT>, Producer> { ~Producer() { std::cout << " Producer destructor\n"; } }; -class Consumer : public TT, Consumer, const int> { - using baseT = TT, Consumer, const int>; +class Consumer : public TT, Consumer, std::tuple> { + using baseT = typename Consumer::ttT; public: Consumer(const std::string &name) : baseT(name, {"input"}, {}) {} @@ -301,6 +304,55 @@ class Everything5 { } }; + +class Everything6 { + static void p(std::tuple> &out) { + ttg::print("produced ", 0); + send<0>(0, 0, out); + } + + static void a(const keyT &key, const int &value, std::tuple, Out> &out) { + if (value < 100) { + send<1>(key + 1, value + 1, out); + sendv<0>(value, out); + } + } + + static void c(const std::vector &values, std::tuple<> &out) { ttg::print("consumed ", values.size()); } + + // !!!! Edges must be constructed before classes that use them + Edge P2A, A2A; + Edge A2C; + + decltype(make_tt(p, edges(), edges(P2A))) wp; + decltype(make_tt(a, edges(fuse(P2A, A2A)), edges(A2C, A2A))) wa; + decltype(make_tt(c, edges(A2C), edges())) wc; + + public: + Everything6() + : P2A("P2A") + , A2A("A2A") + , A2C("A2C") + , wp(make_tt(p, edges(), edges(P2A), "producer", {}, {"start"})) + , wa(make_tt(a, edges(fuse(P2A, A2A)), edges(A2C, A2A), "A", {"input"}, {"result", "iterate"})) + , wc(make_tt(c, edges(A2C), edges(), "consumer", {"result"}, {})) { + wc->set_input_reducer<0>([](std::vector &a, const int &b) { a.push_back(b); }); + if (wc->get_world().rank() == 0) wc->set_argstream_size<0>(100); + } + + void print() { print_ttg(wp.get()); } + + std::string dot() { return Dot{}(wp.get()); } + + void start() { + wp->make_executable(); + wa->make_executable(); + wc->make_executable(); + if (wp->get_world().rank() == 0) wp->invoke(); + } +}; + + class EverythingComposite { std::unique_ptr P; std::unique_ptr AC; @@ -575,6 +627,10 @@ int try_main(int argc, char **argv) { std::cout << q5.dot() << std::endl; q5.start(); + Everything6 q6; + std::cout << q6.dot() << std::endl; + q6.start(); + Fibonacci fi; std::cout << fi.dot() << std::endl << std::endl; if (ttg::default_execution_context().size() == 1) diff --git a/tests/unit/tt.cc b/tests/unit/tt.cc index 9a457f272f..da647d25c7 100644 --- a/tests/unit/tt.cc +++ b/tests/unit/tt.cc @@ -7,8 +7,8 @@ // {task_id,data} = {void, void} namespace tt_v_v { - class tt : public ttg::TT, tt, void> { - using baseT = ttg::TT, tt, void>; + class tt : public ttg::TT, tt, std::tuple> { + using baseT = typename tt::ttT; public: tt(const typename baseT::input_edges_type &inedges, const typename baseT::output_edges_type &outedges, @@ -26,8 +26,8 @@ namespace tt_v_v { // {task_id,data} = {int, void} namespace tt_i_v { - class tt : public ttg::TT, tt, void> { - using baseT = ttg::TT, tt, void>; + class tt : public ttg::TT, tt, std::tuple> { + using baseT = typename tt::ttT; public: tt(const typename baseT::input_edges_type &inedges, const typename baseT::output_edges_type &outedges, @@ -45,8 +45,8 @@ namespace tt_i_v { // {task_id,data} = {void, int} namespace tt_v_i { - class tt : public ttg::TT, tt, const int> { - using baseT = ttg::TT, tt, const int>; + class tt : public ttg::TT, tt, std::tuple> { + using baseT = typename tt::ttT; public: tt(const typename baseT::input_edges_type &inedges, const typename baseT::output_edges_type &outedges, @@ -65,8 +65,8 @@ namespace tt_v_i { // {task_id,data} = {void, int, void} namespace tt_v_iv { - class tt : public ttg::TT, tt, const int, void> { - using baseT = ttg::TT, tt, const int, void>; + class tt : public ttg::TT, tt, std::tuple> { + using baseT = typename tt::ttT; public: tt(const typename baseT::input_edges_type &inedges, const typename baseT::output_edges_type &outedges, @@ -85,8 +85,8 @@ namespace tt_v_iv { // {task_id,data} = {int, int} namespace tt_i_i { - class tt : public ttg::TT, tt, const int> { - using baseT = ttg::TT, tt, const int>; + class tt : public ttg::TT, tt, std::tuple> { + using baseT = typename tt:ttT; public: tt(const typename baseT::input_edges_type &inedges, const typename baseT::output_edges_type &outedges, @@ -104,8 +104,8 @@ namespace tt_i_i { // {task_id,data} = {int, int, void} namespace tt_i_iv { - class tt : public ttg::TT, tt, const int, void> { - using baseT = ttg::TT, tt, const int, void>; + class tt : public ttg::TT, tt, std::tuple> { + using baseT = typename tt::ttT; public: tt(const typename baseT::input_edges_type &inedges, const typename baseT::output_edges_type &outedges, diff --git a/ttg/ttg/broadcast.h b/ttg/ttg/broadcast.h index 21967eee95..38cf979574 100644 --- a/ttg/ttg/broadcast.h +++ b/ttg/ttg/broadcast.h @@ -26,10 +26,10 @@ namespace ttg { /// template class BinaryTreeBroadcast : public TT, Out, Out>, - BinaryTreeBroadcast, Value> { + BinaryTreeBroadcast, std::tuple> { public: using baseT = TT, Out, Out>, - BinaryTreeBroadcast, Value>; + BinaryTreeBroadcast, std::tuple>; BinaryTreeBroadcast(Edge &in, Edge &out, std::vector local_keys, int root = 0, World world = ttg::default_execution_context(), int max_key = -1, diff --git a/ttg/ttg/edge.h b/ttg/ttg/edge.h index 7e59a95fbc..d74e50cf5a 100644 --- a/ttg/ttg/edge.h +++ b/ttg/ttg/edge.h @@ -138,6 +138,19 @@ namespace ttg { typedef std::tuple type; }; + template + struct edges_tuple { + using type = std::tuple...>; + }; + + template + struct edges_tuple> { + using type = std::tuple...>; + }; + + template + using edges_tuple_t = typename edges_tuple::type; + } // namespace ttg diff --git a/ttg/ttg/madness/fwd.h b/ttg/ttg/madness/fwd.h index 05eefe13d1..d5cfa6da61 100644 --- a/ttg/ttg/madness/fwd.h +++ b/ttg/ttg/madness/fwd.h @@ -7,7 +7,8 @@ namespace ttg_madness { - template + template , typename input_argsT = input_terminal_typesT> class TT; /// \internal the OG name diff --git a/ttg/ttg/madness/ttg.h b/ttg/ttg/madness/ttg.h index 195e9154eb..0a90984dfa 100644 --- a/ttg/ttg/madness/ttg.h +++ b/ttg/ttg/madness/ttg.h @@ -22,6 +22,7 @@ #include "ttg/util/meta.h" #include "ttg/util/void.h" #include "ttg/world.h" +#include "ttg/madness/fwd.h" #include #include @@ -178,35 +179,78 @@ namespace ttg_madness { /// \tparam keyT a Key type /// \tparam output_terminalsT /// \tparam derivedT - /// \tparam input_valueTs pack of *value* types (no references; pointers are OK) encoding the types of input values - /// flowing into this TT; a const type indicates nonmutating (read-only) use, nonconst type - /// indicates mutating use (e.g. the corresponding input can be used as scratch, moved-from, etc.) - template + /// \tparam input_valueTs tuple of *value* types (no references; pointers are OK) encoding the types of + /// terminal input values flowing into this TT; a const type indicates nonmutating (read-only) use, + /// nonconst type indicates mutating use (e.g. the corresponding input can be used as scratch, moved-from, etc.) + /// \tparam args_valueTs tuple of *value* types (no references; pointers are OK) encoding the types of + /// operation input values passed to op(); a const type indicates nonmutating (read-only) use, + /// nonconst type indicates mutating use (e.g. the corresponding input can be used as scratch, moved-from, etc.) + template class TT : public ttg::TTBase, - public ::madness::WorldObject> { + public ::madness::WorldObject> { public: /// preconditions - static_assert((!std::is_reference_v && ...), "input_valueTs cannot contain reference types"); + static_assert(ttg::meta::is_tuple_v && ttg::meta::is_tuple_v, + "The last two template arguments of TT must be tuples!"); + static_assert((ttg::meta::tuple_none_has_reference_v), "input_terminal_typesT cannot contain reference types"); + + private: + + static constexpr int numins = std::tuple_size_v; // number of input arguments + static constexpr int numouts = std::tuple_size_v; // number of outputs + static constexpr int numflows = std::max(numins, numouts); // max number of flows + + public: + using input_terminals_type = ttg::input_terminals_tuple_t; + using input_args_type = input_argsT; + using full_args_type = + typename ttg::meta::decayed_tuple_t< + std::conditional_t, input_args_type, + typename ttg::meta::drop_last_n::type>>; + using input_edges_type = ttg::edges_tuple_t>; + static_assert(ttg::meta::is_none_Void_v, "ttg::Void is for internal use only, do not use it"); + static_assert(ttg::meta::is_none_Void_v, "ttg::Void is for internal use only, do not use it"); + // if have data inputs and (always last) control input, convert last input to Void to make logic easier + using input_values_full_tuple_type = ttg::meta::void_to_Void_tuple_t>; + using input_refs_full_tuple_type = + ttg::meta::add_lvalue_reference_tuple_t>; + using args_refs_full_tuple_type = + ttg::meta::add_lvalue_reference_tuple_t>; + using input_values_tuple_type = + std::conditional_t, input_values_full_tuple_type, + typename ttg::meta::drop_last_n::type>; + static_assert(!ttg::meta::is_any_void_v); + using input_refs_tuple_type = + std::conditional_t, input_refs_full_tuple_type, + typename ttg::meta::drop_last_n::type>; + using input_crefs_tuple_type = ttg::meta::add_const_tuple_t; + using args_refs_tuple_type = + std::conditional_t, args_refs_full_tuple_type, + typename ttg::meta::drop_last_n::type>; + static constexpr int numinvals = + std::tuple_size_v; // number of input arguments with values (i.e. omitting the control + // input, if any) + private: ttg::World world; ttg::meta::detail::keymap_t keymap; ttg::meta::detail::keymap_t priomap; // For now use same type for unary/streaming input terminals, and stream reducers assigned at runtime - ttg::meta::detail::input_reducers_t + ttg::meta::detail::input_reducers_t input_reducers; //!< Reducers for the input terminals (empty = expect single value) - std::array static_streamsize; + std::array> static_streamsize; public: ttg::World get_world() const { return world; } protected: - using ttT = TT; + using ttT = TT; using worldobjT = ::madness::WorldObject; - static constexpr int numins = sizeof...(input_valueTs); // number of input arguments - static constexpr int numouts = std::tuple_size::value; // number of outputs or // results // This to support tt fusion @@ -215,23 +259,6 @@ namespace ttg_madness { size_t call_depth = 0; // how deep calls are nested } threaddata; - using input_terminals_type = std::tuple...>; - using input_edges_type = std::tuple>...>; - static_assert(ttg::meta::is_none_Void_v, "ttg::Void is for internal use only, do not use it"); - static_assert(ttg::meta::is_none_void_v || ttg::meta::is_last_void_v, - "at most one void input can be handled, and it must come last"); - // if have data inputs and (always last) control input, convert last input to Void to make logic easier - using input_values_full_tuple_type = std::tuple>...>; - using input_refs_full_tuple_type = - std::tuple>...>; - using input_values_tuple_type = - std::conditional_t, input_values_full_tuple_type, - typename ttg::meta::drop_last_n::type>; - static_assert(!ttg::meta::is_any_void_v); - using input_refs_tuple_type = - std::conditional_t, input_refs_full_tuple_type, - typename ttg::meta::drop_last_n::type>; - using output_terminals_type = output_terminalsT; using output_edges_type = typename ttg::terminals_to_edges::type; @@ -264,21 +291,21 @@ namespace ttg_madness { // - n: if nonstreaming: expect this many more values std::array stream_size; // Expected number of values to receive, to be used for streaming // inputs (0 = unbounded stream, >0 = bounded stream) - input_values_tuple_type input_values; // The input values (does not include control) + full_args_type input_values; // The argument values (does not include control) derivedT *derived; // Pointer to derived class instance std::conditional_t, ttg::Void, keyT> key; // Task key /// makes a tuple of references out of tuple of template - static input_refs_tuple_type make_input_refs_impl(Tuple &&inputs, std::index_sequence) { - return input_refs_tuple_type{ - get>(std::forward(inputs))...}; + static args_refs_tuple_type make_input_refs_impl(Tuple &&inputs, std::index_sequence) { + return args_refs_tuple_type{ + get>(std::forward(inputs))...}; } /// makes a tuple of references out of input_values - input_refs_tuple_type make_input_refs() { + args_refs_tuple_type make_input_refs() { return make_input_refs_impl(this->input_values, - std::make_index_sequence>{}); + std::make_index_sequence>{}); } TTArgs(int prio = 0) @@ -347,6 +374,10 @@ namespace ttg_madness { static_assert(std::is_same_v, std::decay_t>, "TT::set_arg(key,value) given value of type incompatible with TT"); + using input_arg_type = std::decay_t>; + using decay_value_t = std::decay_t; + constexpr const bool edge_arg_convertible = std::is_convertible_v; + const auto owner = keymap(key); if (owner != world.rank()) { ttg::trace(world.rank(), ":", get_name(), " : ", key, ": forwarding setting argument : ", i); @@ -379,8 +410,14 @@ namespace ttg_madness { if constexpr (!ttg::meta::is_void_v) { // for data values // have a value already? if not, set, otherwise reduce if (args->nargs[i] == std::numeric_limits::max()) { - this->get &>(args->input_values) = std::forward(value); - + //this->get &>(args->input_values) = std::forward(value); + if constexpr(edge_arg_convertible) { + /* convert the types by assignment */ + this->get &>(args->input_values) = std::forward(value); + } else { + /* have to call reducer to do the conversion */ + reducer(this->get &>(args->input_values), value); + } // now have a value, reset nargs // check if we have a stream size for the op, which has precedence over the global setting. if (args->stream_size[i] != 0) { @@ -392,7 +429,7 @@ namespace ttg_madness { args->nargs[i] = 1; } } else { - reducer(this->get &>(args->input_values), value); + reducer(this->get &>(args->input_values), value); } } else { reducer(); // even if this was a control input, must execute the reducer for possible side effects @@ -406,11 +443,13 @@ namespace ttg_madness { } args->unlock(); } else { // this is a nonstreaming input => set the value - if constexpr (!ttg::meta::is_void_v) { // for data values + if constexpr(!edge_arg_convertible) { + throw std::logic_error("Types are not convertible and no reducer was set!"); + } else { this->get &>(args->input_values) = std::forward(value); + args->nargs[i] = 0; + args->counter--; } - args->nargs[i] = 0; - args->counter--; } // ready to run the task? @@ -461,6 +500,10 @@ namespace ttg_madness { static_assert(std::is_same, std::decay_t>::value, "TT::set_arg(key,value) given value of type incompatible with TT"); + using input_arg_type = std::decay_t>; + using decay_value_t = std::decay_t; + constexpr const bool edge_arg_convertible = std::is_convertible_v; + const int owner = keymap(); if (owner != world.rank()) { @@ -488,7 +531,13 @@ namespace ttg_madness { if constexpr (!ttg::meta::is_void_v) { // for data values // have a value already? if not, set, otherwise reduce if (args->nargs[i] == std::numeric_limits::max()) { - this->get &>(args->input_values) = std::forward(value); + if constexpr(edge_arg_convertible) { + /* convert the types by assignment */ + this->get &>(args->input_values) = std::forward(value); + } else { + /* have to call reducer to do the conversion */ + reducer(this->get &>(args->input_values), value); + } // now have a value, reset nargs if (args->stream_size[i] != 0) { args->nargs[i] = args->stream_size[i]; @@ -500,7 +549,7 @@ namespace ttg_madness { } } else { // once Future<>::operator= semantics is cleaned up will avoid Future<>::get() - reducer(this->get &>(args->input_values), value); + reducer(this->get &>(args->input_values), value); } } else { // call anyway in case it has side effects reducer(); @@ -517,9 +566,13 @@ namespace ttg_madness { } args->unlock(); } else { // this is a nonstreaming input => set the value - this->get &>(args->input_values) = std::forward(value); - args->nargs[i] = 0; - args->counter--; + if constexpr(!edge_arg_convertible) { + throw std::logic_error("Types are not convertible and no reducer was set!"); + } else { + this->get &>(args->input_values) = std::forward(value); + args->nargs[i] = 0; + args->counter--; + } } // ready to run the task? @@ -1067,23 +1120,23 @@ namespace ttg_madness { /// Manual injection of a task with all input arguments specified as a tuple template - std::enable_if_t && !ttg::meta::is_empty_tuple_v, void> invoke( - const Key &key, const input_values_tuple_type &args) { + std::enable_if_t && !ttg::meta::is_empty_tuple_v, void> invoke( + const Key &key, const input_crefs_tuple_type &args) { TTG_OP_ASSERT_EXECUTABLE(); - set_args(std::make_index_sequence::value>{}, key, args); + set_args(std::make_index_sequence::value>{}, key, args); } /// Manual injection of a key-free task with all input arguments specified as a tuple template - std::enable_if_t && !ttg::meta::is_empty_tuple_v, void> invoke( - const input_values_tuple_type &args) { + std::enable_if_t && !ttg::meta::is_empty_tuple_v, void> invoke( + const input_crefs_tuple_type &args) { TTG_OP_ASSERT_EXECUTABLE(); - set_args(std::make_index_sequence::value>{}, args); + set_args(std::make_index_sequence::value>{}, args); } /// Manual injection of a task that has no arguments template - std::enable_if_t && ttg::meta::is_empty_tuple_v, void> invoke( + std::enable_if_t && ttg::meta::is_empty_tuple_v, void> invoke( const Key &key) { TTG_OP_ASSERT_EXECUTABLE(); set_arg(key); @@ -1091,13 +1144,13 @@ namespace ttg_madness { /// Manual injection of a task that has no key or arguments template - std::enable_if_t && ttg::meta::is_empty_tuple_v, void> invoke() { + std::enable_if_t && ttg::meta::is_empty_tuple_v, void> invoke() { TTG_OP_ASSERT_EXECUTABLE(); set_arg(); } void invoke() override { - if constexpr (ttg::meta::is_void_v && ttg::meta::is_empty_tuple_v) + if constexpr (ttg::meta::is_void_v && ttg::meta::is_empty_tuple_v) invoke(); else TTBase::invoke(); diff --git a/ttg/ttg/make_tt.h b/ttg/ttg/make_tt.h index 7eaeb120bb..91bf7a1f0e 100644 --- a/ttg/ttg/make_tt.h +++ b/ttg/ttg/make_tt.h @@ -10,9 +10,13 @@ // template class CallableWrapTT : public TT, input_valuesT...> { + CallableWrapTT, + std::tuple, + std::decay_t ? 0 : 1, boost::callable_traits::args_t>>> { using baseT = - TT, input_valuesT...>; + TT, + std::tuple, + std::decay_t ? 0 : 1, boost::callable_traits::args_t>>>; using input_values_tuple_type = typename baseT::input_values_tuple_type; using input_refs_tuple_type = typename baseT::input_refs_tuple_type; @@ -65,14 +69,14 @@ class CallableWrapTT : public TT - std::enable_if_t && !ttg::meta::is_void_v, void> op( - Key &&key, output_terminalsT &out) { + std::enable_if_t && !ttg::meta::is_void_v, void> + op(Key &&key, output_terminalsT &out) { call_func(std::forward(key), out); } template - std::enable_if_t && ttg::meta::is_void_v, void> op( - output_terminalsT &out) { + std::enable_if_t && ttg::meta::is_void_v, void> + op(output_terminalsT &out) { call_func(out); } }; @@ -90,15 +94,25 @@ struct CallableWrapTTUnwrapTuple&) // case 2 (keyT == void): void op(input_valuesT&&..., std::tuple&) // -template +template class CallableWrapTTArgs - : public TT, - input_valuesT...> { - using baseT = TT, - input_valuesT...>; + : public TT, + terminal_input_values_tupleT, + args_input_values_tupleT> +{ + using baseT = TT, + terminal_input_values_tupleT, + args_input_values_tupleT>; using input_values_tuple_type = typename baseT::input_values_tuple_type; - using input_refs_tuple_type = typename baseT::input_refs_tuple_type; + using args_refs_tuple_type = typename baseT::args_refs_tuple_type; using input_edges_type = typename baseT::input_edges_type; using output_edges_type = typename baseT::output_edges_type; @@ -140,8 +154,8 @@ class CallableWrapTTArgs : baseT(name, innames, outnames), func(std::forward(f)) {} template - std::enable_if_t && - !ttg::meta::is_empty_tuple_v && !ttg::meta::is_void_v, + std::enable_if_t && + !ttg::meta::is_empty_tuple_v && !ttg::meta::is_void_v, void> op(Key &&key, ArgsTuple &&args_tuple, output_terminalsT &out) { call_func(std::forward(key), std::forward(args_tuple), out, @@ -149,32 +163,31 @@ class CallableWrapTTArgs }; template - std::enable_if_t && - !ttg::meta::is_empty_tuple_v && ttg::meta::is_void_v, + std::enable_if_t && + !ttg::meta::is_empty_tuple_v && ttg::meta::is_void_v, void> op(ArgsTuple &&args_tuple, output_terminalsT &out) { call_func(std::forward(args_tuple), out, std::make_index_sequence::value>{}); }; - template - std::enable_if_t && !ttg::meta::is_void_v, void> op( - Key &&key, output_terminalsT &out) { + template + std::enable_if_t && !ttg::meta::is_void_v, void> + op(Key &&key, output_terminalsT &out) { call_func(std::forward(key), out); }; - template - std::enable_if_t && ttg::meta::is_void_v, void> op( - output_terminalsT &out) { + template + std::enable_if_t && ttg::meta::is_void_v, void> + op(output_terminalsT &out) { call_func(out); }; }; -template -struct CallableWrapTTArgsUnwrapTuple; - -template -struct CallableWrapTTArgsUnwrapTuple> { - using type = CallableWrapTTArgs...>; +template +struct CallableWrapTTArgsUnwrapTuple { + using type = CallableWrapTTArgs; }; // Factory function to assist in wrapping a callable with signature @@ -260,10 +273,11 @@ auto make_tt(funcT &&func, const std::tuple. typename ttg::meta::drop_first_n::type, std::tuple_size_v - (void_key ? 1 : 2)>::type; using decayed_input_args_t = ttg::meta::decayed_tuple_t; + using noref_input_args_t = ttg::meta::nonref_tuple_t; // 3. full_input_args_t = !have_void_datum ? input_args_t : input_args_t+void using full_input_args_t = - std::conditional_t>>; - using wrapT = typename CallableWrapTTArgsUnwrapTuple::type; + std::conditional_t>>; + using wrapT = typename CallableWrapTTArgsUnwrapTuple::type; // not sure if we need this level of type checking ... // TODO determine the generic signature of func if constexpr (!void_key) { @@ -271,8 +285,8 @@ auto make_tt(funcT &&func, const std::tuple. std::is_same_v::type, const keyT &>, "ttg::make_tt(func, inedges, outedges): first argument of func must be const keyT& (unless keyT = void)"); } - static_assert(std::is_same_v, - "ttg::make_tt(func, inedges, outedges): inedges value types do not match argument types of func"); + //static_assert(std::is_same_v, + // "ttg::make_tt(func, inedges, outedges): inedges value types do not match argument types of func"); static_assert( std::is_same_v::type, output_terminals_type &>, "ttg::make_tt(func, inedges, outedges): last argument of func must be std::tuple&"); diff --git a/ttg/ttg/parsec/fwd.h b/ttg/ttg/parsec/fwd.h index c42755daec..abf48627a5 100644 --- a/ttg/ttg/parsec/fwd.h +++ b/ttg/ttg/parsec/fwd.h @@ -7,7 +7,8 @@ namespace ttg_parsec { - template + template , typename input_argsT = input_edge_typesT> class TT; /// \internal the OG name diff --git a/ttg/ttg/parsec/ttg.h b/ttg/ttg/parsec/ttg.h index 6cb66e9b9b..55e1e7c90e 100644 --- a/ttg/ttg/parsec/ttg.h +++ b/ttg/ttg/parsec/ttg.h @@ -575,8 +575,21 @@ namespace ttg_parsec { PARSEC_OBJ_RELEASE(copy); } - template + /** + * Register a new data copy with the task. If necessary, a new data copy will + * be created (i.e., if either the copy is mutable or the input and output types + * are different and a conversion is required). + * + * @param copy_in Input data copy + * @param task The task to register the copy with + * @param readonly Whether the task will use the copy readonly + * + * @tparam ValueCopyIn The type of the value in copy_in + * @tparam ValueCopyOut The type of the value stored in the result copy (if different) + */ + template inline ttg_data_copy_t *register_data_copy(ttg_data_copy_t *copy_in, parsec_ttg_task_base_t *task, bool readonly) { + constexpr const bool in_out_type_same = std::is_same_v, std::decay_t>; ttg_data_copy_t *copy_res = copy_in; bool replace = false; int32_t readers = -1; @@ -618,7 +631,14 @@ namespace ttg_parsec { } if (NULL == copy_res) { - ttg_data_copy_t *new_copy = detail::create_new_datacopy(*static_cast(copy_in->device_private)); + ttg_data_copy_t *new_copy; + if constexpr (in_out_type_same) { + new_copy = detail::create_new_datacopy(*static_cast(copy_in->device_private)); + } else { + /* need to convert types */ + ValueCopyOut v(*static_cast(copy_in->device_private)); + new_copy = detail::create_new_datacopy(std::move(v)); + } if (replace) { /* TODO: Make sure there is no race condition with the release in release_data_copy, * in particular when it comes to setting the callback and replacing the data */ @@ -738,10 +758,18 @@ namespace ttg_parsec { }; } // namespace detail - template + template class TT : public ttg::TTBase, detail::ParsecTTBase { - private: - using ttT = TT; + + /// preconditions + static_assert(ttg::meta::is_tuple_v && ttg::meta::is_tuple_v, + "The last two template arguments of TT must be tuples!"); + static_assert((ttg::meta::tuple_none_has_reference_v), "input_terminal_typesT cannot contain reference types"); + + protected: + using ttT = TT; + private: parsec_mempool_t mempools; // check for a non-type member named have_cuda_op @@ -751,8 +779,8 @@ namespace ttg_parsec { bool alive = true; public: - static constexpr int numins = sizeof...(input_valueTs); // number of input arguments - static constexpr int numouts = std::tuple_size::value; // number of outputs + static constexpr int numins = std::tuple_size_v; // number of input arguments + static constexpr int numouts = std::tuple_size_v; // number of outputs static constexpr int numflows = std::max(numins, numouts); // max number of flows /// @return true if derivedT::have_cuda_op exists and is defined to true @@ -764,26 +792,36 @@ namespace ttg_parsec { } } - using input_terminals_type = std::tuple...>; - using input_args_type = std::tuple; - using input_edges_type = std::tuple>...>; - static_assert(ttg::meta::is_none_Void_v, "ttg::Void is for internal use only, do not use it"); + using input_terminals_type = ttg::input_terminals_tuple_t; + using input_args_type = input_argsT; + using input_edges_type = ttg::edges_tuple_t>; + static_assert(ttg::meta::is_none_Void_v, "ttg::Void is for internal use only, do not use it"); + static_assert(ttg::meta::is_none_Void_v, "ttg::Void is for internal use only, do not use it"); // if have data inputs and (always last) control input, convert last input to Void to make logic easier - using input_values_full_tuple_type = std::tuple>...>; + using input_values_full_tuple_type = ttg::meta::void_to_Void_tuple_t>; using input_refs_full_tuple_type = - std::tuple>...>; + ttg::meta::add_lvalue_reference_tuple_t>; + using args_refs_full_tuple_type = + ttg::meta::add_lvalue_reference_tuple_t>; using input_values_tuple_type = - std::conditional_t, input_values_full_tuple_type, + std::conditional_t, input_values_full_tuple_type, typename ttg::meta::drop_last_n::type>; static_assert(!ttg::meta::is_any_void_v); using input_refs_tuple_type = - std::conditional_t, input_refs_full_tuple_type, + std::conditional_t, input_refs_full_tuple_type, typename ttg::meta::drop_last_n::type>; - using input_unwrapped_values_tuple_type = input_values_tuple_type; + using input_crefs_tuple_type = ttg::meta::add_const_tuple_t; + using args_refs_tuple_type = + std::conditional_t, args_refs_full_tuple_type, + typename ttg::meta::drop_last_n::type>; static constexpr int numinvals = std::tuple_size_v; // number of input arguments with values (i.e. omitting the control // input, if any) + static_assert(std::tuple_size_v == std::tuple_size_v, + "Number of input edge types must match number of invocation arguments!"); + + using output_terminals_type = output_terminalsT; using output_edges_type = typename ttg::terminals_to_edges::type; @@ -833,7 +871,7 @@ namespace ttg_parsec { ttg::meta::detail::keymap_t keymap; ttg::meta::detail::keymap_t priomap; // For now use same type for unary/streaming input terminals, and stream reducers assigned at runtime - ttg::meta::detail::input_reducers_t + ttg::meta::detail::input_reducers_t input_reducers; //!< Reducers for the input terminals (empty = expect single value) std::array static_stream_goal; @@ -854,9 +892,9 @@ namespace ttg_parsec { } template - static input_refs_tuple_type make_tuple_of_ref_from_array(task_t *task, std::index_sequence) { - return input_refs_tuple_type{static_cast::type>( - *reinterpret_cast::type> *>( + static args_refs_tuple_type make_tuple_of_ref_from_array(task_t *task, std::index_sequence) { + return args_refs_tuple_type{static_cast::type>( + *reinterpret_cast::type> *>( task->parsec_task.data[IS].data_in->device_private))...}; } @@ -875,12 +913,12 @@ namespace ttg_parsec { } if constexpr (!ttg::meta::is_void_v && !ttg::meta::is_empty_tuple_v) { - input_refs_tuple_type input = make_tuple_of_ref_from_array(task, std::make_index_sequence{}); + auto input = make_tuple_of_ref_from_array(task, std::make_index_sequence{}); baseobj->template op(task->key, std::move(input), obj->output_terminals); } else if constexpr (!ttg::meta::is_void_v && ttg::meta::is_empty_tuple_v) { baseobj->template op(task->key, obj->output_terminals); } else if constexpr (ttg::meta::is_void_v && !ttg::meta::is_empty_tuple_v) { - input_refs_tuple_type input = make_tuple_of_ref_from_array(task, std::make_index_sequence{}); + auto input = make_tuple_of_ref_from_array(task, std::make_index_sequence{}); baseobj->template op(std::move(input), obj->output_terminals); } else if constexpr (ttg::meta::is_void_v && ttg::meta::is_empty_tuple_v) { baseobj->template op(obj->output_terminals); @@ -1295,6 +1333,11 @@ namespace ttg_parsec { constexpr const bool valueT_is_Void = ttg::meta::is_void_v; constexpr const bool keyT_is_Void = ttg::meta::is_void_v; + using input_arg_type = std::decay_t>; + using decay_value_t = std::decay_t; + constexpr const bool edge_arg_same_type = std::is_same_v; + constexpr const bool edge_arg_convertible = std::is_convertible_v; + if constexpr (!valueT_is_Void) { ttg::trace(world.rank(), ":", get_name(), " : ", key, ": received value for argument : ", i, " : value = ", value); @@ -1311,6 +1354,12 @@ namespace ttg_parsec { task_t *task; auto &world_impl = world.impl(); auto &reducer = std::get(input_reducers); + if constexpr (!edge_arg_same_type && !edge_arg_convertible) { + /* if the types don't match and are not convertible we have to rely on a reducer to be available */ + if (!reducer) { + throw std::logic_error("Types are not convertible and no reducer was set!"); + } + } bool release = false; bool remove_from_hash = true; /* If we have only one input and no reducer on that input we can skip the hash table */ @@ -1339,13 +1388,28 @@ namespace ttg_parsec { if (nullptr == (copy = reinterpret_cast(task->parsec_task.data[i].data_in))) { using decay_valueT = std::decay_t; if (nullptr == copy_in) { - copy = detail::create_new_datacopy(std::forward(value)); + if constexpr(edge_arg_same_type) { + copy = detail::create_new_datacopy(std::forward(value)); + } else if constexpr (edge_arg_convertible) { + /* need to convert */ + copy = detail::create_new_datacopy(static_cast(value)); + } else { + /* terminal and argument value are not convertible so we need to call the reducer */ + copy = detail::create_new_datacopy(input_arg_type{}); + reducer(*reinterpret_cast*>(copy->device_private), value); + } } else { - copy = detail::register_data_copy(copy_in, task, input_is_const); + if constexpr(edge_arg_convertible) { + copy = detail::register_data_copy(copy_in, task, input_is_const); + } else { + /* terminal and argument value are not convertible so we need to call the reducer */ + copy = detail::create_new_datacopy(input_arg_type{}); + reducer(*reinterpret_cast*>(copy->device_private), value); + } } task->parsec_task.data[i].data_in = copy; } else { - reducer(*reinterpret_cast *>(copy->device_private), value); + reducer(*reinterpret_cast*>(copy->device_private), value); } } else { reducer(); // even if this was a control input, must execute the reducer for possible side effects @@ -1373,9 +1437,16 @@ namespace ttg_parsec { if (nullptr != copy) { /* register_data_copy might provide us with a different copy if !input_is_const */ - copy = detail::register_data_copy(copy, task, input_is_const); + copy = detail::register_data_copy(copy, task, input_is_const); } else { - copy = detail::create_new_datacopy(std::forward(value)); + if constexpr(edge_arg_same_type) { + copy = detail::create_new_datacopy(std::forward(value)); + } else if constexpr (edge_arg_convertible) { + /* need to convert */ + copy = detail::create_new_datacopy(static_cast(value)); + } else { + throw std::logic_error("Types not convertible and no reducer provided!"); + } } /* if we registered as a writer and were the first to register with this copy * we need to defer the release of this task to give other tasks a chance to @@ -1880,7 +1951,7 @@ namespace ttg_parsec { // Used by invoke to set all arguments associated with a task template std::enable_if_t, void> set_args(std::index_sequence, const Key &key, - const input_refs_tuple_type &args) { + const input_crefs_tuple_type &args) { int junk[] = {0, (set_arg(key, TT::get(args)), 0)...}; junk[0]++; } @@ -1888,7 +1959,7 @@ namespace ttg_parsec { // Used by invoke to set all arguments associated with a task template std::enable_if_t, void> set_args(std::index_sequence, - const input_refs_tuple_type &args) { + const input_crefs_tuple_type &args) { int junk[] = {0, (set_arg(TT::get(args)), 0)...}; junk[0]++; } @@ -2441,8 +2512,9 @@ namespace ttg_parsec { return; } alive = false; - /* print all outstanding tasks */ - parsec_hash_table_for_all(&tasks_table, ht_iter_cb, this); + /* Not sure why but both GCC-10 and Clang-14 fail if 'this' is passed directly */ + void *cb_data = this; + parsec_hash_table_for_all(&tasks_table, ht_iter_cb, cb_data); parsec_hash_table_fini(&tasks_table); parsec_mempool_destruct(&mempools); // uintptr_t addr = (uintptr_t)self.incarnations; @@ -2491,38 +2563,40 @@ namespace ttg_parsec { // Manual injection of a task with all input arguments specified as a tuple template - std::enable_if_t && !ttg::meta::is_empty_tuple_v, void> invoke( - const Key &key, const input_refs_tuple_type &args) { + std::enable_if_t && + !ttg::meta::is_empty_tuple_v, void> + invoke(const Key &key, const input_crefs_tuple_type &args) { TTG_OP_ASSERT_EXECUTABLE(); - set_args(std::make_index_sequence::value>{}, key, args); + set_args(std::make_index_sequence::value>{}, key, args); } // Manual injection of a key-free task and all input arguments specified as a tuple template - std::enable_if_t && !ttg::meta::is_empty_tuple_v, void> invoke( - const input_refs_tuple_type &args) { + std::enable_if_t && !ttg::meta::is_empty_tuple_v, void> + invoke(const input_crefs_tuple_type &args) { TTG_OP_ASSERT_EXECUTABLE(); - set_args(std::make_index_sequence::value>{}, args); + set_args(std::make_index_sequence::value>{}, args); } // Manual injection of a task that has no arguments template - std::enable_if_t && ttg::meta::is_empty_tuple_v, void> invoke( - const Key &key) { + std::enable_if_t && ttg::meta::is_empty_tuple_v, void> + invoke(const Key &key) { TTG_OP_ASSERT_EXECUTABLE(); set_arg(key); } // Manual injection of a task that has no key or arguments template - std::enable_if_t && ttg::meta::is_empty_tuple_v, void> invoke() { + std::enable_if_t && ttg::meta::is_empty_tuple_v, void> + invoke() { TTG_OP_ASSERT_EXECUTABLE(); set_arg(); } // overrides TTBase::invoke() void invoke() override { - if constexpr (ttg::meta::is_void_v && ttg::meta::is_empty_tuple_v) + if constexpr (ttg::meta::is_void_v && ttg::meta::is_empty_tuple_v) invoke(); else TTBase::invoke(); diff --git a/ttg/ttg/reduce.h b/ttg/ttg/reduce.h index e6c46fb3bd..7becbabdad 100644 --- a/ttg/ttg/reduce.h +++ b/ttg/ttg/reduce.h @@ -28,10 +28,10 @@ namespace ttg { template class BinaryTreeReduce : public TT, Out, Out, Out>, - BinaryTreeReduce, Value, Value, Value> { + BinaryTreeReduce, std::tuple> { public: using baseT = TT, Out, Out, Out>, - BinaryTreeReduce, Value, Value, Value>; + BinaryTreeReduce, std::tuple>; BinaryTreeReduce(Edge &in, Edge &out, int root = 0, OutKey dest_key = OutKey(), BinaryOp op = BinaryOp{}, World world = ttg::default_execution_context(), int max_key = -1, diff --git a/ttg/ttg/terminal.h b/ttg/ttg/terminal.h index 5f38b0acdf..9c67ee05af 100644 --- a/ttg/ttg/terminal.h +++ b/ttg/ttg/terminal.h @@ -178,6 +178,20 @@ namespace ttg { } }; + template + struct input_terminals_tuple { + using type = std::tuple...>; + }; + + template + struct input_terminals_tuple> { + using type = std::tuple...>; + }; + + template + using input_terminals_tuple_t = typename input_terminals_tuple::type; + + // Output terminal template class Out : public TerminalBase { @@ -382,6 +396,20 @@ namespace ttg { } }; + template + struct output_terminals_tuple { + using type = std::tuple...>; + }; + + template + struct output_terminals_tuple> { + using type = std::tuple...>; + }; + + template + using output_terminals_tuple_t = typename output_terminals_tuple::type; + + } // namespace ttg #endif // TTG_TERMINALS_H diff --git a/ttg/ttg/util/env.cpp b/ttg/ttg/util/env.cpp index fd3d463e3a..a4de47b09e 100644 --- a/ttg/ttg/util/env.cpp +++ b/ttg/ttg/util/env.cpp @@ -5,6 +5,7 @@ #include "ttg/util/env.h" #include +#include #include diff --git a/ttg/ttg/util/meta.h b/ttg/ttg/util/meta.h index 4e159f5ff1..847df5d1bf 100644 --- a/ttg/ttg/util/meta.h +++ b/ttg/ttg/util/meta.h @@ -67,7 +67,7 @@ namespace ttg { }; // tuple -> tuple...> - template + template struct nonref_tuple; template @@ -79,7 +79,7 @@ namespace ttg { using nonref_tuple_t = typename nonref_tuple::type; // tuple -> tuple...> - template + template struct decayed_tuple; template @@ -90,6 +90,33 @@ namespace ttg { template using decayed_tuple_t = typename decayed_tuple::type; + + // like std::add_const but adds const to references + template + struct add_const { + using type = std::add_const_t; + }; + + template + struct add_const { + using type = std::add_lvalue_reference_t>; + }; + + template + using add_const_t = typename add_const::type; + + // tuple -> tuple...> + template + struct add_const_tuple; + + template + struct add_const_tuple> { + using type = std::tuple::type...>; + }; + + template + using add_const_tuple_t = typename add_const_tuple::type; + template struct tuple_concat; @@ -154,6 +181,9 @@ namespace ttg { template constexpr bool is_any_Void_v = (is_Void_v || ...); + template + constexpr bool is_any_Void_v> = (is_Void_v || ...); + template constexpr bool is_none_void_v = !is_any_void_v; @@ -186,6 +216,72 @@ namespace ttg { template using void_to_Void_t = typename void_to_Void::type; + + template + struct void_to_Void_tuple; + + template + struct void_to_Void_tuple> { + using type = std::tuple...>; + }; + + template + using void_to_Void_tuple_t = typename void_to_Void_tuple>::type; + + template + struct add_lvalue_reference_tuple; + + template + struct add_lvalue_reference_tuple> { + using type = std::tuple...>; + }; + + template + using add_lvalue_reference_tuple_t = typename add_lvalue_reference_tuple::type; + + template + struct none_has_reference + { + static constexpr bool value = !std::is_reference_v && none_has_reference::value; + }; + + template + struct none_has_reference + { + static constexpr bool value = !std::is_reference_v; + }; + + template + struct tuple_none_has_reference; + + template + struct tuple_none_has_reference> + { + static constexpr bool value = none_has_reference::value; + }; + + template<> + struct tuple_none_has_reference> + { + static constexpr bool value = true; + }; + + + template + constexpr bool tuple_none_has_reference_v = tuple_none_has_reference::value; + + template + struct is_tuple : std::integral_constant + { }; + + template + struct is_tuple> : std::integral_constant + { }; + + template + constexpr bool is_tuple_v = is_tuple::value; + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // is_empty_tuple //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -410,22 +506,27 @@ namespace ttg { // &&)>...> // protected against void valueTs //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - template + template struct input_reducer_type; - template - struct input_reducer_type>> { - using type = std::function &, const std::decay_t &)>; + template + struct input_reducer_type>> { + using type = std::function &, const std::decay_t &)>; }; - template - struct input_reducer_type>> { + template + struct input_reducer_type>> { using type = std::function; }; - template - struct input_reducers { - using type = std::tuple::type...>; + + template + struct input_reducers; + + template + struct input_reducers, std::tuple> { + using type = std::tuple::type...>; }; + template - using input_reducers_t = typename input_reducers::type; + using input_reducers_t = typename input_reducers...>::type; } // namespace detail @@ -445,6 +546,31 @@ namespace ttg { template constexpr bool is_iterable_v = is_iterable::value; + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // The input argument types to the op() call of a TT + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + template + struct op_input_args{ + // drop the key (first) and output terminal (last) argument + using type = typename drop_last_n::type, 1>::type; + }; + + template + struct op_input_args{ + // drop the output terminal (last) argument + using type = typename drop_last_n::type; + }; + + template + struct op_input_args{ + // drop the output terminal (last) argument + using type = typename drop_last_n::type; + }; + + template + using op_input_args_t = typename op_input_args::type; } // namespace meta } // namespace ttg