diff --git a/examples/floyd-warshall/floyd_warshall.cc b/examples/floyd-warshall/floyd_warshall.cc index d6de4b424a..c9c9e8d506 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, ttg::typelist> { + 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, ttg::typelist> { + 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, ttg::typelist> { + 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, ttg::typelist> { + 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..2d86e611d8 100644 --- a/examples/floyd-warshall/floyd_warshall_df.cc +++ b/examples/floyd-warshall/floyd_warshall_df.cc @@ -14,8 +14,8 @@ #include #if __has_include() -#include -#define HAS_EXECUTION_HEADER +//#include +//#define HAS_EXECUTION_HEADER #endif #include "ttg.h" @@ -104,15 +104,35 @@ std::ostream& operator<<(std::ostream& s, const Control ctl) { return s; } +template +struct Policy : ttg::TTPolicyBase { + ProcMap procmap_; + + Policy(const ProcMap& pm) + : TTPolicyBase(), procmap_(pm) + { } + + Policy(const Policy& p) = default; + + int procmap(const Key& key) const { + return procmap_(key); + } + + int priomap(const Key&) const { + return 0; + } + + int inlinemap(const Key&) const { + return 0; + } +}; + template class Initiator : public TT>, Out>, Out>, Out>>, Initiator> { - using baseT = TT>, Out>, Out>, - Out>>, - Initiator>; + using baseT = typename Initiator::ttT; Matrix* adjacency_matrix_ttg; public: @@ -153,9 +173,9 @@ class Initiator : public TT -class Finalizer : public TT, Finalizer, BlockMatrix> { - using baseT = TT, Finalizer, BlockMatrix>; +template +class Finalizer : public TT, Finalizer, ttg::typelist>, Policy> { + using baseT = typename Finalizer::ttT; Matrix* result_matrix_ttg; int problem_size; int blocking_factor; @@ -167,9 +187,9 @@ class Finalizer : public TT, Finalizer, BlockMatrix> { public: Finalizer(Matrix* result_matrix_ttg, int problem_size, int blocking_factor, const std::string& kernel_type, - int recursive_fan_out, int base_size, const std::string& name, T* adjacency_matrix_serial, + int recursive_fan_out, int base_size, const std::string& name, T* adjacency_matrix_serial, Policy policy, bool verify_results = false) - : baseT(name, {"input"}, {}) + : baseT(name, {"input"}, {}, policy) , result_matrix_ttg(result_matrix_ttg) , problem_size(problem_size) , blocking_factor(blocking_factor) @@ -181,8 +201,8 @@ class Finalizer : public TT, Finalizer, BlockMatrix> { Finalizer(Matrix* result_matrix_ttg, int problem_size, int blocking_factor, const std::string& kernel_type, int recursive_fan_out, int base_size, const typename baseT::input_edges_type& inedges, - const typename baseT::output_edges_type& outedges, const std::string& name) - : baseT(inedges, outedges, name, {"input"}, {}) + const typename baseT::output_edges_type& outedges, const std::string& name, Policy policy) + : baseT(inedges, outedges, name, {"input"}, {}, policy) , result_matrix_ttg(result_matrix_ttg) , problem_size(problem_size) , blocking_factor(blocking_factor) @@ -231,17 +251,13 @@ class Finalizer : public TT, Finalizer, BlockMatrix> { } }; -template +template 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, ttg::typelist>, Policy> { + using baseT = typename FuncA::ttT; Matrix* adjacency_matrix_ttg; int problem_size; int blocking_factor; @@ -250,9 +266,10 @@ class FuncA : public TT FuncA(Matrix* adjacency_matrix_ttg, int problem_size, int blocking_factor, const std::string& kernel_type, - int recursive_fan_out, int base_size, const std::string& name) - : baseT(name, {"x_ready"}, {"outA", "outB", "outC", "outD", "readyB", "readyC", "result"}) + int recursive_fan_out, int base_size, const std::string& name, Policy policy) + : baseT(name, {"x_ready"}, {"outA", "outB", "outC", "outD", "readyB", "readyC", "result"}, policy) , adjacency_matrix_ttg(adjacency_matrix_ttg) , problem_size(problem_size) , blocking_factor(blocking_factor) @@ -260,10 +277,11 @@ class FuncA : public TT FuncA(Matrix* adjacency_matrix_ttg, int problem_size, int blocking_factor, const std::string& kernel_type, int recursive_fan_out, int base_size, const typename baseT::input_edges_type& inedges, - const typename baseT::output_edges_type& outedges, const std::string& name) - : baseT(inedges, outedges, name, {"x_ready"}, {"outA", "outB", "outC", "outD", "readyB", "readyC", "result"}) + const typename baseT::output_edges_type& outedges, const std::string& name, Policy policy) + : baseT(inedges, outedges, name, {"x_ready"}, {"outA", "outB", "outC", "outD", "readyB", "readyC", "result"}, policy) , adjacency_matrix_ttg(adjacency_matrix_ttg) , problem_size(problem_size) , blocking_factor(blocking_factor) @@ -335,15 +353,12 @@ class FuncA : public TT +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, ttg::typelist, const BlockMatrix>, Policy> { + using baseT = typename FuncB::ttT; Matrix* adjacency_matrix_ttg; int problem_size; int blocking_factor; @@ -353,8 +368,8 @@ class FuncB : public TT* adjacency_matrix_ttg, int problem_size, int blocking_factor, const std::string& kernel_type, - int recursive_fan_out, int base_size, const std::string& name) - : baseT(name, {"x_ready", "u_ready"}, {"outA", "outB", "outC", "outD", "readyD", "result"}) + int recursive_fan_out, int base_size, const std::string& name, Policy policy) + : baseT(name, {"x_ready", "u_ready"}, {"outA", "outB", "outC", "outD", "readyD", "result"}, policy) , adjacency_matrix_ttg(adjacency_matrix_ttg) , problem_size(problem_size) , blocking_factor(blocking_factor) @@ -364,8 +379,8 @@ class FuncB : public TT* adjacency_matrix_ttg, int problem_size, int blocking_factor, const std::string& kernel_type, int recursive_fan_out, int base_size, const typename baseT::input_edges_type& inedges, - const typename baseT::output_edges_type& outedges, const std::string& name) - : baseT(inedges, outedges, name, {"x_ready", "u_ready"}, {"outA", "outB", "outC", "outD", "readyD", "result"}) + const typename baseT::output_edges_type& outedges, const std::string& name, Policy policy) + : baseT(inedges, outedges, name, {"x_ready", "u_ready"}, {"outA", "outB", "outC", "outD", "readyD", "result"}, policy) , adjacency_matrix_ttg(adjacency_matrix_ttg) , problem_size(problem_size) , blocking_factor(blocking_factor) @@ -428,15 +443,12 @@ class FuncB : public TT +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, ttg::typelist, const BlockMatrix>, Policy> { + using baseT = typename FuncC::ttT; Matrix* adjacency_matrix_ttg; int problem_size; int blocking_factor; @@ -446,8 +458,8 @@ class FuncC : public TT* adjacency_matrix_ttg, int problem_size, int blocking_factor, const std::string& kernel_type, - int recursive_fan_out, int base_size, const std::string& name) - : baseT(name, {"x_ready", "v_ready"}, {"outA", "outB", "outC", "outD", "readyD", "result"}) + int recursive_fan_out, int base_size, const std::string& name, Policy policy) + : baseT(name, {"x_ready", "v_ready"}, {"outA", "outB", "outC", "outD", "readyD", "result"}, policy) , adjacency_matrix_ttg(adjacency_matrix_ttg) , problem_size(problem_size) , blocking_factor(blocking_factor) @@ -457,8 +469,8 @@ class FuncC : public TT* adjacency_matrix_ttg, int problem_size, int blocking_factor, const std::string& kernel_type, int recursive_fan_out, int base_size, const typename baseT::input_edges_type& inedges, - const typename baseT::output_edges_type& outedges, const std::string& name) - : baseT(inedges, outedges, name, {"x_ready", "v_ready"}, {"outA", "outB", "outC", "outD", "readyD", "result"}) + const typename baseT::output_edges_type& outedges, const std::string& name, Policy policy) + : baseT(inedges, outedges, name, {"x_ready", "v_ready"}, {"outA", "outB", "outC", "outD", "readyD", "result"}, policy) , adjacency_matrix_ttg(adjacency_matrix_ttg) , problem_size(problem_size) , blocking_factor(blocking_factor) @@ -520,15 +532,12 @@ class FuncC : public TT +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, ttg::typelist, const BlockMatrix, const BlockMatrix>, Policy> { + using baseT = typename FuncD::ttT; Matrix* adjacency_matrix_ttg; int problem_size; int blocking_factor; @@ -538,8 +547,8 @@ class FuncD : public TT* adjacency_matrix_ttg, int problem_size, int blocking_factor, const std::string& kernel_type, - int recursive_fan_out, int base_size, const std::string& name) - : baseT(name, {"x_ready", "v_ready", "u_ready"}, {"outA", "outB", "outC", "outD", "result"}) + int recursive_fan_out, int base_size, const std::string& name, Policy policy) + : baseT(name, {"x_ready", "v_ready", "u_ready"}, {"outA", "outB", "outC", "outD", "result"}, policy) , adjacency_matrix_ttg(adjacency_matrix_ttg) , problem_size(problem_size) , blocking_factor(blocking_factor) @@ -549,8 +558,8 @@ class FuncD : public TT* adjacency_matrix_ttg, int problem_size, int blocking_factor, const std::string& kernel_type, int recursive_fan_out, int base_size, const typename baseT::input_edges_type& inedges, - const typename baseT::output_edges_type& outedges, const std::string& name) - : baseT(inedges, outedges, name, {"x_ready", "v_ready", "u_ready"}, {"outA", "outB", "outC", "outD", "result"}) + const typename baseT::output_edges_type& outedges, const std::string& name, Policy policy) + : baseT(inedges, outedges, name, {"x_ready", "v_ready", "u_ready"}, {"outA", "outB", "outC", "outD", "result"}, policy) , adjacency_matrix_ttg(adjacency_matrix_ttg) , problem_size(problem_size) , blocking_factor(blocking_factor) @@ -594,38 +603,33 @@ class FuncD : public TT + +template class FloydWarshall { Initiator initiator; - FuncA funcA; - FuncB funcB; - FuncC funcC; - FuncD funcD; - Finalizer finalizer; + FuncA funcA; + FuncB funcB; + FuncC funcC; + FuncD funcD; + Finalizer finalizer; ttg::World world; // Needed for Initiating the execution in Initiator data member (see the function start()) int blocking_factor; public: - template FloydWarshall(Matrix* adjacency_matrix_ttg, Matrix* result_matrix_ttg, int problem_size, int blocking_factor, - const std::string& kernel_type, int recursive_fan_out, int base_size, T* adjacency_matrix_serial, Keymap&& keymap, + const std::string& kernel_type, int recursive_fan_out, int base_size, T* adjacency_matrix_serial, Policy policy, bool verify_results = false) : initiator(adjacency_matrix_ttg, "initiator") - , funcA(adjacency_matrix_ttg, problem_size, blocking_factor, kernel_type, recursive_fan_out, base_size, "funcA") - , funcB(adjacency_matrix_ttg, problem_size, blocking_factor, kernel_type, recursive_fan_out, base_size, "funcB") - , funcC(adjacency_matrix_ttg, problem_size, blocking_factor, kernel_type, recursive_fan_out, base_size, "funcC") - , funcD(adjacency_matrix_ttg, problem_size, blocking_factor, kernel_type, recursive_fan_out, base_size, "funcD") + , funcA(adjacency_matrix_ttg, problem_size, blocking_factor, kernel_type, recursive_fan_out, base_size, "funcA", policy) + , funcB(adjacency_matrix_ttg, problem_size, blocking_factor, kernel_type, recursive_fan_out, base_size, "funcB", policy) + , funcC(adjacency_matrix_ttg, problem_size, blocking_factor, kernel_type, recursive_fan_out, base_size, "funcC", policy) + , funcD(adjacency_matrix_ttg, problem_size, blocking_factor, kernel_type, recursive_fan_out, base_size, "funcD", policy) , finalizer(result_matrix_ttg, problem_size, blocking_factor, kernel_type, recursive_fan_out, base_size, - "finalizer", adjacency_matrix_serial, verify_results) + "finalizer", adjacency_matrix_serial, policy, verify_results) , world(ttg::default_execution_context()) , blocking_factor(blocking_factor) { - funcA.set_keymap(keymap); - funcB.set_keymap(keymap); - funcC.set_keymap(keymap); - funcD.set_keymap(keymap); - finalizer.set_keymap(keymap); initiator.template out<0>()->connect(funcA.template in<0>()); initiator.template out<1>()->connect(funcB.template in<0>()); initiator.template out<2>()->connect(funcC.template in<0>()); @@ -757,6 +761,8 @@ int main(int argc, char** argv) { return ((I%P) + (J%Q)*P); }; + auto policy = Policy(keymap); + auto predicate = [=](int i, int j){ return keymap(Key{i, j, 0}) == rank; }; Matrix* m = new Matrix(n_brows, n_bcols, block_size, block_size, predicate); @@ -784,8 +790,8 @@ int main(int argc, char** argv) { // Running the ttg version std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now(); // Calling the blocked implementation of FW-APSP algorithm on ttg runtime - FloydWarshall fw_apsp(m, r, problem_size, blocking_factor, kernel_type, recursive_fan_out, base_size, - adjacency_matrix_serial, keymap, verify_results); + auto fw_apsp = FloydWarshall(m, r, problem_size, blocking_factor, kernel_type, recursive_fan_out, base_size, + adjacency_matrix_serial, policy, verify_results); // std::cout << fw_apsp.dot() << std::endl; fw_apsp.start(); fw_apsp.fence(); diff --git a/examples/ge/ge.cc b/examples/ge/ge.cc index c25b63a724..6b5d2ba33c 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, ttg::typelist> { + 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, ttg::typelist> { + 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, ttg::typelist> { + 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, ttg::typelist> { + 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..a90387f632 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, ttg::typelist>> { + 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, ttg::typelist>> { + 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, ttg::typelist, 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, ttg::typelist, 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, ttg::typelist, 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..e95efbc325 100644 --- a/examples/madness/madness-1d/madness-1d.cc +++ b/examples/madness/madness-1d/madness-1d.cc @@ -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, ttg::typelist> { + 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, ttg::typelist> { + using baseT = typename GaxpyOp::ttT; double alpha; double beta; @@ -369,8 +369,9 @@ 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, ttg::typelist> { + using baseT = typename BinaryOp::ttT; using funcT = Vector (*)(const Vector &, const Vector&); funcT func; @@ -430,8 +431,9 @@ 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, ttg::typelist> { + using baseT = typename Diff_prologue::ttT; public: @@ -452,8 +454,9 @@ 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, ttg::typelist> { + using baseT = typename Diff_doIt::ttT; Vector unfilter(const Vector &inputVector, int k, const Matrix * hg) const { Vector inputVector_copy(inputVector); @@ -530,8 +533,9 @@ 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, ttg::typelist> { + using baseT = typename Compress_prologue::ttT; public: Compress_prologue(const std::string &name) @@ -564,8 +568,9 @@ 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, ttg::typelist> { + using baseT = typename Compress_doIt::ttT; public: Compress_doIt(const std::string &name) @@ -607,8 +612,9 @@ 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, ttg::typelist> { + using baseT = typename Reconstruct_prologue::ttT; public: Reconstruct_prologue(const std::string &name) @@ -633,8 +639,9 @@ 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, ttg::typelist> { + using baseT = typename Reconstruct_doIt::ttT; public: Reconstruct_doIt(const std::string &name) @@ -672,8 +679,9 @@ class Reconstruct_doIt : public TT, Out, Out>, Project, Control> { - using baseT = TT, Out>, Project, Control>; +class Project : public TT, Out>, + Project, ttg::typelist> { + using baseT = typename Project::ttT; public: using funcT = double(*)(double); @@ -733,7 +741,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 +761,7 @@ class Producer : public TT>, Producer> { // EXAMPLE 1 class Everything : public TT, Everything> { - using baseT = TT, Everything>; + using baseT = typename Everything::ttT; Producer producer; Project project; diff --git a/examples/madness/mrattg.cc b/examples/madness/mrattg.cc index 6c26e0bd40..815ea3c4cc 100644 --- a/examples/madness/mrattg.cc +++ b/examples/madness/mrattg.cc @@ -135,7 +135,7 @@ namespace detail { using compress_out_type = std::tuple>; using compress_in_type = std::tuple; template - using compwrap_type = ttg::CallableWrapTT, compress_out_type, Rin, Rin>; + using compwrap_type = ttg::CallableWrapTT, compress_out_type, ttg::TTPolicyBase>, Rin, Rin>; }; template struct tree_types{ @@ -144,7 +144,7 @@ namespace detail { using compress_out_type = std::tuple>; using compress_in_type = std::tuple; template - using compwrap_type = ttg::CallableWrapTT, compress_out_type, Rin, Rin, Rin, Rin>; + using compwrap_type = ttg::CallableWrapTT, compress_out_type, ttg::TTPolicyBase>, Rin, Rin, Rin, Rin>; }; template struct tree_types{ @@ -153,7 +153,7 @@ namespace detail { using compress_out_type = std::tuple>; using compress_in_type = std::tuple; template - using compwrap_type = ttg::CallableWrapTT, compress_out_type, Rin, Rin, Rin, Rin, Rin, Rin, Rin, Rin>; + using compwrap_type = ttg::CallableWrapTT, compress_out_type, ttg::TTPolicyBase>, Rin, Rin, Rin, Rin, Rin, Rin, Rin, Rin>; }; }; @@ -237,7 +237,8 @@ auto make_compress(rnodeEdge& in, cnodeEdge& out, const std: constexpr size_t num_children = Key::num_children; using sendfuncT = decltype(&send_leaves_up); - using sendwrapT = ttg::CallableWrapTT, typename ::detail::tree_types::compress_out_type, FunctionReconstructedNode >; + using sendwrapT = ttg::CallableWrapTT, typename ::detail::tree_types::compress_out_type, + ttg::TTPolicyBase>, FunctionReconstructedNode >; using compfuncT = decltype(&do_compress); using compwrapT = typename ::detail::tree_types::template compwrap_type; diff --git a/examples/madness/mrattg_streaming.cc b/examples/madness/mrattg_streaming.cc index bceb52b5ef..369f873c31 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, ttg::typelist>; }; 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, ttg::typelist>; }; 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, ttg::typelist>; }; }; diff --git a/examples/spmm/spmm.cc b/examples/spmm/spmm.cc index 8da592ae4f..a04a3d76ff 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, ttg::typelist> { 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) @@ -202,7 +202,7 @@ class Read_SpMatrix : public TT, std::tuple, Blk>>, Read_SpMat auto rank = ttg::default_execution_context().rank(); for (int k = 0; k < matrix_.outerSize(); ++k) { for (typename SpMatrix::InnerIterator it(matrix_, k); it; ++it) { - if (rank == this->get_keymap()(Key<2>({it.row(), it.col()}))) + if (rank == this->procmap(Key<2>({it.row(), it.col()}))) ::send<0>(Key<2>({it.row(), it.col()}), it.value(), out); } } @@ -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, ttg::typelist> { 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, ttg::typelist> { 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, ttg::typelist> { 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) @@ -339,9 +339,8 @@ class SpMM { if (k >= b_rowidx_to_colidx_.size()) return; auto world = default_execution_context(); std::vector procmap(world.size()); - auto keymap = baseT::get_keymap(); for (auto &j : b_rowidx_to_colidx_[k]) { - long proc = keymap(Key<2>({i, j})); + long proc = this->procmap(Key<2>({i, j})); if (!procmap[proc]) { ttg::trace("Broadcasting A[", i, "][", k, "] to proc ", proc); ikp_keys.emplace_back(Key<3>({i, k, proc})); @@ -356,9 +355,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, ttg::typelist> { 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 +390,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, ttg::typelist> { 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) @@ -410,7 +409,7 @@ class SpMM { auto world = default_execution_context(); std::vector procmap(world.size()); for (auto &i : a_colidx_to_rowidx_[k]) { - long proc = baseT::get_keymap()(Key<2>({i, j})); + long proc = this->procmap(Key<2>({i, j})); if (!procmap[proc]) { ttg::trace("Broadcasting A[", k, "][", j, "] to proc ", proc); kjp_keys.emplace_back(Key<3>({k, j, proc})); @@ -426,9 +425,10 @@ 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, ttg::typelist> { 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, @@ -583,6 +583,7 @@ class SpMM { return std::make_tuple(a_colidx, true); } ttg::abort(); // unreachable + return std::make_tuple(0, false); } }; @@ -604,7 +605,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..9db21382f5 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, ttg::typelist> { + 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..887cee4741 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, ttg::typelist> { + using baseT = typename Norm2::ttT; double sumsq; std::mutex charon; diff --git a/examples/test/test.cc b/examples/test/test.cc index 28037b2d4f..bcdcc5bc8d 100644 --- a/examples/test/test.cc +++ b/examples/test/test.cc @@ -12,8 +12,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, ttg::typelist> { + using baseT = typename A::ttT; public: A(const std::string &name) : baseT(name, {"inputA"}, {"resultA", "iterateA"}) {} @@ -50,7 +50,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 +66,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, ttg::typelist> { + using baseT = typename Consumer::ttT; public: Consumer(const std::string &name) : baseT(name, {"input"}, {}) {} diff --git a/examples/ttg_matrix.h b/examples/ttg_matrix.h index a479028deb..3478e2aa45 100644 --- a/examples/ttg_matrix.h +++ b/examples/ttg_matrix.h @@ -193,9 +193,9 @@ namespace ttg { // compute shape of an existing SpMatrix on rank 0 template - class ReadShape : public TT>, ReadShape, void> { + class ReadShape : public TT>, ReadShape, ttg::typelist> { public: - using baseT = TT>, ReadShape, void>; + 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) @@ -218,7 +218,7 @@ namespace ttg { // - 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, void> { + class Read : public TT, std::tuple, Blk>>, Read, ttg::typelist> { public: using baseT = TT, std::tuple, Blk>>, Read, void>; static constexpr const int owner = 0; // where data resides @@ -243,9 +243,9 @@ namespace ttg { // since SpMatrix supports random inserts there is no need to commit the shape into the matrix, other than get the // dimensions template - class WriteShape : public TT>, WriteShape, Shape> { + class WriteShape : public TT>, WriteShape, ttg::typelist> { public: - using baseT = TT>, WriteShape, Shape>; + using baseT = typename WriteShape::ttT; static constexpr const int owner = 0; // where data resides WriteShape(const char *label, SpMatrix &matrix, Edge &in, Edge &out) @@ -267,9 +267,9 @@ namespace ttg { // flow (move?) data into an existing SpMatrix on rank 0 template - class Write : public TT, std::tuple<>, Write, Blk, void> { + class Write : public TT, std::tuple<>, Write, Blk, ttg::typelist> { public: - using baseT = TT, std::tuple<>, Write, Blk, void>; + using baseT = typename Write::ttT; Write(const char *label, SpMatrix &matrix, Edge, Blk> &data_in, Edge, void> &ctl_in) : baseT(edges(data_in, ctl_in), edges(), std::string("write_spmatrix(") + label + ")", @@ -315,9 +315,9 @@ namespace ttg { }; // ShapeAdd adds two Shape objects - class ShapeAdd : public TT>, ShapeAdd, Shape, Shape> { + class ShapeAdd : public TT>, ShapeAdd, ttg::typelist> { public: - using baseT = TT>, ShapeAdd, Shape, Shape>; + using baseT = typename ShapeAdd::ttT; static constexpr const int owner = 0; // where data resides ShapeAdd(Edge &in1, Edge &in2, Edge &out) @@ -330,9 +330,9 @@ namespace ttg { }; // pushes all blocks given by the shape - class Push : public TT, void>>, Push, Shape> { + class Push : public TT, void>>, Push, ttg::typelist> { public: - using baseT = TT, void>>, Push, Shape>; + using baseT = typename Push::ttT; static constexpr const int owner = 0; // where data resides Push(const char *label, Edge &in, Edge, void> &out) diff --git a/tests/movetest.cc b/tests/movetest.cc index 636db34079..22ce7d5192 100644 --- a/tests/movetest.cc +++ b/tests/movetest.cc @@ -42,8 +42,8 @@ class Value { ~Value() {} }; -class A : public TT>, A, Value> { - using baseT = TT>, A, Value>; +class A : public TT>, A, ttg::typelist> { + using baseT = A::ttT; public: A(const std::string& name) : baseT(name, {"input"}, {"result"}) {} @@ -58,8 +58,8 @@ class A : public TT>, A, Value> { ~A() { std::cout << " A destructor\n"; } }; -class Printer : public TT, Printer, Value> { - using baseT = TT, Printer, Value>; +class Printer : public TT, Printer, ttg::typelist> { + using baseT = Printer::ttT; public: Printer() : baseT("printer", {"input"}, {}) {} diff --git a/tests/unit/tt.cc b/tests/unit/tt.cc index 9a457f272f..0f5d7ebf98 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, ttg::typelist> { + 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, ttg::typelist> { + 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, ttg::typelist> { + 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, ttg::typelist> { + 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, ttg::typelist> { + 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, ttg::typelist> { + using baseT = typename tt::ttT; public: tt(const typename baseT::input_edges_type &inedges, const typename baseT::output_edges_type &outedges, @@ -120,6 +120,33 @@ namespace tt_i_iv { }; } // namespace tt_i_iv +// {task_id,data} = {int, int, void} +namespace tt_i_i_p { + + struct Policy : public ttg::TTPolicyBase { + + Policy() : TTPolicyBase() {} + + int procmap(const int&) const { return 0; } + + }; + + class tt : public ttg::TT, tt, ttg::typelist, Policy> { + using baseT = typename tt::ttT; + + public: + tt(const typename baseT::input_edges_type &inedges, const typename baseT::output_edges_type &outedges, + const std::string &name) + : baseT(inedges, outedges, name, {"int"}, {}, Policy()) {} + + static constexpr const bool have_cuda_op = false; + + void op(const int &key, const baseT::input_refs_tuple_type &data, baseT::output_terminals_type &outs) {} + + ~tt() {} + }; +} // namespace tt_i_iv + TEST_CASE("TemplateTask", "[core]") { SECTION("constructors") { { // void task id, void data @@ -157,5 +184,54 @@ TEST_CASE("TemplateTask", "[core]") { CHECK_NOTHROW( ttg::make_tt([](const int &key, const int &datum, std::tuple<> &outs) {}, ttg::edges(in), ttg::edges())); } + { // nonvoid task id, nonvoid data, w/ policies + ttg::Edge in; + CHECK_NOTHROW(std::make_unique(ttg::edges(in), ttg::edges(), "")); + CHECK_NOTHROW( + ttg::make_tt([](const int &key, const int &datum, std::tuple<> &outs) {}, ttg::edges(in), ttg::edges(), + ttg::make_policy([](const int& key){ return 0; }))); + + auto tt = ttg::make_tt([](const int &key, const int &datum, std::tuple<> &outs) {}, ttg::edges(in), ttg::edges(), + ttg::make_policy([](const int& key){ return 0; })); + auto policy = tt->get_policy(); + } + } + + SECTION("policies") { + { // default policy + ttg::Edge in; + auto tt = ttg::make_tt([](const int &key, const int &datum, std::tuple<> &outs) {}, ttg::edges(in), ttg::edges()); + auto policy = tt->get_policy(); + CHECK(tt->procmap(0) == 0); + CHECK(tt->get_procmap()(0) == 0); + CHECK(policy.procmap(0) == 0); + } + { // custom procmap + ttg::Edge in; + auto tt = ttg::make_tt([](const int &key, const int &datum, std::tuple<> &outs) {}, ttg::edges(in), ttg::edges(), + ttg::make_policy([](const int& key){ return 0; })); + auto policy = tt->get_policy(); + CHECK(tt->procmap(1) == 0); + CHECK(tt->get_procmap()(1) == 0); + CHECK(policy.procmap(1) == 0); + tt->set_priomap([](const int&){ return 0; }); + } + { // custom all maps + ttg::Edge in; + auto tt = ttg::make_tt([](const int &key, const int &datum, std::tuple<> &outs) {}, ttg::edges(in), ttg::edges(), + ttg::make_policy([](const int& key){ return 0; }, + [](const int& key){ return 0; }, + [](const int& key){ return 0; })); + auto policy = tt->get_policy(); + CHECK(policy.procmap(1) == 0); + CHECK(tt->procmap(1) == 0); + CHECK(tt->get_procmap()(1) == 0); + + CHECK(tt->priomap(1) == 0); + CHECK(tt->get_priomap()(1) == 0); + + CHECK(tt->inlinemap(1) == 0); + CHECK(tt->get_inlinemap()(1) == 0); + } } } diff --git a/ttg/CMakeLists.txt b/ttg/CMakeLists.txt index 92fbfb9cc1..890df3cd39 100644 --- a/ttg/CMakeLists.txt +++ b/ttg/CMakeLists.txt @@ -18,6 +18,7 @@ set(ttg-util-headers ${CMAKE_CURRENT_SOURCE_DIR}/ttg/util/span.h ${CMAKE_CURRENT_SOURCE_DIR}/ttg/util/trace.h ${CMAKE_CURRENT_SOURCE_DIR}/ttg/util/tree.h + ${CMAKE_CURRENT_SOURCE_DIR}/ttg/util/typelist.h ${CMAKE_CURRENT_SOURCE_DIR}/ttg/util/version.h ${CMAKE_CURRENT_SOURCE_DIR}/ttg/util/void.h ) @@ -35,6 +36,7 @@ set(ttg-impl-headers ${CMAKE_CURRENT_SOURCE_DIR}/ttg/fwd.h ${CMAKE_CURRENT_SOURCE_DIR}/ttg/impl_selector.h ${CMAKE_CURRENT_SOURCE_DIR}/ttg/tt.h + ${CMAKE_CURRENT_SOURCE_DIR}/ttg/policies.h ${CMAKE_CURRENT_SOURCE_DIR}/ttg/reduce.h ${CMAKE_CURRENT_SOURCE_DIR}/ttg/run.h ${CMAKE_CURRENT_SOURCE_DIR}/ttg/runtimes.h diff --git a/ttg/ttg.h b/ttg/ttg.h index 6942cbc405..e0fa9a7029 100644 --- a/ttg/ttg.h +++ b/ttg/ttg.h @@ -10,6 +10,7 @@ #include "ttg/util/print.h" #include "ttg/util/trace.h" #include "ttg/util/void.h" +#include "ttg/util/typelist.h" #include "ttg/base/keymap.h" #include "ttg/base/terminal.h" diff --git a/ttg/ttg/base/keymap.h b/ttg/ttg/base/keymap.h index 8997dd80d2..885e0ba997 100644 --- a/ttg/ttg/base/keymap.h +++ b/ttg/ttg/base/keymap.h @@ -50,6 +50,20 @@ namespace ttg { operator()() const { return 0; } }; + /// the default priority map implementation + template + struct default_inlinemap_impl { + default_inlinemap_impl() = default; + + template + std::enable_if_t,int> + operator()(const Key &key) const { return 0; } + template + std::enable_if_t,int> + operator()() const { return 0; } + }; + + } // namespace detail } // namespace ttg diff --git a/ttg/ttg/base/tt.h b/ttg/ttg/base/tt.h index aed7fb2fce..5f15ef3ead 100644 --- a/ttg/ttg/base/tt.h +++ b/ttg/ttg/base/tt.h @@ -10,6 +10,7 @@ #include "ttg/base/terminal.h" #include "ttg/util/demangle.h" +#include "ttg/util/trace.h" namespace ttg { diff --git a/ttg/ttg/broadcast.h b/ttg/ttg/broadcast.h index 21967eee95..1fa4251c32 100644 --- a/ttg/ttg/broadcast.h +++ b/ttg/ttg/broadcast.h @@ -12,6 +12,7 @@ #include "ttg/tt.h" #include "ttg/util/tree.h" #include "ttg/world.h" +#include "ttg/policies.h" namespace ttg { @@ -26,16 +27,15 @@ namespace ttg { /// template class BinaryTreeBroadcast : public TT, Out, Out>, - BinaryTreeBroadcast, Value> { + BinaryTreeBroadcast, ttg::typelist> { public: - using baseT = TT, Out, Out>, - BinaryTreeBroadcast, Value>; + using baseT = typename BinaryTreeBroadcast::ttT; BinaryTreeBroadcast(Edge &in, Edge &out, std::vector local_keys, int root = 0, World world = ttg::default_execution_context(), int max_key = -1, Edge inout_l = Edge{}, Edge inout_r = Edge{}) : baseT(edges(fuse(in, inout_l, inout_r)), edges(inout_l, inout_r, out), "BinaryTreeBroadcast", - {"in|inout_l|inout_r"}, {"inout_l", "inout_r", "out"}, world, [](int key) { return key; }) + {"in|inout_l|inout_r"}, {"inout_l", "inout_r", "out"}, world, ttg::TTPolicyBase([](int key) { return key; })) , tree_((max_key == -1 ? world.size() : max_key), root) , local_keys_(std::move(local_keys)) {} diff --git a/ttg/ttg/edge.h b/ttg/ttg/edge.h index 7e59a95fbc..20bbef6bac 100644 --- a/ttg/ttg/edge.h +++ b/ttg/ttg/edge.h @@ -138,6 +138,19 @@ namespace ttg { typedef std::tuple type; }; + namespace detail{ + template + struct edges_tuple; + + template + struct edges_tuple> { + using type = std::tuple...>; + }; + + template + using edges_tuple_t = typename edges_tuple::type; + } // namespace detail + } // namespace ttg diff --git a/ttg/ttg/madness/fwd.h b/ttg/ttg/madness/fwd.h index 05eefe13d1..19eff25cf1 100644 --- a/ttg/ttg/madness/fwd.h +++ b/ttg/ttg/madness/fwd.h @@ -2,20 +2,23 @@ #define TTG_MADNESS_FWD_H #include "ttg/fwd.h" +#include "ttg/util/typelist.h" +#include "ttg/policies.h" #include namespace ttg_madness { - template + template , + typename PolicyT = ttg::TTPolicyBase> class TT; /// \internal the OG name template - using Op [[deprecated("use TT instead")]] = TT; + using Op [[deprecated("use TT instead")]] = TT>; /// \internal the name in the ESPM2 paper template - using TemplateTask = TT; + using TemplateTask = TT>; class WorldImpl; diff --git a/ttg/ttg/madness/ttg.h b/ttg/ttg/madness/ttg.h index 1e45252e41..ab008372d1 100644 --- a/ttg/ttg/madness/ttg.h +++ b/ttg/ttg/madness/ttg.h @@ -174,34 +174,39 @@ 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 + /// \tparam input_valueTs ttg::typelist 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 + template class TT : public ttg::TTBase, - public ::madness::WorldObject> { + public ::madness::WorldObject>, + public ttg::detail::TTPolicyWrapper { + + static_assert(ttg::detail::is_typelist_v, "The fourth template for ttg::TT must be a ttg::typelist containing the input types"); + using input_tuple_type = typename input_valueTs::tuple_type; + + using PolicyWrapper = typename ttg::detail::TTPolicyWrapper; + public: + using ttT = TT; /// preconditions - static_assert((!std::is_reference_v && ...), "input_valueTs cannot contain reference types"); + static_assert((ttg::meta::none_has_reference_v), "input_valueTs cannot contain reference types"); 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 worldobjT = ::madness::WorldObject; - static constexpr int numins = sizeof...(input_valueTs); // number of input arguments + static constexpr int numins = std::tuple_size_v; // number of input arguments static constexpr int numouts = std::tuple_size::value; // number of outputs or // results @@ -211,26 +216,28 @@ 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, + public: + using input_terminals_type = ttg::detail::input_terminals_tuple_t; + using input_edges_type = ttg::detail::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::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_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 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 output_terminals_type = output_terminalsT; using output_edges_type = typename ttg::terminals_to_edges::type; + protected: template static resultT get(InTuple &&intuple) { return static_cast(std::get(std::forward(intuple))); @@ -340,7 +347,7 @@ namespace ttg_madness { static_assert(std::is_same_v, std::decay_t>, "TT::set_arg(key,value) given value of type incompatible with TT"); - const auto owner = keymap(key); + const auto owner = this->keymap(key); if (owner != world.rank()) { ttg::trace(world.rank(), ":", get_name(), " : ", key, ": forwarding setting argument : ", i); // should be able on the other end to consume value (since it is just a temporary byproduct of serialization) @@ -463,7 +470,7 @@ namespace ttg_madness { static_assert(std::is_same, std::decay_t>::value, "TT::set_arg(key,value) given value of type incompatible with TT"); - const int owner = keymap(); + const int owner = this->keymap(); if (owner != world.rank()) { ttg::trace(world.rank(), ":", get_name(), " : forwarding setting argument : ", i); @@ -554,7 +561,7 @@ namespace ttg_madness { std::enable_if_t, void> set_arg(const Key &key) { static_assert(ttg::meta::is_empty_tuple_v, "set_arg called without a value but valueT!=void"); - const int owner = keymap(key); + const int owner = this->keymap(key); if (owner != world.rank()) { ttg::trace(world.rank(), ":", get_name(), " : ", key, ": forwarding no-arg task: "); @@ -580,7 +587,7 @@ namespace ttg_madness { std::enable_if_t, void> set_arg() { static_assert(ttg::meta::is_empty_tuple_v, "set_arg called without a value but valueT!=void"); - const int owner = keymap(); + const int owner = this->keymap(); if (owner != world.rank()) { ttg::trace(world.rank(), ":", get_name(), " : forwarding no-arg task: "); @@ -613,7 +620,7 @@ namespace ttg_madness { assert(size > 0 && "TT::set_argstream_size(size) called with size=0"); // body - const auto owner = keymap(); + const auto owner = this->keymap(); if (owner != world.rank()) { ttg::trace(world.rank(), ":", get_name(), " : forwarding stream size for terminal ", i); worldobjT::send(owner, &ttT::template set_argstream_size, size); @@ -693,7 +700,7 @@ namespace ttg_madness { assert(size > 0 && "TT::set_argstream_size(key,size) called with size=0"); // body - const auto owner = keymap(key); + const auto owner = this->keymap(key); if (owner != world.rank()) { ttg::trace(world.rank(), ":", get_name(), " : ", key, ": forwarding stream size for terminal ", i); worldobjT::send(owner, &ttT::template set_argstream_size, key, size); @@ -748,7 +755,7 @@ namespace ttg_madness { assert(std::get(input_reducers) && "TT::finalize_argstream called on nonstreaming input terminal"); // body - const auto owner = keymap(key); + const auto owner = this->keymap(key); if (owner != world.rank()) { ttg::trace(world.rank(), ":", get_name(), " : ", key, ": forwarding stream finalize for terminal ", i); worldobjT::send(owner, &ttT::template finalize_argstream, key); @@ -797,7 +804,7 @@ namespace ttg_madness { assert(std::get(input_reducers) && "TT::finalize_argstream called on nonstreaming input terminal"); // body - const int owner = keymap(); + const int owner = this->keymap(); if (owner != world.rank()) { ttg::trace(world.rank(), ":", get_name(), " : forwarding stream finalize for terminal ", i); worldobjT::send(owner, &ttT::template finalize_argstream); @@ -960,19 +967,14 @@ namespace ttg_madness { } public: - template , - typename priomapT = ttg::detail::default_priomap> + template TT(const std::string &name, const std::vector &innames, const std::vector &outnames, - ttg::World world, keymapT &&keymap_ = keymapT(), priomapT &&priomap_ = priomapT()) + ttg::World world, PolicyT_&& policy) : ttg::TTBase(name, numins, numouts) + , PolicyWrapper(world, std::forward(policy)) , static_streamsize() , worldobjT(world.impl().impl()) - , world(world) - // if using default keymap, rebind to the given world - , keymap(std::is_same>::value - ? decltype(keymap)(ttg::detail::default_keymap(world)) - : decltype(keymap)(std::forward(keymap_))) - , priomap(decltype(keymap)(std::forward(priomap_))) { + , world(world) { // Cannot call these in base constructor since terminals not yet constructed if (innames.size() != std::tuple_size::value) { ttg::print_error(world.rank(), ":", get_name(), "#input_names", innames.size(), "!= #input_terminals", @@ -988,27 +990,52 @@ namespace ttg_madness { register_input_callbacks(std::make_index_sequence{}); } - template , - typename priomapT = ttg::detail::default_priomap> + template , PolicyT>>> + TT(const std::string &name, const std::vector &innames, const std::vector &outnames, + policyT&& policy) + : TT(name, innames, outnames, ttg::default_execution_context(), std::forward(policy)) + {} + + template , PolicyT>>> + TT(const std::string &name, const std::vector &innames, const std::vector &outnames) + : TT(name, innames, outnames, ttg::default_execution_context(), policyT()) + {} + + template >>> TT(const std::string &name, const std::vector &innames, const std::vector &outnames, - keymapT &&keymap = keymapT(ttg::default_execution_context()), priomapT &&priomap = priomapT()) - : TT(name, innames, outnames, ttg::default_execution_context(), std::forward(keymap), - std::forward(priomap)) {} + ttg::meta::detail::keymap_t keymap) + : TT(name, innames, outnames, ttg::default_execution_context(), + policyT(std::move(keymap))) {} - template , - typename priomapT = ttg::detail::default_priomap> + template >>> + TT(const input_edges_type &inedges, const output_edges_type &outedges, const std::string &name, + const std::vector &innames, const std::vector &outnames, ttg::World world, + ttg::meta::detail::keymap_t keymap) + : TT(inedges, outedges, name, innames, outnames, world, + policyT(std::move(keymap))) + { } + + template , PolicyT>>> + TT(const input_edges_type &inedges, const output_edges_type &outedges, const std::string &name, + const std::vector &innames, const std::vector &outnames, + policyT&& policy) + : TT(inedges, outedges, name, innames, outnames, ttg::default_execution_context(), std::forward(policy)) + { } + template , PolicyT>>> TT(const input_edges_type &inedges, const output_edges_type &outedges, const std::string &name, const std::vector &innames, const std::vector &outnames, ttg::World world, - keymapT &&keymap_ = keymapT(), priomapT &&priomap_ = priomapT()) + policyT&& policy) : ttg::TTBase(name, numins, numouts) + , PolicyWrapper(world, std::forward(policy)) , static_streamsize() - , worldobjT(ttg::default_execution_context().impl().impl()) - , world(ttg::default_execution_context()) - // if using default keymap, rebind to the given world - , keymap(std::is_same>::value - ? decltype(keymap)(ttg::detail::default_keymap(world)) - : decltype(keymap)(std::forward(keymap_))) - , priomap(decltype(keymap)(std::forward(priomap_))) { + , worldobjT(world.impl().impl()) + , world(world) { // Cannot call in base constructor since terminals not yet constructed if (innames.size() != std::tuple_size::value) { ttg::print_error(world.rank(), ":", get_name(), "#input_names", innames.size(), "!= #input_terminals", @@ -1027,13 +1054,21 @@ namespace ttg_madness { connect_my_outputs_to_outgoing_edge_inputs(std::make_index_sequence{}, outedges); } - template , - typename priomapT = ttg::detail::default_priomap> + template >>> TT(const input_edges_type &inedges, const output_edges_type &outedges, const std::string &name, const std::vector &innames, const std::vector &outnames, - keymapT &&keymap = keymapT(ttg::default_execution_context()), priomapT &&priomap = priomapT()) + ttg::meta::detail::keymap_t keymap) + : TT(inedges, outedges, name, innames, outnames, ttg::default_execution_context(), + policyT(std::move(keymap))) {} + + template >> + TT(const input_edges_type &inedges, const output_edges_type &outedges, const std::string &name, + const std::vector &innames, const std::vector &outnames) : TT(inedges, outedges, name, innames, outnames, ttg::default_execution_context(), - std::forward(keymap), std::forward(priomap)) {} + policyT()) {} + // Destructor checks for unexecuted tasks virtual ~TT() { @@ -1071,21 +1106,6 @@ namespace ttg_madness { set_static_argstream_size(size); } - template - void set_keymap(Keymap &&km) { - keymap = km; - } - - auto get_priomap(void) const { return priomap; } - - /// Set the priority map, mapping a Key to an integral value. - /// Higher values indicate higher priority. The default priority is 0, higher - /// values are treated as high priority tasks in the MADNESS backend. - template - void set_priomap(Priomap &&pm) { - priomap = pm; - } - /// implementation of TTBase::make_executable() void make_executable() override { this->process_pending(); @@ -1150,23 +1170,19 @@ namespace ttg_madness { TTBase::invoke(); } - /// keymap accessor - /// @return the keymap - const decltype(keymap) &get_keymap() const { return keymap; } - /// computes the owner of key @c key /// @param[in] key the key /// @return the owner of @c key template std::enable_if_t, int> owner(const Key &key) const { - return keymap(key); + return this->keymap(key); } /// computes the owner of void key /// @return the owner of void key template std::enable_if_t, int> owner() const { - return keymap(); + return this->keymap(); } }; diff --git a/ttg/ttg/make_tt.h b/ttg/ttg/make_tt.h index 7eaeb120bb..1de98888fe 100644 --- a/ttg/ttg/make_tt.h +++ b/ttg/ttg/make_tt.h @@ -8,11 +8,11 @@ // case 1 (keyT != void): void op(auto&& key, std::tuple&&, std::tuple&) // case 2 (keyT == void): void op(std::tuple&&, std::tuple&) // -template +template class CallableWrapTT : public TT, input_valuesT...> { - using baseT = - TT, input_valuesT...>; + CallableWrapTT, + ttg::typelist, PolicyT> { + using baseT = typename CallableWrapTT::ttT; using input_values_tuple_type = typename baseT::input_values_tuple_type; using input_refs_tuple_type = typename baseT::input_refs_tuple_type; @@ -37,16 +37,35 @@ class CallableWrapTT : public TT + template + CallableWrapTT(funcT_ &&f, const input_edges_type &inedges, const output_edges_type &outedges, + PolicyT_&& policy, + const std::string &name, const std::vector &innames, + const std::vector &outnames) + : baseT(inedges, outedges, name, innames, outnames, std::forward(policy)), + func(std::forward(f)) {} + + template CallableWrapTT(funcT_ &&f, const input_edges_type &inedges, const output_edges_type &outedges, const std::string &name, const std::vector &innames, const std::vector &outnames) - : baseT(inedges, outedges, name, innames, outnames), func(std::forward(f)) {} + : baseT(inedges, outedges, name, innames, outnames), + func(std::forward(f)) {} + + template + CallableWrapTT(funcT_ &&f, + PolicyT_&& policy, + const std::string &name, const std::vector &innames, + const std::vector &outnames) + : baseT(name, innames, outnames, std::forward(policy)), + func(std::forward(f)) {} template - CallableWrapTT(funcT_ &&f, const std::string &name, const std::vector &innames, + CallableWrapTT(funcT_ &&f, + const std::string &name, const std::vector &innames, const std::vector &outnames) - : baseT(name, innames, outnames), func(std::forward(f)) {} + : baseT(name, innames, outnames), + func(std::forward(f)) {} template std::enable_if_t && !ttg::meta::is_empty_tuple_v && @@ -77,12 +96,12 @@ class CallableWrapTT : public TT +template struct CallableWrapTTUnwrapTuple; -template -struct CallableWrapTTUnwrapTuple> { - using type = CallableWrapTT...>; +template +struct CallableWrapTTUnwrapTuple, PolicyT> { + using type = CallableWrapTT...>; }; // Class to wrap a callable with signature @@ -90,12 +109,11 @@ 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, + ttg::typelist, PolicyT> { + using baseT = typename CallableWrapTTArgs::ttT; using input_values_tuple_type = typename baseT::input_values_tuple_type; using input_refs_tuple_type = typename baseT::input_refs_tuple_type; @@ -128,16 +146,21 @@ class CallableWrapTTArgs } public: - template + template CallableWrapTTArgs(funcT_ &&f, const input_edges_type &inedges, const typename baseT::output_edges_type &outedges, + PolicyT_&& policy, const std::string &name, const std::vector &innames, const std::vector &outnames) - : baseT(inedges, outedges, name, innames, outnames), func(std::forward(f)) {} + : baseT(inedges, outedges, name, innames, outnames, std::forward(policy)), + func(std::forward(f)) {} - template - CallableWrapTTArgs(funcT_ &&f, const std::string &name, const std::vector &innames, + template + CallableWrapTTArgs(funcT_ &&f, + PolicyT_&& policy, + const std::string &name, const std::vector &innames, const std::vector &outnames) - : baseT(name, innames, outnames), func(std::forward(f)) {} + : baseT(name, innames, outnames, std::forward(policy)), + func(std::forward(f)) {} template std::enable_if_t && @@ -169,21 +192,23 @@ class CallableWrapTTArgs }; }; -template +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 // // case 1 (keyT != void): void op(const input_keyT&, std::tuple&&, std::tuple&) // case 2 (keyT == void): void op(std::tuple&&, std::tuple&) -template +template >> auto make_tt_tpl(funcT &&func, const std::tuple...> &inedges, - const std::tuple &outedges, const std::string &name = "wrapper", + const std::tuple &outedges, + PolicyT&& policy, const std::string &name = "wrapper", const std::vector &innames = std::vector( std::tuple_size...>>::value, "input"), const std::vector &outnames = @@ -200,7 +225,7 @@ auto make_tt_tpl(funcT &&func, const std::tuple.. // 2. input_args_t = {input_valuesT&&...} using input_args_t = std::decay_t::type>; using decayed_input_args_t = ttg::meta::decayed_tuple_t; - using wrapT = typename CallableWrapTTUnwrapTuple::type; + using wrapT = typename CallableWrapTTUnwrapTuple::type; // not sure if we need this level of type checking ... // TODO determine the generic signature of func if constexpr (!void_key) { @@ -214,7 +239,17 @@ auto make_tt_tpl(funcT &&func, const std::tuple.. std::is_same_v::type, output_terminals_type &>, "ttg::make_tt_tpl(func, inedges, outedges): last argument of func must be std::tuple&"); - return std::make_unique(std::forward(func), inedges, outedges, name, innames, outnames); + return std::make_unique(std::forward(func), inedges, outedges, std::forward(policy), name, innames, outnames); +} + +template +auto make_tt_tpl(funcT &&func, const std::tuple...> &inedges, + const std::tuple &outedges, const std::string &name = "wrapper", + const std::vector &innames = std::vector( + std::tuple_size...>>::value, "input"), + const std::vector &outnames = + std::vector(std::tuple_size>::value, "output")) { + return make_tt_tpl(std::forward(func), inedges, outedges, ttg::TTPolicyBase(), name, innames, outnames); } // Factory function to assist in wrapping a callable with signature @@ -223,9 +258,11 @@ auto make_tt_tpl(funcT &&func, const std::tuple.. // case 2 (keyT == void): void op(input_valuesT&&..., std::tuple&) // // input edges can contain at most one control input, and it must be last, if present -template +template >> auto make_tt(funcT &&func, const std::tuple...> &inedges, - const std::tuple &outedges, const std::string &name = "wrapper", + const std::tuple &outedges, PolicyT&& policy, + const std::string &name = "wrapper", const std::vector &innames = std::vector( std::tuple_size...>>::value, "input"), const std::vector &outnames = @@ -263,7 +300,7 @@ auto make_tt(funcT &&func, const std::tuple. // 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; + 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) { @@ -277,7 +314,17 @@ auto make_tt(funcT &&func, const std::tuple. std::is_same_v::type, output_terminals_type &>, "ttg::make_tt(func, inedges, outedges): last argument of func must be std::tuple&"); - return std::make_unique(std::forward(func), inedges, outedges, name, innames, outnames); + return std::make_unique(std::forward(func), inedges, outedges, std::forward(policy), name, innames, outnames); +} + +template +auto make_tt(funcT &&func, const std::tuple...> &inedges, + const std::tuple &outedges, const std::string &name = "wrapper", + const std::vector &innames = std::vector( + std::tuple_size...>>::value, "input"), + const std::vector &outnames = + std::vector(std::tuple_size>::value, "output")) { + return make_tt(std::forward(func), inedges, outedges, ttg::TTPolicyBase(), name, innames, outnames); } template diff --git a/ttg/ttg/parsec/fwd.h b/ttg/ttg/parsec/fwd.h index c42755daec..3e396cd212 100644 --- a/ttg/ttg/parsec/fwd.h +++ b/ttg/ttg/parsec/fwd.h @@ -2,20 +2,22 @@ #define TTG_PARSEC_FWD_H #include "ttg/fwd.h" +#include "ttg/util/typelist.h" +#include "ttg/policies.h" #include namespace ttg_parsec { - template + template , typename Policies = ttg::TTPolicyBase> class TT; /// \internal the OG name template - using Op [[deprecated("use TT instead")]] = TT; + using Op [[deprecated("use TT instead")]] = TT>; /// \internal the name in the ESPM2 paper template - using TemplateTask = TT; + using TemplateTask = TT>; class WorldImpl; diff --git a/ttg/ttg/parsec/ttg.h b/ttg/ttg/parsec/ttg.h index 851f077780..d1a1411df3 100644 --- a/ttg/ttg/parsec/ttg.h +++ b/ttg/ttg/parsec/ttg.h @@ -25,6 +25,7 @@ #include "ttg/util/print.h" #include "ttg/util/trace.h" #include "ttg/util/env.h" +#include "ttg/util/typelist.h" #include "ttg/serialization/data_descriptor.h" @@ -738,10 +739,19 @@ namespace ttg_parsec { }; } // namespace detail - template - class TT : public ttg::TTBase, detail::ParsecTTBase { + template + class TT : public ttg::TTBase, detail::ParsecTTBase, public ttg::detail::TTPolicyWrapper { private: - using ttT = TT; + /// preconditions + static_assert(ttg::detail::is_typelist_v, "The fourth template for ttg::TT must be a ttg::typelist containing the input types"); + using input_tuple_type = typename input_valueTs::tuple_type; + static_assert(ttg::meta::is_tuple_v, "Second template argument for ttg::TT must be std::tuple containing the output terminal types"); + static_assert((ttg::meta::none_has_reference_v), "Input typelist cannot contain reference types"); + static_assert(ttg::meta::is_none_Void_v, "ttg::Void is for internal use only, do not use it"); + static_assert(ttg::detail::is_policy_v, "The policy must implement procmap(), priomap(), and inlinemap()"); + + using PolicyWrapper = typename ttg::detail::TTPolicyWrapper; + parsec_mempool_t mempools; // check for a non-type member named have_cuda_op @@ -750,8 +760,7 @@ namespace ttg_parsec { bool alive = true; - public: - static constexpr int numins = sizeof...(input_valueTs); // number of input arguments + static constexpr int numins = std::tuple_size_v; // number of input arguments static constexpr int numouts = std::tuple_size::value; // number of outputs static constexpr int numflows = std::max(numins, numouts); // max number of flows @@ -764,22 +773,21 @@ 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"); + public: + using ttT = TT; + using input_terminals_type = ttg::detail::input_terminals_tuple_t; + using input_args_type = input_tuple_type; + using input_edges_type = ttg::detail::edges_tuple_t>; // 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 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; static constexpr int numinvals = std::tuple_size_v; // number of input arguments with values (i.e. omitting the control // input, if any) @@ -830,14 +838,14 @@ namespace ttg_parsec { make_finalize_argstream_fcts(std::make_index_sequence{}); 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_stream_goal; public: + ttg::World get_world() const { return world; } private: @@ -875,17 +883,18 @@ 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); - } else + } else { abort(); + } parsec_ttg_caller = NULL; if (obj->tracing()) { @@ -1056,7 +1065,7 @@ namespace ttg_parsec { for (int k = 0; k < num_keys; ++k) { keyT key; pos = unpack(key, msg->bytes, pos); - assert(keymap(key) == rank); + assert(this->keymap(key) == rank); keylist.push_back(std::move(key)); } // case 1 @@ -1189,11 +1198,11 @@ namespace ttg_parsec { auto rank = world.rank(); keyT key; pos = unpack(key, msg->bytes, pos); - assert(keymap(key) == rank); + assert(this->keymap(key) == rank); finalize_argstream(key); } else { auto rank = world.rank(); - assert(keymap() == rank); + assert(this->keymap() == rank); finalize_argstream(); } } @@ -1208,13 +1217,13 @@ namespace ttg_parsec { auto rank = world.rank(); keyT key; pos = unpack(key, msg->bytes, pos); - assert(keymap(key) == rank); + assert(this->keymap(key) == rank); std::size_t argstream_size; pos = unpack(argstream_size, msg->bytes, pos); set_argstream_size(key, argstream_size); } else { auto rank = world.rank(); - assert(keymap() == rank); + assert(this->keymap() == rank); std::size_t argstream_size; pos = unpack(argstream_size, msg->bytes, pos); set_argstream_size(argstream_size); @@ -1260,11 +1269,11 @@ namespace ttg_parsec { char *taskobj = (char *)parsec_thread_mempool_allocate(mempool); int32_t priority; if constexpr (!keyT_is_Void) { - priority = priomap(key); + priority = this->priomap(key); /* placement-new the task */ newtask = new (taskobj) task_t(key, mempool, &this->self, world_impl.taskpool(), this, priority); } else { - priority = priomap(); + priority = this->priomap(); /* placement-new the task */ newtask = new (taskobj) task_t(mempool, &this->self, world_impl.taskpool(), this, priority); } @@ -1302,7 +1311,7 @@ namespace ttg_parsec { parsec_key_t hk = 0; if constexpr (!keyT_is_Void) { hk = reinterpret_cast(&key); - assert(keymap(key) == world.rank()); + assert(this->keymap(key) == world.rank()); } task_t *task; @@ -1490,9 +1499,9 @@ namespace ttg_parsec { int owner; if constexpr (!ttg::meta::is_void_v) - owner = keymap(key); + owner = this->keymap(key); else - owner = keymap(); + owner = this->keymap(); if (owner == world.rank()) { if constexpr (!ttg::meta::is_void_v) set_arg_local(key, std::forward(value)); @@ -1596,7 +1605,7 @@ namespace ttg_parsec { static_assert(ttg::meta::is_empty_tuple_v, "logic error: set_arg (case 3) called but input_refs_tuple_type is nonempty"); - const auto owner = keymap(key); + const auto owner = this->keymap(key); auto &world_impl = world.impl(); if (owner == world.rank()) { // create PaRSEC task @@ -1606,7 +1615,7 @@ namespace ttg_parsec { parsec_thread_mempool_t *mempool = get_task_mempool(); char *taskobj = (char *)parsec_thread_mempool_allocate(mempool); - task = new (taskobj) task_t(key, mempool, &this->self, world_impl.taskpool(), this, priomap(key)); + task = new (taskobj) task_t(key, mempool, &this->self, world_impl.taskpool(), this, this->priomap(key)); task->function_template_class_ptr[static_cast(ttg::ExecutionSpace::Host)] = reinterpret_cast(&TT::static_op_noarg); @@ -1637,9 +1646,9 @@ namespace ttg_parsec { template std::enable_if_t, void> set_arg() { static_assert(ttg::meta::is_empty_tuple_v, - "logic error: set_arg (case 3) called but input_refs_tuple_type is nonempty"); + "logic error: set_arg (case 6) called but input_refs_tuple_type is nonempty"); - const auto owner = keymap(); + const auto owner = this->keymap(); if (owner == ttg_default_execution_context().rank()) { // create PaRSEC task // and give it to the scheduler @@ -1648,7 +1657,7 @@ namespace ttg_parsec { parsec_execution_stream_s *es = world_impl.execution_stream(); parsec_thread_mempool_t *mempool = get_task_mempool(); task = new (parsec_thread_mempool_allocate(mempool)) - task_t(mempool, &this->self, world_impl.taskpool(), this, priomap()); + task_t(mempool, &this->self, world_impl.taskpool(), this, this->priomap()); task->function_template_class_ptr[static_cast(ttg::ExecutionSpace::Host)] = reinterpret_cast(&TT::static_op_noarg); if constexpr (derived_has_cuda_op()) @@ -1687,7 +1696,7 @@ namespace ttg_parsec { int rank = world.rank(); bool have_remote = keylist.end() != std::find_if(keylist.begin(), keylist.end(), - [&](const Key &key) { return keymap(key) != rank; }); + [&](const Key &key) { return this->keymap(key) != rank; }); if (have_remote) { std::vector keylist_sorted(keylist.begin(), keylist.end()); @@ -1698,8 +1707,8 @@ namespace ttg_parsec { /* sort the input key list by owner and check whether there are remote keys */ std::sort(keylist_sorted.begin(), keylist_sorted.end(), [&](const Key &a, const Key &b) mutable { - int rank_a = keymap(a); - int rank_b = keymap(b); + int rank_a = this->keymap(a); + int rank_b = this->keymap(b); return rank_a < rank_b; }); @@ -1712,12 +1721,12 @@ namespace ttg_parsec { parsec_taskpool_t *tp = world_impl.taskpool(); for (auto it = keylist_sorted.begin(); it < keylist_sorted.end(); /* increment inline */) { - auto owner = keymap(*it); + auto owner = this->keymap(*it); if (owner == rank) { /* make sure we don't lose local keys */ local_begin = it; local_end = - std::find_if_not(++it, keylist_sorted.end(), [&](const Key &key) { return keymap(key) == rank; }); + std::find_if_not(++it, keylist_sorted.end(), [&](const Key &key) { return this->keymap(key) == rank; }); it = local_end; continue; } @@ -1729,7 +1738,7 @@ namespace ttg_parsec { ++num_keys; pos = pack(*it, msg->bytes, pos); ++it; - } while (it < keylist_sorted.end() && keymap(*it) == owner); + } while (it < keylist_sorted.end() && this->keymap(*it) == owner); msg->tt_id.num_keys = num_keys; /* TODO: use RMA to transfer the value */ @@ -1758,7 +1767,7 @@ namespace ttg_parsec { auto world = ttg_default_execution_context(); int rank = world.rank(); bool have_remote = keylist.end() != std::find_if(keylist.begin(), keylist.end(), - [&](const Key &key) { return keymap(key) != rank; }); + [&](const Key &key) { return this->keymap(key) != rank; }); if (have_remote) { using decvalueT = std::decay_t; @@ -1766,8 +1775,8 @@ namespace ttg_parsec { /* sort the input key list by owner and check whether there are remote keys */ std::vector keylist_sorted(keylist.begin(), keylist.end()); std::sort(keylist_sorted.begin(), keylist_sorted.end(), [&](const Key &a, const Key &b) mutable { - int rank_a = keymap(a); - int rank_b = keymap(b); + int rank_a = this->keymap(a); + int rank_b = this->keymap(b); return rank_a < rank_b; }); @@ -1810,12 +1819,12 @@ namespace ttg_parsec { parsec_taskpool_t *tp = world_impl.taskpool(); for (auto it = keylist_sorted.begin(); it < keylist_sorted.end(); /* increment done inline */) { - auto owner = keymap(*it); + auto owner = this->keymap(*it); if (owner == rank) { local_begin = it; /* find first non-local key */ local_end = - std::find_if_not(++it, keylist_sorted.end(), [&](const Key &key) { return keymap(key) == rank; }); + std::find_if_not(++it, keylist_sorted.end(), [&](const Key &key) { return this->keymap(key) == rank; }); it = local_end; continue; } @@ -1828,7 +1837,7 @@ namespace ttg_parsec { ++num_keys; pos = pack(*it, msg->bytes, pos); ++it; - } while (it < keylist_sorted.end() && keymap(*it) == owner); + } while (it < keylist_sorted.end() && this->keymap(*it) == owner); msg->tt_id.num_keys = num_keys; /* pack the metadata */ @@ -1935,7 +1944,7 @@ namespace ttg_parsec { assert(size > 0 && "TT::set_argstream_size(key,size) called with size=0"); // body - const auto owner = keymap(key); + const auto owner = this->keymap(key); if (owner != world.rank()) { ttg::trace(world.rank(), ":", get_name(), ":", key, " : forwarding stream size for terminal ", i); using msg_t = detail::msg_t; @@ -1985,7 +1994,7 @@ namespace ttg_parsec { assert(size > 0 && "TT::set_argstream_size(key,size) called with size=0"); // body - const auto owner = keymap(); + const auto owner = this->keymap(); if (owner != world.rank()) { ttg::trace(world.rank(), ":", get_name(), " : forwarding stream size for terminal ", i); using msg_t = detail::msg_t; @@ -2032,7 +2041,7 @@ namespace ttg_parsec { assert(std::get(input_reducers) && "TT::finalize_argstream called on nonstreaming input terminal"); // body - const auto owner = keymap(key); + const auto owner = this->keymap(key); if (owner != world.rank()) { ttg::trace(world.rank(), ":", get_name(), " : ", key, ": forwarding stream finalize for terminal ", i); using msg_t = detail::msg_t; @@ -2078,7 +2087,7 @@ namespace ttg_parsec { assert(std::get(input_reducers) && "TT::finalize_argstream called on nonstreaming input terminal"); // body - const auto owner = keymap(); + const auto owner = this->keymap(); if (owner != world.rank()) { ttg::trace(world.rank(), ":", get_name(), ": forwarding stream finalize for terminal ", i); using msg_t = detail::msg_t; @@ -2307,17 +2316,12 @@ namespace ttg_parsec { } public: - template , - typename priomapT = ttg::detail::default_priomap> + template TT(const std::string &name, const std::vector &innames, const std::vector &outnames, - ttg::World world, keymapT &&keymap_ = keymapT(), priomapT &&priomap_ = priomapT()) + ttg::World world, policyT&& policy) : ttg::TTBase(name, numins, numouts) + , PolicyWrapper(world, std::forward(policy)) , world(world) - // if using default keymap, rebind to the given world - , keymap(std::is_same>::value - ? decltype(keymap)(ttg::detail::default_keymap(world)) - : decltype(keymap)(std::forward(keymap_))) - , priomap(decltype(keymap)(std::forward(priomap_))) , static_stream_goal() { // Cannot call these in base constructor since terminals not yet constructed if (innames.size() != std::tuple_size::value) @@ -2413,32 +2417,112 @@ namespace ttg_parsec { NULL); } - template , - typename priomapT = ttg::detail::default_priomap> - TT(const std::string &name, const std::vector &innames, const std::vector &outnames, - keymapT &&keymap = keymapT(ttg::default_execution_context()), priomapT &&priomap = priomapT()) - : TT(name, innames, outnames, ttg::default_execution_context(), std::forward(keymap), - std::forward(priomap)) {} - - template , - typename priomapT = ttg::detail::default_priomap> - TT(const input_edges_type &inedges, const output_edges_type &outedges, const std::string &name, - const std::vector &innames, const std::vector &outnames, ttg::World world, - keymapT &&keymap_ = keymapT(), priomapT &&priomap = priomapT()) - : TT(name, innames, outnames, world, std::forward(keymap_), std::forward(priomap)) { + template >>> + TT(const std::string &name, + const std::vector &innames, + const std::vector &outnames, + ttg::World world, + ttg::meta::detail::keymap_t keymap) + : TT(name, innames, outnames, world, PolicyT(std::move(keymap))) + {} + + TT(const std::string &name, + const std::vector &innames, + const std::vector &outnames, + ttg::World world) + : TT(name, innames, outnames, world, PolicyT()) + {} + + template , PolicyT>>> + TT(const std::string &name, + const std::vector &innames, + const std::vector &outnames, + policyT&& policy) + : TT(name, innames, outnames, ttg::default_execution_context(), std::forward(policy)) + {} + + template >>> + TT(const std::string &name, + const std::vector &innames, + const std::vector &outnames, + ttg::meta::detail::keymap_t keymap) + : TT(name, innames, outnames, ttg::default_execution_context(), + PolicyT(std::move(keymap))) + {} + + + template >> + TT(const std::string &name, + const std::vector &innames, + const std::vector &outnames) + : TT(name, innames, outnames, ttg::default_execution_context(), policyT()) + {} + + template , PolicyT>>> + TT(const input_edges_type &inedges, + const output_edges_type &outedges, + const std::string &name, + const std::vector &innames, + const std::vector &outnames, + ttg::World world, + policyT&& policy) + : TT(name, innames, outnames, world, std::forward(policy)) { connect_my_inputs_to_incoming_edge_outputs(std::make_index_sequence{}, inedges); connect_my_outputs_to_outgoing_edge_inputs(std::make_index_sequence{}, outedges); } - template , - typename priomapT = ttg::detail::default_priomap> - TT(const input_edges_type &inedges, const output_edges_type &outedges, const std::string &name, - const std::vector &innames, const std::vector &outnames, - keymapT &&keymap = keymapT(ttg::default_execution_context()), priomapT &&priomap = priomapT()) - : TT(inedges, outedges, name, innames, outnames, ttg::default_execution_context(), std::forward(keymap), - std::forward(priomap)) {} + + + template >>> + TT(const input_edges_type &inedges, + const output_edges_type &outedges, + const std::string &name, + const std::vector &innames, + const std::vector &outnames, + ttg::World world, + ttg::meta::detail::keymap_t keymap) + : TT(inedges, outedges, name, innames, outnames, world, + PolicyT(std::move(keymap))) + { } + + template , PolicyT>>> + TT(const input_edges_type &inedges, + const output_edges_type &outedges, + const std::string &name, + const std::vector &innames, + const std::vector &outnames, + ttg::World world) + : TT(inedges, outedges, name, innames, outnames, world, policyT()) + { } + + template + TT(const input_edges_type &inedges, + const output_edges_type &outedges, + const std::string &name, + const std::vector &innames, + const std::vector &outnames, + policyT&& policy) + : TT(inedges, outedges, name, innames, outnames, ttg::default_execution_context(), + std::forward(policy)) + {} + + template >> + TT(const input_edges_type &inedges, + const output_edges_type &outedges, + const std::string &name, + const std::vector &innames, + const std::vector &outnames) + : TT(inedges, outedges, name, innames, outnames, ttg::default_execution_context(), policyT()) + {} // Destructor checks for unexecuted tasks - ~TT() { release(); } + virtual ~TT() { release(); } static void ht_iter_cb(void *item, void *cb_data) { task_t *task = (task_t *)item; @@ -2451,6 +2535,10 @@ namespace ttg_parsec { } virtual void release() override { + do_release(); + } + + void do_release() { if (!alive) { return; } @@ -2475,6 +2563,7 @@ namespace ttg_parsec { world.impl().deregister_op(this); } + static constexpr const ttg::Runtime runtime = ttg::Runtime::PaRSEC; template @@ -2548,27 +2637,6 @@ namespace ttg_parsec { ttg::TTBase::make_executable(); } - /// keymap accessor - /// @return the keymap - const decltype(keymap) &get_keymap() const { return keymap; } - - /// keymap setter - template - void set_keymap(Keymap &&km) { - keymap = km; - } - - /// priority map accessor - /// @return the priority map - const decltype(priomap) &get_priomap() const { return priomap; } - - /// priomap setter - /// @arg pm a function that maps a key to an integral priority value. - template - void set_priomap(Priomap &&pm) { - priomap = pm; - } - // Register the static_op function to associate it to instance_id void register_static_op_function(void) { int rank; diff --git a/ttg/ttg/policies.h b/ttg/ttg/policies.h new file mode 100644 index 0000000000..38c9ab72b6 --- /dev/null +++ b/ttg/ttg/policies.h @@ -0,0 +1,460 @@ + +#ifndef TTG_POLICIES_H +#define TTG_POLICIES_H + +#include "ttg/base/keymap.h" +#include "ttg/util/meta.h" + +namespace ttg { + + namespace detail { + template + struct is_default_keymap : std::false_type + { }; + + template + struct is_default_keymap> : std::true_type + { }; + + template + constexpr const bool is_default_keymap_v = is_default_keymap::value; + + template + struct map_type { + using type = MapT; + }; + + template + struct map_type> { + using type = ttg::meta::detail::keymap_t; + }; + + template + using map_type_t = typename map_type::type; + + + /* Some handy trait to check if a type is std::function */ + template + struct is_std_function_ptr : std::false_type + { }; + + /** std::function member pointer */ + template + struct is_std_function_ptr T::*> : std::true_type + { }; + + template + struct is_std_function_ptr*> : std::true_type + { }; + + template + constexpr bool is_std_function_ptr_v = is_std_function_ptr::value; + + } // namespace detail + + /** + * \brief Base class for task execution policies. + * + * Policies are properties of tasks. Tasks are identified through the key. + * A policy implementation maps a key to an integer value and can be set per TT. + * Supported policies include: + * * Process mapping: maps a key identifying a task to a process to run on. + * * Priority mapping: assigns a priority (positive integer) to a task identified by a key. + * Higher values increase the task's priority. + * * Inline mapping: whether a task can be executed inline, i.e., without dispatching the + * task to a scheduler first. The task will be executed in the send or + * broadcast call. The returned value denotes the maximum recirsion depth, + * i.e., how many tasks may be executed inline consecutively. Zero denotes + * no inlining. This is the default. + * + * The default mapping functions are not inlined and can be set dynamically + * in the TT. By inheriting from \c TTPolicyBase and passing callables to its + * constructor, applications can define policies at compile-time. This may + * yield improved performance since the compiler is potentially able to inline + * the calls. In that case, the dynamic setting of mapping functions in the + * TT will be disabled. + * + * \tparam Key The type of the key used to identify tasks. + * \tparam ProcMap The type of the process map callback. + * \tparam PrioMap The type of the priority map callback. + * \tparam InlineMap The type of the inline map callback. + * + * \sa ttg::make_policy + */ + template, + typename PrioMap = typename ttg::meta::detail::keymap_t, + typename InlineMap = typename ttg::meta::detail::keymap_t> + struct TTPolicyBase { + + using PolicyBaseT = TTPolicyBase; + + using procmap_t = detail::map_type_t; + using priomap_t = detail::map_type_t; + using inlinemap_t = detail::map_type_t; + + using key_type = Key; + + procmap_t procmap; + priomap_t priomap; + inlinemap_t inlinemap; + + template && + std::is_default_constructible_v && + std::is_default_constructible_v>> + TTPolicyBase() + { } + + template && + std::is_default_constructible_v && + std::is_default_constructible_v>> + TTPolicyBase(ProcMap_&& procmap) + : procmap(std::forward(procmap)) + { } + + template>> + TTPolicyBase(ProcMap_&& procmap, PrioMap_&& priomap) + : procmap(std::forward(procmap)) + , priomap(std::forward(priomap)) + { } + + template + TTPolicyBase(ProcMap_&& procmap, + PrioMap_&& priomap, + InlineMap_&& im) + : procmap(std::forward(procmap)) + , priomap(std::forward(priomap)) + , inlinemap(std::forward(im)) + { } + + TTPolicyBase(const PolicyBaseT&) = default; + TTPolicyBase(PolicyBaseT&&) = default; + + }; + + namespace detail { + + /** + * Wrapper around a policy implementation. + * The wrapper provides default implementations for properties that + * are not set at compile-time and not yet set at runtime. + * By using a wrapper object, we can inspect the \c procmap(), \c priomap(), + * and \c inlinemap() of the policy to see whether a compile-time implementation + * of them was provided and gracefull catch attempts at setting + * properties that were provided at compile-time. + * + * TT implementations can inherit from this class to get the necessary + * mapping functions as well as functions to query and set mapping functions. + */ + template + struct TTPolicyWrapper { + private: + TTPolicyImpl m_policy; + + ttg::detail::default_keymap_impl m_default_procmap; + ttg::detail::default_priomap_impl m_default_priomap; + ttg::detail::default_inlinemap_impl m_default_inlinemap; + + static constexpr bool procmap_is_std_function = detail::is_std_function_ptr_v; + static constexpr bool priomap_is_std_function = detail::is_std_function_ptr_v; + static constexpr bool inlinemap_is_std_function = detail::is_std_function_ptr_v; + + public: + + /** + * Construct a wrapper from a provided world (needed for some of the defaults) + * and provided policy implementation. + */ + template + TTPolicyWrapper(WorldT world, ImplT&& impl) + : m_policy(std::forward(impl)) + , m_default_procmap(world.size()) + { } + + /** + * Return a copy of the used policy, with proper defaults. + */ + auto get_policy() { + TTPolicyImpl policy = m_policy; + if constexpr (procmap_is_std_function) { + if (!m_policy.procmap) { + /* create a std::function from the default implementation */ + policy.procmap = m_default_procmap; + } + } + if constexpr (priomap_is_std_function) { + if (!m_policy.priomap) { + /* create a std::function from the default implementation */ + policy.priomap = m_default_priomap; + } + } + if constexpr (inlinemap_is_std_function) { + if (!m_policy.inlinemap) { + /* create a std::function from the default implementation */ + policy.inlinemap = m_default_inlinemap; + } + } + return policy; + } + + /** + * Return a callable for the current process map. + * Returns a std::function object (not a reference) that can be invoked. + */ + inline auto get_procmap() const { + if constexpr (procmap_is_std_function) { + if (!m_policy.procmap) { + /* create a std::function from the default implementation */ + return ttg::meta::detail::keymap_t(m_default_procmap); + } else { + /* return the current std::function */ + return m_policy.procmap; + } + } else { + /* wrap whatever the procmap is in a lambda */ + return ttg::meta::detail::keymap_t([=](const Key& key){ return m_policy.procmap(key); }); + } + } + + /** + * Return a callable for the current priority map. + * Returns a std::function object (not a reference) that can be invoked. + */ + inline auto get_priomap() const { + if constexpr (priomap_is_std_function) { + if (!m_policy.priomap) { + /* create a std::function from the default implementation */ + return ttg::meta::detail::keymap_t(m_default_priomap); + } else { + /* return the current std::function */ + return m_policy.priomap; + } + } else { + /* wrap whatever the procmap is in a lambda */ + return ttg::meta::detail::keymap_t([=](const Key& key){ return m_policy.priomap(key); }); + } + } + + inline auto get_inlinemap() const { + if constexpr (inlinemap_is_std_function) { + if (!m_policy.inlinemap) { + /* create a std::function from the default implementation */ + return ttg::meta::detail::keymap_t(m_default_inlinemap); + } else { + /* return the current std::function */ + return m_policy.inlinemap; + } + } else { + /* wrap whatever the procmap is in a lambda */ + return ttg::meta::detail::keymap_t([=](const Key& key){ return m_policy.inlinemap(key); }); + } + } + + template>> + inline int procmap(const KeyT& key) const { + if constexpr (procmap_is_std_function) { + if (m_policy.procmap) return m_policy.procmap(key); + else return m_default_procmap(key); + } else { + return m_policy.procmap(key); + } + } + + template>> + inline int procmap() const { + if constexpr (procmap_is_std_function) { + if (m_policy.procmap) return m_policy.procmap(); + else return m_default_procmap(); + } else { + return m_policy.procmap(); + } + } + + /** Deprecated, use procmap instead */ + template>> + inline int keymap(const KeyT& key) const { + return procmap(key); + } + + /** Deprecated, use procmap instead */ + template>> + inline int keymap() const { + return procmap(); + } + + template>> + inline int priomap(const KeyT& key) const { + if constexpr (priomap_is_std_function) { + if (m_policy.priomap) return m_policy.priomap(key); + else return m_default_priomap(key); + } else { + return m_policy.priomap(key); + } + } + + template>> + inline int priomap() const { + if constexpr (priomap_is_std_function) { + if (m_policy.priomap) return m_policy.priomap(); + else return m_default_priomap(); + } else { + return m_policy.priomap(); + } + } + + template>> + inline int inlinemap(const KeyT& key) const { + if constexpr (inlinemap_is_std_function) { + if (m_policy.inlinemap) return m_policy.inlinemap(key); + else return m_default_inlinemap(key); + } else { + return m_policy.inlinemap(key); + } + } + + template>> + inline int inlinemap() const { + if constexpr (inlinemap_is_std_function) { + if (m_policy.inlinemap) return m_policy.inlinemap(); + else return m_default_inlinemap(); + } else { + return m_policy.inlinemap(); + } + } + + template + void set_procmap(ProcMap&& pm) { + static_assert(std::is_assignable_v, + "Cannot set process map on compile-time policy property!"); + m_policy.procmap = std::forward(pm); + } + + template + void set_keymap(KeyMap&& pm) { + set_procmap(std::forward(pm)); + } + + template + void set_priomap(PrioMap&& pm) { + static_assert(std::is_assignable_v, + "Cannot set process map on compile-time policy property!"); + m_policy.priomap = std::forward(pm); + } + + template + void set_inlinemap(InlineMap&& pm) { + static_assert(std::is_assignable_v, + "Cannot set process map on compile-time policy property!"); + m_policy.inlinemap = std::forward(pm); + } + + }; + } // namespace detail + + /** + * Helper function to create a TT policy from arbitrary function objects. + * The order of callables is + * 1) Process map + * 2) Priority map + * 3) Inline map + * + * Example use: + * + * ttg::make_policy( + * // Process map: round robin on field i of key + * [&](const Key& key){ return key.i % world.size(); }, + * // Priority map: use key field p as priority + * [&](const Key& key){ return key.p; }, + * // Inline map: never inline + * [&](const Key& key){ return 0; }); + * + * \sa TTPolicy + */ + template + auto make_policy(ProcMap&& pm, Args&& ...args) + { + return TTPolicyBase(std::forward(pm), std::forward(args)...); + } + + + namespace detail { + + /** + * Generate traits to check policy objects for procmap(), priomap(), and inlinemap() members + */ +#define TTG_POLICY_CREATE_CHECK_FOR(_Pol) \ + /* specialization that does the checking */ \ + template \ + struct has_##_Pol { \ + private: \ + template \ + static constexpr auto check(T*) \ + -> typename \ + std::is_same< \ + /* policy function take a key and return int */ \ + decltype( std::declval(). _Pol ( std::declval() ) ), \ + int \ + >::type; \ + template \ + static constexpr std::false_type check(...); \ + typedef decltype(check(0)) type; \ + public: \ + static constexpr bool value = type::value; \ + }; \ + template \ + struct has_##_Pol { \ + private: \ + template \ + static constexpr auto check(T*) \ + -> typename \ + std::is_same< \ + /* policy function for void simply return int */ \ + decltype( std::declval(). _Pol ( ) ), \ + int \ + >::type; \ + template \ + static constexpr std::false_type check(...); \ + typedef decltype(check(0)) type; \ + public: \ + static constexpr bool value = type::value; \ + }; \ + template \ + constexpr const bool has_##_Pol ## _v = has_ ## _Pol::value; + + TTG_POLICY_CREATE_CHECK_FOR(procmap); + TTG_POLICY_CREATE_CHECK_FOR(priomap); + TTG_POLICY_CREATE_CHECK_FOR(inlinemap); + + /** Whether PolicyT is a valid policy object using KeyT */ + template + struct is_policy { + static constexpr bool value = has_procmap_v && + has_priomap_v && + has_inlinemap_v; + }; + + /** Whether PolicyT is a valid policy object using KeyT */ + template + constexpr const bool is_policy_v = is_policy::value; + + /* sanity base check */ + static_assert(is_policy_v>); + static_assert(is_policy_v>>); + + static_assert(is_policy_v>); + static_assert(is_policy_v>>); + } // namespace detail + + +} // namespace ttg + +#endif // TTG_POLICIES_H diff --git a/ttg/ttg/reduce.h b/ttg/ttg/reduce.h index e6c46fb3bd..e19b45704a 100644 --- a/ttg/ttg/reduce.h +++ b/ttg/ttg/reduce.h @@ -10,6 +10,7 @@ #include #include "ttg/util/tree.h" +#include "ttg/policies.h" namespace ttg { @@ -28,17 +29,17 @@ namespace ttg { template class BinaryTreeReduce : public TT, Out, Out, Out>, - BinaryTreeReduce, Value, Value, Value> { + BinaryTreeReduce, ttg::typelist> { public: - using baseT = TT, Out, Out, Out>, - BinaryTreeReduce, Value, Value, Value>; + using baseT = typename BinaryTreeReduce::ttT; 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, Edge inout = Edge{}, Edge inout_l = Edge{}, Edge inout_r = Edge{}) : baseT(edges(fuse(in, inout), inout_l, inout_r), edges(inout, inout_l, inout_r, out), "BinaryTreeReduce", - {"in|inout", "inout_l", "inout_r"}, {"inout", "inout_l", "inout_r", "out"}, world, [](int key) { return key; }) + {"in|inout", "inout_l", "inout_r"}, {"inout", "inout_l", "inout_r", "out"}, world, + ttg::TTPolicyBase([](int key) { return key; })) , tree_((max_key == -1 ? world.size() : max_key), root) , dest_key_(dest_key) , op_(std::move(op)) { @@ -92,7 +93,7 @@ namespace ttg { // iterate over keys that map to me ... if keys are equivalent to ranks this can be made simpler const auto my_rank = this->get_world().rank(); for (auto key = 0; key != tree_.size(); ++key) { - if (my_rank == this->get_keymap()(key)) { + if (my_rank == this->procmap(key)) { auto keys = tree_.child_keys(key); if (keys.first == -1) this->template set_arg<1>(key, Value()); if (keys.second == -1) this->template set_arg<2>(key, Value()); diff --git a/ttg/ttg/terminal.h b/ttg/ttg/terminal.h index 47f8ea761c..50fbf2f617 100644 --- a/ttg/ttg/terminal.h +++ b/ttg/ttg/terminal.h @@ -178,6 +178,21 @@ namespace ttg { } }; + namespace detail { + 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; + } // namespace detail + // Output terminal template class Out : public TerminalBase { diff --git a/ttg/ttg/util/meta.h b/ttg/ttg/util/meta.h index 4e159f5ff1..9bdb08f794 100644 --- a/ttg/ttg/util/meta.h +++ b/ttg/ttg/util/meta.h @@ -5,6 +5,7 @@ #include #include "ttg/util/span.h" +#include "ttg/util/typelist.h" namespace ttg { @@ -145,21 +146,39 @@ namespace ttg { template constexpr bool is_all_void_v = (is_void_v && ...); + template + constexpr bool is_all_void_v> = is_all_void_v; + + template + constexpr bool is_all_Void_v = (is_Void_v && ...); + + template + constexpr bool is_all_Void_v> = is_all_Void_v; + template constexpr bool is_any_void_v = (is_void_v || ...); template - constexpr bool is_any_void_v> = (is_void_v || ...); + constexpr bool is_any_void_v> = is_all_void_v; template constexpr bool is_any_Void_v = (is_Void_v || ...); + template + constexpr bool is_any_Void_v> = is_any_Void_v; + template constexpr bool is_none_void_v = !is_any_void_v; + template + constexpr bool is_none_void_v> = is_none_void_v; + template constexpr bool is_none_Void_v = !is_any_Void_v; + template + constexpr bool is_none_Void_v> = is_none_Void_v; + template struct is_last_void; @@ -172,6 +191,12 @@ namespace ttg { template struct is_last_void : public is_last_void {}; + template + struct is_last_void> : public is_last_void {}; + + template + struct is_last_void> : public is_last_void {}; + template constexpr bool is_last_void_v = is_last_void::value; @@ -186,6 +211,67 @@ namespace ttg { template using void_to_Void_t = typename void_to_Void::type; + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Tuple-element type conversions + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + 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 none_has_reference> : none_has_reference + { }; + + template<> + struct none_has_reference> : std::true_type + { }; + + template + constexpr bool none_has_reference_v = 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 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -425,6 +511,10 @@ namespace ttg { using type = std::tuple::type...>; }; template + struct input_reducers> { + using type = std::tuple::type...>; + }; + template using input_reducers_t = typename input_reducers::type; } // namespace detail diff --git a/ttg/ttg/util/typelist.h b/ttg/ttg/util/typelist.h new file mode 100644 index 0000000000..ba35f25b29 --- /dev/null +++ b/ttg/ttg/util/typelist.h @@ -0,0 +1,39 @@ +#ifndef TTG_UTIL_INPUTTYPES_H +#define TTG_UTIL_INPUTTYPES_H + +#include + +namespace ttg { + + /** + * \brief A container for types. + * + * We use this to work around ADL issues when templating ttg::TT with + * std::tuple. This is a simple wrapper type holding type information. + * A tuple containing the types can be extracted using the \c tuple_type + * member type. + */ + template + struct typelist + { + using tuple_type = std::tuple; + }; + + namespace detail { + + template + struct is_typelist : std::false_type + { }; + + template + struct is_typelist> : std::true_type + { }; + + template + constexpr bool is_typelist_v = is_typelist::value; + + } // namespace detail + +} // namespace ttg + +#endif // TTG_UTIL_INPUTTYPES_H