From 99f0dd35e34dec70eacae23d0046d09d7d17bf2a Mon Sep 17 00:00:00 2001 From: Jonathan Lifflander Date: Thu, 10 Jun 2021 14:19:17 -0700 Subject: [PATCH 1/8] #1395: greedylb: implement alternative strategies to scatter --- .../collection/balance/greedylb/greedylb.cc | 64 +++++++++++++++---- .../collection/balance/greedylb/greedylb.h | 4 +- .../balance/greedylb/greedylb_msgs.h | 38 +++++++++++ 3 files changed, 94 insertions(+), 12 deletions(-) diff --git a/src/vt/vrt/collection/balance/greedylb/greedylb.cc b/src/vt/vrt/collection/balance/greedylb/greedylb.cc index 50f5efd0f0..7fc5c3579b 100644 --- a/src/vt/vrt/collection/balance/greedylb/greedylb.cc +++ b/src/vt/vrt/collection/balance/greedylb/greedylb.cc @@ -214,24 +214,39 @@ GreedyLB::ObjIDType GreedyLB::objSetNode( return new_id; } -void GreedyLB::recvObjsDirect(GreedyLBTypes::ObjIDType* objs) { +void GreedyLB::recvObjs(GreedySendMsg* msg) { + vt_debug_print( + normal, lb, + "recvObjs: msg->transfer_.size={}\n", msg->transfer_.size() + ); + recvObjsDirect(msg->transfer_.size(), &msg->transfer_[0]); +} + +void GreedyLB::recvObjsBcast(GreedyBcastMsg* msg) { + auto const n = theContext()->getNode(); + vt_debug_print( + normal, lb, + "recvObjs: msg->transfer_.size={}\n", msg->transfer_[n].size() + ); + recvObjsDirect(msg->transfer_[n].size(), &msg->transfer_[n][0]); +} + +void GreedyLB::recvObjsDirect(std::size_t len, GreedyLBTypes::ObjIDType* objs) { auto const& this_node = theContext()->getNode(); - auto const& num_recs = *objs; - auto recs = objs + 1; + auto const& num_recs = len; vt_debug_print( normal, lb, "recvObjsDirect: num_recs={}\n", num_recs ); - for (decltype(+num_recs.id) i = 0; i < num_recs.id; i++) { - auto const to_node = objGetNode(recs[i]); - auto const new_obj_id = objSetNode(this_node,recs[i]); + for (std::size_t i = 0; i < len; i++) { + auto const to_node = objGetNode(objs[i]); + auto const new_obj_id = objSetNode(this_node,objs[i]); vt_debug_print( verbose, lb, - "\t recvObjs: i={}, to_node={}, obj={}, new_obj_id={}, num_recs={}, " - "byte_offset={}\n", - i, to_node, recs[i], new_obj_id, num_recs, - reinterpret_cast(recs) - reinterpret_cast(objs) + "\t recvObjs: i={}, to_node={}, obj={}, new_obj_id={}, num_recs={}" + "\n", + i, to_node, objs[i], new_obj_id, num_recs ); migrateObjectTo(new_obj_id, to_node); @@ -243,11 +258,17 @@ void GreedyLB::recvObjsDirect(GreedyLBTypes::ObjIDType* objs) { verbose, lb, "recvObjsHan: num_recs={}\n", *objs ); - scatter_proxy.get()->recvObjsDirect(objs); + scatter_proxy.get()->recvObjsDirect(static_cast(objs->id), objs+1); } void GreedyLB::transferObjs(std::vector&& in_load) { +#define SCATTER 0 +#define PT2PT 0 +#define BROADCAST 1 + +#if SCATTER std::size_t max_recs = 0, max_bytes = 0; +#endif std::vector load(std::move(in_load)); std::vector> node_transfer(load.size()); for (auto&& elm : load) { @@ -259,10 +280,14 @@ void GreedyLB::transferObjs(std::vector&& in_load) { if (cur_node != node) { auto const new_obj_id = objSetNode(node, rec); node_transfer[cur_node].push_back(new_obj_id); +#if SCATTER max_recs = std::max(max_recs, node_transfer[cur_node].size() + 1); +#endif } } } + +#if SCATTER max_bytes = max_recs * sizeof(GreedyLBTypes::ObjIDType); vt_debug_print( normal, lb, @@ -280,6 +305,23 @@ void GreedyLB::transferObjs(std::vector&& in_load) { } } ); +#elif PT2PT + for (NodeType n = 0; n < theContext()->getNumNodes(); n++) { + vtAssert( + node_transfer.size() == static_cast(theContext()->getNumNodes()), + "Must contain all nodes" + ); + proxy[n].send(node_transfer[n]); + } +#elif BROADCAST + proxy.broadcast(node_transfer); +#else +# error "Must select some strategy for distribuing info" +#endif + +#undef BROADCAST +#undef PT2PT +#undef SCATTER } double GreedyLB::getAvgLoad() const { diff --git a/src/vt/vrt/collection/balance/greedylb/greedylb.h b/src/vt/vrt/collection/balance/greedylb/greedylb.h index edb3bc0103..19d17c27ca 100644 --- a/src/vt/vrt/collection/balance/greedylb/greedylb.h +++ b/src/vt/vrt/collection/balance/greedylb/greedylb.h @@ -86,7 +86,9 @@ struct GreedyLB : BaseLB { void runBalancer(ObjSampleType&& objs, LoadProfileType&& profile); void transferObjs(std::vector&& load); ObjIDType objSetNode(NodeType const& node, ObjIDType const& id); - void recvObjsDirect(GreedyLBTypes::ObjIDType* objs); + void recvObjsDirect(std::size_t len, GreedyLBTypes::ObjIDType* objs); + void recvObjs(GreedySendMsg* msg); + void recvObjsBcast(GreedyBcastMsg* msg); void finishedTransferExchange(); void collectHandler(GreedyCollectMsg* msg); diff --git a/src/vt/vrt/collection/balance/greedylb/greedylb_msgs.h b/src/vt/vrt/collection/balance/greedylb/greedylb_msgs.h index 0112a575f9..401545d3f3 100644 --- a/src/vt/vrt/collection/balance/greedylb/greedylb_msgs.h +++ b/src/vt/vrt/collection/balance/greedylb/greedylb_msgs.h @@ -129,6 +129,44 @@ struct GreedyCollectMsg : GreedyLBTypes, collective::ReduceTMsg { } }; +struct GreedySendMsg : GreedyLBTypes, vt::Message { + using MessageParentType = vt::Message; + vt_msg_serialize_required(); // vector + + GreedySendMsg() = default; + explicit GreedySendMsg(std::vector const& in) + : transfer_(in) + { } + + template + void serialize(SerializerT& s) { + MessageParentType::serialize(s); + s | transfer_; + } + + std::vector transfer_; +}; + +struct GreedyBcastMsg : GreedyLBTypes, vt::Message { + using MessageParentType = vt::Message; + vt_msg_serialize_required(); // vector + + using DataType = std::vector>; + + GreedyBcastMsg() = default; + explicit GreedyBcastMsg(DataType const& in) + : transfer_(in) + { } + + template + void serialize(SerializerT& s) { + MessageParentType::serialize(s); + s | transfer_; + } + + DataType transfer_; +}; + }}}} /* end namespace vt::vrt::collection::lb */ #endif /*INCLUDED_VT_VRT_COLLECTION_BALANCE_GREEDYLB_GREEDYLB_MSGS_H*/ From bcd33e7981dbc839799e0353e9ef38179f5f9210 Mon Sep 17 00:00:00 2001 From: Jonathan Lifflander Date: Thu, 10 Jun 2021 15:10:39 -0700 Subject: [PATCH 2/8] #1395: greedylb: fix bug in scatter (recs must be >= 1) --- src/vt/vrt/collection/balance/greedylb/greedylb.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vt/vrt/collection/balance/greedylb/greedylb.cc b/src/vt/vrt/collection/balance/greedylb/greedylb.cc index 7fc5c3579b..c9394ff48c 100644 --- a/src/vt/vrt/collection/balance/greedylb/greedylb.cc +++ b/src/vt/vrt/collection/balance/greedylb/greedylb.cc @@ -267,7 +267,7 @@ void GreedyLB::transferObjs(std::vector&& in_load) { #define BROADCAST 1 #if SCATTER - std::size_t max_recs = 0, max_bytes = 0; + std::size_t max_recs = 1, max_bytes = 0; #endif std::vector load(std::move(in_load)); std::vector> node_transfer(load.size()); From 6ae2e46307b87a4315dbffa203a155ec7f06022a Mon Sep 17 00:00:00 2001 From: Jonathan Lifflander Date: Thu, 10 Jun 2021 15:10:55 -0700 Subject: [PATCH 3/8] #1395: greedylb: enable scatter by default now --- src/vt/vrt/collection/balance/greedylb/greedylb.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vt/vrt/collection/balance/greedylb/greedylb.cc b/src/vt/vrt/collection/balance/greedylb/greedylb.cc index c9394ff48c..95cedaa4a5 100644 --- a/src/vt/vrt/collection/balance/greedylb/greedylb.cc +++ b/src/vt/vrt/collection/balance/greedylb/greedylb.cc @@ -262,9 +262,9 @@ void GreedyLB::recvObjsDirect(std::size_t len, GreedyLBTypes::ObjIDType* objs) { } void GreedyLB::transferObjs(std::vector&& in_load) { -#define SCATTER 0 +#define SCATTER 1 #define PT2PT 0 -#define BROADCAST 1 +#define BROADCAST 0 #if SCATTER std::size_t max_recs = 1, max_bytes = 0; From 1c98aa338e1c8dea1064aedc15efaaf08b10cc1d Mon Sep 17 00:00:00 2001 From: Jonathan Lifflander Date: Tue, 29 Jun 2021 16:18:29 -0700 Subject: [PATCH 4/8] #1395: lb: make greedylb distribution strategy runtime configurable --- .../collection/balance/greedylb/greedylb.cc | 80 +++++++++---------- .../collection/balance/greedylb/greedylb.h | 13 +++ 2 files changed, 52 insertions(+), 41 deletions(-) diff --git a/src/vt/vrt/collection/balance/greedylb/greedylb.cc b/src/vt/vrt/collection/balance/greedylb/greedylb.cc index 95cedaa4a5..ce1eecff7c 100644 --- a/src/vt/vrt/collection/balance/greedylb/greedylb.cc +++ b/src/vt/vrt/collection/balance/greedylb/greedylb.cc @@ -72,11 +72,23 @@ void GreedyLB::init(objgroup::proxy::Proxy in_proxy) { } void GreedyLB::inputParams(balance::SpecEntry* spec) { - std::vector allowed{"min", "max", "auto"}; + std::vector allowed{"min", "max", "auto", "strategy"}; spec->checkAllowedKeys(allowed); min_threshold = spec->getOrDefault("min", greedy_threshold_p); max_threshold = spec->getOrDefault("max", greedy_max_threshold_p); auto_threshold = spec->getOrDefault("auto", greedy_auto_threshold_p); + + std::string extract = spec->getOrDefault("strategy", "scatter"); + if (extract.compare("scatter") == 0) { + strat_ = DataDistStrategy::SCATTER; + } else if (extract.compare("pt2pt") == 0) { + strat_ = DataDistStrategy::PT2PT; + } else if (extract.compare("broadcast") == 0) { + strat_ = DataDistStrategy::BCAST; + } else { + auto str = fmt::format("GreedyLB strategy={} is not valid", extract); + vtAbort(str); + } } void GreedyLB::runLB() { @@ -262,13 +274,7 @@ void GreedyLB::recvObjsDirect(std::size_t len, GreedyLBTypes::ObjIDType* objs) { } void GreedyLB::transferObjs(std::vector&& in_load) { -#define SCATTER 1 -#define PT2PT 0 -#define BROADCAST 0 - -#if SCATTER std::size_t max_recs = 1, max_bytes = 0; -#endif std::vector load(std::move(in_load)); std::vector> node_transfer(load.size()); for (auto&& elm : load) { @@ -280,48 +286,40 @@ void GreedyLB::transferObjs(std::vector&& in_load) { if (cur_node != node) { auto const new_obj_id = objSetNode(node, rec); node_transfer[cur_node].push_back(new_obj_id); -#if SCATTER max_recs = std::max(max_recs, node_transfer[cur_node].size() + 1); -#endif } } } -#if SCATTER - max_bytes = max_recs * sizeof(GreedyLBTypes::ObjIDType); - vt_debug_print( - normal, lb, - "GreedyLB::transferObjs: max_recs={}, max_bytes={}\n", - max_recs, max_bytes - ); - theCollective()->scatter( - max_bytes*load.size(),max_bytes,nullptr,[&](NodeType node, void* ptr){ - auto ptr_out = reinterpret_cast(ptr); - auto const& proc = node_transfer[node]; - auto const& rec_size = proc.size(); - ptr_out->id = rec_size; - for (size_t i = 0; i < rec_size; i++) { - *(ptr_out + i + 1) = proc[i]; + if (strat_ == DataDistStrategy::SCATTER) { + max_bytes = max_recs * sizeof(GreedyLBTypes::ObjIDType); + vt_debug_print( + normal, lb, + "GreedyLB::transferObjs: max_recs={}, max_bytes={}\n", + max_recs, max_bytes + ); + theCollective()->scatter( + max_bytes*load.size(),max_bytes,nullptr,[&](NodeType node, void* ptr){ + auto ptr_out = reinterpret_cast(ptr); + auto const& proc = node_transfer[node]; + auto const& rec_size = proc.size(); + ptr_out->id = rec_size; + for (size_t i = 0; i < rec_size; i++) { + *(ptr_out + i + 1) = proc[i]; + } } - } - ); -#elif PT2PT - for (NodeType n = 0; n < theContext()->getNumNodes(); n++) { - vtAssert( - node_transfer.size() == static_cast(theContext()->getNumNodes()), - "Must contain all nodes" ); - proxy[n].send(node_transfer[n]); + } else if (strat_ == DataDistStrategy::PT2PT) { + for (NodeType n = 0; n < theContext()->getNumNodes(); n++) { + vtAssert( + node_transfer.size() == static_cast(theContext()->getNumNodes()), + "Must contain all nodes" + ); + proxy[n].send(node_transfer[n]); + } + } else if (strat_ == DataDistStrategy::BCAST) { + proxy.broadcast(node_transfer); } -#elif BROADCAST - proxy.broadcast(node_transfer); -#else -# error "Must select some strategy for distribuing info" -#endif - -#undef BROADCAST -#undef PT2PT -#undef SCATTER } double GreedyLB::getAvgLoad() const { diff --git a/src/vt/vrt/collection/balance/greedylb/greedylb.h b/src/vt/vrt/collection/balance/greedylb/greedylb.h index 19d17c27ca..f1bcce9881 100644 --- a/src/vt/vrt/collection/balance/greedylb/greedylb.h +++ b/src/vt/vrt/collection/balance/greedylb/greedylb.h @@ -60,6 +60,17 @@ namespace vt { namespace vrt { namespace collection { namespace lb { +/** + * \enum DataDistStrategy + * + * \brief How to distribute the data after the centralized LB makes a decision. + */ +enum struct DataDistStrategy : uint8_t { + SCATTER = 0, + BCAST = 1, + PT2PT = 2 +}; + struct GreedyLB : BaseLB { using ElementLoadType = std::unordered_map; using TransferType = std::map>; @@ -107,6 +118,8 @@ struct GreedyLB : BaseLB { double max_threshold = 0.0f; double min_threshold = 0.0f; bool auto_threshold = true; + + DataDistStrategy strat_ = DataDistStrategy::SCATTER; }; }}}} /* end namespace vt::vrt::collection::lb */ From da5c21e160d7fc021b0feaef54bc6680757346d1 Mon Sep 17 00:00:00 2001 From: Jonathan Lifflander Date: Tue, 29 Jun 2021 16:42:56 -0700 Subject: [PATCH 5/8] #1395: tests: add more testing across GreedyLB strategies --- tests/unit/collection/test_lb.extended.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/unit/collection/test_lb.extended.cc b/tests/unit/collection/test_lb.extended.cc index e2eec57736..a3ec89e8c2 100644 --- a/tests/unit/collection/test_lb.extended.cc +++ b/tests/unit/collection/test_lb.extended.cc @@ -101,6 +101,12 @@ void TestLoadBalancer::runTest() { fmt::print("Using lb_args {}\n", lb_args); } } + if (lb_name.substr(0, 8).compare("GreedyLB") == 0) { + vt::theConfig()->vt_lb_name = "GreedyLB"; + auto strat_arg = lb_name.substr(9, lb_name.size() - 9); + fmt::print("strat_arg={}\n", strat_arg); + vt::theConfig()->vt_lb_args = strat_arg; + } vt::theCollective()->barrier(); @@ -161,7 +167,9 @@ auto balancers = ::testing::Values( "RotateLB", "HierarchicalLB", "TemperedLB", - "GreedyLB" + "GreedyLB:strategy=scatter", + "GreedyLB:strategy=pt2pt", + "GreedyLB:strategy=broadcast" # if vt_check_enabled(zoltan) , "ZoltanLB" # endif From 77ebe0806f873af2db01529be6728c452d629956 Mon Sep 17 00:00:00 2001 From: Jonathan Lifflander Date: Thu, 1 Jul 2021 09:53:15 -0700 Subject: [PATCH 6/8] #1395: lb: use lb enum converter --- .../collection/balance/greedylb/greedylb.cc | 26 +++++++++---------- .../collection/balance/greedylb/greedylb.h | 8 +++--- tests/unit/collection/test_lb.extended.cc | 2 +- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/vt/vrt/collection/balance/greedylb/greedylb.cc b/src/vt/vrt/collection/balance/greedylb/greedylb.cc index ce1eecff7c..47f5bd5c14 100644 --- a/src/vt/vrt/collection/balance/greedylb/greedylb.cc +++ b/src/vt/vrt/collection/balance/greedylb/greedylb.cc @@ -56,6 +56,7 @@ #include "vt/context/context.h" #include "vt/vrt/collection/manager.h" #include "vt/collective/reduce/reduce.h" +#include "vt/vrt/collection/balance/lb_args_enum_converter.h" #include #include @@ -78,17 +79,14 @@ void GreedyLB::inputParams(balance::SpecEntry* spec) { max_threshold = spec->getOrDefault("max", greedy_max_threshold_p); auto_threshold = spec->getOrDefault("auto", greedy_auto_threshold_p); - std::string extract = spec->getOrDefault("strategy", "scatter"); - if (extract.compare("scatter") == 0) { - strat_ = DataDistStrategy::SCATTER; - } else if (extract.compare("pt2pt") == 0) { - strat_ = DataDistStrategy::PT2PT; - } else if (extract.compare("broadcast") == 0) { - strat_ = DataDistStrategy::BCAST; - } else { - auto str = fmt::format("GreedyLB strategy={} is not valid", extract); - vtAbort(str); - } + balance::LBArgsEnumConverter strategy_converter_( + "strategy", "DataDistStrategy", { + {DataDistStrategy::scatter, "scatter"}, + {DataDistStrategy::pt2pt, "pt2pt"}, + {DataDistStrategy::bcast, "bcast"} + } + ); + strat_ = strategy_converter_.getFromSpec(spec, strat_); } void GreedyLB::runLB() { @@ -291,7 +289,7 @@ void GreedyLB::transferObjs(std::vector&& in_load) { } } - if (strat_ == DataDistStrategy::SCATTER) { + if (strat_ == DataDistStrategy::scatter) { max_bytes = max_recs * sizeof(GreedyLBTypes::ObjIDType); vt_debug_print( normal, lb, @@ -309,7 +307,7 @@ void GreedyLB::transferObjs(std::vector&& in_load) { } } ); - } else if (strat_ == DataDistStrategy::PT2PT) { + } else if (strat_ == DataDistStrategy::pt2pt) { for (NodeType n = 0; n < theContext()->getNumNodes(); n++) { vtAssert( node_transfer.size() == static_cast(theContext()->getNumNodes()), @@ -317,7 +315,7 @@ void GreedyLB::transferObjs(std::vector&& in_load) { ); proxy[n].send(node_transfer[n]); } - } else if (strat_ == DataDistStrategy::BCAST) { + } else if (strat_ == DataDistStrategy::bcast) { proxy.broadcast(node_transfer); } } diff --git a/src/vt/vrt/collection/balance/greedylb/greedylb.h b/src/vt/vrt/collection/balance/greedylb/greedylb.h index f1bcce9881..a99018c76a 100644 --- a/src/vt/vrt/collection/balance/greedylb/greedylb.h +++ b/src/vt/vrt/collection/balance/greedylb/greedylb.h @@ -66,9 +66,9 @@ namespace vt { namespace vrt { namespace collection { namespace lb { * \brief How to distribute the data after the centralized LB makes a decision. */ enum struct DataDistStrategy : uint8_t { - SCATTER = 0, - BCAST = 1, - PT2PT = 2 + scatter = 0, + bcast = 1, + pt2pt = 2 }; struct GreedyLB : BaseLB { @@ -119,7 +119,7 @@ struct GreedyLB : BaseLB { double min_threshold = 0.0f; bool auto_threshold = true; - DataDistStrategy strat_ = DataDistStrategy::SCATTER; + DataDistStrategy strat_ = DataDistStrategy::scatter; }; }}}} /* end namespace vt::vrt::collection::lb */ diff --git a/tests/unit/collection/test_lb.extended.cc b/tests/unit/collection/test_lb.extended.cc index a3ec89e8c2..7de9b142b4 100644 --- a/tests/unit/collection/test_lb.extended.cc +++ b/tests/unit/collection/test_lb.extended.cc @@ -169,7 +169,7 @@ auto balancers = ::testing::Values( "TemperedLB", "GreedyLB:strategy=scatter", "GreedyLB:strategy=pt2pt", - "GreedyLB:strategy=broadcast" + "GreedyLB:strategy=bcast" # if vt_check_enabled(zoltan) , "ZoltanLB" # endif From c1ad7c7274c335368288a69fd64694fb0628ec93 Mon Sep 17 00:00:00 2001 From: Jonathan Lifflander Date: Mon, 23 Aug 2021 11:23:29 -0700 Subject: [PATCH 7/8] #1395: lb: reduce scope of variable based on Codacy suggestion --- src/vt/vrt/collection/balance/greedylb/greedylb.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vt/vrt/collection/balance/greedylb/greedylb.cc b/src/vt/vrt/collection/balance/greedylb/greedylb.cc index 47f5bd5c14..7ae604ab1b 100644 --- a/src/vt/vrt/collection/balance/greedylb/greedylb.cc +++ b/src/vt/vrt/collection/balance/greedylb/greedylb.cc @@ -272,7 +272,7 @@ void GreedyLB::recvObjsDirect(std::size_t len, GreedyLBTypes::ObjIDType* objs) { } void GreedyLB::transferObjs(std::vector&& in_load) { - std::size_t max_recs = 1, max_bytes = 0; + std::size_t max_recs = 1; std::vector load(std::move(in_load)); std::vector> node_transfer(load.size()); for (auto&& elm : load) { @@ -290,7 +290,7 @@ void GreedyLB::transferObjs(std::vector&& in_load) { } if (strat_ == DataDistStrategy::scatter) { - max_bytes = max_recs * sizeof(GreedyLBTypes::ObjIDType); + std::size_t max_bytes = max_recs * sizeof(GreedyLBTypes::ObjIDType); vt_debug_print( normal, lb, "GreedyLB::transferObjs: max_recs={}, max_bytes={}\n", From 79efa85b0c286ca121b7615a78ee0f7a484faf8c Mon Sep 17 00:00:00 2001 From: Jonathan Lifflander Date: Mon, 23 Aug 2021 11:23:46 -0700 Subject: [PATCH 8/8] #1395: lb: add hash for new enum --- src/vt/vrt/collection/balance/greedylb/greedylb.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/vt/vrt/collection/balance/greedylb/greedylb.h b/src/vt/vrt/collection/balance/greedylb/greedylb.h index a99018c76a..614c7ce728 100644 --- a/src/vt/vrt/collection/balance/greedylb/greedylb.h +++ b/src/vt/vrt/collection/balance/greedylb/greedylb.h @@ -124,4 +124,18 @@ struct GreedyLB : BaseLB { }}}} /* end namespace vt::vrt::collection::lb */ +namespace std { + +template <> +struct hash<::vt::vrt::collection::lb::DataDistStrategy> { + size_t operator()(::vt::vrt::collection::lb::DataDistStrategy const& in) const { + using under = std::underlying_type< + ::vt::vrt::collection::lb::DataDistStrategy + >::type; + return std::hash()(static_cast(in)); + } +}; + +} /* end namespace std */ + #endif /*INCLUDED_VT_VRT_COLLECTION_BALANCE_GREEDYLB_GREEDYLB_H*/