diff --git a/examples/callback/callback_context.cc b/examples/callback/callback_context.cc index e72915cf00..e61d851bfa 100644 --- a/examples/callback/callback_context.cc +++ b/examples/callback/callback_context.cc @@ -108,8 +108,9 @@ int main(int argc, char** argv) { auto cb = vt::theCB()->makeFunc( vt::pipe::LifetimeEnum::Once, &my_global_ctx, callbackFn ); - auto msg = vt::makeMessage(cb); - vt::theMsg()->sendMsg(1, msg); + + auto const default_proxy = vt::theObjGroup()->getDefault(); + default_proxy[1].send(cb); } vt::finalize(); diff --git a/src/vt/objgroup/manager.cc b/src/vt/objgroup/manager.cc index 825d644216..657cc453b6 100644 --- a/src/vt/objgroup/manager.cc +++ b/src/vt/objgroup/manager.cc @@ -52,6 +52,10 @@ namespace vt { namespace objgroup { +proxy::DefaultProxyType ObjGroupManager::getDefault() const { + return proxy::DefaultProxyType{}; +} + ObjGroupProxyType ObjGroupManager::getProxy(ObjGroupProxyType proxy) { return proxy; } diff --git a/src/vt/objgroup/manager.h b/src/vt/objgroup/manager.h index 9d21a4b9a2..914ef4428c 100644 --- a/src/vt/objgroup/manager.h +++ b/src/vt/objgroup/manager.h @@ -110,6 +110,14 @@ struct ObjGroupManager : runtime::component::Component { * communicator */ + /** + * \brief Construct a special proxy instance that allows sending, broadcasting + * and reducing without actual object group. + * + * \return proxy to the object group + */ + proxy::DefaultProxyType getDefault() const; + /** * \brief Collectively construct a new object group. Allocates and constructs * the object on each node by forwarding constructor arguments. diff --git a/src/vt/objgroup/proxy/proxy_objgroup.h b/src/vt/objgroup/proxy/proxy_objgroup.h index a191b0870c..8c7a3f30f3 100644 --- a/src/vt/objgroup/proxy/proxy_objgroup.h +++ b/src/vt/objgroup/proxy/proxy_objgroup.h @@ -373,6 +373,98 @@ struct Proxy { ObjGroupProxyType proxy_ = no_obj_group; /**< The raw proxy ID bits */ }; +template <> +struct Proxy { + /** + * \brief Index the proxy to get the element proxy for a particular node + * + * \param[in] node the desired node + * + * \return an indexed proxy to that node + */ + DefaultProxyElm operator[](NodeType node) const; + + /** + * \brief Broadcast a message. + * + * \note Creates message from given args + * + * \param[in] args the arguments used to make a message + * + * \return the \c PendingSend for the sent message + */ + template * f, typename... Args> + messaging::PendingSend broadcast(Args&&... args) const; + + /** + * \brief Broadcast a message. + * + * \note Takes ownership of the supplied message. + * + * \param[in] msg the message to broadcast + * \param[in] tag the tag to put on the message + * + * \return the \c PendingSend for the sent message + */ + template * f> + messaging::PendingSend + broadcastMsg(messaging::MsgPtrThief msg, TagType tag = no_tag) const; + + /** + * \brief Reduce a message up the tree, possibly delayed through a pending + * send + * + * \note Creates message from given args + * + * \param[in] root the root node where the final handler provides the result + * \param[in] args the arguments used to make a message + * + * \return the pending send corresponding to the reduce + */ + template < + typename OpT, + typename FunctorT, + typename MsgT, + typename... Args + > + messaging::PendingSend reduce(NodeType root, Args&&... args) const; + + template < + typename OpT, + typename FunctorT, + typename MsgT, + ActiveTypedFnType* f, + typename... Args + > + messaging::PendingSend reduce(NodeType root, Args&&... args) const; + + /** + * \brief Reduce a message up the tree, possibly delayed through a pending + * send + * + * \param[in] root the root node where the final handler provides the result + * \param[in] msg the message to reduce on this node + * + * \return the pending send corresponding to the reduce + */ + template < + typename OpT, + typename FunctorT, + typename MsgT + > + messaging::PendingSend reduceMsg(NodeType root, MsgT* const msg) const; + + template < + typename OpT, + typename FunctorT, + typename MsgT, + ActiveTypedFnType* f + > + messaging::PendingSend reduceMsg(NodeType root, MsgT* const msg) const; +}; + +using DefaultProxyType = Proxy; + }}} /* end namespace vt::objgroup::proxy */ #endif /*INCLUDED_VT_OBJGROUP_PROXY_PROXY_OBJGROUP_H*/ diff --git a/src/vt/objgroup/proxy/proxy_objgroup.impl.h b/src/vt/objgroup/proxy/proxy_objgroup.impl.h index f5cc824870..411a6155d7 100644 --- a/src/vt/objgroup/proxy/proxy_objgroup.impl.h +++ b/src/vt/objgroup/proxy/proxy_objgroup.impl.h @@ -223,6 +223,72 @@ void Proxy::destroyHandleSetRDMA(vt::rdma::HandleSet set) const { return vt::theHandleRDMA()->deleteHandleSetCollectiveObjGroup(set); } +inline DefaultProxyElm Proxy::operator[](NodeType node) const { + return DefaultProxyElm{node}; +} + +template * f, typename... Args> +messaging::PendingSend Proxy::broadcast(Args&&... args) const { + return broadcastMsg(makeMessage(std::forward(args)...)); +} + +template * f> +messaging::PendingSend +Proxy::broadcastMsg(messaging::MsgPtrThief msg, TagType tag) const { + return theMsg()->broadcastMsg(msg, tag); +} + +template +messaging::PendingSend +Proxy::reduce(NodeType root, Args&&... args) const { + return reduce< + OpT, + FunctorT, + MsgT, + &MsgT::template msgHandler, + Args... + >(root, std::forward(args)...); +} + +template < + typename OpT, + typename FunctorT, + typename MsgT, + ActiveTypedFnType* f, + typename... Args +> +messaging::PendingSend +Proxy::reduce(NodeType root, Args&&... args) const { + auto const msg = makeMessage(std::forward(args)...); + return reduceMsg(root, msg.get()); +} + +template < + typename OpT, + typename FunctorT, + typename MsgT +> +messaging::PendingSend +Proxy::reduceMsg(NodeType root, MsgT* const msg) const { + return reduceMsg< + OpT, + FunctorT, + MsgT, + &MsgT::template msgHandler + >(root, msg); +} + +template < + typename OpT, + typename FunctorT, + typename MsgT, + ActiveTypedFnType* f +> +messaging::PendingSend +Proxy::reduceMsg(NodeType root, MsgT* const msg) const { + return theCollective()->global()->reduce(root, msg); +} + }}} /* end namespace vt::objgroup::proxy */ #endif /*INCLUDED_VT_OBJGROUP_PROXY_PROXY_OBJGROUP_IMPL_H*/ diff --git a/src/vt/objgroup/proxy/proxy_objgroup_elm.h b/src/vt/objgroup/proxy/proxy_objgroup_elm.h index db840c8590..4fefcc82e5 100644 --- a/src/vt/objgroup/proxy/proxy_objgroup_elm.h +++ b/src/vt/objgroup/proxy/proxy_objgroup_elm.h @@ -50,6 +50,7 @@ #include "vt/objgroup/proxy/proxy_bits.h" #include "vt/objgroup/active_func/active_func.h" #include "vt/messaging/message/smart_ptr.h" +#include "vt/activefn/activefn.h" namespace vt { namespace objgroup { namespace proxy { @@ -179,6 +180,25 @@ struct ProxyElm { NodeType node_ = uninitialized_destination; /**< The indexed node */ }; +template <> +struct ProxyElm { + explicit ProxyElm(NodeType in_node); + + /** + * \brief Send a message to the node indexed by this proxy to be + * delivered to the local object instance + * + * \param[in] args args to pass to the message constructor + */ + template * f, typename... Args> + void send(Args&&... args) const; + +private: + NodeType node_ = uninitialized_destination; /**< The indexed node */ +}; + +using DefaultProxyElm = ProxyElm; + }}} /* end namespace vt::objgroup::proxy */ #endif /*INCLUDED_VT_OBJGROUP_PROXY_PROXY_OBJGROUP_ELM_H*/ diff --git a/src/vt/objgroup/proxy/proxy_objgroup_elm.impl.h b/src/vt/objgroup/proxy/proxy_objgroup_elm.impl.h index 2c1aa6fe90..1ca1641b29 100644 --- a/src/vt/objgroup/proxy/proxy_objgroup_elm.impl.h +++ b/src/vt/objgroup/proxy/proxy_objgroup_elm.impl.h @@ -97,6 +97,14 @@ ObjT* ProxyElm::get() const { return theObjGroup()->get(proxy); } +inline ProxyElm::ProxyElm(NodeType in_node) : node_{in_node} {} + +template * f, typename... Args> +void ProxyElm::send(Args&&... args) const { + vt::theMsg()->sendMsg( + node_, vt::makeMessage(std::forward(args)...)); +} + }}} /* end namespace vt::objgroup::proxy */ #endif /*INCLUDED_VT_OBJGROUP_PROXY_PROXY_OBJGROUP_ELM_IMPL_H*/ diff --git a/tests/unit/collectives/test_collectives_reduce.extended.cc b/tests/unit/collectives/test_collectives_reduce.extended.cc index c675cab48b..7679fa2b09 100644 --- a/tests/unit/collectives/test_collectives_reduce.extended.cc +++ b/tests/unit/collectives/test_collectives_reduce.extended.cc @@ -107,10 +107,12 @@ TEST_F(TestReduce, test_reduce_vec_int_msg) { vecOfInt.push_back(3); auto const root = 0; - auto msg = makeMessage>(vecOfInt); - theCollective()->global()->reduce< - PlusOp>, Verify - >(root, msg.get()); + auto const default_proxy = theObjGroup()->getDefault(); + default_proxy.reduce< + PlusOp>, + Verify, + ReduceVecMsg + >(root, vecOfInt); } }}} // end namespace vt::tests::unit diff --git a/tests/unit/test_parallel_harness.h b/tests/unit/test_parallel_harness.h index d496b38c20..aeac5d3162 100644 --- a/tests/unit/test_parallel_harness.h +++ b/tests/unit/test_parallel_harness.h @@ -92,7 +92,6 @@ struct TestParallelHarnessAny : TestHarnessAny { TestHarnessAny::SetUp(); - // TODO (STRZ) - do we want to use additional args here as well? if (mpi_singleton == nullptr) { mpi_singleton = std::make_unique(test_argc, test_argv); diff --git a/tutorial/tutorial_1d.h b/tutorial/tutorial_1d.h index b68a73c989..0a22d3dfbb 100644 --- a/tutorial/tutorial_1d.h +++ b/tutorial/tutorial_1d.h @@ -74,20 +74,26 @@ static inline void activeMessageBroadcast() { (void)num_nodes; // don't warn about unused variable /* - * The theMsg()->broadcastMsg(..) will send the message to every node in the + * default_proxy.broadcast(..) will send the message to every node in the * system. Every node will include all the nodes that VT has depending on the * MPI communicator passed in or the size attained (number of ranks) when * executing MPI init directly in non-interoperability mode. * * -- Message Ownership -- - * As with sendMsg, sending with broadcastMsg relinquishes ownership of - * the message. Most calls to VT that supply a message are expected - * to relinquish ownership. + * default_proxy.broadcast(..) will create message out of args passed + * into it. There's an alternative - default_proxy.broadcastMsg(..) - which + * relinquishes ownership of the message passed to: + * + * auto msg = ::vt::makeMessage(1.0, 2.0, 3.0); + * auto const default_proxy = theObjGroup()->getDefault(); + * default_proxy.broadcastMsg(msg); + * + * Most calls to VT that supply a message are expected to relinquish ownership. */ if (this_node == 0) { - auto msg = ::vt::makeMessage(1.0,2.0,3.0); - ::vt::theMsg()->broadcastMsg(msg); + auto const default_proxy = theObjGroup()->getDefault(); + default_proxy.broadcast(1.0, 2.0, 3.0); } } diff --git a/tutorial/tutorial_1h.h b/tutorial/tutorial_1h.h index 56d0391391..3051bf6414 100644 --- a/tutorial/tutorial_1h.h +++ b/tutorial/tutorial_1h.h @@ -90,7 +90,8 @@ static inline void activeMessageReduce() { // Get a reference to the value to set it in this reduce msg reduce_msg->getVal() = 50; - ::vt::theCollective()->global()->reduce( + auto const default_proxy = theObjGroup()->getDefault(); + default_proxy.reduceMsg( root_reduce_node, reduce_msg.get() ); }