Learning about collective epochs
// VT Base Message // \----------------/ // \ / struct ExampleMsg : ::vt::Message { ExampleMsg() = default; explicit ExampleMsg(int32_t in_ttl) : ttl(in_ttl-1) { } int32_t ttl = 0; }; // Forward declaration for the active message handler static void recurHandler(ExampleMsg* msg); // Tutorial code to demonstrate using a callback static inline void activeMessageTerm() { NodeType const this_node = ::vt::theContext()->getNode(); NodeType const num_nodes = ::vt::theContext()->getNumNodes(); (void)num_nodes; // don't warn about unused variable /* * Termination will allow us to track a subcomputation with causality to * determine when a sub-computation terminated in a distributed-manner. The * tutorial demonstrates how to use `collective` epochs. Rooted epoch will be * demonstrated in a follow-on tutorial. */ // Create a new epoch: this is a collective invocation auto const new_epoch = theTerm()->makeEpochCollective(); if (this_node == 0) { auto msg = vt::makeMessage<ExampleMsg>(8); envelopeSetEpoch(msg->env, new_epoch); vt::theMsg()->sendMsg<recurHandler>(this_node+1, msg); } // Any node that wishes to have a notification on termination for a given // epoch can add actions for the termination detector theTerm()->addAction( new_epoch, []{ auto const node = vt::theContext()->getNode(); fmt::print("{}: recurHandler terminated\n", node); } ); // This is not explicitly a collective, but all nodes need to call // `finishedEpoch` to tell the system they are finished sending messages // for the epoch. theTerm()->finishedEpoch(new_epoch); } // Message handler that recursively sends messages static void recurHandler(ExampleMsg* msg) { NodeType const num_nodes = ::vt::theContext()->getNumNodes(); NodeType const this_node = ::vt::theContext()->getNode(); ::fmt::print( "{}: recurHandler: ttl={}, triggered\n", this_node, msg->ttl ); if (msg->ttl > 0) { auto const num_send = static_cast<int32_t>(drand48() * 3); for (auto i = 0; i < num_send; i++) { auto next_node = (this_node + 1 > num_nodes - 1) ? 0 : (this_node + 1); ::fmt::print( "{}: recurHandler: i={}, next_node={}, num_send={}\n", this_node, i, next_node, num_send ); auto msg_send = vt::makeMessage<ExampleMsg>(msg->ttl); vt::theMsg()->sendMsg<recurHandler>(next_node, msg_send); } } }