diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 808b248dfd..e88d9440da 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,7 @@ set(TOP_LEVEL_SUBDIRS configs collective + elm epoch group messaging @@ -33,6 +34,7 @@ set( collective/scatter/ collective/reduce/ collective/reduce/operators collective/reduce/functors + elm group/id group/region group/global group/msg group/collective group/rooted group/base pipe/id pipe/msg pipe/state pipe/signal pipe/interface pipe/callback diff --git a/src/vt/context/runnable_context/base.h b/src/vt/context/runnable_context/base.h index 799fce5343..f0672eb3b5 100644 --- a/src/vt/context/runnable_context/base.h +++ b/src/vt/context/runnable_context/base.h @@ -45,6 +45,7 @@ #define INCLUDED_VT_CONTEXT_RUNNABLE_CONTEXT_BASE_H #include "vt/configs/types/types_type.h" +#include "vt/elm/elm_id.h" namespace vt { namespace ctx { @@ -95,7 +96,7 @@ struct Base { * \param[in] size the size of the message * \param[in] bcast whether the message is being broadcast or sent */ - virtual void send(NodeType dest, MsgSizeType size, bool bcast) { } + virtual void send(elm::ElementIDStruct dest, MsgSizeType bytes) { } }; }} /* end namespace vt::ctx */ diff --git a/src/vt/context/runnable_context/lb_stats.cc b/src/vt/context/runnable_context/lb_stats.cc index a6f3459a42..9738756f3d 100644 --- a/src/vt/context/runnable_context/lb_stats.cc +++ b/src/vt/context/runnable_context/lb_stats.cc @@ -60,8 +60,8 @@ void LBStats::end() { } } -void LBStats::send(NodeType dest, MsgSizeType size, bool bcast) { - stats_->recvToNode(dest, cur_elm_id_, size, bcast); +void LBStats::send(elm::ElementIDStruct dest, MsgSizeType bytes) { + stats_->sendToEntity(dest, cur_elm_id_, bytes); } void LBStats::suspend() { diff --git a/src/vt/context/runnable_context/lb_stats.h b/src/vt/context/runnable_context/lb_stats.h index 7ff430c244..c186d69ab6 100644 --- a/src/vt/context/runnable_context/lb_stats.h +++ b/src/vt/context/runnable_context/lb_stats.h @@ -46,7 +46,7 @@ #include "vt/context/runnable_context/base.h" #include "vt/vrt/collection/balance/lb_common.h" -#include "vt/vrt/collection/balance/elm_stats.fwd.h" +#include "vt/elm/elm_stats.fwd.h" namespace vt { namespace ctx { @@ -56,8 +56,8 @@ namespace vt { namespace ctx { * \brief Context for collection LB statistics when a task runs */ struct LBStats final : Base { - using ElementIDStruct = vrt::collection::balance::ElementIDStruct; - using ElementStats = vrt::collection::balance::ElementStats; + using ElementIDStruct = elm::ElementIDStruct; + using ElementStats = elm::ElementStats; /** * \brief Construct a \c LBStats @@ -71,10 +71,14 @@ struct LBStats final : Base { /** * \brief Construct a \c LBStats * - * \param[in] in_elm the collection element + * \param[in] in_stats the statistics + * \param[in] in_elm_id the element ID */ - template - explicit LBStats(ElmT* in_elm); + LBStats(ElementStats* in_stats, ElementIDStruct const& in_elm_id) + : stats_(in_stats), + cur_elm_id_(in_elm_id), + should_instrument_(true) + { } /** * \brief Set the context and timing for a collection task @@ -94,7 +98,7 @@ struct LBStats final : Base { * \param[in] size the size of the message * \param[in] bcast whether the message is being broadcast or sent */ - void send(NodeType dest, MsgSizeType size, bool bcast) final override; + void send(elm::ElementIDStruct dest, MsgSizeType bytes) final override; void suspend() final override; void resume() final override; diff --git a/src/vt/context/runnable_context/lb_stats.impl.h b/src/vt/context/runnable_context/lb_stats.impl.h index 0391bc6960..190a1cfbe4 100644 --- a/src/vt/context/runnable_context/lb_stats.impl.h +++ b/src/vt/context/runnable_context/lb_stats.impl.h @@ -46,7 +46,7 @@ #include "vt/context/runnable_context/lb_stats.h" #include "vt/messaging/active.h" -#include "vt/vrt/collection/balance/elm_stats.h" +#include "vt/elm/elm_stats.h" #include "vt/vrt/collection/manager.h" #include @@ -63,13 +63,6 @@ LBStats::LBStats(ElmT* in_elm, MsgT* msg) theCollection()->recordStats(in_elm, msg); } -template -LBStats::LBStats(ElmT* in_elm) - : stats_(&in_elm->getStats()), - cur_elm_id_(in_elm->getElmID()), - should_instrument_(true) -{ } - }} /* end namespace vt::ctx */ #endif /*INCLUDED_VT_CONTEXT_RUNNABLE_CONTEXT_LB_STATS_IMPL_H*/ diff --git a/src/vt/vrt/collection/balance/lb_comm.h b/src/vt/elm/elm_comm.h similarity index 80% rename from src/vt/vrt/collection/balance/lb_comm.h rename to src/vt/elm/elm_comm.h index 2de140976b..b723c30bcd 100644 --- a/src/vt/vrt/collection/balance/lb_comm.h +++ b/src/vt/elm/elm_comm.h @@ -2,7 +2,7 @@ //@HEADER // ***************************************************************************** // -// lb_comm.h +// elm_comm.h // DARMA/vt => Virtual Transport // // Copyright 2019-2021 National Technology & Engineering Solutions of Sandia, LLC @@ -41,15 +41,14 @@ //@HEADER */ -#if !defined INCLUDED_VT_VRT_COLLECTION_BALANCE_LB_COMM_H -#define INCLUDED_VT_VRT_COLLECTION_BALANCE_LB_COMM_H +#if !defined INCLUDED_VT_ELM_ELM_COMM_H +#define INCLUDED_VT_ELM_ELM_COMM_H -#include "vt/config.h" -#include "vt/vrt/collection/balance/lb_common.h" +#include "vt/elm/elm_id.h" #include -namespace vt { namespace vrt { namespace collection { namespace balance { +namespace vt { namespace elm { enum struct CommCategory : int8_t { SendRecv = 1, @@ -66,32 +65,41 @@ inline NodeType objGetNode(ElementIDStruct const id) { return id.curr_node; } -struct LBCommKey { +struct CommKey { + struct SendRecvTag { }; struct CollectionTag { }; struct CollectionToNodeTag { }; struct NodeToCollectionTag { }; - LBCommKey() = default; - LBCommKey(LBCommKey const&) = default; - LBCommKey(LBCommKey&&) = default; - LBCommKey& operator=(LBCommKey const&) = default; + CommKey() = default; + CommKey(CommKey const&) = default; + CommKey(CommKey&&) = default; + CommKey& operator=(CommKey const&) = default; - LBCommKey( + CommKey( + SendRecvTag, + ElementIDStruct from, ElementIDStruct to, + bool bcast + ) : from_(from), to_(to), + cat_(bcast ? CommCategory::Broadcast : CommCategory::SendRecv) + { } + + CommKey( CollectionTag, ElementIDStruct from, ElementIDStruct to, bool bcast ) : from_(from), to_(to), cat_(bcast ? CommCategory::Broadcast : CommCategory::SendRecv) { } - LBCommKey( + CommKey( CollectionToNodeTag, ElementIDStruct from, NodeType to, bool bcast ) : from_(from), nto_(to), cat_(bcast ? CommCategory::CollectionToNodeBcast : CommCategory::CollectionToNode) { } - LBCommKey( + CommKey( NodeToCollectionTag, NodeType from, ElementIDStruct to, bool bcast @@ -99,10 +107,10 @@ struct LBCommKey { cat_(bcast ? CommCategory::NodeToCollectionBcast : CommCategory::NodeToCollection) { } - ElementIDStruct from_ = { no_element_id, uninitialized_destination, uninitialized_destination }; - ElementIDStruct to_ = { no_element_id, uninitialized_destination, uninitialized_destination }; + ElementIDStruct from_ = {}; + ElementIDStruct to_ = {}; - ElementIDStruct edge_id_ = { no_element_id, uninitialized_destination, uninitialized_destination }; + ElementIDStruct edge_id_ = {}; NodeType nfrom_ = uninitialized_destination; NodeType nto_ = uninitialized_destination; CommCategory cat_ = CommCategory::SendRecv; @@ -127,7 +135,7 @@ struct LBCommKey { } bool onNode() const { return !offNode(); } - bool operator==(LBCommKey const& k) const { + bool operator==(CommKey const& k) const { return k.from_ == from_ and k.to_ == to_ and k.nfrom_ == nfrom_ and k.nto_ == nto_ and @@ -141,7 +149,7 @@ struct LBCommKey { }; // Set the types for the communication graph -using CommKeyType = LBCommKey; +using CommKeyType = CommKey; using CommBytesType = double; struct CommVolume { @@ -153,6 +161,11 @@ struct CommVolume { bytes += b; } + void sendMsg(double b) { + messages++; + bytes += b; + } + void operator+=(const CommVolume &rhs) { bytes += rhs.bytes; messages += rhs.messages; @@ -166,13 +179,13 @@ struct CommVolume { using CommMapType = std::unordered_map; -}}}} /* end namespace vt::vrt::collection::balance */ +}} /* end namespace vt::elm */ namespace std { -using CommCategoryType = vt::vrt::collection::balance::CommCategory; -using LBCommKeyType = vt::vrt::collection::balance::LBCommKey; -using ElementIDStructType = vt::vrt::collection::balance::ElementIDStruct; +using CommCategoryType = vt::elm::CommCategory; +using CommKeyType = vt::elm::CommKey; +using ElementIDStructType = vt::elm::ElementIDStruct; template <> struct hash { @@ -184,8 +197,8 @@ struct hash { }; template <> -struct hash { - size_t operator()(LBCommKeyType const& in) const { +struct hash { + size_t operator()(CommKeyType const& in) const { return std::hash()( std::hash()(in.from_) ^ std::hash()(in.to_) ^ in.nfrom_ ^ in.nto_ @@ -195,4 +208,4 @@ struct hash { } /* end namespace std */ -#endif /*INCLUDED_VT_VRT_COLLECTION_BALANCE_LB_COMM_H*/ +#endif /*INCLUDED_VT_ELM_ELM_COMM_H*/ diff --git a/src/vt/elm/elm_id.cc b/src/vt/elm/elm_id.cc new file mode 100644 index 0000000000..089ed2953e --- /dev/null +++ b/src/vt/elm/elm_id.cc @@ -0,0 +1,61 @@ +/* +//@HEADER +// ***************************************************************************** +// +// elm_id.cc +// DARMA/vt => Virtual Transport +// +// Copyright 2019-2021 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Questions? Contact darma@sandia.gov +// +// ***************************************************************************** +//@HEADER +*/ + +#include "vt/elm/elm_id.h" +#include "vt/elm/elm_id_bits.h" + +namespace vt { namespace elm { + +bool ElementIDStruct::isMigratable() const { + return ElmIDBits::isMigratable(id); +} + +NodeType ElementIDStruct::getHomeNode() const { + return ElmIDBits::getNode(id); +} + +NodeType ElementIDStruct::getCurrNode() const { + return curr_node; +} + +}} /* end namespace vt::elm */ diff --git a/src/vt/elm/elm_id.h b/src/vt/elm/elm_id.h new file mode 100644 index 0000000000..36bb57f6e0 --- /dev/null +++ b/src/vt/elm/elm_id.h @@ -0,0 +1,142 @@ +/* +//@HEADER +// ***************************************************************************** +// +// elm_id.h +// DARMA/vt => Virtual Transport +// +// Copyright 2019-2021 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Questions? Contact darma@sandia.gov +// +// ***************************************************************************** +//@HEADER +*/ + +#if !defined INCLUDED_VT_ELM_ELM_ID_H +#define INCLUDED_VT_ELM_ELM_ID_H + +#include "vt/configs/types/types_type.h" +#include "vt/configs/types/types_sentinels.h" + +namespace vt { namespace elm { + +/// The underlying element ID type +using ElementIDType = uint64_t; + +/// Sentinel value for no element ID +static constexpr ElementIDType const no_element_id = 0; + +/** + * \struct ElementIDStruct + * + * \brief A general identifier for a task context. The \c id is unique in the + * system. + */ +struct ElementIDStruct { + using isByteCopyable = std::true_type; + + bool operator==(const ElementIDStruct& rhs) const { + return id == rhs.id; + } + + bool operator<(const ElementIDStruct& rhs) const { + return id < rhs.id; + } + + ElementIDType id = no_element_id; /**< id must be unique across nodes */ + NodeType curr_node = uninitialized_destination; /**< the current node */ + + bool isMigratable() const; + NodeType getHomeNode() const; + NodeType getCurrNode() const; +}; + + +}} /* end namespace vt::elm */ + +namespace std { + +template <> +struct hash { + size_t operator()(vt::elm::ElementIDStruct const& in) const { + return std::hash()(in.id); + } +}; + +} /* end namespace std */ + +#include + +namespace fmt { + +/// Custom fmt formatter/print for \c vt::elm::ElementIDStruct +template <> +struct formatter { + /// Presentation format: + /// - 'x' - hex (default) + /// - 'd' - decimal + /// - 'b' - binary + char presentation = 'x'; + + /// Parses format specifications of the form ['x' | 'd' | 'b']. + auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) { + // Parse the presentation format and store it in the formatter: + auto it = ctx.begin(), end = ctx.end(); + if (it != end && (*it == 'x' || *it == 'd' || *it == 'b')) { + presentation = *it++; + } + + // Check if reached the end of the range: + if (it != end && *it != '}') { + throw format_error("invalid format"); + } + + // Return an iterator past the end of the parsed range: + return it; + } + + /// Formats the epoch using the parsed format specification (presentation) + /// stored in this formatter. + template + auto format(vt::elm::ElementIDStruct const& e, FormatContext& ctx) { + std::string id_format = + presentation == 'b' ? "{:b}" : (presentation == 'd' ? "{:d}" : "{:x}"); + auto fmt_str = "(" + id_format + ",{},{},{})"; + return format_to( + ctx.out(), fmt_str, e.id, e.getHomeNode(), e.curr_node, e.isMigratable() + ); + } +}; + +} /* end namespace fmt */ + +#endif /*INCLUDED_VT_ELM_ELM_ID_H*/ diff --git a/src/vt/elm/elm_id_bits.cc b/src/vt/elm/elm_id_bits.cc new file mode 100644 index 0000000000..5e060af528 --- /dev/null +++ b/src/vt/elm/elm_id_bits.cc @@ -0,0 +1,156 @@ +/* +//@HEADER +// ***************************************************************************** +// +// elm_id_bits.cc +// DARMA/vt => Virtual Transport +// +// Copyright 2019-2021 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Questions? Contact darma@sandia.gov +// +// ***************************************************************************** +//@HEADER +*/ + +#include "vt/elm/elm_id_bits.h" +#include "vt/utils/bits/bits_common.h" +#include "vt/objgroup/common.h" +#include "vt/objgroup/proxy/proxy_bits.h" +#include "vt/vrt/collection/balance/node_stats.h" + +namespace vt { namespace elm { + +/*static*/ ElementIDStruct ElmIDBits::createCollection( + bool migratable, NodeType curr_node +) { + auto const seq_id = theNodeStats()->getNextElm(); + auto const home_node = theContext()->getNode(); + return createCollectionImpl(migratable, seq_id, home_node, curr_node); +} + +/*static*/ ElementIDStruct ElmIDBits::createCollectionImpl( + bool migratable, ElementIDType seq_id, NodeType home_node, NodeType curr_node +) { + ElementIDType ret = 0; + setCollectionID(ret, migratable, seq_id, home_node); + return ElementIDStruct{ret, curr_node}; +} + +/*static*/ ElementIDStruct ElmIDBits::createObjGroup( + ObjGroupProxyType proxy, NodeType node +) { + ElementIDType ret = 0; + setObjGroup(ret, proxy, node); + auto const this_node = theContext()->getNode(); + return ElementIDStruct{ret, this_node}; +} + +/*static*/ ElementIDStruct ElmIDBits::createBareHandler(NodeType node) { + ElementIDType ret = 0; + BitPackerType::setField( + ret, BareHandler + ); + constexpr auto num_node_bits = BitCounterType::value; + BitPackerType::setField( + ret, node + ); + return ElementIDStruct{ret, node}; +} + +/*static*/ void ElmIDBits::setObjGroup( + ElementIDType& id, ObjGroupProxyType proxy, NodeType node +) { + BitPackerType::setField( + id, ObjGroup + ); + objgroup::proxy::ObjGroupProxy::setNode(proxy, node); + constexpr auto proxy_bits = BitCounterType::value - 2; + BitPackerType::setField( + id, proxy + ); +} + +/*static*/ void ElmIDBits::setCollectionID( + ElementIDType& id, bool migratable, ElementIDType seq_id, NodeType node +) { + BitPackerType::setField( + id, migratable ? CollectionMigratable : CollectionNonMigratable + ); + constexpr auto num_node_bits = BitCounterType::value; + BitPackerType::setField( + id, node + ); + BitPackerType::setField( + id, seq_id + ); +} + +/*static*/ eElmIDControlBits ElmIDBits::getControlBits(ElementIDType id) { + auto const n = num_control_bits; + auto r = BitPackerType::getField(id); + return static_cast(r); +} + +/*static*/ bool ElmIDBits::isMigratable(ElementIDType id) { + auto const ctrl = getControlBits(id); + return not ( + ctrl == BareHandler or ctrl == ObjGroup or ctrl == CollectionNonMigratable + ); +} + +/*static*/ NodeType ElmIDBits::getNode(ElementIDType id) { + auto const ctrl = getControlBits(id); + if (ctrl == ObjGroup) { + auto const proxy = ElmIDBits::getObjGroupProxy(id, true); + return objgroup::proxy::ObjGroupProxy::getNode(proxy); + } else { + constexpr auto num_node_bits = BitCounterType::value; + return BitPackerType::getField< + eElmIDProxyBitsNonObjGroup::Node, num_node_bits, NodeType + >(id); + } +} + +/*static*/ ObjGroupProxyType ElmIDBits::getObjGroupProxy( + ElementIDType id, bool include_node +) { + constexpr auto proxy_bits = BitCounterType::value - 2; + auto proxy = BitPackerType::getField< + eElmIDProxyBitsObjGroup::ObjGroupID, proxy_bits, ObjGroupProxyType + >(id); + if (not include_node) { + objgroup::proxy::ObjGroupProxy::setNode(proxy, 0); + } + return proxy; +} + +}} /* end namespace vt::elm */ diff --git a/src/vt/elm/elm_id_bits.h b/src/vt/elm/elm_id_bits.h new file mode 100644 index 0000000000..4dab5c5c0d --- /dev/null +++ b/src/vt/elm/elm_id_bits.h @@ -0,0 +1,100 @@ +/* +//@HEADER +// ***************************************************************************** +// +// elm_id_bits.h +// DARMA/vt => Virtual Transport +// +// Copyright 2019-2021 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Questions? Contact darma@sandia.gov +// +// ***************************************************************************** +//@HEADER +*/ + +#if !defined INCLUDED_VT_ELM_ELM_ID_BITS_H +#define INCLUDED_VT_ELM_ELM_ID_BITS_H + +#include "vt/configs/types/types_type.h" +#include "vt/utils/bits/bits_common.h" +#include "vt/elm/elm_id.h" + +namespace vt { namespace elm { + +enum eElmIDControlBits { + ObjGroup = 0, /**< An objgroup element ID (non-migratable) */ + BareHandler = 1, /**< A bare handler element ID */ + CollectionNonMigratable = 2, /**< A non-migratable collection element */ + CollectionMigratable = 3 /**< A migratable collection element */ +}; + +static constexpr BitCountType const num_control_bits = 2; + +enum eElmIDProxyBitsObjGroup { + Control = 0, + ObjGroupID = num_control_bits +}; + +enum eElmIDProxyBitsNonObjGroup { + Control2 = 0, + Node = num_control_bits, + ID = eElmIDProxyBitsNonObjGroup::Node + BitCounterType::value +}; + +static constexpr BitCountType const elm_id_num_bits = + BitCounterType::value - (2 + BitCounterType::value); + +struct ElmIDBits { + static ElementIDStruct createCollection(bool migratable, NodeType curr_node); + static ElementIDStruct createObjGroup(ObjGroupProxyType proxy, NodeType node); + static ElementIDStruct createBareHandler(NodeType node); + + static ElementIDStruct createCollectionImpl( + bool migratable, ElementIDType seq_id, NodeType home_node, NodeType curr_node + ); + + static void setObjGroup( + ElementIDType& id, ObjGroupProxyType proxy, NodeType node + ); + static void setCollectionID( + ElementIDType& id, bool migratable, ElementIDType seq_id, NodeType node + ); + + static eElmIDControlBits getControlBits(ElementIDType id); + static bool isMigratable(ElementIDType id); + static NodeType getNode(ElementIDType id); + static ObjGroupProxyType getObjGroupProxy(ElementIDType id, bool include_node); +}; + +}} /* end namespace vt::elm */ + +#endif /*INCLUDED_VT_ELM_ELM_ID_BITS_H*/ diff --git a/src/vt/vrt/collection/balance/elm_stats.cc b/src/vt/elm/elm_stats.cc similarity index 86% rename from src/vt/vrt/collection/balance/elm_stats.cc rename to src/vt/elm/elm_stats.cc index 2417c96889..4a11b15176 100644 --- a/src/vt/vrt/collection/balance/elm_stats.cc +++ b/src/vt/elm/elm_stats.cc @@ -41,13 +41,12 @@ //@HEADER */ -#include "vt/config.h" -#include "vt/vrt/collection/balance/elm_stats.h" -#include "vt/timing/timing.h" +#if !defined INCLUDED_VT_ELM_ELM_STATS_CC +#define INCLUDED_VT_ELM_ELM_STATS_CC -#include +#include "vt/elm/elm_stats.h" -namespace vt { namespace vrt { namespace collection { namespace balance { +namespace vt { namespace elm { void ElementStats::startTime() { auto const start_time = timing::Timing::getCurrentTime(); @@ -78,8 +77,21 @@ void ElementStats::stopTime() { ); } +void ElementStats::sendToEntity( + ElementIDStruct to, ElementIDStruct from, double bytes +) { + elm::CommKey key(elm::CommKey::SendRecvTag{}, from, to, false); + sendComm(key, bytes); +} + +void ElementStats::sendComm(elm::CommKey key, double bytes) { + phase_comm_[cur_phase_][key].sendMsg(bytes); + subphase_comm_[cur_phase_].resize(cur_subphase_ + 1); + subphase_comm_[cur_phase_].at(cur_subphase_)[key].sendMsg(bytes); +} + void ElementStats::recvComm( - LBCommKey key, double bytes + elm::CommKey key, double bytes ) { phase_comm_[cur_phase_][key].receiveMsg(bytes); subphase_comm_[cur_phase_].resize(cur_subphase_ + 1); @@ -90,7 +102,7 @@ void ElementStats::recvObjData( ElementIDStruct pto, ElementIDStruct pfrom, double bytes, bool bcast ) { - LBCommKey key(LBCommKey::CollectionTag{}, pfrom, pto, bcast); + elm::CommKey key(elm::CommKey::CollectionTag{}, pfrom, pto, bcast); recvComm(key, bytes); } @@ -98,7 +110,7 @@ void ElementStats::recvFromNode( ElementIDStruct pto, NodeType from, double bytes, bool bcast ) { - LBCommKey key(LBCommKey::NodeToCollectionTag{}, from, pto, bcast); + elm::CommKey key(elm::CommKey::NodeToCollectionTag{}, from, pto, bcast); recvComm(key, bytes); } @@ -106,7 +118,7 @@ void ElementStats::recvToNode( NodeType to, ElementIDStruct pfrom, double bytes, bool bcast ) { - LBCommKey key(LBCommKey::CollectionToNodeTag{}, pfrom, to, bcast); + elm::CommKey key(elm::CommKey::CollectionToNodeTag{}, pfrom, to, bcast); recvComm(key, bytes); } @@ -183,6 +195,10 @@ TimeType ElementStats::getLoad(PhaseType phase, SubphaseType subphase) const { return total_load; } +std::vector const& ElementStats::getSubphaseTimes(PhaseType phase) { + return subphase_timings_[phase]; +} + CommMapType const& ElementStats::getComm(PhaseType const& phase) { auto const& phase_comm = phase_comm_[phase]; @@ -242,20 +258,6 @@ std::size_t ElementStats::getSubphaseCommPhaseCount() const { return subphase_comm_.size(); } -/*static*/ -void ElementStats::setFocusedSubPhase(VirtualProxyType collection, SubphaseType subphase) { - focused_subphase_[collection] = subphase; -} - -/*static*/ -SubphaseType ElementStats::getFocusedSubPhase(VirtualProxyType collection) { - auto i = focused_subphase_.find(collection); - if (i != focused_subphase_.end()) - return i->second; - else - return no_subphase; -} - -/*static*/ std::unordered_map ElementStats::focused_subphase_; +}} /* end namespace vt::elm */ -}}}} /* end namespace vt::vrt::collection::balance */ +#endif /*INCLUDED_VT_ELM_ELM_STATS_CC*/ diff --git a/src/vt/vrt/collection/balance/elm_stats.fwd.h b/src/vt/elm/elm_stats.fwd.h similarity index 86% rename from src/vt/vrt/collection/balance/elm_stats.fwd.h rename to src/vt/elm/elm_stats.fwd.h index b5b928d76e..7b1e19fa73 100644 --- a/src/vt/vrt/collection/balance/elm_stats.fwd.h +++ b/src/vt/elm/elm_stats.fwd.h @@ -41,15 +41,13 @@ //@HEADER */ -#if !defined INCLUDED_VT_VRT_COLLECTION_BALANCE_ELM_STATS_FWD_H -#define INCLUDED_VT_VRT_COLLECTION_BALANCE_ELM_STATS_FWD_H +#if !defined INCLUDED_VT_ELM_ELM_STATS_FWD_H +#define INCLUDED_VT_ELM_ELM_STATS_FWD_H -#include "vt/config.h" - -namespace vt { namespace vrt { namespace collection { namespace balance { +namespace vt { namespace elm { struct ElementStats; -}}}} /* end namespace vt::vrt::collection::balance */ +}} /* end namespace vt::elm */ -#endif /*INCLUDED_VT_VRT_COLLECTION_BALANCE_ELM_STATS_FWD_H*/ +#endif /*INCLUDED_VT_ELM_ELM_STATS_FWD_H*/ diff --git a/src/vt/vrt/collection/balance/elm_stats.h b/src/vt/elm/elm_stats.h similarity index 78% rename from src/vt/vrt/collection/balance/elm_stats.h rename to src/vt/elm/elm_stats.h index 2650fd7744..31bd5989da 100644 --- a/src/vt/vrt/collection/balance/elm_stats.h +++ b/src/vt/elm/elm_stats.h @@ -41,25 +41,21 @@ //@HEADER */ -#if !defined INCLUDED_VT_VRT_COLLECTION_BALANCE_ELM_STATS_H -#define INCLUDED_VT_VRT_COLLECTION_BALANCE_ELM_STATS_H - -#include "vt/config.h" -#include "vt/vrt/collection/balance/lb_common.h" -#include "vt/vrt/collection/balance/lb_comm.h" -#include "vt/vrt/collection/balance/elm_stats.fwd.h" -#include "vt/vrt/collection/balance/phase_msg.h" -#include "vt/vrt/collection/balance/stats_msg.h" -#include "vt/timing/timing.h" -#include "vt/vrt/collection/types/migratable.fwd.h" +#if !defined INCLUDED_VT_ELM_ELM_STATS_H +#define INCLUDED_VT_ELM_ELM_STATS_H -#include -#include -#include -#include +#include "vt/elm/elm_id.h" +#include "vt/elm/elm_comm.h" +#include "vt/timing/timing.h" namespace vt { namespace vrt { namespace collection { namespace balance { +struct NodeStats; + +}}}} /* end namespace vt::vrt::collection::balance */ + +namespace vt { namespace elm { + struct ElementStats { ElementStats() = default; ElementStats(ElementStats const&) = default; @@ -68,7 +64,11 @@ struct ElementStats { void startTime(); void stopTime(); void addTime(TimeType const& time); - void recvComm(LBCommKey key, double bytes); + + void sendToEntity(ElementIDStruct to, ElementIDStruct from, double bytes); + void sendComm(elm::CommKey key, double bytes); + + void recvComm(elm::CommKey key, double bytes); void recvObjData( ElementIDStruct to_perm, ElementIDStruct from_perm, double bytes, bool bcast @@ -89,6 +89,7 @@ struct ElementStats { CommMapType const& getComm(PhaseType const& phase); std::vector const& getSubphaseComm(PhaseType phase); + std::vector const& getSubphaseTimes(PhaseType phase); void setSubPhase(SubphaseType subphase); SubphaseType getSubPhase() const; @@ -98,18 +99,20 @@ struct ElementStats { std::size_t getSubphaseLoadPhaseCount() const; std::size_t getSubphaseCommPhaseCount() const; - static const constexpr SubphaseType no_subphase = std::numeric_limits::max(); - static void setFocusedSubPhase(VirtualProxyType collection, SubphaseType subphase); - static SubphaseType getFocusedSubPhase(VirtualProxyType collection); - template - void serialize(Serializer& s); - -public: - template - static void syncNextPhase(CollectStatsMsg* msg, ColT* col); - - friend struct collection::Migratable; + void serialize(Serializer& s) { + s | cur_time_started_; + s | cur_time_; + s | cur_phase_; + s | phase_timings_; + s | phase_comm_; + s | cur_subphase_; + s | subphase_timings_; + s | subphase_comm_; + } + + static const constexpr SubphaseType no_subphase = + std::numeric_limits::max(); protected: /** @@ -117,6 +120,8 @@ struct ElementStats { */ void releaseStatsFromUnneededPhases(PhaseType phase, unsigned int look_back); + friend struct vrt::collection::balance::NodeStats; + protected: bool cur_time_started_ = false; TimeType cur_time_ = 0.0; @@ -127,10 +132,8 @@ struct ElementStats { SubphaseType cur_subphase_ = 0; std::unordered_map> subphase_timings_ = {}; std::unordered_map> subphase_comm_ = {}; - - static std::unordered_map focused_subphase_; }; -}}}} /* end namespace vt::vrt::collection::balance */ +}} /* end namespace vt::elm */ -#endif /*INCLUDED_VT_VRT_COLLECTION_BALANCE_ELM_STATS_H*/ +#endif /*INCLUDED_VT_ELM_ELM_STATS_H*/ diff --git a/src/vt/messaging/active.cc b/src/vt/messaging/active.cc index 829efd3f01..e32d56051d 100644 --- a/src/vt/messaging/active.cc +++ b/src/vt/messaging/active.cc @@ -55,6 +55,9 @@ #include "vt/runtime/mpi_access.h" #include "vt/scheduler/scheduler.h" #include "vt/runnable/make_runnable.h" +#include "vt/vrt/collection/balance/node_stats.h" +#include "vt/phase/phase_manager.h" +#include "vt/elm/elm_id_bits.h" namespace vt { namespace messaging { @@ -149,6 +152,21 @@ ActiveMessenger::ActiveMessenger() }; } +void ActiveMessenger::startup() { + auto const this_node = theContext()->getNode(); + bare_handler_dummy_elm_id_for_lb_stats_ = + elm::ElmIDBits::createBareHandler(this_node); + +#if vt_check_enabled(lblite) + // Hook to collect statistics about objgroups + thePhase()->registerHookCollective(phase::PhaseHook::End, [this]{ + theNodeStats()->addNodeStats( + bare_handler_dummy_elm_id_for_lb_stats_, &bare_handler_stats_ + ); + }); +#endif +} + /*virtual*/ ActiveMessenger::~ActiveMessenger() { // Pop all extraneous epochs off the stack greater than 1 auto stack_size = epoch_stack_.size(); @@ -432,7 +450,15 @@ EventType ActiveMessenger::sendMsgBytes( } if (theContext()->getTask() != nullptr) { - theContext()->getTask()->send(dest, msg_size, is_bcast); + auto lb = theContext()->getTask()->get(); + if (lb) { + auto const already_recorded = + envelopeCommStatsRecordedAboveBareHandler(msg->env); + if (not already_recorded) { + auto dest_elm_id = elm::ElmIDBits::createBareHandler(dest); + theContext()->getTask()->send(dest_elm_id, msg_size); + } + } } return event_id; @@ -550,10 +576,6 @@ SendInfo ActiveMessenger::sendData( theTerm()->produce(term::any_epoch_sentinel,1,dest); theTerm()->hangDetectSend(); - if (theContext()->getTask() != nullptr) { - theContext()->getTask()->send(dest, num_bytes, false); - } - return SendInfo{event_id, send_tag, num}; } @@ -961,6 +983,7 @@ bool ActiveMessenger::prepareActiveMsgToRun( .withContinuation(cont) .withTag(tag) .withTDEpochFromMsg(is_term) + .withLBStats(&bare_handler_stats_, bare_handler_dummy_elm_id_for_lb_stats_) .enqueue(); if (is_term) { diff --git a/src/vt/messaging/active.h b/src/vt/messaging/active.h index e9bbc7abf5..55230bf7eb 100644 --- a/src/vt/messaging/active.h +++ b/src/vt/messaging/active.h @@ -62,6 +62,8 @@ #include "vt/trace/trace_common.h" #include "vt/utils/static_checks/functor.h" #include "vt/runtime/component/component_pack.h" +#include "vt/elm/elm_id.h" +#include "vt/elm/elm_stats.h" #if vt_check_enabled(trace_enabled) #include "vt/trace/trace_headers.h" @@ -336,9 +338,10 @@ struct ActiveMessenger : runtime::component::PollableComponent */ virtual ~ActiveMessenger(); - std::string name() override { return "ActiveMessenger"; } + void startup() override; + /** * \brief Mark a message as a termination message. * @@ -1764,6 +1767,10 @@ struct ActiveMessenger : runtime::component::PollableComponent // Diagnostic counters for counting forwarded messages diagnostic::CounterGauge amForwardCounterGauge; + +private: + elm::ElementIDStruct bare_handler_dummy_elm_id_for_lb_stats_ = {}; + elm::ElementStats bare_handler_stats_; }; }} // end namespace vt::messaging diff --git a/src/vt/messaging/envelope/envelope_base.h b/src/vt/messaging/envelope/envelope_base.h index f39c886ccb..28a4074b5e 100644 --- a/src/vt/messaging/envelope/envelope_base.h +++ b/src/vt/messaging/envelope/envelope_base.h @@ -101,6 +101,10 @@ struct ActiveEnvelope { // Used only for broadcast to default group // Determines whether message should also be sent to the sender bool deliver_bcast_to_sender : 1; + + /// Used to denote that the message's bare handlers shouldn't record + /// communication statistics due to redundancy + bool comm_stats_recorded_above_bare_handler : 1; }; }} /* end namespace vt::messaging */ diff --git a/src/vt/messaging/envelope/envelope_set.h b/src/vt/messaging/envelope/envelope_set.h index ec73ca7752..121a5bfefa 100644 --- a/src/vt/messaging/envelope/envelope_set.h +++ b/src/vt/messaging/envelope/envelope_set.h @@ -206,6 +206,19 @@ inline void envelopeSetTraceRuntimeEnabled(Env& env, bool is_trace_enabled); template inline void envelopeSetHasBeenSerialized(Env& env, bool has_been_serialized); +/** + * \brief Set whether this message shouldn't record bare handler communication + * stats for LB + * + * \param[in,out] env the envelope + * \param[in] comm_stats_recorded_above_bare_handler value indicating message + * shouldn't record bare handler stats + */ +template +inline void envelopeSetCommStatsRecordedAboveBareHandler( + Env& env, bool comm_stats_recorded_above_bare_handler +); + /** * \brief Set whether this message's envelope is locked. * diff --git a/src/vt/messaging/envelope/envelope_set.impl.h b/src/vt/messaging/envelope/envelope_set.impl.h index 1463aed406..a167a00c23 100644 --- a/src/vt/messaging/envelope/envelope_set.impl.h +++ b/src/vt/messaging/envelope/envelope_set.impl.h @@ -151,6 +151,14 @@ inline void envelopeSetHasBeenSerialized(Env& env, bool has_been_serialized) { reinterpret_cast(&env)->has_been_serialized = has_been_serialized; } +template +inline void envelopeSetCommStatsRecordedAboveBareHandler( + Env& env, bool comm_stats_recorded_above_bare_handler +) { + reinterpret_cast(&env)->comm_stats_recorded_above_bare_handler = + comm_stats_recorded_above_bare_handler; +} + template inline void envelopeSetIsLocked(Env& env, bool is_locked) { reinterpret_cast(&env)->is_locked = is_locked; diff --git a/src/vt/messaging/envelope/envelope_setup.impl.h b/src/vt/messaging/envelope/envelope_setup.impl.h index 1622206ab8..9a4f9058be 100644 --- a/src/vt/messaging/envelope/envelope_setup.impl.h +++ b/src/vt/messaging/envelope/envelope_setup.impl.h @@ -75,6 +75,7 @@ inline void envelopeInit(Env& env) { envelopeSetTraceEvent(env, trace::no_trace_event); #endif envelopeSetHasBeenSerialized(env, false); + envelopeSetCommStatsRecordedAboveBareHandler(env, false); } inline void envelopeInitEmpty(Envelope& env) { diff --git a/src/vt/messaging/envelope/envelope_test.h b/src/vt/messaging/envelope/envelope_test.h index dd87d1a959..a598b8185e 100644 --- a/src/vt/messaging/envelope/envelope_test.h +++ b/src/vt/messaging/envelope/envelope_test.h @@ -136,6 +136,15 @@ inline bool envelopeHasBeenSerialized(Env& env); template inline bool envelopeIsLocked(Env& env); +/** + * \brief Test if an envelope indicates that bare handlers shouldn't record LB + * comm stats + * + * \param[in] env the envelope + */ +template +inline bool envelopeCommStatsRecordedAboveBareHandler(Env& env); + }} //end namespace vt::messaging #include "vt/messaging/envelope/envelope_test.impl.h" diff --git a/src/vt/messaging/envelope/envelope_test.impl.h b/src/vt/messaging/envelope/envelope_test.impl.h index 71f8337986..94242768d2 100644 --- a/src/vt/messaging/envelope/envelope_test.impl.h +++ b/src/vt/messaging/envelope/envelope_test.impl.h @@ -97,6 +97,12 @@ inline bool envelopeIsLocked(Env& env) { return reinterpret_cast(&env)->is_locked; } +template +inline bool envelopeCommStatsRecordedAboveBareHandler(Env& env) { + return reinterpret_cast(&env)-> + comm_stats_recorded_above_bare_handler; +} + }} //end namespace vt::messaging #endif /*INCLUDED_VT_MESSAGING_ENVELOPE_ENVELOPE_TEST_IMPL_H*/ diff --git a/src/vt/objgroup/holder/holder_base.h b/src/vt/objgroup/holder/holder_base.h index d92a961bba..428ae76110 100644 --- a/src/vt/objgroup/holder/holder_base.h +++ b/src/vt/objgroup/holder/holder_base.h @@ -46,16 +46,32 @@ #include "vt/config.h" #include "vt/objgroup/common.h" +#include "vt/elm/elm_id.h" +#include "vt/elm/elm_stats.h" namespace vt { namespace objgroup { namespace holder { struct HolderBase { + using ElmIDType = elm::ElementIDStruct; + using ElementStatsType = elm::ElementStats; + virtual ~HolderBase() = default; virtual bool exists() = 0; virtual void* getPtr() = 0; template - void serialize(Serializer& s) {} + void serialize(Serializer& s) { + s | stats_; + s | elm_id_; + } + + ElmIDType getElmID() const { return elm_id_; } + void setElmID(ElmIDType in_elm_id) { elm_id_ = in_elm_id; } + ElementStatsType& getStats() { return stats_; } + +protected: + ElementStatsType stats_; + ElmIDType elm_id_ = {}; }; template diff --git a/src/vt/objgroup/manager.cc b/src/vt/objgroup/manager.cc index 7a8fb9b6a1..10efebb61e 100644 --- a/src/vt/objgroup/manager.cc +++ b/src/vt/objgroup/manager.cc @@ -49,9 +49,32 @@ #include "vt/context/context.h" #include "vt/messaging/message/smart_ptr.h" #include "vt/runnable/make_runnable.h" +#include "vt/elm/elm_id.h" +#include "vt/vrt/collection/balance/node_stats.h" +#include "vt/phase/phase_manager.h" +#include "vt/elm/elm_id_bits.h" namespace vt { namespace objgroup { +void ObjGroupManager::startup() { +#if vt_check_enabled(lblite) + // Hook to collect statistics about objgroups + thePhase()->registerHookCollective(phase::PhaseHook::End, []{ + auto& objs = theObjGroup()->objs_; + for (auto&& obj : objs) { + auto holder = obj.second.get(); + auto const& elm_id = holder->getElmID(); + if (elm_id.id != elm::no_element_id) { + auto proxy = elm::ElmIDBits::getObjGroupProxy(elm_id.id, false); + vtAssertExpr(proxy == obj.first); + theNodeStats()->registerObjGroupInfo(elm_id, obj.first); + theNodeStats()->addNodeStats(elm_id, &holder->getStats()); + } + } + }); +#endif +} + proxy::DefaultProxyType ObjGroupManager::getDefault() const { return proxy::DefaultProxyType{}; } @@ -113,6 +136,51 @@ ObjGroupProxyType ObjGroupManager::makeCollectiveImpl( return proxy; } +ObjGroupManager::HolderBaseType* ObjGroupManager::getHolderBase(HandlerType han) { + auto const ctrl = HandlerManager::getHandlerControl(han); + auto const type_idx = auto_registry::getAutoHandlerObjTypeIdx(han); + auto const node = 0; + auto const proxy = proxy::ObjGroupProxy::create(ctrl, type_idx, node, true); + vt_debug_print( + normal, objgroup, + "getHolderBase: type_idx={:x}, ctrl={:x}, han={:x}, proxy={:x}\n", + type_idx, ctrl, han, proxy + ); + auto iter = objs_.find(proxy); + if (iter != objs_.end()) { + return iter->second.get(); + } else { + for (auto&& elm : derived_to_bases_) { + for (auto&& base : elm.second) { + if (base == proxy) { + auto const derived = elm.first; + auto iter2 = objs_.find(derived); + if (iter2 != objs_.end()) { + return iter2->second.get(); + } + } + } + } + } + return nullptr; +} + +namespace detail { +holder::HolderBase* getHolderBase(HandlerType handler) { + return theObjGroup()->getHolderBase(handler); +} +} /* end namespace detail */ + +elm::ElementIDStruct ObjGroupManager::getNextElm(ObjGroupProxyType proxy) { + // Avoid startup races + if (theNodeStats()) { + auto const this_node = theContext()->getNode(); + return elm::ElmIDBits::createObjGroup(proxy, this_node); + } else { + return elm::ElementIDStruct{}; + } +} + void dispatchObjGroup(MsgSharedPtr msg, HandlerType han) { vt_debug_print( verbose, objgroup, @@ -121,13 +189,4 @@ void dispatchObjGroup(MsgSharedPtr msg, HandlerType han) { return theObjGroup()->dispatch(msg,han); } -void scheduleMsg( - MsgSharedPtr msg, HandlerType han, EpochType epoch -) { - auto const node = theContext()->getNode(); - runnable::makeRunnable(msg, true, han, node) - .withTDEpoch(epoch) - .enqueue(); -} - }} /* end namespace vt::objgroup */ diff --git a/src/vt/objgroup/manager.fwd.h b/src/vt/objgroup/manager.fwd.h index 180962f51b..2a423fe08f 100644 --- a/src/vt/objgroup/manager.fwd.h +++ b/src/vt/objgroup/manager.fwd.h @@ -49,8 +49,16 @@ namespace vt { namespace objgroup { +namespace holder { +struct HolderBase; +} /* end namespace holder */ + struct ObjGroupManager; +namespace detail { +holder::HolderBase* getHolderBase(HandlerType handler); +} /* end namespace detail */ + void dispatchObjGroup(MsgSharedPtr msg, HandlerType han); template @@ -59,9 +67,6 @@ template void invoke(messaging::MsgPtrThief msg, HandlerType han, NodeType node); template void broadcast(MsgSharedPtr msg, HandlerType han); -void scheduleMsg( - MsgSharedPtr msg, HandlerType han, EpochType epoch -); }} /* end namespace vt::objgroup */ diff --git a/src/vt/objgroup/manager.h b/src/vt/objgroup/manager.h index 271d0d36b9..55ae2daf27 100644 --- a/src/vt/objgroup/manager.h +++ b/src/vt/objgroup/manager.h @@ -56,6 +56,7 @@ #include "vt/messaging/message/message.h" #include "vt/messaging/message/smart_ptr.h" #include "vt/messaging/pending_send.h" +#include "vt/elm/elm_id.h" #include #include @@ -103,6 +104,8 @@ struct ObjGroupManager : runtime::component::Component { std::string name() override { return "ObjGroupManager"; } + void startup() override; + /* * Creation of a new object group across the distributed system. For now, * these use the default group which includes all the nodes in the @@ -397,10 +400,6 @@ struct ObjGroupManager : runtime::component::Component { */ ObjGroupProxyType getProxy(ObjGroupProxyType proxy); - friend void scheduleMsg( - MsgSharedPtr msg, HandlerType han, EpochType ep - ); - template void serialize(SerializerT& s) { s | cur_obj_id_ @@ -411,6 +410,9 @@ struct ObjGroupManager : runtime::component::Component { | derived_to_bases_; } + // Friend function to access the holder without including this header file + friend holder::HolderBase* detail::getHolderBase(HandlerType handler); + private: /** * \internal \brief Untyped system call to make a new collective objgroup @@ -445,6 +447,24 @@ struct ObjGroupManager : runtime::component::Component { template void regObjProxy(ObjT* obj, ObjGroupProxyType proxy); + /** + * \internal \brief Get the holder for an objgroup from a handler + * + * \param[in] han the handler + * + * \return the base holder + */ + HolderBaseType* getHolderBase(HandlerType han); + + /** + * \internal \brief Get the next element ID from \c NodeStats + * + * \param[in] proxy the objgroup proxy + * + * \return the next element ID + */ + elm::ElementIDStruct getNextElm(ObjGroupProxyType proxy); + private: /// The current obj ID, sequential on each node for collective construction std::unordered_map cur_obj_id_; diff --git a/src/vt/objgroup/manager.impl.h b/src/vt/objgroup/manager.impl.h index b833de6b29..0fa8745e10 100644 --- a/src/vt/objgroup/manager.impl.h +++ b/src/vt/objgroup/manager.impl.h @@ -58,6 +58,7 @@ #include "vt/collective/collective_alg.h" #include "vt/messaging/active.h" #include "vt/runnable/invoke.h" +#include "vt/elm/elm_id_bits.h" #include @@ -107,6 +108,10 @@ ObjGroupManager::makeCollectiveObj(ObjT* obj, HolderBasePtrType holder) { auto const obj_type_idx = registry::makeObjIdx(); auto const obj_ptr = reinterpret_cast(obj); auto const proxy = makeCollectiveImpl(std::move(holder),obj_type_idx,obj_ptr); + auto iter = objs_.find(proxy); + vtAssert(iter != objs_.end(), "Obj must exist on this node"); + HolderBaseType* h = iter->second.get(); + h->setElmID(getNextElm(proxy)); vt_debug_print( terse, objgroup, "makeCollectiveObj: obj_type_idx={}, proxy={:x}\n", @@ -254,11 +259,23 @@ void ObjGroupManager::send(ProxyElmType proxy, MsgSharedPtr msg) { auto const dest_node = proxy.getNode(); auto const ctrl = proxy::ObjGroupProxy::getID(proxy_bits); auto const han = auto_registry::makeAutoHandlerObjGroup(ctrl); + + // set bit so it isn't recorded as it routes through bare + // handlers + envelopeSetCommStatsRecordedAboveBareHandler(msg->env, true); + + if (theContext()->getTask() != nullptr) { + auto dest_elm_id = elm::ElmIDBits::createObjGroup(proxy_bits, dest_node); + auto const num_bytes = serialization::MsgSizer::get(msg.get()); + theContext()->getTask()->send(dest_elm_id, num_bytes); + } + vt_debug_print( terse, objgroup, "ObjGroupManager::send: proxy={:x}, node={}, ctrl={:x}, han={:x}\n", proxy_bits, dest_node, ctrl, han ); + send(msg,han,dest_node); } diff --git a/src/vt/objgroup/manager.static.h b/src/vt/objgroup/manager.static.h index 64b15fe80e..1de65daeb4 100644 --- a/src/vt/objgroup/manager.static.h +++ b/src/vt/objgroup/manager.static.h @@ -46,6 +46,7 @@ #include "vt/config.h" #include "vt/objgroup/common.h" +#include "vt/objgroup/holder/holder_base.h" #include "vt/messaging/active.h" #include "vt/runnable/make_runnable.h" @@ -59,10 +60,17 @@ void send(MsgSharedPtr msg, HandlerType han, NodeType dest_node) { if (dest_node != this_node) { theMsg()->sendMsg(dest_node, han,msg, no_tag); } else { - // Get the current epoch for the message + // Get the current epoch for the message auto const cur_epoch = theMsg()->setupEpochMsg(msg); - // Schedule the work of dispatching the message handler for later - scheduleMsg(msg.template toVirtual(),han,cur_epoch); + + auto holder = detail::getHolderBase(han); + auto const& elm_id = holder->getElmID(); + auto stats = &holder->getStats(); + + runnable::makeRunnable(msg, true, han, this_node) + .withTDEpoch(cur_epoch) + .withLBStats(stats, elm_id) + .enqueue(); } } diff --git a/src/vt/objgroup/proxy/proxy_bits.h b/src/vt/objgroup/proxy/proxy_bits.h index 54bc5aabb5..f78c037f92 100644 --- a/src/vt/objgroup/proxy/proxy_bits.h +++ b/src/vt/objgroup/proxy/proxy_bits.h @@ -57,16 +57,21 @@ static constexpr BitCountType const objgrp_id_num_bits = BitCounterType::value; static constexpr BitCountType const objgrp_proxy_num_bits = BitCounterType::value; + +// Remove two extra bits for ElementIDStruct for the control bits static constexpr BitCountType const objgrp_idx_num_bits = objgrp_proxy_num_bits - - (objgrp_is_collective_num_bits + objgrp_node_num_bits + objgrp_id_num_bits); + (objgrp_is_collective_num_bits + + objgrp_control_num_bits + + objgrp_node_num_bits + + objgrp_id_num_bits + 2); enum eObjGroupProxyBits { ObjGroup = 0, Collective = eObjGroupProxyBits::ObjGroup + objgrp_control_num_bits, Node = eObjGroupProxyBits::Collective + objgrp_is_collective_num_bits, - TypeIdx = eObjGroupProxyBits::Node + objgrp_idx_num_bits, - ID = eObjGroupProxyBits::TypeIdx + objgrp_node_num_bits + TypeIdx = eObjGroupProxyBits::Node + objgrp_node_num_bits, + ID = eObjGroupProxyBits::TypeIdx + objgrp_idx_num_bits }; struct ObjGroupProxy { diff --git a/src/vt/runnable/make_runnable.h b/src/vt/runnable/make_runnable.h index d472c82e35..5b8ccd8527 100644 --- a/src/vt/runnable/make_runnable.h +++ b/src/vt/runnable/make_runnable.h @@ -185,8 +185,19 @@ struct RunnableMaker { */ template RunnableMaker&& withLBStatsVoidMsg(ElmT* elm) { + return withLBStats(&elm->getStats(), elm->getElmID()); + } + + /** + * \brief Add LB stats for instrumentation directly with element ID and stats + * + * \param[in] stats the stats + * \param[in] elm_id the element ID + */ + template + RunnableMaker&& withLBStats(StatsT* stats, T elm_id) { #if vt_check_enabled(lblite) - impl_->template addContext(elm); + impl_->template addContext(stats, elm_id); #endif return std::move(*this); } diff --git a/src/vt/runnable/runnable.cc b/src/vt/runnable/runnable.cc index 700eba07c1..a867cc4d6f 100644 --- a/src/vt/runnable/runnable.cc +++ b/src/vt/runnable/runnable.cc @@ -222,9 +222,9 @@ void RunnableNew::resume() { } } -void RunnableNew::send(NodeType dest, MsgSizeType size, bool bcast) { +void RunnableNew::send(elm::ElementIDStruct elm, MsgSizeType bytes) { for (auto&& ctx : contexts_) { - ctx->send(dest, size, bcast); + ctx->send(elm, bytes); } } diff --git a/src/vt/runnable/runnable.h b/src/vt/runnable/runnable.h index 0943c6e65e..3634fa7e57 100644 --- a/src/vt/runnable/runnable.h +++ b/src/vt/runnable/runnable.h @@ -46,6 +46,7 @@ #include "vt/messaging/message/smart_ptr.h" #include "vt/context/runnable_context/base.h" +#include "vt/elm/elm_id.h" // fwd-declarations for the element types namespace vt { namespace vrt { @@ -188,11 +189,10 @@ struct RunnableNew { * \brief Loop through all contexts add run the \c send() method associated * with this runnable * - * \param[in] dest the destination node for the send - * \param[in] size the message size - * \param[in] bcast whether it's a broadcast + * \param[in] dest the destination element for the send + * \param[in] bytes the message size */ - void send(NodeType dest, MsgSizeType size, bool bcast); + void send(elm::ElementIDStruct elm, MsgSizeType bytes); /** * \brief Get a context object by the type \c T diff --git a/src/vt/termination/interval/interval.h b/src/vt/termination/interval/interval.h index 0660d72bf2..cbe7b38c8b 100644 --- a/src/vt/termination/interval/interval.h +++ b/src/vt/termination/interval/interval.h @@ -46,6 +46,10 @@ #include "vt/config.h" +#include + +#include + namespace vt { namespace term { namespace interval { /* diff --git a/src/vt/vrt/collection/balance/baselb/baselb.cc b/src/vt/vrt/collection/balance/baselb/baselb.cc index e2aefcf8d2..615b89944a 100644 --- a/src/vt/vrt/collection/balance/baselb/baselb.cc +++ b/src/vt/vrt/collection/balance/baselb/baselb.cc @@ -46,7 +46,6 @@ #include "vt/config.h" #include "vt/vrt/collection/balance/baselb/baselb.h" -#include "vt/vrt/collection/balance/lb_comm.h" #include "vt/vrt/collection/balance/read_lb.h" #include "vt/vrt/collection/balance/lb_invoke/lb_manager.h" #include "vt/vrt/collection/balance/node_stats.h" @@ -251,10 +250,6 @@ void BaseLB::finalize(CountMsg* msg) { } } -NodeType BaseLB::objGetNode(ObjIDType const id) const { - return balance::objGetNode(id); -} - }}}} /* end namespace vt::vrt::collection::lb */ #endif /*INCLUDED_VT_VRT_COLLECTION_BALANCE_BASELB_BASELB_CC*/ diff --git a/src/vt/vrt/collection/balance/baselb/baselb.h b/src/vt/vrt/collection/balance/baselb/baselb.h index 6bf6c50ff7..605351d3a9 100644 --- a/src/vt/vrt/collection/balance/baselb/baselb.h +++ b/src/vt/vrt/collection/balance/baselb/baselb.h @@ -47,7 +47,7 @@ #include "vt/config.h" #include "vt/vrt/collection/balance/lb_common.h" #include "vt/vrt/collection/balance/baselb/baselb_msgs.h" -#include "vt/vrt/collection/balance/lb_comm.h" +#include "vt/elm/elm_comm.h" #include "vt/vrt/collection/balance/read_lb.h" #include "vt/objgroup/headers.h" @@ -67,7 +67,7 @@ namespace lb { struct BaseLB { using ObjIDType = balance::ElementIDStruct; using ElementLoadType = std::unordered_map; - using ElementCommType = balance::CommMapType; + using ElementCommType = elm::CommMapType; using TransferDestType = std::tuple; using TransferVecType = std::vector; using TransferType = std::map; @@ -114,7 +114,6 @@ struct BaseLB { ); static LoadType loadMilli(LoadType const& load); - NodeType objGetNode(ObjIDType const id) const; void notifyCurrentHostNodeOfObjectsDeparting( TransferMsg* msg diff --git a/src/vt/vrt/collection/balance/baselb/load_sampler.cc b/src/vt/vrt/collection/balance/baselb/load_sampler.cc index 0fa25bc8bf..7b4d592443 100644 --- a/src/vt/vrt/collection/balance/baselb/load_sampler.cc +++ b/src/vt/vrt/collection/balance/baselb/load_sampler.cc @@ -53,13 +53,15 @@ void LoadSamplerBaseLB::buildHistogram() { ); auto const& load_milli = loadMilli(load); auto const& bin = histogramSample(load_milli); - obj_sample[bin].push_back(obj); + if (obj.isMigratable()) { + obj_sample[bin].push_back(obj); + } vt_debug_print( verbose, lb, "\t buildHistogram: obj={}, home={}, load={}, " "load_milli={}, bin={}\n", - obj.id, obj.home_node, load, load_milli, bin + obj.id, obj.getHomeNode(), load, load_milli, bin ); } } diff --git a/src/vt/vrt/collection/balance/col_stats.cc b/src/vt/vrt/collection/balance/col_stats.cc new file mode 100644 index 0000000000..37aeaf7341 --- /dev/null +++ b/src/vt/vrt/collection/balance/col_stats.cc @@ -0,0 +1,72 @@ +/* +//@HEADER +// ***************************************************************************** +// +// col_stats.cc +// DARMA/vt => Virtual Transport +// +// Copyright 2019-2021 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Questions? Contact darma@sandia.gov +// +// ***************************************************************************** +//@HEADER +*/ + +#include "vt/config.h" +#include "vt/vrt/collection/balance/col_stats.h" +#include "vt/timing/timing.h" + +#include + +namespace vt { namespace vrt { namespace collection { namespace balance { + +/*static*/ +void CollectionStats::setFocusedSubPhase( + VirtualProxyType collection, SubphaseType subphase +) { + focused_subphase_[collection] = subphase; +} + +/*static*/ +SubphaseType CollectionStats::getFocusedSubPhase(VirtualProxyType collection) { + auto i = focused_subphase_.find(collection); + if (i != focused_subphase_.end()) + return i->second; + else + return no_subphase; +} + +/*static*/ +std::unordered_map +CollectionStats::focused_subphase_; + +}}}} /* end namespace vt::vrt::collection::balance */ diff --git a/src/vt/vrt/collection/balance/col_stats.h b/src/vt/vrt/collection/balance/col_stats.h new file mode 100644 index 0000000000..20f3f00816 --- /dev/null +++ b/src/vt/vrt/collection/balance/col_stats.h @@ -0,0 +1,83 @@ +/* +//@HEADER +// ***************************************************************************** +// +// col_stats.h +// DARMA/vt => Virtual Transport +// +// Copyright 2019-2021 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Questions? Contact darma@sandia.gov +// +// ***************************************************************************** +//@HEADER +*/ + +#if !defined INCLUDED_VT_VRT_COLLECTION_BALANCE_COL_STATS_H +#define INCLUDED_VT_VRT_COLLECTION_BALANCE_COL_STATS_H + +#include "vt/config.h" +#include "vt/elm/elm_stats.h" +#include "vt/elm/elm_comm.h" +#include "vt/vrt/collection/balance/lb_common.h" +#include "vt/vrt/collection/balance/phase_msg.h" +#include "vt/vrt/collection/balance/stats_msg.h" +#include "vt/vrt/collection/types/migratable.fwd.h" + +#include +#include +#include +#include + +namespace vt { namespace vrt { namespace collection { namespace balance { + +struct CollectionStats : elm::ElementStats { + static void setFocusedSubPhase(VirtualProxyType collection, SubphaseType subphase); + static SubphaseType getFocusedSubPhase(VirtualProxyType collection); + + template + void serialize(Serializer& s) { + elm::ElementStats::serialize(s); + } + +public: + template + static void syncNextPhase(CollectStatsMsg* msg, ColT* col); + + friend struct collection::Migratable; + +protected: + static std::unordered_map focused_subphase_; +}; + +}}}} /* end namespace vt::vrt::collection::balance */ + +#endif /*INCLUDED_VT_VRT_COLLECTION_BALANCE_COL_STATS_H*/ diff --git a/src/vt/vrt/collection/balance/elm_stats.impl.h b/src/vt/vrt/collection/balance/col_stats.impl.h similarity index 68% rename from src/vt/vrt/collection/balance/elm_stats.impl.h rename to src/vt/vrt/collection/balance/col_stats.impl.h index 26d9deb4a2..06654a6628 100644 --- a/src/vt/vrt/collection/balance/elm_stats.impl.h +++ b/src/vt/vrt/collection/balance/col_stats.impl.h @@ -2,7 +2,7 @@ //@HEADER // ***************************************************************************** // -// elm_stats.impl.h +// col_stats.impl.h // DARMA/vt => Virtual Transport // // Copyright 2019-2021 National Technology & Engineering Solutions of Sandia, LLC @@ -41,11 +41,11 @@ //@HEADER */ -#if !defined INCLUDED_VT_VRT_COLLECTION_BALANCE_ELM_STATS_IMPL_H -#define INCLUDED_VT_VRT_COLLECTION_BALANCE_ELM_STATS_IMPL_H +#if !defined INCLUDED_VT_VRT_COLLECTION_BALANCE_COL_STATS_IMPL_H +#define INCLUDED_VT_VRT_COLLECTION_BALANCE_COL_STATS_IMPL_H #include "vt/config.h" -#include "vt/vrt/collection/balance/elm_stats.h" +#include "vt/vrt/collection/balance/col_stats.h" #include "vt/vrt/collection/balance/phase_msg.h" #include "vt/vrt/collection/balance/stats_msg.h" #include "vt/vrt/collection/balance/lb_type.h" @@ -59,21 +59,9 @@ namespace vt { namespace vrt { namespace collection { namespace balance { -template -void ElementStats::serialize(Serializer& s) { - s | cur_time_started_; - s | cur_time_; - s | cur_phase_; - s | phase_timings_; - s | phase_comm_; - s | cur_subphase_; - s | subphase_timings_; - s | subphase_comm_; -} - template /*static*/ -void ElementStats::syncNextPhase(CollectStatsMsg* msg, ColT* col) { +void CollectionStats::syncNextPhase(CollectStatsMsg* msg, ColT* col) { auto& stats = col->stats_; vt_debug_print( @@ -84,34 +72,20 @@ void ElementStats::syncNextPhase(CollectStatsMsg* msg, ColT* col) { ); vtAssert(stats.getPhase() == msg->getPhase(), "Phases must match"); - stats.updatePhase(1); - - auto const& cur_phase = msg->getPhase(); - auto const& untyped_proxy = col->getProxy(); - auto const& total_load = stats.getLoad(cur_phase, getFocusedSubPhase(untyped_proxy)); - auto const& comm = stats.getComm(cur_phase); - auto const& subphase_comm = stats.getSubphaseComm(cur_phase); - std::vector empty_sub_phase; - std::vector* subphase_loads = &empty_sub_phase; - auto iter = stats.subphase_timings_.find(cur_phase); - if (iter != stats.subphase_timings_.end()) { - subphase_loads = &iter->second; - } + auto const proxy = col->getProxy(); + auto const subphase = getFocusedSubPhase(proxy); + theNodeStats()->addNodeStats(col->elm_id_, &col->stats_, subphase); std::vector idx; for (index::NumDimensionsType i = 0; i < col->getIndex().ndims(); i++) { idx.push_back(static_cast(col->getIndex()[i])); } - theNodeStats()->addNodeStats( - col, cur_phase, total_load, *subphase_loads, comm, subphase_comm, idx - ); - - auto model = theLBManager()->getLoadModel(); - stats.releaseStatsFromUnneededPhases(cur_phase, model->getNumPastPhasesNeeded()); + auto migrate = [col](NodeType node){ col->migrate(node); }; + theNodeStats()->registerCollectionInfo(col->elm_id_, proxy, idx, migrate); } }}}} /* end namespace vt::vrt::collection::balance */ -#endif /*INCLUDED_VT_VRT_COLLECTION_BALANCE_ELM_STATS_IMPL_H*/ +#endif /*INCLUDED_VT_VRT_COLLECTION_BALANCE_COL_STATS_IMPL_H*/ diff --git a/src/vt/vrt/collection/balance/greedylb/greedylb_types.h b/src/vt/vrt/collection/balance/greedylb/greedylb_types.h index a6b885e6af..b6d7c8b4ce 100644 --- a/src/vt/vrt/collection/balance/greedylb/greedylb_types.h +++ b/src/vt/vrt/collection/balance/greedylb/greedylb_types.h @@ -75,9 +75,7 @@ struct GreedyRecord { ObjType getObj() const { return obj_; } private: - GreedyLBTypes::ObjIDType obj_ = { - 0, uninitialized_destination, uninitialized_destination - }; + GreedyLBTypes::ObjIDType obj_ = { elm::no_element_id, uninitialized_destination }; LoadType load_ = 0.0f; }; diff --git a/src/vt/vrt/collection/balance/lb_common.cc b/src/vt/vrt/collection/balance/lb_common.cc index 6ecb214ba5..f0d0285ab6 100644 --- a/src/vt/vrt/collection/balance/lb_common.cc +++ b/src/vt/vrt/collection/balance/lb_common.cc @@ -47,18 +47,8 @@ #include "vt/vrt/collection/balance/node_stats.h" #include "vt/scheduler/scheduler.h" -#include -#include - namespace vt { namespace vrt { namespace collection { namespace balance { -std::ostream& operator<<( - std::ostream& os, const ::vt::vrt::collection::balance::ElementIDStruct& id -) { - os << "(" << id.id << "," << id.home_node << "," << id.curr_node << ")"; - return os; -} - LoadSummary getObjectLoads(std::shared_ptr model, ElementIDStruct object, PhaseOffset when) { return getObjectLoads(model.get(), object, when); @@ -102,7 +92,7 @@ void applyReassignment(const std::shared_ptr &reass vt_debug_print( normal, lb, "migrateObjectTo, obj_id={}, home={}, from={}, to={}\n", - obj_id.id, obj_id.home_node, from, to + obj_id.id, obj_id.getHomeNode(), from, to ); theNodeStats()->migrateObjTo(obj_id, to); diff --git a/src/vt/vrt/collection/balance/lb_common.h b/src/vt/vrt/collection/balance/lb_common.h index dfe6bdcf1b..bd56bf744a 100644 --- a/src/vt/vrt/collection/balance/lb_common.h +++ b/src/vt/vrt/collection/balance/lb_common.h @@ -45,68 +45,22 @@ #define INCLUDED_VT_VRT_COLLECTION_BALANCE_LB_COMMON_H #include "vt/config.h" +#include "vt/elm/elm_id.h" +#include "vt/elm/elm_comm.h" #include "vt/timing/timing_type.h" #include "vt/messaging/message/message.h" -#include -#include -#include -#include #include - -#include +#include namespace vt { namespace vrt { namespace collection { namespace balance { -using ElementIDType = uint64_t; - -struct ElementIDStruct { - using isByteCopyable = std::true_type; - - ElementIDStruct() = default; - ElementIDStruct( - ElementIDType in_id, NodeType in_home_node, NodeType in_curr_node - ) : id(in_id), - home_node(in_home_node), - curr_node(in_curr_node) - { } - - // id must be unique across nodes - ElementIDType id = 0; - NodeType home_node = uninitialized_destination; - NodeType curr_node = uninitialized_destination; - - bool operator==(const ElementIDStruct& rhs) const { - return id == rhs.id; - } - - bool operator<(const ElementIDStruct& rhs) const { - return id < rhs.id; - } -}; - -std::ostream& operator<<( - std::ostream& os, const ::vt::vrt::collection::balance::ElementIDStruct& id -); - -static constexpr ElementIDType const no_element_id = 0; +using ElementIDStruct = elm::ElementIDStruct; +using ElementIDType = elm::ElementIDType; +using CommMapType = elm::CommMapType; -}}}} - -namespace std { - -template <> -struct hash { - size_t operator()(vt::vrt::collection::balance::ElementIDStruct const& in) const { - return std::hash()(in.id); - } -}; - -} /* end namespace std */ - -namespace vt { namespace vrt { namespace collection { -namespace balance { +static constexpr ElementIDType const no_element_id = elm::no_element_id; /** * \brief A description of the interval of interest for a modeled load query @@ -179,6 +133,7 @@ LoadSummary getObjectLoads(LoadModel* model, ElementIDStruct object, PhaseOffset when); LoadSummary getNodeLoads(std::shared_ptr model, PhaseOffset when); + } /* end namespace balance */ namespace lb { diff --git a/src/vt/vrt/collection/balance/lb_invoke/lb_manager.cc b/src/vt/vrt/collection/balance/lb_invoke/lb_manager.cc index 9d3e7d4682..ba155d29de 100644 --- a/src/vt/vrt/collection/balance/lb_invoke/lb_manager.cc +++ b/src/vt/vrt/collection/balance/lb_invoke/lb_manager.cc @@ -178,8 +178,8 @@ LBManager::runLB(LBProxyType base_proxy, PhaseType phase) { computeStatistics(model_, false, phase); }); - balance::CommMapType empty_comm; - balance::CommMapType const* comm = &empty_comm; + elm::CommMapType empty_comm; + elm::CommMapType const* comm = &empty_comm; auto iter = theNodeStats()->getNodeComm()->find(phase); if (iter != theNodeStats()->getNodeComm()->end()) { comm = &iter->second; @@ -437,8 +437,8 @@ void LBManager::computeStatistics( total_load += work; } - balance::CommMapType empty_comm; - balance::CommMapType const* comm_data = &empty_comm; + elm::CommMapType empty_comm; + elm::CommMapType const* comm_data = &empty_comm; auto iter = theNodeStats()->getNodeComm()->find(phase); if (iter != theNodeStats()->getNodeComm()->end()) { comm_data = &iter->second; @@ -465,7 +465,7 @@ void LBManager::computeStatistics( std::vector O_c; for (auto&& elm : *comm_data) { // Only count object-to-object direct edges in the O_c statistics - if (elm.first.cat_ == balance::CommCategory::SendRecv and not elm.first.selfEdge()) { + if (elm.first.cat_ == elm::CommCategory::SendRecv and not elm.first.selfEdge()) { O_c.emplace_back(LoadData{lb::Statistic::O_c, elm.second.bytes}); } } @@ -491,11 +491,11 @@ LBManager::reduceVec( } } -bool LBManager::isCollectiveComm(balance::CommCategory cat) const { +bool LBManager::isCollectiveComm(elm::CommCategory cat) const { bool is_collective = - cat == balance::CommCategory::Broadcast or - cat == balance::CommCategory::CollectionToNodeBcast or - cat == balance::CommCategory::NodeToCollectionBcast; + cat == elm::CommCategory::Broadcast or + cat == elm::CommCategory::CollectionToNodeBcast or + cat == elm::CommCategory::NodeToCollectionBcast; return is_collective; } diff --git a/src/vt/vrt/collection/balance/lb_invoke/lb_manager.h b/src/vt/vrt/collection/balance/lb_invoke/lb_manager.h index 473397ce9a..6e74c0d71a 100644 --- a/src/vt/vrt/collection/balance/lb_invoke/lb_manager.h +++ b/src/vt/vrt/collection/balance/lb_invoke/lb_manager.h @@ -219,7 +219,7 @@ struct LBManager : runtime::component::Component { balance::LoadData reduceVec( lb::Statistic stat, std::vector&& vec ) const; - bool isCollectiveComm(balance::CommCategory cat) const; + bool isCollectiveComm(elm::CommCategory cat) const; private: PhaseType cached_phase_ = no_lb_phase; diff --git a/src/vt/vrt/collection/balance/model/load_model.h b/src/vt/vrt/collection/balance/model/load_model.h index d03955713b..6700fc5d15 100644 --- a/src/vt/vrt/collection/balance/model/load_model.h +++ b/src/vt/vrt/collection/balance/model/load_model.h @@ -46,7 +46,7 @@ #include "vt/config.h" #include "vt/vrt/collection/balance/lb_common.h" -#include "vt/vrt/collection/balance/lb_comm.h" +#include "vt/elm/elm_comm.h" namespace vt { namespace vrt { namespace collection { namespace balance { diff --git a/src/vt/vrt/collection/balance/model/raw_data.h b/src/vt/vrt/collection/balance/model/raw_data.h index 8b4c6418dc..5a33c8042b 100644 --- a/src/vt/vrt/collection/balance/model/raw_data.h +++ b/src/vt/vrt/collection/balance/model/raw_data.h @@ -45,7 +45,7 @@ #define INCLUDED_VT_VRT_COLLECTION_BALANCE_MODEL_RAW_DATA_H #include "vt/vrt/collection/balance/model/load_model.h" -#include "vt/vrt/collection/balance/lb_comm.h" +#include "vt/elm/elm_comm.h" #include namespace vt { namespace vrt { namespace collection { namespace balance { diff --git a/src/vt/vrt/collection/balance/node_stats.cc b/src/vt/vrt/collection/balance/node_stats.cc index ff2f0f3440..cae053e981 100644 --- a/src/vt/vrt/collection/balance/node_stats.cc +++ b/src/vt/vrt/collection/balance/node_stats.cc @@ -50,6 +50,7 @@ #include "vt/runtime/runtime.h" #include "vt/utils/json/json_appender.h" #include "vt/vrt/collection/balance/stats_data.h" +#include "vt/elm/elm_stats.h" #include #include @@ -117,13 +118,11 @@ void NodeStats::startIterCleanup(PhaseType phase, unsigned int look_back) { // Clear migrate lambdas and proxy lookup since LB is complete NodeStats::node_migrate_.clear(); node_collection_lookup_.clear(); + node_objgroup_lookup_.clear(); } -ElementIDStruct NodeStats::getNextElm() { - auto const& this_node = theContext()->getNode(); - auto id = (next_elm_++ << 32) | this_node; - ElementIDStruct elm{id, this_node, this_node}; - return elm; +ElementIDType NodeStats::getNextElm() { + return next_elm_++; } void NodeStats::initialize() { @@ -188,24 +187,24 @@ void NodeStats::closeStatsFile() { } std::pair -getRecvSendDirection(CommKeyType const& comm) { +getRecvSendDirection(elm::CommKeyType const& comm) { switch (comm.cat_) { - case CommCategory::SendRecv: - case CommCategory::Broadcast: + case elm::CommCategory::SendRecv: + case elm::CommCategory::Broadcast: return std::make_pair(comm.toObj().id, comm.fromObj().id); - case CommCategory::NodeToCollection: - case CommCategory::NodeToCollectionBcast: + case elm::CommCategory::NodeToCollection: + case elm::CommCategory::NodeToCollectionBcast: return std::make_pair(comm.toObj().id, comm.fromNode()); - case CommCategory::CollectionToNode: - case CommCategory::CollectionToNodeBcast: + case elm::CommCategory::CollectionToNode: + case elm::CommCategory::CollectionToNodeBcast: return std::make_pair(comm.toNode(), comm.fromObj().id); // Comm stats are not recorded for local operations // this case is just to avoid warning of not handled enum - case CommCategory::CollectiveToCollectionBcast: - case CommCategory::LocalInvoke: + case elm::CommCategory::CollectiveToCollectionBcast: + case elm::CommCategory::LocalInvoke: return std::make_pair(ElementIDType{}, ElementIDType{}); } @@ -228,40 +227,53 @@ void NodeStats::outputStatsForPhase(PhaseType phase) { writer->addElm(*j); } -ElementIDStruct NodeStats::addNodeStats( - Migratable* col_elm, - PhaseType const& phase, TimeType const& time, - std::vector const& subphase_time, - CommMapType const& comm, std::vector const& subphase_comm, - std::vector const& index +void NodeStats::registerCollectionInfo( + ElementIDStruct id, VirtualProxyType proxy, + std::vector const& index, MigrateFnType migrate_fn ) { - // The ID struct is modified when a object is migrated into a node + // Add the index to the map + stats_->node_idx_[id] = std::make_tuple(proxy, index); + node_migrate_[id] = migrate_fn; + node_collection_lookup_[id] = proxy; +} - auto const obj_id = col_elm->elm_id_; +void NodeStats::registerObjGroupInfo( + ElementIDStruct id, ObjGroupProxyType proxy +) { + stats_->node_objgroup_[id] = proxy; + node_objgroup_lookup_[id] = proxy; +} +void NodeStats::addNodeStats( + ElementIDStruct id, elm::ElementStats* in, SubphaseType focused_subphase +) { vt_debug_print( normal, lb, - "NodeStats::addNodeStats: obj_id={}, phase={}, subphases={}, load={}\n", - obj_id, phase, subphase_time.size(), time + "NodeStats::addNodeStats: id={}\n", id ); - // Add the index to the map - stats_->node_idx_[obj_id] = std::make_tuple(col_elm->getProxy(), index); + auto const phase = in->getPhase(); + auto const& total_load = in->getLoad(phase, focused_subphase); auto &phase_data = stats_->node_data_[phase]; - auto elm_iter = phase_data.find(obj_id); + auto elm_iter = phase_data.find(id); vtAssert(elm_iter == phase_data.end(), "Must not exist"); + + auto& subphase_times = in->getSubphaseTimes(phase); + phase_data.emplace( std::piecewise_construct, - std::forward_as_tuple(obj_id), - std::forward_as_tuple(LoadSummary{time, subphase_time}) + std::forward_as_tuple(id), + std::forward_as_tuple(LoadSummary{total_load, subphase_times}) ); + auto const& comm = in->getComm(phase); auto &comm_data = stats_->node_comm_[phase]; for (auto&& c : comm) { comm_data[c.first] += c.second; } + auto const& subphase_comm = in->getSubphaseComm(phase); auto &subphase_comm_data = stats_->node_subphase_comm_[phase]; for (SubphaseType i = 0; i < subphase_comm.size(); i++) { for (auto& sp : subphase_comm[i]) { @@ -269,21 +281,10 @@ ElementIDStruct NodeStats::addNodeStats( } } - auto migrate_iter = node_migrate_.find(obj_id); - if (migrate_iter == node_migrate_.end()) { - node_migrate_.emplace( - std::piecewise_construct, - std::forward_as_tuple(obj_id), - std::forward_as_tuple([col_elm](NodeType node){ - col_elm->migrate(node); - }) - ); - } - - auto const col_proxy = col_elm->getProxy(); - node_collection_lookup_[obj_id] = col_proxy; + in->updatePhase(1); - return obj_id; + auto model = theLBManager()->getLoadModel(); + in->releaseStatsFromUnneededPhases(phase, model->getNumPastPhasesNeeded()); } VirtualProxyType NodeStats::getCollectionProxyForElement( @@ -296,4 +297,14 @@ VirtualProxyType NodeStats::getCollectionProxyForElement( return iter->second; } +ObjGroupProxyType NodeStats::getObjGroupProxyForElement( + ElementIDStruct obj_id +) const { + auto iter = node_objgroup_lookup_.find(obj_id); + if (iter == node_objgroup_lookup_.end()) { + return no_obj_group; + } + return iter->second; +} + }}}} /* end namespace vt::vrt::collection::balance */ diff --git a/src/vt/vrt/collection/balance/node_stats.h b/src/vt/vrt/collection/balance/node_stats.h index 1f4c905206..38a13d3447 100644 --- a/src/vt/vrt/collection/balance/node_stats.h +++ b/src/vt/vrt/collection/balance/node_stats.h @@ -46,7 +46,8 @@ #include "vt/config.h" #include "vt/vrt/collection/balance/lb_common.h" -#include "vt/vrt/collection/balance/lb_comm.h" +#include "vt/elm/elm_comm.h" +#include "vt/elm/elm_stats.fwd.h" #include "vt/vrt/collection/balance/phase_msg.h" #include "vt/vrt/collection/balance/stats_msg.h" #include "vt/vrt/collection/types/migratable.h" @@ -103,22 +104,36 @@ struct NodeStats : runtime::component::Component { static std::unique_ptr construct(); /** - * \internal \brief Add node statistics for local object + * \internal \brief Add collection element info * - * \param[in] col_elm the collection element pointer - * \param[in] phase the current phase - * \param[in] time the time the object took - * \param[in] comm the comm graph for the object + * \param[in] id the element ID + * \param[in] proxy the collection proxy * \param[in] index the index for the object + * \param[in] migrate_fn the migration function + */ + void registerCollectionInfo( + ElementIDStruct id, VirtualProxyType proxy, + std::vector const& index, MigrateFnType migrate_fn + ); + + /** + * \internal \brief Add objgroup element info * - * \return the ID struct for the object assigned for this phase + * \param[in] id the element ID + * \param[in] proxy the objgroup proxy */ - ElementIDStruct addNodeStats( - Migratable* col_elm, - PhaseType const& phase, TimeType const& time, - std::vector const& subphase_time, - CommMapType const& comm, std::vector const& subphase_comm, - std::vector const& index + void registerObjGroupInfo(ElementIDStruct id, ObjGroupProxyType proxy); + + /** + * \internal \brief Add statistics for element (non-collection) + * + * \param[in] id the element ID + * \param[in] in the stats + * \param[in] focused_subphase the focused subphase (optional) + */ + void addNodeStats( + ElementIDStruct id, elm::ElementStats* in, + SubphaseType focused_subphase = elm::ElementStats::no_subphase ); /** @@ -132,40 +147,18 @@ struct NodeStats : runtime::component::Component { void startIterCleanup(PhaseType phase, unsigned int look_back); /** - * \internal \brief Output stats file for given phase based on instrumented data - * - * The contents of the file consist of a series of records separated - * by newlines. Each record consists of comma separated fields. The - * first field of each record is a decimal integer phase which the - * record describes. + * \internal \brief Output stats file for given phase based on instrumented + * data * - * The first batch of records representing object workloads contain - * 5 fields. The first field is the phase, as above. The second - * field contains a unique object identifier, as a decimal - * integer. The third field contains the object's total workload - * during the phase, measured by elapsed time, and represented as a - * floating-point decimal number. The fourth field contains the - * number of subphases that made up the phase, as a decimal - * integer. The fifth field contains a "[]"-bracketed list of - * workloads, one decimal floating point value per subphase, - * separate by commas. - * - * The second batch of records representing communication graph - * edges contain 5 fields. The first field is the phase, as - * above. The second and third fields are the recipient and source - * of a communication, as decimal integers. The fourth field is the - * weight of the edge, representing the number of bytes transmitted - * between the end-points, as a decimal integer. The fifth field is - * the category of the communication, relating the sender and - * recipient and distinguishing point-to-point messages from - * broadcasts, as a decimal integer. + * This outputs statistics in JSON format that includes task timings, + * mappings, and communication. */ void outputStatsForPhase(PhaseType phase); /** * \internal \brief Generate the next object element ID for LB */ - ElementIDStruct getNextElm(); + ElementIDType getNextElm(); /** * \internal \brief Get stored object loads @@ -217,15 +210,35 @@ struct NodeStats : runtime::component::Component { */ VirtualProxyType getCollectionProxyForElement(ElementIDStruct obj_id) const; + /** + * \internal \brief Get the objgroup proxy for a given element ID + * + * \param[in] obj_id the ID struct for the element + * + * \return the objgroup proxy if the element is part of an objgroup; + * otherwise \c no_obj_group + */ + ObjGroupProxyType getObjGroupProxyForElement(ElementIDStruct obj_id) const; + void initialize() override; void finalize() override; void fatalError() override; + /** + * \brief Get the underlying stats data + * + * \warning For testing only! + * + * \return the stats data + */ + StatsData* getStatsData() { return stats_.get(); } + template void serialize(SerializerT& s) { s | proxy_ | node_migrate_ | node_collection_lookup_ + | node_objgroup_lookup_ | next_elm_ | created_dir_ | stats_; @@ -249,8 +262,10 @@ struct NodeStats : runtime::component::Component { std::unordered_map node_migrate_; /// Map from element ID to the collection's virtual proxy (untyped) std::unordered_map node_collection_lookup_; + /// Map from element ID to the objgroup's proxy (untyped) + std::unordered_map node_objgroup_lookup_; /// The current element ID - ElementIDType next_elm_; + ElementIDType next_elm_ = 1; /// Whether the stats directory has been created bool created_dir_ = false; /// The appender for outputting stat files in JSON format diff --git a/src/vt/vrt/collection/balance/randomlb/randomlb.cc b/src/vt/vrt/collection/balance/randomlb/randomlb.cc index 92b7b06b7d..ac970773f8 100644 --- a/src/vt/vrt/collection/balance/randomlb/randomlb.cc +++ b/src/vt/vrt/collection/balance/randomlb/randomlb.cc @@ -121,7 +121,9 @@ void RandomLB::runLB(TimeType) { // Sort the objects so we have a deterministic order over them std::set objs; for (auto obj : *load_model_) { - objs.insert(obj); + if (obj.isMigratable()) { + objs.insert(obj); + } } // we skip the first object to be certain we never end up with zero objects @@ -131,7 +133,7 @@ void RandomLB::runLB(TimeType) { vt_debug_print( terse, lb, "RandomLB: migrating obj={:x} home={} from={} to={}\n", - it->id, it->home_node, this_node, to_node + it->id, it->getHomeNode(), this_node, to_node ); migrateObjectTo(*it, to_node); } diff --git a/src/vt/vrt/collection/balance/rotatelb/rotatelb.cc b/src/vt/vrt/collection/balance/rotatelb/rotatelb.cc index 442dfebf17..deaebb72a6 100644 --- a/src/vt/vrt/collection/balance/rotatelb/rotatelb.cc +++ b/src/vt/vrt/collection/balance/rotatelb/rotatelb.cc @@ -81,7 +81,9 @@ void RotateLB::runLB(TimeType) { "\t RotateLB::migrating object to: obj={}, load={}, to_node={}\n", obj, load, next_node ); - migrateObjectTo(obj, next_node); + if (obj.isMigratable()) { + migrateObjectTo(obj, next_node); + } } } diff --git a/src/vt/vrt/collection/balance/stats_data.cc b/src/vt/vrt/collection/balance/stats_data.cc index 644505f2e3..b8c2742045 100644 --- a/src/vt/vrt/collection/balance/stats_data.cc +++ b/src/vt/vrt/collection/balance/stats_data.cc @@ -48,6 +48,26 @@ namespace vt { namespace vrt { namespace collection { namespace balance { +void StatsData::outputEntity(nlohmann::json& j, ElementIDStruct const& id) const { + j["type"] = "object"; + j["id"] = id.id; + j["home"] = id.getHomeNode(); + j["migratable"] = id.isMigratable(); + if (node_idx_.find(id) != node_idx_.end()) { + auto const& proxy_id = std::get<0>(node_idx_.find(id)->second); + auto const& idx_vec = std::get<1>(node_idx_.find(id)->second); + j["collection_id"] = proxy_id; + for (std::size_t x = 0; x < idx_vec.size(); x++) { + j["index"][x] = idx_vec[x]; + } + } else if (node_objgroup_.find(id) != node_objgroup_.end()) { + auto const& proxy_id = node_objgroup_.find(id)->second; + j["objgroup_id"] = proxy_id; + } else { + // bare handler + } +} + std::unique_ptr StatsData::toJson(PhaseType phase) const { using json = nlohmann::json; @@ -62,17 +82,7 @@ std::unique_ptr StatsData::toJson(PhaseType phase) const { j["tasks"][i]["resource"] = "cpu"; j["tasks"][i]["node"] = theContext()->getNode(); j["tasks"][i]["time"] = time; - j["tasks"][i]["entity"]["type"] = "object"; - j["tasks"][i]["entity"]["id"] = id.id; - j["tasks"][i]["entity"]["home"] = id.home_node; - if (node_idx_.find(id) != node_idx_.end()) { - auto const& proxy_id = std::get<0>(node_idx_.find(id)->second); - auto const& idx_vec = std::get<1>(node_idx_.find(id)->second); - j["tasks"][i]["entity"]["collection_id"] = proxy_id; - for (std::size_t x = 0; x < idx_vec.size(); x++) { - j["tasks"][i]["entity"]["index"][x] = idx_vec[x]; - } - } + outputEntity(j["tasks"][i]["entity"], id); auto const& subphase_times = elm.second.subphase_loads; std::size_t const subphases = subphase_times.size(); @@ -96,24 +106,20 @@ std::unique_ptr StatsData::toJson(PhaseType phase) const { j["communications"][i]["messages"] = volume.messages; switch(key.cat_) { - case CommCategory::Broadcast: - case CommCategory::SendRecv: { - if (key.cat_ == CommCategory::SendRecv) { + case elm::CommCategory::Broadcast: + case elm::CommCategory::SendRecv: { + if (key.cat_ == elm::CommCategory::SendRecv) { j["communications"][i]["type"] = "SendRecv"; } else { j["communications"][i]["type"] = "Broadcast"; } - j["communications"][i]["from"]["type"] = "object"; - j["communications"][i]["from"]["id"] = key.fromObj().id; - j["communications"][i]["from"]["home"] = key.fromObj().home_node; - j["communications"][i]["to"]["type"] = "object"; - j["communications"][i]["to"]["id"] = key.toObj().id; - j["communications"][i]["to"]["home"] = key.toObj().home_node; + outputEntity(j["communications"][i]["from"], key.fromObj()); + outputEntity(j["communications"][i]["to"], key.toObj()); break; } - case CommCategory::NodeToCollection: - case CommCategory::NodeToCollectionBcast: { - if (key.cat_ == CommCategory::NodeToCollection) { + case elm::CommCategory::NodeToCollection: + case elm::CommCategory::NodeToCollectionBcast: { + if (key.cat_ == elm::CommCategory::NodeToCollection) { j["communications"][i]["type"] = "NodeToCollection"; } else { j["communications"][i]["type"] = "NodeToCollectionBcast"; @@ -121,14 +127,12 @@ std::unique_ptr StatsData::toJson(PhaseType phase) const { j["communications"][i]["from"]["type"] = "node"; j["communications"][i]["from"]["id"] = key.fromNode(); - j["communications"][i]["to"]["type"] = "object"; - j["communications"][i]["to"]["id"] = key.toObj().id; - j["communications"][i]["to"]["home"] = key.toObj().home_node; + outputEntity(j["communications"][i]["to"], key.toObj()); break; } - case CommCategory::CollectionToNode: - case CommCategory::CollectionToNodeBcast: { - if (key.cat_ == CommCategory::CollectionToNode) { + case elm::CommCategory::CollectionToNode: + case elm::CommCategory::CollectionToNodeBcast: { + if (key.cat_ == elm::CommCategory::CollectionToNode) { j["communications"][i]["type"] = "CollectionToNode"; } else { j["communications"][i]["type"] = "CollectionToNodeBcast"; @@ -136,13 +140,11 @@ std::unique_ptr StatsData::toJson(PhaseType phase) const { j["communications"][i]["to"]["type"] = "node"; j["communications"][i]["to"]["id"] = key.toNode(); - j["communications"][i]["from"]["type"] = "object"; - j["communications"][i]["from"]["id"] = key.fromObj().id; - j["communications"][i]["from"]["home"] = key.fromObj().home_node; + outputEntity(j["communications"][i]["from"], key.fromObj()); break; } - case CommCategory::LocalInvoke: - case CommCategory::CollectiveToCollectionBcast: + case elm::CommCategory::LocalInvoke: + case elm::CommCategory::CollectiveToCollectionBcast: // not currently supported break; } @@ -178,14 +180,7 @@ StatsData::StatsData(nlohmann::json const& j) { auto object = task["entity"]["id"]; vtAssertExpr(object.is_number()); - NodeType home = uninitialized_destination; - if (task["entity"].find("home") != task["entity"].end()) { - auto home_json = task["entity"]["home"]; - vtAssertExpr(home_json.is_number()); - home = home_json; - } - - auto elm = ElementIDStruct{object, home, node}; + auto elm = ElementIDStruct{object, node}; this->node_data_[id][elm].whole_phase_load = time; if ( @@ -221,6 +216,9 @@ StatsData::StatsData(nlohmann::json const& j) { } } + using CommKey = elm::CommKey; + using CommVolume = elm::CommVolume; + if (phase.find("communications") != phase.end()) { auto comms = phase["communications"]; if (comms.is_array()) { @@ -238,26 +236,14 @@ StatsData::StatsData(nlohmann::json const& j) { auto from_object = comm["from"]["id"]; vtAssertExpr(from_object.is_number()); - NodeType from_home = uninitialized_destination; - if (comm["from"].find("home") != comm["from"].end()) { - auto home_json = comm["from"]["home"]; - vtAssertExpr(home_json.is_number()); - from_home = home_json; - } - auto from_elm = ElementIDStruct{from_object, from_home, this_node}; + auto from_elm = ElementIDStruct{from_object, this_node}; auto to_object = comm["to"]["id"]; vtAssertExpr(to_object.is_number()); - NodeType to_home = uninitialized_destination; - if (comm["to"].find("home") != comm["to"].end()) { - auto home_json = comm["to"]["home"]; - vtAssertExpr(home_json.is_number()); - to_home = home_json; - } - auto to_elm = ElementIDStruct{to_object, to_home, this_node}; + auto to_elm = ElementIDStruct{to_object, this_node}; - LBCommKey key( - LBCommKey::CollectionTag{}, + CommKey key( + CommKey::CollectionTag{}, from_elm, to_elm, type == "Broadcast" ); CommVolume vol{bytes, messages}; @@ -273,16 +259,10 @@ StatsData::StatsData(nlohmann::json const& j) { auto to_object = comm["to"]["id"]; vtAssertExpr(to_object.is_number()); - NodeType to_home = uninitialized_destination; - if (comm["to"].find("home") != comm["to"].end()) { - auto home_json = comm["to"]["home"]; - vtAssertExpr(home_json.is_number()); - to_home = home_json; - } - auto to_elm = ElementIDStruct{to_object, to_home, this_node}; + auto to_elm = ElementIDStruct{to_object, this_node}; - LBCommKey key( - LBCommKey::NodeToCollectionTag{}, + CommKey key( + CommKey::NodeToCollectionTag{}, static_cast(from_node), to_elm, type == "NodeToCollectionBcast" ); @@ -296,19 +276,13 @@ StatsData::StatsData(nlohmann::json const& j) { auto from_object = comm["from"]["id"]; vtAssertExpr(from_object.is_number()); - NodeType from_home = uninitialized_destination; - if (comm["from"].find("home") != comm["from"].end()) { - auto home_json = comm["from"]["home"]; - vtAssertExpr(home_json.is_number()); - from_home = home_json; - } - auto from_elm = ElementIDStruct{from_object, from_home, this_node}; + auto from_elm = ElementIDStruct{from_object, this_node}; auto to_node = comm["to"]["id"]; vtAssertExpr(to_node.is_number()); - LBCommKey key( - LBCommKey::CollectionToNodeTag{}, + CommKey key( + CommKey::CollectionToNodeTag{}, from_elm, static_cast(to_node), type == "CollectionToNodeBcast" ); diff --git a/src/vt/vrt/collection/balance/stats_data.h b/src/vt/vrt/collection/balance/stats_data.h index 244732a34e..2f50428b86 100644 --- a/src/vt/vrt/collection/balance/stats_data.h +++ b/src/vt/vrt/collection/balance/stats_data.h @@ -46,7 +46,7 @@ #include "vt/config.h" #include "vt/vrt/collection/balance/lb_common.h" -#include "vt/vrt/collection/balance/lb_comm.h" +#include "vt/elm/elm_comm.h" #include #include @@ -93,6 +93,15 @@ struct StatsData { */ void clear(); +private: + /** + * \brief Output an entity to json + * + * \param[in] j the json + * \param[in] elm_id the element to output + */ + void outputEntity(nlohmann::json& j, ElementIDStruct const& elm_id) const; + public: /// Node timings for each local object std::unordered_map node_data_; @@ -102,6 +111,8 @@ struct StatsData { std::unordered_map> node_subphase_comm_; /// Node indices for each ID along with the proxy ID std::unordered_map>> node_idx_; + /// Map from id to objgroup proxy + std::unordered_map node_objgroup_; }; }}}} /* end namespace vt::vrt::collection::balance */ diff --git a/src/vt/vrt/collection/balance/stats_restart_reader.cc b/src/vt/vrt/collection/balance/stats_restart_reader.cc index 55e98f8f27..66cbb65255 100644 --- a/src/vt/vrt/collection/balance/stats_restart_reader.cc +++ b/src/vt/vrt/collection/balance/stats_restart_reader.cc @@ -47,7 +47,6 @@ #include "vt/config.h" #include "vt/vrt/collection/balance/stats_restart_reader.h" #include "vt/objgroup/manager.h" -#include "vt/vrt/collection/balance/lb_comm.h" #include "vt/vrt/collection/balance/stats_data.h" #include "vt/utils/json/json_reader.h" #include "vt/utils/json/decompression_input_container.h" @@ -109,7 +108,9 @@ std::deque> StatsRestartReader::readIntoElementHistory( for (PhaseType phase = 0; phase < sd.node_data_.size(); phase++) { std::set buffer; for (auto const& obj : sd.node_data_.at(phase)) { - buffer.insert(obj.first.id); + if (obj.first.isMigratable()) { + buffer.insert(obj.first.id); + } } element_history.emplace_back(std::move(buffer)); } diff --git a/src/vt/vrt/collection/balance/statsmaplb/statsmaplb.cc b/src/vt/vrt/collection/balance/statsmaplb/statsmaplb.cc index c90fa12b4f..ca712419ff 100644 --- a/src/vt/vrt/collection/balance/statsmaplb/statsmaplb.cc +++ b/src/vt/vrt/collection/balance/statsmaplb/statsmaplb.cc @@ -58,7 +58,7 @@ void StatsMapLB::runLB(TimeType) { auto const& myNewList = theStatsReader()->getMoveList(phase_); for (size_t in = 0; in < myNewList.size(); in += 2) { auto this_node = theContext()->getNode(); - ObjIDType id{myNewList[in], this_node, this_node}; + ObjIDType id{myNewList[in], this_node}; migrateObjectTo(id, myNewList[in+1]); } diff --git a/src/vt/vrt/collection/balance/temperedlb/temperedlb.cc b/src/vt/vrt/collection/balance/temperedlb/temperedlb.cc index 8957e92aa1..8431188a35 100644 --- a/src/vt/vrt/collection/balance/temperedlb/temperedlb.cc +++ b/src/vt/vrt/collection/balance/temperedlb/temperedlb.cc @@ -480,8 +480,13 @@ void TemperedLB::doLBStages(TimeType start_imb) { if (first_iter) { // Copy this node's object assignments to a local, mutable copy cur_objs_.clear(); - for (auto obj : *load_model_) - cur_objs_[obj] = load_model_->getWork(obj, {balance::PhaseOffset::NEXT_PHASE, balance::PhaseOffset::WHOLE_PHASE}); + for (auto obj : *load_model_) { + if (obj.isMigratable()) { + cur_objs_[obj] = load_model_->getWork( + obj, {balance::PhaseOffset::NEXT_PHASE, balance::PhaseOffset::WHOLE_PHASE} + ); + } + } this_new_load_ = this_load; } else { // Clear out data structures from previous iteration @@ -1077,11 +1082,13 @@ std::vector TemperedLB::orderObjects( return left_load < right_load; } ); - vt_debug_print( - normal, temperedlb, - "TemperedLB::decide: over_avg={}, single_obj_load={}\n", - over_avg, cur_objs[ordered_obj_ids[0]] - ); + if (cur_objs.size() > 0) { + vt_debug_print( + normal, temperedlb, + "TemperedLB::decide: over_avg={}, single_obj_load={}\n", + over_avg, cur_objs[ordered_obj_ids[0]] + ); + } } break; case ObjectOrderEnum::SmallObjects: @@ -1135,11 +1142,13 @@ std::vector TemperedLB::orderObjects( return left_load < right_load; } ); - vt_debug_print( - normal, temperedlb, - "TemperedLB::decide: over_avg={}, marginal_obj_load={}\n", - over_avg, cur_objs[ordered_obj_ids[0]] - ); + if (cur_objs.size() > 0) { + vt_debug_print( + normal, temperedlb, + "TemperedLB::decide: over_avg={}, marginal_obj_load={}\n", + over_avg, cur_objs[ordered_obj_ids[0]] + ); + } } break; case ObjectOrderEnum::LargestObjects: @@ -1234,7 +1243,7 @@ void TemperedLB::decide() { selected_node, selected_load, obj_id.id, - obj_id.home_node, + obj_id.getHomeNode(), obj_load, target_max_load_, this_new_load_, diff --git a/src/vt/vrt/collection/balance/zoltanlb/zoltanlb.cc b/src/vt/vrt/collection/balance/zoltanlb/zoltanlb.cc index 6de91807c7..2a0adb6730 100644 --- a/src/vt/vrt/collection/balance/zoltanlb/zoltanlb.cc +++ b/src/vt/vrt/collection/balance/zoltanlb/zoltanlb.cc @@ -48,6 +48,7 @@ #include "vt/vrt/collection/balance/zoltanlb/zoltanlb.h" #include "vt/vrt/collection/balance/model/load_model.h" #include "vt/collective/collective_alg.h" +#include "vt/elm/elm_comm.h" #if vt_check_enabled(zoltan) @@ -183,7 +184,9 @@ void ZoltanLB::runLB(TimeType total_load) { std::set load_objs; for (auto obj : *load_model_) { - load_objs.insert(obj); + if (obj.isMigratable()) { + load_objs.insert(obj); + } } for (int i = 0; i < num_export; i++) { @@ -197,9 +200,7 @@ void ZoltanLB::runLB(TimeType total_load) { auto const obj_id = export_global_ids[i]; auto iter = load_objs.find( - ObjIDType{ - obj_id, uninitialized_destination, uninitialized_destination - } + ObjIDType{obj_id, uninitialized_destination} ); vtAssert(iter != load_objs.end(), "Object must exist here"); @@ -225,7 +226,7 @@ void ZoltanLB::makeGraphSymmetric() { for (auto&& elm : *comm_data) { if ( - elm.first.cat_ == balance::CommCategory::SendRecv and + elm.first.cat_ == elm::CommCategory::SendRecv and not elm.first.selfEdge() ) { auto from = elm.first.fromObj(); @@ -284,8 +285,8 @@ void ZoltanLB::combineEdges() { auto from = std::max(e1.first.fromObj(), e1.first.toObj()); auto to = std::min(e1.first.fromObj(), e1.first.toObj()); - auto key = balance::LBCommKey{ - balance::LBCommKey::CollectionTag{}, from, to, false + auto key = elm::CommKey{ + elm::CommKey::CollectionTag{}, from, to, false }; load_comm_combined[key] += e1.second; } @@ -306,7 +307,7 @@ void ZoltanLB::countEdges() { auto const this_node = theContext()->getNode(); for (auto&& elm : load_comm_symm) { if ( - elm.first.cat_ == balance::CommCategory::SendRecv and + elm.first.cat_ == elm::CommCategory::SendRecv and not elm.first.selfEdge() ) { auto from = elm.first.fromObj(); @@ -440,7 +441,9 @@ std::unique_ptr ZoltanLB::makeGraph() { // traverse them for building the graph consistenly std::set load_objs; for (auto obj : *load_model_) { - load_objs.insert(obj); + if (obj.isMigratable()) { + load_objs.insert(obj); + } } auto graph = std::make_unique(); @@ -492,7 +495,7 @@ std::unique_ptr ZoltanLB::makeGraph() { if (do_edges_) { // Only get communication edges between vertices/migratable elements // Insert local comm objs into a std::set for deterministic ordering - std::vector comm_objs; + std::vector comm_objs; for (auto&& elm : load_comm_edge_id) { comm_objs.push_back(elm.first); } @@ -526,7 +529,7 @@ std::unique_ptr ZoltanLB::makeGraph() { auto comm = iter->second; vtAssert( - iter->first.edge_id_.id != balance::no_element_id, + iter->first.edge_id_.id != elm::no_element_id, "Must have element ID" ); diff --git a/src/vt/vrt/collection/manager.cc b/src/vt/vrt/collection/manager.cc index 32b988dbd9..d98462945d 100644 --- a/src/vt/vrt/collection/manager.cc +++ b/src/vt/vrt/collection/manager.cc @@ -83,7 +83,7 @@ getDispatcher(auto_registry::AutoHandlerType const han) { return theCollection()->getDispatcher(han); } -balance::ElementIDStruct CollectionManager::getCurrentContext() const { +elm::ElementIDStruct CollectionManager::getCurrentContext() const { # if vt_check_enabled(lblite) if (theContext()->getTask() != nullptr) { auto lb = theContext()->getTask()->get(); @@ -92,9 +92,7 @@ balance::ElementIDStruct CollectionManager::getCurrentContext() const { } } #endif - return balance::ElementIDStruct{ - balance::no_element_id, uninitialized_destination, uninitialized_destination - }; + return elm::ElementIDStruct{}; } void CollectionManager::schedule(ActionType action) { diff --git a/src/vt/vrt/collection/manager.h b/src/vt/vrt/collection/manager.h index ca7ecda76b..0a45b95b13 100644 --- a/src/vt/vrt/collection/manager.h +++ b/src/vt/vrt/collection/manager.h @@ -1491,8 +1491,8 @@ struct CollectionManager template friend struct CollectionElmDestroyAttorney; - friend struct balance::ElementStats; - + friend struct balance::CollectionStats; + friend struct elm::ElementStats; friend struct ctx::LBStats; template @@ -1721,7 +1721,7 @@ struct CollectionManager * * \return the element ID */ - balance::ElementIDStruct getCurrentContext() const; + elm::ElementIDStruct getCurrentContext() const; //////////////////////////////////////////////////////////////////////////////// private: @@ -1826,7 +1826,7 @@ struct CollectionManager #include "vt/vrt/collection/destroy/manager_destroy_attorney.impl.h" #include "vt/vrt/collection/broadcast/broadcastable.impl.h" #include "vt/vrt/collection/rdmaable/rdmaable.impl.h" -#include "vt/vrt/collection/balance/elm_stats.impl.h" +#include "vt/vrt/collection/balance/col_stats.impl.h" #include "vt/vrt/collection/types/indexable.impl.h" #include "vt/vrt/collection/dispatch/dispatch.impl.h" #include "vt/vrt/collection/dispatch/registry.impl.h" diff --git a/src/vt/vrt/collection/manager.impl.h b/src/vt/vrt/collection/manager.impl.h index bcb18d9be8..3cea74f625 100644 --- a/src/vt/vrt/collection/manager.impl.h +++ b/src/vt/vrt/collection/manager.impl.h @@ -363,30 +363,34 @@ template template /*static*/ void CollectionManager::recordStats(ColT* col_ptr, MsgT* msg) { + auto const pfrom = msg->getSenderElm(); + + if (pfrom.id == elm::no_element_id) { + return; + } + auto const pto = col_ptr->getElmID(); - auto const pfrom = msg->getElm(); auto& stats = col_ptr->getStats(); auto const msg_size = serialization::MsgSizer::get(msg); auto const cat = msg->getCat(); vt_debug_print( - verbose, vrt_coll, + normal, vrt_coll, "recordStats: receive msg: elm(to={}, from={})," " no={}, size={}, category={}\n", - pto, pfrom, balance::no_element_id, msg_size, - static_cast::type>(cat) + pto, pfrom, elm::no_element_id, msg_size, + static_cast::type>(cat) ); if ( - cat == balance::CommCategory::SendRecv or - cat == balance::CommCategory::Broadcast + cat == elm::CommCategory::SendRecv or + cat == elm::CommCategory::Broadcast ) { - vtAssert(pfrom.id != balance::no_element_id, "Must not be no element ID"); - bool bcast = cat == balance::CommCategory::SendRecv ? false : true; + bool bcast = cat == elm::CommCategory::SendRecv ? false : true; stats.recvObjData(pto, pfrom, msg_size, bcast); } else if ( - cat == balance::CommCategory::NodeToCollection or - cat == balance::CommCategory::NodeToCollectionBcast + cat == elm::CommCategory::NodeToCollection or + cat == elm::CommCategory::NodeToCollectionBcast ) { - bool bcast = cat == balance::CommCategory::NodeToCollection ? false : true; + bool bcast = cat == elm::CommCategory::NodeToCollection ? false : true; auto nfrom = msg->getFromNode(); stats.recvFromNode(pto, nfrom, msg_size, bcast); } @@ -539,11 +543,10 @@ void CollectionManager::invokeMsgImpl( elm_id ); - if (elm_id.id != balance::no_element_id) { - msgPtr->setElm(elm_id); + if (elm_id.id != elm::no_element_id) { + msgPtr->setSenderElm(elm_id); + msgPtr->setCat(elm::CommCategory::LocalInvoke); } - msgPtr->setCat(balance::CommCategory::LocalInvoke); - #endif auto const cur_epoch = theMsg()->setupEpochMsg(msgPtr); @@ -703,7 +706,7 @@ messaging::PendingSend CollectionManager::broadcastCollectiveMsgImpl( #if vt_check_enabled(lblite) msg->setLBLiteInstrument(instrument); - msg->setCat(balance::CommCategory::CollectiveToCollectionBcast); + msg->setCat(elm::CommCategory::CollectiveToCollectionBcast); #endif theMsg()->markAsCollectionMessage(msg); @@ -869,11 +872,9 @@ messaging::PendingSend CollectionManager::broadcastMsgUntypedHandler( elm_id ); - if (elm_id.id != balance::no_element_id) { - msg->setElm(elm_id); - msg->setCat(balance::CommCategory::Broadcast); - } else { - msg->setCat(balance::CommCategory::NodeToCollection); + if (elm_id.id != elm::no_element_id) { + msg->setSenderElm(elm_id); + msg->setCat(elm::CommCategory::Broadcast); } # endif @@ -1135,14 +1136,15 @@ messaging::PendingSend CollectionManager::sendMsgUntypedHandler( elm_id ); - if (elm_id.id != balance::no_element_id) { - msg->setElm(elm_id); - msg->setCat(balance::CommCategory::SendRecv); - } else { - msg->setCat(balance::CommCategory::NodeToCollection); + if (elm_id.id != elm::no_element_id) { + msg->setSenderElm(elm_id); + msg->setCat(elm::CommCategory::SendRecv); } # endif + // set bit so it isn't recorded as it routes through bare handlers + envelopeSetCommStatsRecordedAboveBareHandler(msg->env, true); + # if vt_check_enabled(trace_enabled) // Create the trace creation event here to connect it a higher semantic // level. Do it in the imm_context so we see the send event when the user @@ -1377,7 +1379,7 @@ void CollectionManager::insertMetaCollection( using MsgType = CollectStatsMsg; auto const phase = thePhase()->getCurrentPhase(); CollectionProxyWrapType p{bits}; - p.template broadcastCollective>( + p.template broadcastCollective>( phase ); }; diff --git a/src/vt/vrt/collection/messages/user.h b/src/vt/vrt/collection/messages/user.h index b8cf9eba10..86e3ace541 100644 --- a/src/vt/vrt/collection/messages/user.h +++ b/src/vt/vrt/collection/messages/user.h @@ -51,7 +51,7 @@ #include "vt/vrt/collection/proxy.h" #include "vt/vrt/vrt_common.h" #include "vt/vrt/collection/balance/lb_common.h" -#include "vt/vrt/collection/balance/lb_comm.h" +#include "vt/elm/elm_comm.h" #include @@ -111,10 +111,10 @@ struct CollectionMessage : RoutedMessageType { #if vt_check_enabled(lblite) bool lbLiteInstrument() const; void setLBLiteInstrument(bool const& val); - balance::ElementIDStruct getElm() const; - void setElm(balance::ElementIDStruct elm); - balance::CommCategory getCat() const; - void setCat(balance::CommCategory cat); + balance::ElementIDStruct getSenderElm() const; + void setSenderElm(balance::ElementIDStruct elm); + elm::CommCategory getCat() const; + void setCat(elm::CommCategory cat); #endif template @@ -136,10 +136,8 @@ struct CollectionMessage : RoutedMessageType { * (sendMsg,broadcastMsg) they are automatically instrumented */ bool lb_lite_instrument_ = false; - balance::ElementIDStruct elm_ = { - 0, uninitialized_destination, uninitialized_destination - }; - balance::CommCategory cat_ = balance::CommCategory::SendRecv; + balance::ElementIDStruct sender_elm_ = {}; + elm::CommCategory cat_ = elm::CommCategory::SendRecv; #endif #if vt_check_enabled(trace_enabled) diff --git a/src/vt/vrt/collection/messages/user.impl.h b/src/vt/vrt/collection/messages/user.impl.h index 446d43d736..800d996b67 100644 --- a/src/vt/vrt/collection/messages/user.impl.h +++ b/src/vt/vrt/collection/messages/user.impl.h @@ -113,7 +113,7 @@ void CollectionMessage::serialize(SerializerT& s) { #if vt_check_enabled(lblite) s | lb_lite_instrument_; - s | elm_; + s | sender_elm_; s | cat_; #endif @@ -144,24 +144,25 @@ void CollectionMessage::setLBLiteInstrument(bool const& val) { } template -balance::ElementIDStruct CollectionMessage::getElm() const { - return elm_; +balance::ElementIDStruct +CollectionMessage::getSenderElm() const { + return sender_elm_; } template -void CollectionMessage::setElm( - balance::ElementIDStruct elm +void CollectionMessage::setSenderElm( + balance::ElementIDStruct sender_elm ) { - elm_ = elm; + sender_elm_ = sender_elm; } template -balance::CommCategory CollectionMessage::getCat() const { +elm::CommCategory CollectionMessage::getCat() const { return cat_; } template -void CollectionMessage::setCat(balance::CommCategory cat) { +void CollectionMessage::setCat(elm::CommCategory cat) { cat_ = cat; } diff --git a/src/vt/vrt/collection/types/migratable.cc b/src/vt/vrt/collection/types/migratable.cc index 34abf66025..1156f38008 100644 --- a/src/vt/vrt/collection/types/migratable.cc +++ b/src/vt/vrt/collection/types/migratable.cc @@ -45,11 +45,17 @@ #include "vt/vrt/vrt_common.h" #include "vt/vrt/collection/types/migratable.h" #include "vt/vrt/collection/manager.h" +#include "vt/vrt/proxy/proxy_bits.h" +#include "vt/elm/elm_id_bits.h" namespace vt { namespace vrt { namespace collection { Migratable::Migratable() - : elm_id_(theNodeStats()->getNextElm()) + : elm_id_( + elm::ElmIDBits::createCollection( + VirtualProxyBuilder::isMigratable(getProxy()), theContext()->getNode() + ) + ) { } /*virtual*/ void Migratable::destroy() { diff --git a/src/vt/vrt/collection/types/migratable.h b/src/vt/vrt/collection/types/migratable.h index 395910bf38..1492d960a8 100644 --- a/src/vt/vrt/collection/types/migratable.h +++ b/src/vt/vrt/collection/types/migratable.h @@ -51,7 +51,7 @@ #include "vt/vrt/collection/types/migratable.fwd.h" #include "vt/vrt/collection/types/storage/storable.h" #include "vt/vrt/collection/balance/lb_common.h" -#include "vt/vrt/collection/balance/elm_stats.h" +#include "vt/vrt/collection/balance/col_stats.h" namespace vt { namespace vrt { namespace collection { @@ -106,13 +106,13 @@ struct Migratable : MigrateHookBase, storage::Storable { void serialize(Serializer& s); protected: - friend struct balance::ElementStats; + friend struct balance::CollectionStats; friend struct balance::NodeStats; - balance::ElementStats stats_; + balance::CollectionStats stats_; public: - balance::ElementStats& getStats() { return stats_; } + balance::CollectionStats& getStats() { return stats_; } protected: - balance::ElementIDStruct elm_id_ = {0, uninitialized_destination, uninitialized_destination}; + balance::ElementIDStruct elm_id_ = {}; }; }}} /* end namespace vt::vrt::collection */ diff --git a/src/vt/vrt/proxy/collection_proxy.impl.h b/src/vt/vrt/proxy/collection_proxy.impl.h index 3794be9728..2d2479c5da 100644 --- a/src/vt/vrt/proxy/collection_proxy.impl.h +++ b/src/vt/vrt/proxy/collection_proxy.impl.h @@ -48,7 +48,7 @@ #include "vt/vrt/proxy/collection_proxy.h" #include "vt/vrt/proxy/base_elm_proxy.h" #include "vt/vrt/collection/proxy_traits/proxy_col_traits.h" -#include "vt/vrt/collection/balance/elm_stats.h" +#include "vt/vrt/collection/balance/col_stats.h" namespace vt { namespace vrt { namespace collection { @@ -103,7 +103,7 @@ CollectionProxy::operator()(IndexU const& idx) const { template void CollectionProxy::setFocusedSubPhase(SubphaseType subphase) { - balance::ElementStats::setFocusedSubPhase(this->getProxy(), subphase); + balance::CollectionStats::setFocusedSubPhase(this->getProxy(), subphase); } }}} /* end namespace vt::vrt::collection */ diff --git a/tests/unit/collection/test_lb.extended.cc b/tests/unit/collection/test_lb.extended.cc index 80c37dfde3..2fe20948bf 100644 --- a/tests/unit/collection/test_lb.extended.cc +++ b/tests/unit/collection/test_lb.extended.cc @@ -340,9 +340,9 @@ TEST_F(TestRestoreStatsData, test_restore_stats_data_1) { vt::vrt::collection::balance::StatsData sd; PhaseType write_phase = 0; - using LBCommKey = vt::vrt::collection::balance::LBCommKey; - using CommVolume = vt::vrt::collection::balance::CommVolume; - using CommBytesType = vt::vrt::collection::balance::CommBytesType; + using CommKey = vt::elm::CommKey; + using CommVolume = vt::elm::CommVolume; + using CommBytesType = vt::elm::CommBytesType; // @todo: should do other types of comm @@ -369,15 +369,15 @@ TEST_F(TestRestoreStatsData, test_restore_stats_data_1) { sd.node_data_[phase][elm_id].whole_phase_load = dur; sd.node_data_[phase][elm_id].subphase_loads = dur_vec; - LBCommKey ntockey( - LBCommKey::NodeToCollectionTag{}, this_node, elm_id, false + CommKey ntockey( + CommKey::NodeToCollectionTag{}, this_node, elm_id, false ); CommVolume ntocvol{ntoc, ntocm}; sd.node_comm_[phase][ntockey] = ntocvol; sd.node_subphase_comm_[phase][i % 2][ntockey] = ntocvol; - LBCommKey ctonkey( - LBCommKey::CollectionToNodeTag{}, elm_id, this_node, false + CommKey ctonkey( + CommKey::CollectionToNodeTag{}, elm_id, this_node, false ); CommVolume ctonvol{cton, ctonm}; sd.node_comm_[phase][ctonkey] = ctonvol; @@ -420,22 +420,22 @@ TEST_F(TestRestoreStatsData, test_restore_stats_data_1) { "Unexpected element ID read in whole-phase loads on phase={}: " "id={}, home={}, curr={}", phase, - read_elm_id.id, read_elm_id.home_node, read_elm_id.curr_node + read_elm_id.id, read_elm_id.getHomeNode(), read_elm_id.curr_node ); } else { auto orig_elm_id = orig_load_map.find(read_elm_id)->first; - EXPECT_EQ(read_elm_id.home_node, orig_elm_id.home_node); + EXPECT_EQ(read_elm_id.getHomeNode(), orig_elm_id.getHomeNode()); EXPECT_EQ(read_elm_id.curr_node, orig_elm_id.curr_node); if ( - read_elm_id.home_node != orig_elm_id.home_node || + read_elm_id.getHomeNode() != orig_elm_id.getHomeNode() || read_elm_id.curr_node != orig_elm_id.curr_node ) { fmt::print( "Corrupted element ID read in whole-phase loads on phase={}: " "id={}, home={}, curr={} (expected id={}, home={}, curr={})", phase, - read_elm_id.id, read_elm_id.home_node, read_elm_id.curr_node, - orig_elm_id.id, orig_elm_id.home_node, orig_elm_id.curr_node + read_elm_id.id, read_elm_id.getHomeNode(), read_elm_id.curr_node, + orig_elm_id.id, orig_elm_id.getHomeNode(), orig_elm_id.curr_node ); } auto read_load = read_load_map[read_elm_id]; @@ -465,7 +465,7 @@ TEST_F(TestRestoreStatsData, test_restore_stats_data_1) { fmt::print( "Unexpected element ID read in index mapping: " "id={}, home={}, curr={}", - read_elm_id.id, read_elm_id.home_node, read_elm_id.curr_node + read_elm_id.id, read_elm_id.getHomeNode(), read_elm_id.curr_node ); } else { auto orig_idx = sd.node_idx_[read_elm_id]; @@ -474,7 +474,7 @@ TEST_F(TestRestoreStatsData, test_restore_stats_data_1) { if (orig_idx != read_idx) { fmt::print( "Unexpected collection index for elm id={}, home={}, curr={}", - read_elm_id.id, read_elm_id.home_node, read_elm_id.curr_node + read_elm_id.id, read_elm_id.getHomeNode(), read_elm_id.curr_node ); } } diff --git a/tests/unit/collection/test_lbstats_retention.cc b/tests/unit/collection/test_lbstats_retention.cc index 42f95ed6d5..0f1f2a2514 100644 --- a/tests/unit/collection/test_lbstats_retention.cc +++ b/tests/unit/collection/test_lbstats_retention.cc @@ -41,7 +41,7 @@ //@HEADER */ -#include +#include #include #include #include diff --git a/tests/unit/collection/test_model_comm_overhead.nompi.cc b/tests/unit/collection/test_model_comm_overhead.nompi.cc index 56fe5b8534..ff1549c740 100644 --- a/tests/unit/collection/test_model_comm_overhead.nompi.cc +++ b/tests/unit/collection/test_model_comm_overhead.nompi.cc @@ -43,7 +43,7 @@ #include #include -#include +#include #include @@ -55,11 +55,11 @@ namespace vt { namespace tests { namespace unit { namespace comm { using TestModelCommOverhead = TestHarness; -using vt::vrt::collection::balance::CommKeyType; -using vt::vrt::collection::balance::CommMapType; +using vt::elm::CommKeyType; +using vt::elm::CommMapType; +using vt::elm::CommVolume; +using vt::elm::ElementIDStruct; using vt::vrt::collection::balance::CommOverhead; -using vt::vrt::collection::balance::CommVolume; -using vt::vrt::collection::balance::ElementIDStruct; using vt::vrt::collection::balance::LoadMapType; using vt::vrt::collection::balance::LoadModel; using vt::vrt::collection::balance::ObjectIterator; @@ -114,13 +114,13 @@ TEST_F(TestModelCommOverhead, test_model_comm_overhead_1) { // For simplicity's sake, the elements are on the home node // Element 1 (home node == 1) - ElementIDStruct const elem1 = {1, 1, 1}; + ElementIDStruct const elem1 = {1, 1}; // Element 2 (home node == 2) - ElementIDStruct const elem2 = {2, 2, 2}; + ElementIDStruct const elem2 = {2, 2}; // Element 3 (home node == 3) - ElementIDStruct const elem3 = {3, 3, 3}; + ElementIDStruct const elem3 = {3, 3}; ProcLoadMap proc_load = {{0, LoadMapType{{elem2, {TimeType{150}, {}}}}}}; diff --git a/tests/unit/collection/test_model_linear_model.nompi.cc b/tests/unit/collection/test_model_linear_model.nompi.cc index 2250fb8cf2..7aa4342fde 100644 --- a/tests/unit/collection/test_model_linear_model.nompi.cc +++ b/tests/unit/collection/test_model_linear_model.nompi.cc @@ -106,8 +106,8 @@ TEST_F(TestLinearModel, test_model_linear_model_1) { // For linear regression there needs to be at least 2 phases completed // so we begin with 1 phase already done std::unordered_map proc_loads{{0, LoadMapType{ - {ElementIDStruct{1,this_node,this_node}, {TimeType{10}, {}}}, - {ElementIDStruct{2,this_node,this_node}, {TimeType{40}, {}}} + {ElementIDStruct{1,this_node}, {TimeType{10}, {}}}, + {ElementIDStruct{2,this_node}, {TimeType{40}, {}}} }}}; test_model->setLoads(&proc_loads, nullptr); test_model->updateLoads(0); @@ -115,23 +115,23 @@ TEST_F(TestLinearModel, test_model_linear_model_1) { // Work loads to be added in each test iteration std::vector load_holder{ LoadMapType{ - {ElementIDStruct{1,this_node,this_node}, {TimeType{5}, {}}}, - {ElementIDStruct{2,this_node,this_node}, {TimeType{10}, {}}}}, + {ElementIDStruct{1,this_node}, {TimeType{5}, {}}}, + {ElementIDStruct{2,this_node}, {TimeType{10}, {}}}}, LoadMapType{ - {ElementIDStruct{1,this_node,this_node}, {TimeType{30}, {}}}, - {ElementIDStruct{2,this_node,this_node}, {TimeType{100}, {}}}}, + {ElementIDStruct{1,this_node}, {TimeType{30}, {}}}, + {ElementIDStruct{2,this_node}, {TimeType{100}, {}}}}, LoadMapType{ - {ElementIDStruct{1,this_node,this_node}, {TimeType{50}, {}}}, - {ElementIDStruct{2,this_node,this_node}, {TimeType{40}, {}}}}, + {ElementIDStruct{1,this_node}, {TimeType{50}, {}}}, + {ElementIDStruct{2,this_node}, {TimeType{40}, {}}}}, LoadMapType{ - {ElementIDStruct{1,this_node,this_node}, {TimeType{2}, {}}}, - {ElementIDStruct{2,this_node,this_node}, {TimeType{50}, {}}}}, + {ElementIDStruct{1,this_node}, {TimeType{2}, {}}}, + {ElementIDStruct{2,this_node}, {TimeType{50}, {}}}}, LoadMapType{ - {ElementIDStruct{1,this_node,this_node}, {TimeType{60}, {}}}, - {ElementIDStruct{2,this_node,this_node}, {TimeType{20}, {}}}}, + {ElementIDStruct{1,this_node}, {TimeType{60}, {}}}, + {ElementIDStruct{2,this_node}, {TimeType{20}, {}}}}, LoadMapType{ - {ElementIDStruct{1,this_node,this_node}, {TimeType{100}, {}}}, - {ElementIDStruct{2,this_node,this_node}, {TimeType{10}, {}}}}, + {ElementIDStruct{1,this_node}, {TimeType{100}, {}}}, + {ElementIDStruct{2,this_node}, {TimeType{10}, {}}}}, }; std::array, num_test_interations> expected_data{ diff --git a/tests/unit/collection/test_model_multiple_phases.nompi.cc b/tests/unit/collection/test_model_multiple_phases.nompi.cc index 7baef7bdf5..4c2d694897 100644 --- a/tests/unit/collection/test_model_multiple_phases.nompi.cc +++ b/tests/unit/collection/test_model_multiple_phases.nompi.cc @@ -100,17 +100,17 @@ TEST_F(TestModelMultiplePhases, test_model_multiple_phases_1) { NodeType this_node = 0; std::unordered_map proc_loads = { {0, LoadMapType{ - {ElementIDStruct{1,this_node,this_node}, {TimeType{10}, {}}}, - {ElementIDStruct{2,this_node,this_node}, {TimeType{40}, {}}}}}, + {ElementIDStruct{1,this_node}, {TimeType{10}, {}}}, + {ElementIDStruct{2,this_node}, {TimeType{40}, {}}}}}, {1, LoadMapType{ - {ElementIDStruct{1,this_node,this_node}, {TimeType{20}, {}}}, - {ElementIDStruct{2,this_node,this_node}, {TimeType{30}, {}}}}}, + {ElementIDStruct{1,this_node}, {TimeType{20}, {}}}, + {ElementIDStruct{2,this_node}, {TimeType{30}, {}}}}}, {2, LoadMapType{ - {ElementIDStruct{1,this_node,this_node}, {TimeType{30}, {}}}, - {ElementIDStruct{2,this_node,this_node}, {TimeType{10}, {}}}}}, + {ElementIDStruct{1,this_node}, {TimeType{30}, {}}}, + {ElementIDStruct{2,this_node}, {TimeType{10}, {}}}}}, {3, LoadMapType{ - {ElementIDStruct{1,this_node,this_node}, {TimeType{40}, {}}}, - {ElementIDStruct{2,this_node,this_node}, {TimeType{5}, {}}}}}}; + {ElementIDStruct{1,this_node}, {TimeType{40}, {}}}, + {ElementIDStruct{2,this_node}, {TimeType{5}, {}}}}}}; auto test_model = std::make_shared(std::make_shared(), 4); diff --git a/tests/unit/collection/test_model_naive_persistence.nompi.cc b/tests/unit/collection/test_model_naive_persistence.nompi.cc index b2731970b4..48ab9afe35 100644 --- a/tests/unit/collection/test_model_naive_persistence.nompi.cc +++ b/tests/unit/collection/test_model_naive_persistence.nompi.cc @@ -103,17 +103,17 @@ TEST_F(TestModelNaivePersistence, test_model_naive_persistence_1) { NodeType this_node = 0; std::unordered_map proc_loads = { {0, LoadMapType{ - {ElementIDStruct{1,this_node,this_node}, {TimeType{10}, {}}}, - {ElementIDStruct{2,this_node,this_node}, {TimeType{40}, {}}}}}, + {ElementIDStruct{1,this_node}, {TimeType{10}, {}}}, + {ElementIDStruct{2,this_node}, {TimeType{40}, {}}}}}, {1, LoadMapType{ - {ElementIDStruct{1,this_node,this_node}, {TimeType{4}, {}}}, - {ElementIDStruct{2,this_node,this_node}, {TimeType{10}, {}}}}}, + {ElementIDStruct{1,this_node}, {TimeType{4}, {}}}, + {ElementIDStruct{2,this_node}, {TimeType{10}, {}}}}}, {2, LoadMapType{ - {ElementIDStruct{1,this_node,this_node}, {TimeType{20}, {}}}, - {ElementIDStruct{2,this_node,this_node}, {TimeType{50}, {}}}}}, + {ElementIDStruct{1,this_node}, {TimeType{20}, {}}}, + {ElementIDStruct{2,this_node}, {TimeType{50}, {}}}}}, {3, LoadMapType{ - {ElementIDStruct{1,this_node,this_node}, {TimeType{40}, {}}}, - {ElementIDStruct{2,this_node,this_node}, {TimeType{100}, {}}}}}}; + {ElementIDStruct{1,this_node}, {TimeType{40}, {}}}, + {ElementIDStruct{2,this_node}, {TimeType{100}, {}}}}}}; auto test_model = std::make_shared(std::make_shared()); diff --git a/tests/unit/collection/test_model_norm.nompi.cc b/tests/unit/collection/test_model_norm.nompi.cc index eb9213fb54..a79acafc3e 100644 --- a/tests/unit/collection/test_model_norm.nompi.cc +++ b/tests/unit/collection/test_model_norm.nompi.cc @@ -107,8 +107,8 @@ TEST_F(TestModelNorm, test_model_norm_1) { ProcLoadMap proc_load = { {0, LoadMapType{ - {ElementIDStruct{1,this_node,this_node}, {TimeType{60}, {TimeType{10}, TimeType{20}, TimeType{30}}}}, - {ElementIDStruct{2,this_node,this_node}, {TimeType{150}, {TimeType{40}, TimeType{50}, TimeType{60}}}}}}}; + {ElementIDStruct{1,this_node}, {TimeType{60}, {TimeType{10}, TimeType{20}, TimeType{30}}}}, + {ElementIDStruct{2,this_node}, {TimeType{150}, {TimeType{40}, TimeType{50}, TimeType{60}}}}}}}; auto test_model = std::make_shared(std::make_shared(), 3.0); test_model->setLoads(&proc_load, nullptr); @@ -135,8 +135,8 @@ TEST_F(TestModelNorm, test_model_norm_2) { ProcLoadMap proc_load = { {0, LoadMapType{ - {ElementIDStruct{1,this_node,this_node}, {TimeType{60}, {TimeType{10}, TimeType{20}, TimeType{30}}}}, - {ElementIDStruct{2,this_node,this_node}, {TimeType{150}, {TimeType{40}, TimeType{50}, TimeType{60}}}}}}}; + {ElementIDStruct{1,this_node}, {TimeType{60}, {TimeType{10}, TimeType{20}, TimeType{30}}}}, + {ElementIDStruct{2,this_node}, {TimeType{150}, {TimeType{40}, TimeType{50}, TimeType{60}}}}}}}; // finite 'power' value auto test_model = std::make_shared(std::make_shared(), 3.0); @@ -164,8 +164,8 @@ TEST_F(TestModelNorm, test_model_norm_3) { ProcLoadMap proc_load = { {0, LoadMapType{ - {ElementIDStruct{1,this_node,this_node}, {TimeType{60}, {TimeType{10}, TimeType{20}, TimeType{30}}}}, - {ElementIDStruct{2,this_node,this_node}, {TimeType{150}, {TimeType{40}, TimeType{50}, TimeType{60}}}}}}}; + {ElementIDStruct{1,this_node}, {TimeType{60}, {TimeType{10}, TimeType{20}, TimeType{30}}}}, + {ElementIDStruct{2,this_node}, {TimeType{150}, {TimeType{40}, TimeType{50}, TimeType{60}}}}}}}; // infinite 'power' value auto test_model = std::make_shared( diff --git a/tests/unit/collection/test_model_per_collection.extended.cc b/tests/unit/collection/test_model_per_collection.extended.cc index ebae9ad643..81f80e5832 100644 --- a/tests/unit/collection/test_model_per_collection.extended.cc +++ b/tests/unit/collection/test_model_per_collection.extended.cc @@ -152,7 +152,9 @@ TEST_F(TestModelPerCollection, test_model_per_collection_1) { model->updateLoads(0); for (auto&& obj : *model) { auto work_val = model->getWork(obj, {PhaseOffset::NEXT_PHASE, PhaseOffset::WHOLE_PHASE}); - EXPECT_DOUBLE_EQ(work_val, static_cast(id_proxy_map[obj])); + if (id_proxy_map.find(obj) != id_proxy_map.end()) { + EXPECT_DOUBLE_EQ(work_val, static_cast(id_proxy_map[obj])); + } //fmt::print("{:x} {}\n", obj, work_val); } #endif diff --git a/tests/unit/collection/test_model_persistence_median_last_n.nompi.cc b/tests/unit/collection/test_model_persistence_median_last_n.nompi.cc index 4860a43847..16c33cf74b 100644 --- a/tests/unit/collection/test_model_persistence_median_last_n.nompi.cc +++ b/tests/unit/collection/test_model_persistence_median_last_n.nompi.cc @@ -110,26 +110,26 @@ TEST_F(TestModelPersistenceMedianLastN, test_model_persistence_median_last_n_1) // Work loads to be added in each test iteration std::vector load_holder{ LoadMapType{ - {ElementIDStruct{1,this_node,this_node}, {TimeType{10}, {}}}, - {ElementIDStruct{2,this_node,this_node}, {TimeType{40}, {}}}}, + {ElementIDStruct{1,this_node}, {TimeType{10}, {}}}, + {ElementIDStruct{2,this_node}, {TimeType{40}, {}}}}, LoadMapType{ - {ElementIDStruct{1,this_node,this_node}, {TimeType{4}, {}}}, - {ElementIDStruct{2,this_node,this_node}, {TimeType{10}, {}}}}, + {ElementIDStruct{1,this_node}, {TimeType{4}, {}}}, + {ElementIDStruct{2,this_node}, {TimeType{10}, {}}}}, LoadMapType{ - {ElementIDStruct{1,this_node,this_node}, {TimeType{20}, {}}}, - {ElementIDStruct{2,this_node,this_node}, {TimeType{100}, {}}}}, + {ElementIDStruct{1,this_node}, {TimeType{20}, {}}}, + {ElementIDStruct{2,this_node}, {TimeType{100}, {}}}}, LoadMapType{ - {ElementIDStruct{1,this_node,this_node}, {TimeType{50}, {}}}, - {ElementIDStruct{2,this_node,this_node}, {TimeType{40}, {}}}}, + {ElementIDStruct{1,this_node}, {TimeType{50}, {}}}, + {ElementIDStruct{2,this_node}, {TimeType{40}, {}}}}, LoadMapType{ - {ElementIDStruct{1,this_node,this_node}, {TimeType{2}, {}}}, - {ElementIDStruct{2,this_node,this_node}, {TimeType{50}, {}}}}, + {ElementIDStruct{1,this_node}, {TimeType{2}, {}}}, + {ElementIDStruct{2,this_node}, {TimeType{50}, {}}}}, LoadMapType{ - {ElementIDStruct{1,this_node,this_node}, {TimeType{60}, {}}}, - {ElementIDStruct{2,this_node,this_node}, {TimeType{20}, {}}}}, + {ElementIDStruct{1,this_node}, {TimeType{60}, {}}}, + {ElementIDStruct{2,this_node}, {TimeType{20}, {}}}}, LoadMapType{ - {ElementIDStruct{1,this_node,this_node}, {TimeType{100}, {}}}, - {ElementIDStruct{2,this_node,this_node}, {TimeType{10}, {}}}}, + {ElementIDStruct{1,this_node}, {TimeType{100}, {}}}, + {ElementIDStruct{2,this_node}, {TimeType{10}, {}}}}, }; std::array, num_total_phases> expected_medians{ diff --git a/tests/unit/collection/test_model_raw_data.nompi.cc b/tests/unit/collection/test_model_raw_data.nompi.cc index b89ae0eab3..0bb25d7d2f 100644 --- a/tests/unit/collection/test_model_raw_data.nompi.cc +++ b/tests/unit/collection/test_model_raw_data.nompi.cc @@ -71,8 +71,8 @@ TEST_F(TestRawData, test_model_raw_data_scalar) { std::unordered_map proc_loads; test_model->setLoads(&proc_loads, nullptr); - ElementIDStruct id1{1,this_node,this_node}; - ElementIDStruct id2{2,this_node,this_node}; + ElementIDStruct id1{1,this_node}; + ElementIDStruct id2{2,this_node}; // Work loads to be added in each test iteration std::vector load_holder{ diff --git a/tests/unit/collection/test_model_select_subphases.nompi.cc b/tests/unit/collection/test_model_select_subphases.nompi.cc index 02a7ef1a1a..2e920359fa 100644 --- a/tests/unit/collection/test_model_select_subphases.nompi.cc +++ b/tests/unit/collection/test_model_select_subphases.nompi.cc @@ -109,8 +109,8 @@ struct StubModel : LoadModel { TEST_F(TestModelSelectSubphases, test_model_select_subphases_1) { NodeType this_node = 0; - ElementIDStruct id1{1,this_node,this_node}; - ElementIDStruct id2{2,this_node,this_node}; + ElementIDStruct id1{1,this_node}; + ElementIDStruct id2{2,this_node}; ProcLoadMap proc_load = { {0, @@ -159,9 +159,9 @@ TEST_F(TestModelSelectSubphases, test_model_select_subphases_2) { ProcLoadMap proc_load = { {0, LoadMapType{ - {ElementIDStruct{1,this_node,this_node}, + {ElementIDStruct{1,this_node}, {TimeType{60}, {TimeType{10}, TimeType{20}, TimeType{30}}}}, - {ElementIDStruct{2,this_node,this_node}, + {ElementIDStruct{2,this_node}, {TimeType{150}, {TimeType{40}, TimeType{50}, TimeType{60}}}} } } @@ -177,8 +177,8 @@ TEST_F(TestModelSelectSubphases, test_model_select_subphases_2) { test_model->updateLoads(0); std::unordered_map expected_values = { - {ElementIDStruct{1,this_node,this_node}, TimeType{50}}, - {ElementIDStruct{2,this_node,this_node}, TimeType{110}}}; + {ElementIDStruct{1,this_node}, TimeType{50}}, + {ElementIDStruct{2,this_node}, TimeType{110}}}; int objects_seen = 0; diff --git a/tests/unit/lb/test_lb_stats_comm.cc b/tests/unit/lb/test_lb_stats_comm.cc new file mode 100644 index 0000000000..c5eba0d073 --- /dev/null +++ b/tests/unit/lb/test_lb_stats_comm.cc @@ -0,0 +1,750 @@ +/* +//@HEADER +// ***************************************************************************** +// +// test_lb_stats_comm.cc +// DARMA/vt => Virtual Transport +// +// Copyright 2019-2021 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Questions? Contact darma@sandia.gov +// +// ***************************************************************************** +//@HEADER +*/ + +#include "test_parallel_harness.h" + +#include +#include +#include +#include +#include + +#include + +#if vt_check_enabled(lblite) + +namespace vt { namespace tests { namespace unit { namespace comm { + +/** + * -------------------------------------- + * Communication Record Summary + * -------------------------------------- + * -------- || --------- Sender --------- + * Receiver || ColT | ObjGroup | Handler + * -------------------------------------- + * ColT || R | R | R + * ObjGroup || S | S | S + * Handler || S | S | S + * -------------------------------------- + */ + +using TestLBStatsComm = TestParallelHarness; +using StatsData = vt::vrt::collection::balance::StatsData; + +StatsData getStatsDataForPhase(vt::PhaseType phase) { + using JSONAppender = vt::util::json::Appender; + using vt::util::json::DecompressionInputContainer; + using vt::vrt::collection::balance::StatsData; + using json = nlohmann::json; + std::stringstream ss{std::ios_base::out | std::ios_base::in}; + auto ap = std::make_unique("phases", std::move(ss), true); + auto j = vt::theNodeStats()->getStatsData()->toJson(phase); + ap->addElm(*j); + ss = ap->finish(); + auto c = DecompressionInputContainer{ + DecompressionInputContainer::AnyStreamTag{}, std::move(ss) + }; + return StatsData{json::parse(c)}; +} + +namespace { + +auto constexpr dim1 = 64; +auto constexpr num_sends = 4; + +struct MyCol : vt::Collection { }; +struct MyMsg : vt::CollectionMessage { double x, y, z; }; +struct MyObjMsg : vt::Message { double x, y, z; }; +struct ElementInfo { + using MapType = std::map; + ElementInfo() = default; + explicit ElementInfo(MapType in_map) : elms(in_map) { } + friend ElementInfo operator+(ElementInfo a1, ElementInfo const& a2) { + for (auto&& x : a2.elms) a1.elms.insert(x); + return a1; + } + template + void serialize(SerializerT& s) { + s | elms; + } + MapType elms; +}; +struct ReduceMsg : SerializeRequired< + vt::collective::ReduceTMsg, ReduceMsg +> { + using MessageParentType = SerializeRequired< + vt::collective::ReduceTMsg, ReduceMsg + >; + + ReduceMsg() = default; + ReduceMsg(vt::Index1D idx, vt::elm::ElementIDStruct elm_id) + : MessageParentType( + ElementInfo{ + std::map{{idx, elm_id}} + } + ) + { } + + template + void serialize(SerializerT& s) { + MessageParentType::serialize(s); + } +}; +struct ColProxyMsg : vt::Message { + using ProxyType = vt::CollectionProxy; + ColProxyMsg(ProxyType in_proxy) : proxy(in_proxy) { } + ProxyType proxy; +}; +struct ProxyMsg; +struct MyObj { + void dummyHandler(MyObjMsg* msg) {} + void simulateObjGroupColTSends(ColProxyMsg* msg); + void simulateObjGroupObjGroupSends(ProxyMsg* msg); + void simulateObjGroupHandlerSends(MyMsg* msg); +}; +struct ProxyMsg : vt::CollectionMessage { + using ProxyType = vt::objgroup::proxy::Proxy; + ProxyMsg(ProxyType in_proxy) : obj_proxy(in_proxy) { } + ProxyType obj_proxy; +}; + +void handler2(MyMsg* msg, MyCol* col) {} + +void MyObj::simulateObjGroupColTSends(ColProxyMsg* msg) { + auto proxy = msg->proxy; + auto this_node = theContext()->getNode(); + auto num_nodes = theContext()->getNumNodes(); + auto next = (this_node + 1) % num_nodes; + for (int i = 0; i < dim1; i++) { + vt::Index1D idx{i}; + auto node = vt::theCollection()->getMappedNode(proxy, idx); + if (node == next) { + for (int j = 0; j < num_sends; j++) { + proxy(idx).template send(); + } + } + } +} + +void MyObj::simulateObjGroupObjGroupSends(ProxyMsg* msg) { + auto obj_proxy = msg->obj_proxy; + auto this_node = theContext()->getNode(); + auto num_nodes = theContext()->getNumNodes(); + auto next = (this_node + 1) % num_nodes; + for (int i = 0; i < num_sends; i++) { + obj_proxy[next].template send(); + } +} + +void simulateColTColTSends(MyMsg* msg, MyCol* col) { + auto proxy = col->getCollectionProxy(); + auto index = col->getIndex(); + auto next = (index.x() + 1) % dim1; + for (int i = 0; i < num_sends; i++) { + proxy(next).template send(); + } +} + +void simulateColTObjGroupSends(ProxyMsg* msg, MyCol* col) { + auto obj_proxy = msg->obj_proxy; + auto this_node = theContext()->getNode(); + auto num_nodes = theContext()->getNumNodes(); + auto next = (this_node + 1) % num_nodes; + for (int i = 0; i < num_sends; i++) { + obj_proxy[next].template send(); + } +} + +void bareDummyHandler(MyObjMsg* msg) {} + +void simulateColTHandlerSends(MyMsg* msg, MyCol* col) { + auto this_node = theContext()->getNode(); + auto num_nodes = theContext()->getNumNodes(); + auto next = (this_node + 1) % num_nodes; + for (int i = 0; i < num_sends; i++) { + auto msg2 = makeMessage(); + vt::theMsg()->sendMsg(next, msg2); + } +} + +void MyObj::simulateObjGroupHandlerSends(MyMsg* msg) { + auto this_node = theContext()->getNode(); + auto num_nodes = theContext()->getNumNodes(); + auto next = (this_node + 1) % num_nodes; + for (int i = 0; i < num_sends; i++) { + auto msg2 = makeMessage(); + vt::theMsg()->sendMsg(next, msg2); + } +} + +void simulateHandlerColTSends(ColProxyMsg* msg) { + auto proxy = msg->proxy; + auto this_node = theContext()->getNode(); + auto num_nodes = theContext()->getNumNodes(); + auto next = (this_node + 1) % num_nodes; + for (int i = 0; i < dim1; i++) { + vt::Index1D idx{i}; + auto node = vt::theCollection()->getMappedNode(proxy, idx); + if (node == next) { + for (int j = 0; j < num_sends; j++) { + proxy(idx).template send(); + } + } + } +} + +void simulateHandlerObjGroupSends(ProxyMsg* msg) { + auto obj_proxy = msg->obj_proxy; + auto this_node = theContext()->getNode(); + auto num_nodes = theContext()->getNumNodes(); + auto next = (this_node + 1) % num_nodes; + for (int i = 0; i < num_sends; i++) { + obj_proxy[next].template send(); + } +} + +void simulateHandlerHandlerSends(MyMsg* msg) { + auto this_node = theContext()->getNode(); + auto num_nodes = theContext()->getNumNodes(); + auto next = (this_node + 1) % num_nodes; + for (int i = 0; i < num_sends; i++) { + auto msg2 = makeMessage(); + vt::theMsg()->sendMsg(next, msg2); + } +} + +std::map all_elms; + +auto idxToElmID = [](vt::Index1D i) -> vt::elm::ElementIDType { + return all_elms.find(i)->second.id; +}; + +void recvElementIDs(ReduceMsg* msg) { all_elms = msg->getVal().elms; } + +void doReduce(MyMsg*, MyCol* col) { + auto proxy = col->getCollectionProxy(); + auto index = col->getIndex(); + auto cb = theCB()->makeBcast(); + auto msg = makeMessage(index, col->getElmID()); + proxy.reduce>(msg.get(), cb); +} + +// ColT -> ColT, expected communication edge on receive side +TEST_F(TestLBStatsComm, test_lb_stats_comm_col_to_col_send) { + auto range = vt::Index1D{dim1}; + auto proxy = vt::makeCollection() + .bounds(range) + .bulkInsert() + .wait(); + + vt::runInEpochCollective("simulateColTColTSends", [&]{ + for (int i = 0; i < dim1; i++) { + if (proxy(i).tryGetLocalPtr()) { + proxy(i).invoke(); + } + } + }); + + vt::thePhase()->nextPhaseCollective(); + + vt::runInEpochCollective("doReduce", [&]{ + for (int i = 0; i < dim1; i++) { + if (proxy(i).tryGetLocalPtr()) { + proxy(i).invoke(); + } + } + }); + + vt::PhaseType phase = 0; + auto sd = getStatsDataForPhase(phase); + auto& comm = sd.node_comm_; + + // Check that communication exists on the receive side as expected + for (int i = 0; i < dim1; i++) { + vt::Index1D idx{i}; + auto prev_i = i-1 >= 0 ? i-1 : dim1-1; + vt::Index1D prev_idx{prev_i}; + if (proxy(i).tryGetLocalPtr()) { + bool found = false; + for (auto&& x : comm) { + for (auto&& y : x.second) { + auto key = y.first; + auto vol = y.second; + if (key.to_.id == idxToElmID(idx)) { + EXPECT_TRUE(key.to_.isMigratable()); + EXPECT_TRUE(key.from_.isMigratable()); + EXPECT_EQ(key.from_.id, idxToElmID(prev_idx)); + EXPECT_EQ(vol.bytes, sizeof(MyMsg) * num_sends); + EXPECT_EQ(vol.messages, num_sends); + found = true; + } + } + } + EXPECT_TRUE(found); + } + } +} + +// ColT -> ObjGroup, expected communication edge on send side +TEST_F(TestLBStatsComm, test_lb_stats_comm_col_to_objgroup_send) { + auto range = vt::Index1D{dim1}; + auto proxy = vt::makeCollection() + .bounds(range) + .bulkInsert() + .wait(); + + auto obj_proxy = vt::theObjGroup()->makeCollective(); + + vt::runInEpochCollective("simulateColTObjGroupSends", [&]{ + for (int i = 0; i < dim1; i++) { + if (proxy(i).tryGetLocalPtr()) { + proxy(i).invoke(obj_proxy); + } + } + }); + + vt::thePhase()->nextPhaseCollective(); + + vt::runInEpochCollective("doReduce", [&]{ + for (int i = 0; i < dim1; i++) { + if (proxy(i).tryGetLocalPtr()) { + proxy(i).invoke(); + } + } + }); + + vt::PhaseType phase = 0; + auto sd = getStatsDataForPhase(phase); + auto& comm = sd.node_comm_; + + auto this_node = theContext()->getNode(); + auto num_nodes = theContext()->getNumNodes(); + auto next = (this_node + 1) % num_nodes; + auto op = obj_proxy.getProxy(); + + // Check that communication exists on the send side as expected + for (int i = 0; i < dim1; i++) { + vt::Index1D idx{i}; + if (proxy(i).tryGetLocalPtr()) { + bool found = false; + auto idb = vt::elm::ElmIDBits::createObjGroup(op, next).id; + for (auto&& x : comm) { + for (auto&& y : x.second) { + auto key = y.first; + auto vol = y.second; + if (key.from_.id == idxToElmID(idx) /*and key.to_.id == idb*/) { + EXPECT_TRUE(key.from_.isMigratable()); + EXPECT_EQ(key.from_.id, idxToElmID(idx)); + EXPECT_FALSE(key.to_.isMigratable()); + EXPECT_EQ(key.to_.id, idb); + EXPECT_EQ(vol.bytes, sizeof(MyObjMsg) * num_sends); + EXPECT_EQ(vol.messages, num_sends); + found = true; + } + } + } + EXPECT_TRUE(found); + } + } +} + +// ObjGroup -> ColT, expected communication edge on receive side +TEST_F(TestLBStatsComm, test_lb_stats_comm_objgroup_to_col_send) { + auto range = vt::Index1D{dim1}; + auto proxy = vt::makeCollection() + .bounds(range) + .bulkInsert() + .wait(); + + auto obj_proxy = vt::theObjGroup()->makeCollective(); + + vt::runInEpochCollective("simulateObjGroupColTSends", [&]{ + auto node = theContext()->getNode(); + // @note: .invoke does not work here because it doesn't create the LBStats + // context! + obj_proxy(node).send(proxy); + }); + + vt::thePhase()->nextPhaseCollective(); + + vt::runInEpochCollective("doReduce", [&]{ + for (int i = 0; i < dim1; i++) { + if (proxy(i).tryGetLocalPtr()) { + proxy(i).invoke(); + } + } + }); + + vt::PhaseType phase = 0; + auto sd = getStatsDataForPhase(phase); + auto& comm = sd.node_comm_; + + auto this_node = theContext()->getNode(); + auto num_nodes = theContext()->getNumNodes(); + auto prev = this_node - 1 >= 0 ? this_node - 1 : num_nodes-1; + auto op = obj_proxy.getProxy(); + + // Check that communication exists on the receive side as expected + for (int i = 0; i < dim1; i++) { + vt::Index1D idx{i}; + if (proxy(i).tryGetLocalPtr()) { + bool found = false; + for (auto&& x : comm) { + for (auto&& y : x.second) { + auto key = y.first; + auto vol = y.second; + if (key.to_.id == idxToElmID(idx)) { + EXPECT_TRUE(key.to_.isMigratable()); + EXPECT_EQ(key.to_.id, idxToElmID(idx)); + EXPECT_FALSE(key.from_.isMigratable()); + EXPECT_EQ(key.from_.id, vt::elm::ElmIDBits::createObjGroup(op, prev).id); + EXPECT_EQ(vol.bytes, sizeof(MyMsg) * num_sends); + EXPECT_EQ(vol.messages, num_sends); + found = true; + } + } + } + EXPECT_TRUE(found); + } + } +} + +// ObjGroup -> ObjGroup, expected communication edge on send side +TEST_F(TestLBStatsComm, test_lb_stats_comm_objgroup_to_objgroup_send) { + auto obj_proxy_a = vt::theObjGroup()->makeCollective(); + auto obj_proxy_b = vt::theObjGroup()->makeCollective(); + + vt::runInEpochCollective("simulateObjGroupObjGroupSends", [&]{ + auto node = theContext()->getNode(); + // @note: .invoke does not work here because it doesn't create the LBStats + // context! + obj_proxy_a(node).send( + obj_proxy_b + ); + }); + + vt::thePhase()->nextPhaseCollective(); + + vt::PhaseType phase = 0; + auto sd = getStatsDataForPhase(phase); + auto& comm = sd.node_comm_; + + auto this_node = theContext()->getNode(); + auto num_nodes = theContext()->getNumNodes(); + auto next = (this_node + 1) % num_nodes; + auto opa = obj_proxy_a.getProxy(); + auto opb = obj_proxy_b.getProxy(); + auto ida = vt::elm::ElmIDBits::createObjGroup(opa, this_node).id; + auto idb = vt::elm::ElmIDBits::createObjGroup(opb, next).id; + + // Check that communication exists on the send side as expected + bool found = false; + for (auto&& x : comm) { + for (auto&& y : x.second) { + auto key = y.first; + auto vol = y.second; + if (key.from_.id == ida /*and key.to_.id == idb*/) { + EXPECT_FALSE(key.to_.isMigratable()); + EXPECT_EQ(key.from_.id, ida); + EXPECT_FALSE(key.from_.isMigratable()); + EXPECT_EQ(key.to_.id, idb); + EXPECT_EQ(vol.bytes, sizeof(MyObjMsg) * num_sends); + EXPECT_EQ(vol.messages, num_sends); + found = true; + } + } + } + EXPECT_TRUE(found); +} + +// Handler -> ColT, expected communication edge on receive side +TEST_F(TestLBStatsComm, test_lb_stats_comm_handler_to_col_send) { + auto range = vt::Index1D{dim1}; + auto proxy = vt::makeCollection() + .bounds(range) + .bulkInsert() + .wait(); + + vt::runInEpochCollective("simulateHandlerColTSends", [&]{ + auto this_node = theContext()->getNode(); + auto num_nodes = theContext()->getNumNodes(); + auto next = (this_node + 1) % num_nodes; + auto msg = makeMessage(proxy); + theMsg()->sendMsg(next, msg); + }); + + vt::thePhase()->nextPhaseCollective(); + + vt::runInEpochCollective("doReduce", [&]{ + for (int i = 0; i < dim1; i++) { + if (proxy(i).tryGetLocalPtr()) { + proxy(i).invoke(); + } + } + }); + + vt::PhaseType phase = 0; + auto sd = getStatsDataForPhase(phase); + auto& comm = sd.node_comm_; + + auto this_node = theContext()->getNode(); + auto num_nodes = theContext()->getNumNodes(); + auto prev = this_node - 1 >= 0 ? this_node - 1 : num_nodes-1; + + // Check that communication exists on the receive side as expected + for (int i = 0; i < dim1; i++) { + vt::Index1D idx{i}; + if (proxy(i).tryGetLocalPtr()) { + bool found = false; + for (auto&& x : comm) { + for (auto&& y : x.second) { + auto key = y.first; + auto vol = y.second; + if (key.to_.id == idxToElmID(idx)) { + EXPECT_TRUE(key.to_.isMigratable()); + EXPECT_EQ(key.to_.id, idxToElmID(idx)); + EXPECT_FALSE(key.from_.isMigratable()); + EXPECT_EQ(key.from_.id, vt::elm::ElmIDBits::createBareHandler(prev).id); + EXPECT_EQ(vol.bytes, sizeof(MyMsg) * num_sends); + EXPECT_EQ(vol.messages, num_sends); + found = true; + } + } + } + EXPECT_TRUE(found); + } + } +} + + +// ColT -> Handler, expected communication edge on send side +TEST_F(TestLBStatsComm, test_lb_stats_comm_col_to_handler_send) { + auto range = vt::Index1D{dim1}; + auto proxy = vt::makeCollection() + .bounds(range) + .bulkInsert() + .wait(); + + vt::runInEpochCollective("simulateColTHandlerSends", [&]{ + for (int i = 0; i < dim1; i++) { + if (proxy(i).tryGetLocalPtr()) { + proxy(i).invoke(); + } + } + }); + + vt::thePhase()->nextPhaseCollective(); + + vt::runInEpochCollective("doReduce", [&]{ + for (int i = 0; i < dim1; i++) { + if (proxy(i).tryGetLocalPtr()) { + proxy(i).invoke(); + } + } + }); + + vt::PhaseType phase = 0; + auto sd = getStatsDataForPhase(phase); + auto& comm = sd.node_comm_; + + auto this_node = theContext()->getNode(); + auto num_nodes = theContext()->getNumNodes(); + auto next = (this_node + 1) % num_nodes; + + // Check that communication exists on the send side as expected + for (int i = 0; i < dim1; i++) { + vt::Index1D idx{i}; + if (proxy(i).tryGetLocalPtr()) { + bool found = false; + for (auto&& x : comm) { + for (auto&& y : x.second) { + auto key = y.first; + auto vol = y.second; + fmt::print("from={}, to={}\n", key.from_, key.to_); + if (key.from_.id == idxToElmID(idx)) { + EXPECT_TRUE(key.from_.isMigratable()); + EXPECT_EQ(key.from_.id, idxToElmID(idx)); + EXPECT_FALSE(key.to_.isMigratable()); + EXPECT_EQ(key.to_.id, vt::elm::ElmIDBits::createBareHandler(next).id); + EXPECT_EQ(vol.bytes, sizeof(MyObjMsg) * num_sends); + EXPECT_EQ(vol.messages, num_sends); + found = true; + } + } + } + EXPECT_TRUE(found); + } + } +} + +// ObjGroup -> Handler, expected communication edge on send side +TEST_F(TestLBStatsComm, test_lb_stats_comm_objgroup_to_handler_send) { + auto obj_proxy_a = vt::theObjGroup()->makeCollective(); + + vt::runInEpochCollective("simulateObjGroupHandlerSends", [&]{ + auto node = theContext()->getNode(); + // @note: .invoke does not work here because it doesn't create the LBStats + // context! + obj_proxy_a(node).send(); + }); + + + vt::thePhase()->nextPhaseCollective(); + + vt::PhaseType phase = 0; + auto sd = getStatsDataForPhase(phase); + auto& comm = sd.node_comm_; + + auto this_node = theContext()->getNode(); + auto num_nodes = theContext()->getNumNodes(); + auto next = (this_node + 1) % num_nodes; + auto opa = obj_proxy_a.getProxy(); + auto ida = vt::elm::ElmIDBits::createObjGroup(opa, this_node).id; + + // Check that communication exists on the send side as expected + bool found = false; + for (auto&& x : comm) { + for (auto&& y : x.second) { + auto key = y.first; + auto vol = y.second; + if (key.from_.id == ida) { + EXPECT_FALSE(key.to_.isMigratable()); + EXPECT_EQ(key.to_.id, vt::elm::ElmIDBits::createBareHandler(next).id); + EXPECT_FALSE(key.from_.isMigratable()); + EXPECT_EQ(vol.bytes, sizeof(MyObjMsg) * num_sends); + EXPECT_EQ(vol.messages, num_sends); + found = true; + } + } + } + EXPECT_TRUE(found); +} + +// Handler -> ObjGroup, expected communication edge on send side +TEST_F(TestLBStatsComm, test_lb_stats_comm_handler_to_objgroup_send) { + auto obj_proxy_a = vt::theObjGroup()->makeCollective(); + + vt::runInEpochCollective("simulateHandlerObjGroupSends", [&]{ + auto this_node = theContext()->getNode(); + auto num_nodes = theContext()->getNumNodes(); + auto next = (this_node + 1) % num_nodes; + auto msg = makeMessage(obj_proxy_a); + theMsg()->sendMsg(next, msg); + }); + + vt::thePhase()->nextPhaseCollective(); + + vt::PhaseType phase = 0; + auto sd = getStatsDataForPhase(phase); + auto& comm = sd.node_comm_; + + auto this_node = theContext()->getNode(); + auto num_nodes = theContext()->getNumNodes(); + auto next = (this_node + 1) % num_nodes; + auto opa = obj_proxy_a.getProxy(); + auto ida = vt::elm::ElmIDBits::createObjGroup(opa, next).id; + + // Check that communication exists on the send side as expected + bool found = false; + for (auto&& x : comm) { + for (auto&& y : x.second) { + auto key = y.first; + auto vol = y.second; + if (key.to_.id == ida) { + EXPECT_FALSE(key.to_.isMigratable()); + EXPECT_EQ(key.from_.id, vt::elm::ElmIDBits::createBareHandler(this_node).id); + EXPECT_FALSE(key.from_.isMigratable()); + EXPECT_EQ(vol.bytes, sizeof(MyObjMsg) * num_sends); + EXPECT_EQ(vol.messages, num_sends); + found = true; + } + } + } + EXPECT_TRUE(found); +} + +// Handler -> Handler, expected communication edge on send side +TEST_F(TestLBStatsComm, test_lb_stats_comm_handler_to_handler_send) { + vt::runInEpochCollective("simulateHandlerHandlerSends", [&]{ + auto this_node = theContext()->getNode(); + auto num_nodes = theContext()->getNumNodes(); + auto next = (this_node + 1) % num_nodes; + auto msg = makeMessage(); + theMsg()->sendMsg(next, msg); + }); + + vt::thePhase()->nextPhaseCollective(); + + vt::PhaseType phase = 0; + auto sd = getStatsDataForPhase(phase); + auto& comm = sd.node_comm_; + + auto this_node = theContext()->getNode(); + auto num_nodes = theContext()->getNumNodes(); + auto next = (this_node + 1) % num_nodes; + auto ida = vt::elm::ElmIDBits::createBareHandler(next).id; + auto idb = vt::elm::ElmIDBits::createBareHandler(this_node).id; + + // Check that communication exists on the send side as expected + bool found = false; + for (auto&& x : comm) { + for (auto&& y : x.second) { + auto key = y.first; + auto vol = y.second; + if (key.to_.id == ida and key.from_.id == idb) { + EXPECT_FALSE(key.to_.isMigratable()); + EXPECT_FALSE(key.from_.isMigratable()); + EXPECT_GE(vol.bytes, sizeof(MyObjMsg) * num_sends); + EXPECT_GE(vol.messages, num_sends); + found = true; + } + } + } + EXPECT_TRUE(found); +} + +} /* end anon namespace */ + +}}}} // end namespace vt::tests::unit::comm + +#endif diff --git a/tests/unit/lb/test_lb_stats_reader.cc b/tests/unit/lb/test_lb_stats_reader.cc index ff67fbd5b5..7cacd347bf 100644 --- a/tests/unit/lb/test_lb_stats_reader.cc +++ b/tests/unit/lb/test_lb_stats_reader.cc @@ -45,6 +45,7 @@ #include #include +#include #include #include #include @@ -58,11 +59,6 @@ namespace vt { namespace tests { namespace unit { struct TestLBStatsReader : TestParallelHarness { }; using ElementIDType = uint64_t; -ElementIDType getElemPermID(size_t elm, NodeType inode) { - //--- Formula inside the function "Stats::getNextElem()" - return static_cast((elm << 32) | inode); -} - TEST_F(TestLBStatsReader, test_lb_stats_read_1) { // Iter 0 @@ -89,10 +85,9 @@ TEST_F(TestLBStatsReader, test_lb_stats_read_1) { std::vector myElemList(numElements); for (size_t ii = 0; ii < numElements; ++ii) { - //--- Shift by 1 to avoid the null permID - myElemList[ii] = ElementIDStruct{ - getElemPermID(ii+1, this_node), this_node, this_node - }; + myElemList[ii] = elm::ElmIDBits::createCollectionImpl( + true, ii+1, this_node, this_node + ); } using JSONAppender = vt::util::json::Appender; @@ -122,7 +117,9 @@ TEST_F(TestLBStatsReader, test_lb_stats_read_1) { } for (NodeType in = 0; in+1 < num_nodes; ++in) { for (uint64_t elmID = 1; elmID < numElements; ++elmID) { - auto permID = ElementIDStruct{getElemPermID(elmID+1, in), this_node, in}; + auto permID = elm::ElmIDBits::createCollectionImpl( + true, elmID+1, in, in + ); sd->node_data_[phase][permID].whole_phase_load = tval; } } @@ -168,7 +165,7 @@ TEST_F(TestLBStatsReader, test_lb_stats_read_1) { auto it = std::find(myList.begin(), myList.end(), myPermID.id); EXPECT_TRUE(it != myList.end()); size_t shift = static_cast(it - myList.begin()); - EXPECT_TRUE(myList[shift+1] == static_cast(num_nodes - 1)); + EXPECT_EQ(myList[shift+1], static_cast(num_nodes - 1)); } } @@ -182,7 +179,9 @@ TEST_F(TestLBStatsReader, test_lb_stats_read_1) { EXPECT_TRUE(myList.size() % 2 == 0); for (NodeType in = 0; in+1 < num_nodes; ++in) { for (ElementIDType elmID = 1; elmID < numElements; ++elmID) { - ElementIDType permID = getElemPermID(elmID + 1, in); + ElementIDType permID = elm::ElmIDBits::createCollectionImpl( + true, elmID+1, in, in + ).id; auto it = std::find(myList.begin(), myList.end(), permID); EXPECT_TRUE(it != myList.end()); size_t shift = static_cast(it - myList.begin()); diff --git a/tests/unit/lb/test_temperedlb.nompi.cc b/tests/unit/lb/test_temperedlb.nompi.cc index 90401a0aa8..bd0c15e811 100644 --- a/tests/unit/lb/test_temperedlb.nompi.cc +++ b/tests/unit/lb/test_temperedlb.nompi.cc @@ -58,12 +58,12 @@ TimeType setupProblem( std::unordered_map &cur_objs ) { // total load of 29 seconds - cur_objs.emplace(ElementIDStruct{3,0,0}, 4.0); - cur_objs.emplace(ElementIDStruct{5,0,0}, 5.0); - cur_objs.emplace(ElementIDStruct{2,0,0}, 9.0); - cur_objs.emplace(ElementIDStruct{0,0,0}, 2.0); - cur_objs.emplace(ElementIDStruct{1,0,0}, 6.0); - cur_objs.emplace(ElementIDStruct{4,0,0}, 3.0); + cur_objs.emplace(ElementIDStruct{3,0}, 4.0); + cur_objs.emplace(ElementIDStruct{5,0}, 5.0); + cur_objs.emplace(ElementIDStruct{2,0}, 9.0); + cur_objs.emplace(ElementIDStruct{0,0}, 2.0); + cur_objs.emplace(ElementIDStruct{1,0}, 6.0); + cur_objs.emplace(ElementIDStruct{4,0}, 3.0); // compute the load for this processor TimeType my_load = 0;