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