From 7c823e017a4ccef4fa0ddc76bdcee1853e6afe9e Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Mon, 17 Oct 2022 14:57:52 +0200 Subject: [PATCH 01/82] #1934: Add parameter to control minimal retention of historical LB data # Conflicts: # src/vt/vrt/collection/balance/lb_invoke/lb_manager.cc --- src/vt/configs/arguments/app_config.h | 2 ++ src/vt/configs/arguments/args.cc | 3 +++ .../balance/lb_invoke/lb_manager.cc | 8 +++++-- .../collection/balance/lb_invoke/lb_manager.h | 5 ++++- src/vt/vrt/collection/balance/node_lb_data.cc | 22 ++++++++++++++++++- src/vt/vrt/collection/balance/node_lb_data.h | 21 ++++++++++++++++-- 6 files changed, 55 insertions(+), 6 deletions(-) diff --git a/src/vt/configs/arguments/app_config.h b/src/vt/configs/arguments/app_config.h index 6548dc2fd1..9bd6c75d1a 100644 --- a/src/vt/configs/arguments/app_config.h +++ b/src/vt/configs/arguments/app_config.h @@ -148,6 +148,7 @@ struct AppConfig { bool vt_lb_data = false; bool vt_lb_data_compress = true; bool vt_lb_data_in = false; + uint32_t vt_lb_data_retention = 0; std::string vt_lb_data_dir = "vt_lb_data"; std::string vt_lb_data_file = "data.%p.json"; std::string vt_lb_data_dir_in = "vt_lb_data_in"; @@ -325,6 +326,7 @@ struct AppConfig { | vt_lb_interval | vt_lb_data | vt_lb_data_compress + | vt_lb_data_retention | vt_lb_data_dir | vt_lb_data_file | vt_lb_data_in diff --git a/src/vt/configs/arguments/args.cc b/src/vt/configs/arguments/args.cc index 2cde3f1710..41879594cd 100644 --- a/src/vt/configs/arguments/args.cc +++ b/src/vt/configs/arguments/args.cc @@ -911,6 +911,7 @@ void addLbArgs(CLI::App& app, AppConfig& appConfig) { auto lb_data = "Enable load balancing data"; auto lb_data_in = "Enable load balancing data input"; auto lb_data_comp = "Compress load balancing data output with brotli"; + auto lb_data_hist = "Minimal number of historical LB data phases to retain"; auto lb_data_dir = "Load balancing data output directory"; auto lb_data_file = "Load balancing data output file name"; auto lb_data_dir_in = "Load balancing data input directory"; @@ -934,6 +935,7 @@ void addLbArgs(CLI::App& app, AppConfig& appConfig) { auto ww = app.add_flag("--vt_lb_data", appConfig.vt_lb_data, lb_data); auto za = app.add_flag("--vt_lb_data_in", appConfig.vt_lb_data_in, lb_data_in); auto xz = app.add_flag("--vt_lb_data_compress", appConfig.vt_lb_data_compress, lb_data_comp); + auto dr = app.add_option("--vt_lb_data_retention", appConfig.vt_lb_data_retention, lb_data_hist); auto wx = app.add_option("--vt_lb_data_dir", appConfig.vt_lb_data_dir, lb_data_dir)->capture_default_str(); auto wy = app.add_option("--vt_lb_data_file", appConfig.vt_lb_data_file, lb_data_file)->capture_default_str(); auto xx = app.add_option("--vt_lb_data_dir_in", appConfig.vt_lb_data_dir_in, lb_data_dir_in)->capture_default_str(); @@ -967,6 +969,7 @@ void addLbArgs(CLI::App& app, AppConfig& appConfig) { xx->group(debugLB); xy->group(debugLB); xz->group(debugLB); + dr->group(debugLB); yx->group(debugLB); yy->group(debugLB); yz->group(debugLB); 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 ce20121e22..b0f2b82f21 100644 --- a/src/vt/vrt/collection/balance/lb_invoke/lb_manager.cc +++ b/src/vt/vrt/collection/balance/lb_invoke/lb_manager.cc @@ -174,8 +174,12 @@ LBType LBManager::decideLBToRun(PhaseType phase, bool try_file) { } void LBManager::setLoadModel(std::shared_ptr model) { - model_ = model; auto nlb_data = theNodeLBData(); + min_hist_lb_data_ = std::max(model->getNumPastPhasesNeeded(), theConfig()->vt_lb_data_retention); + nlb_data->setMinLBDataHistory(min_hist_lb_data_); + nlb_data->trimLBDataHistory(cached_phase_); + + model_ = model; model_->setLoads(nlb_data->getNodeLoad(), nlb_data->getNodeComm(), nlb_data->getUserData()); @@ -539,7 +543,7 @@ void LBManager::finishedLB(PhaseType phase) { "finishedLB\n" ); - theNodeLBData()->startIterCleanup(phase, model_->getNumPastPhasesNeeded()); + theNodeLBData()->startIterCleanup(phase); theNodeLBData()->outputLBDataForPhase(phase); destroyLB(); 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 446d8b9498..fd3ad4fcfa 100644 --- a/src/vt/vrt/collection/balance/lb_invoke/lb_manager.h +++ b/src/vt/vrt/collection/balance/lb_invoke/lb_manager.h @@ -213,7 +213,8 @@ struct LBManager : runtime::component::Component { | model_ | lb_instances_ | stats - | created_lbstats_dir_; + | created_lbstats_dir_ + | min_hist_lb_data_; } void stagePreLBStatistics(const StatisticMapType &statistics); @@ -307,6 +308,8 @@ struct LBManager : runtime::component::Component { std::unique_ptr statistics_writer_ = nullptr; /// Whether the LB statistics directory has been created bool created_lbstats_dir_ = false; + //// The amount of phases of historical LB data to hold + uint32_t min_hist_lb_data_ = 0; }; void makeGraphSymmetric( diff --git a/src/vt/vrt/collection/balance/node_lb_data.cc b/src/vt/vrt/collection/balance/node_lb_data.cc index 75935ac138..0a13a20d80 100644 --- a/src/vt/vrt/collection/balance/node_lb_data.cc +++ b/src/vt/vrt/collection/balance/node_lb_data.cc @@ -143,6 +143,26 @@ void NodeLBData::startIterCleanup(PhaseType phase, unsigned int look_back) { node_objgroup_lookup_.clear(); } +void NodeLBData::trimLBDataHistory(PhaseType phase) { + if (phase != no_lb_phase && phase > min_hist_lb_data_) { + auto phaseToLookFor = phase - min_hist_lb_data_ - 1; + + // Trim all maps to have 'min_hist_lb_data_ + 1' phases of data + auto fromData = lb_data_->node_data_.find(phaseToLookFor); + lb_data_->node_data_.erase(fromData, lb_data_->node_data_.end()); + + auto fromComm = lb_data_->node_comm_.find(phaseToLookFor); + lb_data_->node_comm_.erase(fromComm, lb_data_->node_comm_.end()); + + auto fromSub = lb_data_->node_subphase_comm_.find(phaseToLookFor); + lb_data_->node_subphase_comm_.erase(fromSub, lb_data_->node_subphase_comm_.end()); + + NodeLBData::node_migrate_.clear(); + node_collection_lookup_.clear(); + node_objgroup_lookup_.clear(); + } +} + ElementIDType NodeLBData::getNextElm() { return next_elm_++; } @@ -376,7 +396,7 @@ void NodeLBData::addNodeLBData( in->updatePhase(1); auto model = theLBManager()->getLoadModel(); - in->releaseLBDataFromUnneededPhases(phase, model->getNumPastPhasesNeeded()); + in->releaseLBDataFromUnneededPhases(phase, min_hist_lb_data_); } VirtualProxyType NodeLBData::getCollectionProxyForElement( diff --git a/src/vt/vrt/collection/balance/node_lb_data.h b/src/vt/vrt/collection/balance/node_lb_data.h index 5088090e3d..c0da213628 100644 --- a/src/vt/vrt/collection/balance/node_lb_data.h +++ b/src/vt/vrt/collection/balance/node_lb_data.h @@ -146,7 +146,7 @@ struct NodeLBData : runtime::component::Component { /** * \internal \brief Cleanup after LB runs */ - void startIterCleanup(PhaseType phase, unsigned int look_back); + void startIterCleanup(PhaseType phase); /** * \internal \brief Load and broadcast the LB specification file @@ -270,6 +270,20 @@ struct NodeLBData : runtime::component::Component { */ LBDataHolder* getLBData() { return lb_data_.get(); } + /** + * \brief Set the minimal amount of historical LB data which should be retained + * + * \param[in] hist_len the minimal amount of LB data to hold + */ + void setMinLBDataHistory(uint32_t hist_len) { min_hist_lb_data_ = hist_len; } + + /** + * \brief Trim the cached LB Data + * + * \param[in] phase the current phase + */ + void trimLBDataHistory(PhaseType phase); + template void serialize(SerializerT& s) { s | proxy_ @@ -280,7 +294,8 @@ struct NodeLBData : runtime::component::Component { | next_elm_ | created_dir_ | lb_data_writer_ - | lb_data_; + | lb_data_ + | min_hist_lb_data_; } private: @@ -313,6 +328,8 @@ struct NodeLBData : runtime::component::Component { std::unique_ptr lb_data_writer_ = nullptr; /// The struct that holds all the LB data std::unique_ptr lb_data_ = nullptr; + //// The minimal amount of historical LB data to hold + uint32_t min_hist_lb_data_ = 0; }; }}}} /* end namespace vt::vrt::collection::balance */ From 932f1d682a4e4144b1a2835d854808d199acf7dd Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 18 Oct 2022 16:45:26 +0200 Subject: [PATCH 02/82] #1934: Add UTs for minimal LB data retention --- src/vt/vrt/collection/balance/node_lb_data.h | 2 +- .../unit/collection/test_lb_data_retention.cc | 196 +++++++++++++++++- 2 files changed, 196 insertions(+), 2 deletions(-) diff --git a/src/vt/vrt/collection/balance/node_lb_data.h b/src/vt/vrt/collection/balance/node_lb_data.h index c0da213628..bd2d2679a6 100644 --- a/src/vt/vrt/collection/balance/node_lb_data.h +++ b/src/vt/vrt/collection/balance/node_lb_data.h @@ -273,7 +273,7 @@ struct NodeLBData : runtime::component::Component { /** * \brief Set the minimal amount of historical LB data which should be retained * - * \param[in] hist_len the minimal amount of LB data to hold + * \param[in] hist_len the minimal amount of LB data to retain */ void setMinLBDataHistory(uint32_t hist_len) { min_hist_lb_data_ = hist_len; } diff --git a/tests/unit/collection/test_lb_data_retention.cc b/tests/unit/collection/test_lb_data_retention.cc index fea6645da4..f8ad316724 100644 --- a/tests/unit/collection/test_lb_data_retention.cc +++ b/tests/unit/collection/test_lb_data_retention.cc @@ -58,6 +58,19 @@ namespace vt { namespace tests { namespace unit { +void checkNodeLBData(int expected_phases_amount) { + #if vt_check_enabled(lblite) + EXPECT_EQ(expected_phases_amount, theNodeLBData()->getLBData()->node_comm_.size()); + EXPECT_EQ(expected_phases_amount, theNodeLBData()->getLBData()->node_data_.size()); + EXPECT_EQ(expected_phases_amount, theNodeLBData()->getLBData()->node_subphase_comm_.size()); + #else + (void)expected_phases_amount; + EXPECT_EQ(0, theNodeLBData()->getLBData()->node_comm_.size()); + EXPECT_EQ(0, theNodeLBData()->getLBData()->node_data_.size()); + EXPECT_EQ(0, theNodeLBData()->getLBData()->node_subphase_comm_.size()); + #endif +} + struct TestCol : vt::Collection { unsigned int prev_calls_ = thePhase()->getCurrentPhase(); @@ -74,7 +87,7 @@ struct TestCol : vt::Collection { #if vt_check_enabled(lblite) auto phase = col->prevCalls(); auto model = theLBManager()->getLoadModel(); - auto phases_needed = model->getNumPastPhasesNeeded(); + auto phases_needed = std::max(model->getNumPastPhasesNeeded(), theConfig()->vt_lb_data_retention); if (phase > phases_needed) { // updatePhase will have caused entries to be added for the // next phase already @@ -102,6 +115,29 @@ struct TestCol : vt::Collection { EXPECT_EQ(sp_comm_phase_count, 0); #endif } + + static void expect7PhasesOfData(TestCol* col) { + auto& lb_data = col->lb_data_; + auto load_phase_count = lb_data.getLoadPhaseCount(); + auto comm_phase_count = lb_data.getCommPhaseCount(); + auto sp_load_phase_count = lb_data.getSubphaseLoadPhaseCount(); + auto sp_comm_phase_count = lb_data.getSubphaseCommPhaseCount(); + + #if vt_check_enabled(lblite) + auto phases_needed = 7; + EXPECT_EQ(load_phase_count, phases_needed); + EXPECT_EQ(sp_load_phase_count, phases_needed); + EXPECT_EQ(comm_phase_count, phases_needed); + EXPECT_EQ(sp_comm_phase_count, phases_needed); + #else + EXPECT_EQ(load_phase_count, 0); + EXPECT_EQ(sp_load_phase_count, 0); + EXPECT_EQ(comm_phase_count, 0); + EXPECT_EQ(sp_comm_phase_count, 0); + #endif + } + + static void emptyColHandler(TestCol*) { } }; static constexpr int32_t const num_elms = 16; @@ -154,6 +190,8 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_last1) { TEST_F(TestLBDataRetention, test_lbdata_retention_last2) { static constexpr int const num_phases = 6; + // Minimum retention lower than the amount of phases needed by model - will be ignored + theConfig()->vt_lb_data_retention = 2; auto range = vt::Index1D(num_elms); @@ -188,6 +226,8 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_last2) { TEST_F(TestLBDataRetention, test_lbdata_retention_last4) { static constexpr int const num_phases = 8; + // Minimum retention equal to the amount of phases needed by model + theConfig()->vt_lb_data_retention = 4; auto range = vt::Index1D(num_elms); @@ -220,4 +260,158 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_last4) { } } +TEST_F(TestLBDataRetention, test_lbdata_config_retention_higher) { + // Minimum retention higher than the amount of phases needed by model + theConfig()->vt_lb_data_retention = 140; + + // We must have more or equal number of elements than nodes for this test to + // work properly + EXPECT_GE(num_elms, vt::theContext()->getNumNodes()); + + auto range = vt::Index1D(num_elms); + + vt::vrt::collection::CollectionProxy proxy; + + // Construct two collections + runInEpochCollective([&]{ + proxy = vt::theCollection()->constructCollective( + range, "test_lbdata_config_retention_higher" + ); + }); + + // Get the base model, assert it's valid + auto base = theLBManager()->getBaseLoadModel(); + EXPECT_NE(base, nullptr); + + // Create a new model + auto persist = std::make_shared(base, 4U); + + // Set the new model + theLBManager()->setLoadModel(persist); + + for (uint32_t i=0; ivt_lb_data_retention; ++i) { + runInEpochCollective([&]{ + // Do some work. + proxy.broadcastCollective(); + }); + // Go to the next phase. + vt::thePhase()->nextPhaseCollective(); + } +} + +TEST_F(TestLBDataRetention, test_lbdata_retention_model_switch_1) { + static constexpr int const first_stage_num_phases = 11; + theConfig()->vt_lb_data_retention = 0; + + // We must have more or equal number of elements than nodes for this test to + // work properly + EXPECT_GE(num_elms, vt::theContext()->getNumNodes()); + auto range = vt::Index1D(num_elms); + vt::vrt::collection::CollectionProxy proxy; + + // Construct two collections + runInEpochCollective([&]{ + proxy = vt::theCollection()->constructCollective( + range, "test_lbdata_retention_model_switch_1" + ); + }); + + // Get the base model, assert it's valid + auto base = theLBManager()->getBaseLoadModel(); + EXPECT_NE(base, nullptr); + + // Create a new models + auto model_10_phases = std::make_shared(base, 10U); + auto model_1_phase = std::make_shared(base, 1U); + + // Set model which needs 10 phases of data + theLBManager()->setLoadModel(model_10_phases); + + for (uint32_t i=0; i(); + }); + // Go to the next phase. + vt::thePhase()->nextPhaseCollective(); + } + + // Set model which needs only 1 phase of data + theLBManager()->setLoadModel(model_1_phase); + + // Check amount of phase data in the node + checkNodeLBData(2); + + for (uint32_t i=0; i(); + }); + // Go to the next phase. + vt::thePhase()->nextPhaseCollective(); + } + + // Check amount of phase data in the node + checkNodeLBData(2); +} + +TEST_F(TestLBDataRetention, test_lbdata_retention_model_switch_2) { + static constexpr int const first_stage_num_phases = 6; + theConfig()->vt_lb_data_retention = 0; + + // We must have more or equal number of elements than nodes for this test to + // work properly + EXPECT_GE(num_elms, vt::theContext()->getNumNodes()); + auto range = vt::Index1D(num_elms); + vt::vrt::collection::CollectionProxy proxy; + + // Construct two collections + runInEpochCollective([&]{ + proxy = vt::theCollection()->constructCollective( + range, "test_lbdata_retention_model_switch_2" + ); + }); + + // Get the base model, assert it's valid + auto base = theLBManager()->getBaseLoadModel(); + EXPECT_NE(base, nullptr); + + // Create and set model which needs 10 phases of data + auto model_10_phases = std::make_shared(base, 10U); + theLBManager()->setLoadModel(model_10_phases); + + // Do only 6 phases of work + for (uint32_t i=0; i(); + }); + // Go to the next phase. + vt::thePhase()->nextPhaseCollective(); + } + + // Check amount of phase data in the node + checkNodeLBData(6); + + // Set model which needs only 1 phase of data + auto model_1_phase = std::make_shared(base, 1U); + theLBManager()->setLoadModel(model_1_phase); + + // Check amount of phase data in the node + checkNodeLBData(2); + + // Check that amount of the retained data in TestCol is not changed and still contains 7 phases of data + for (uint32_t i=0; i<10; ++i) { + runInEpochCollective([&]{ + // Do some work. + proxy.broadcastCollective(); + }); + // Go to the next phase. + vt::thePhase()->nextPhaseCollective(); + } + + // Check amount of phase data in the node + checkNodeLBData(2); +} + }}} // end namespace vt::tests::unit From f2b2a6de5eea0e6898510b1da992b9ef3bd5078e Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Fri, 27 Jan 2023 15:19:15 +0100 Subject: [PATCH 03/82] #1934: Store LB data in ordered map --- .../vrt/collection/balance/lb_data_holder.h | 10 ++--- .../balance/lb_invoke/lb_manager.cc | 2 +- .../balance/model/weighted_messages.h | 2 +- src/vt/vrt/collection/balance/node_lb_data.cc | 37 +++++++++---------- src/vt/vrt/collection/balance/node_lb_data.h | 12 +++--- .../unit/collection/test_lb_data_retention.cc | 22 +++++++++-- .../test_model_linear_model.nompi.cc | 2 +- .../test_model_multiple_phases.nompi.cc | 4 +- .../test_model_naive_persistence.nompi.cc | 4 +- ...t_model_persistence_median_last_n.nompi.cc | 4 +- 10 files changed, 54 insertions(+), 45 deletions(-) diff --git a/src/vt/vrt/collection/balance/lb_data_holder.h b/src/vt/vrt/collection/balance/lb_data_holder.h index 618fe52a42..dfa094b66f 100644 --- a/src/vt/vrt/collection/balance/lb_data_holder.h +++ b/src/vt/vrt/collection/balance/lb_data_holder.h @@ -184,13 +184,13 @@ struct LBDataHolder { /// Node attributes for the current rank ElmUserDataType rank_attributes_; /// Node timings for each local object - std::unordered_map node_data_; + std::map node_data_; /// Node communication graph for each local object - std::unordered_map node_comm_; + std::map node_comm_; /// Node communication graph for each subphase - std::unordered_map> node_subphase_comm_; - /// User-defined data from each phase for JSON output - std::unordered_map> node_subphase_comm_; + /// User-defined data from each phase + std::map >> user_defined_json_; 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 b0f2b82f21..1569553163 100644 --- a/src/vt/vrt/collection/balance/lb_invoke/lb_manager.cc +++ b/src/vt/vrt/collection/balance/lb_invoke/lb_manager.cc @@ -177,7 +177,7 @@ void LBManager::setLoadModel(std::shared_ptr model) { auto nlb_data = theNodeLBData(); min_hist_lb_data_ = std::max(model->getNumPastPhasesNeeded(), theConfig()->vt_lb_data_retention); nlb_data->setMinLBDataHistory(min_hist_lb_data_); - nlb_data->trimLBDataHistory(cached_phase_); + nlb_data->trimLBDataHistory(); model_ = model; model_->setLoads(nlb_data->getNodeLoad(), diff --git a/src/vt/vrt/collection/balance/model/weighted_messages.h b/src/vt/vrt/collection/balance/model/weighted_messages.h index 937c537a2c..afca6470b6 100644 --- a/src/vt/vrt/collection/balance/model/weighted_messages.h +++ b/src/vt/vrt/collection/balance/model/weighted_messages.h @@ -77,7 +77,7 @@ struct WeightedMessages : public ComposedModel { private: // observer pointer to the underlying comm data - std::unordered_map const* proc_comm_; + std::map const* proc_comm_; LoadType per_msg_weight_; LoadType per_byte_weight_; diff --git a/src/vt/vrt/collection/balance/node_lb_data.cc b/src/vt/vrt/collection/balance/node_lb_data.cc index 0a13a20d80..7c0b9fd1bb 100644 --- a/src/vt/vrt/collection/balance/node_lb_data.cc +++ b/src/vt/vrt/collection/balance/node_lb_data.cc @@ -57,6 +57,7 @@ #include #include #include +#include namespace vt { namespace vrt { namespace collection { namespace balance { @@ -90,7 +91,7 @@ bool NodeLBData::migrateObjTo(ElementIDStruct obj_id, NodeType to_node) { return true; } -std::unordered_map const* +std::map const* NodeLBData::getNodeLoad() const { return &lb_data_->node_data_; } @@ -109,7 +110,7 @@ std::unordered_map const* NodeLBData::getNodeComm() cons return &lb_data_->node_comm_; } -std::unordered_map> const* NodeLBData::getNodeSubphaseComm() const { +std::map> const* NodeLBData::getNodeSubphaseComm() const { return &lb_data_->node_subphase_comm_; } @@ -143,24 +144,22 @@ void NodeLBData::startIterCleanup(PhaseType phase, unsigned int look_back) { node_objgroup_lookup_.clear(); } -void NodeLBData::trimLBDataHistory(PhaseType phase) { - if (phase != no_lb_phase && phase > min_hist_lb_data_) { - auto phaseToLookFor = phase - min_hist_lb_data_ - 1; - - // Trim all maps to have 'min_hist_lb_data_ + 1' phases of data - auto fromData = lb_data_->node_data_.find(phaseToLookFor); - lb_data_->node_data_.erase(fromData, lb_data_->node_data_.end()); - - auto fromComm = lb_data_->node_comm_.find(phaseToLookFor); - lb_data_->node_comm_.erase(fromComm, lb_data_->node_comm_.end()); +void NodeLBData::trimLBDataHistory() { + auto trim_data = [this](auto& map){ + if(map.size() > min_hist_lb_data_ + 1) { + auto target = map.lower_bound(map.rbegin()->first - min_hist_lb_data_); + map.erase(map.begin(), target); + } + }; - auto fromSub = lb_data_->node_subphase_comm_.find(phaseToLookFor); - lb_data_->node_subphase_comm_.erase(fromSub, lb_data_->node_subphase_comm_.end()); + trim_data(lb_data_->node_data_); + trim_data(lb_data_->node_comm_); + trim_data(lb_data_->node_subphase_comm_); + trim_data(lb_data_->user_defined_json_); - NodeLBData::node_migrate_.clear(); - node_collection_lookup_.clear(); - node_objgroup_lookup_.clear(); - } + NodeLBData::node_migrate_.clear(); + node_collection_lookup_.clear(); + node_objgroup_lookup_.clear(); } ElementIDType NodeLBData::getNextElm() { @@ -394,8 +393,6 @@ void NodeLBData::addNodeLBData( } in->updatePhase(1); - - auto model = theLBManager()->getLoadModel(); in->releaseLBDataFromUnneededPhases(phase, min_hist_lb_data_); } diff --git a/src/vt/vrt/collection/balance/node_lb_data.h b/src/vt/vrt/collection/balance/node_lb_data.h index bd2d2679a6..17c47a4b12 100644 --- a/src/vt/vrt/collection/balance/node_lb_data.h +++ b/src/vt/vrt/collection/balance/node_lb_data.h @@ -172,14 +172,14 @@ struct NodeLBData : runtime::component::Component { * * \return an observer pointer to the load map */ - std::unordered_map const* getNodeLoad() const; + std::map const* getNodeLoad() const; /** * \internal \brief Get stored object comm graph * * \return an observer pointer to the comm graph */ - std::unordered_map const* getNodeComm() const; + std::map const* getNodeComm() const; /** * \internal \brief Get the user-defined LB data @@ -209,7 +209,7 @@ struct NodeLBData : runtime::component::Component { * * \return an observer pointer to the comm subphase graph */ - std::unordered_map> const* getNodeSubphaseComm() const; + std::map> const* getNodeSubphaseComm() const; /** * \internal \brief Get stored node attributes @@ -278,11 +278,9 @@ struct NodeLBData : runtime::component::Component { void setMinLBDataHistory(uint32_t hist_len) { min_hist_lb_data_ = hist_len; } /** - * \brief Trim the cached LB Data - * - * \param[in] phase the current phase + * \brief Trim the cached LB Data to it's minimum retention size */ - void trimLBDataHistory(PhaseType phase); + void trimLBDataHistory(); template void serialize(SerializerT& s) { diff --git a/tests/unit/collection/test_lb_data_retention.cc b/tests/unit/collection/test_lb_data_retention.cc index f8ad316724..d94f8c30a0 100644 --- a/tests/unit/collection/test_lb_data_retention.cc +++ b/tests/unit/collection/test_lb_data_retention.cc @@ -63,11 +63,13 @@ void checkNodeLBData(int expected_phases_amount) { EXPECT_EQ(expected_phases_amount, theNodeLBData()->getLBData()->node_comm_.size()); EXPECT_EQ(expected_phases_amount, theNodeLBData()->getLBData()->node_data_.size()); EXPECT_EQ(expected_phases_amount, theNodeLBData()->getLBData()->node_subphase_comm_.size()); + EXPECT_EQ(expected_phases_amount, theNodeLBData()->getLBData()->user_defined_json_.size()); #else (void)expected_phases_amount; EXPECT_EQ(0, theNodeLBData()->getLBData()->node_comm_.size()); EXPECT_EQ(0, theNodeLBData()->getLBData()->node_data_.size()); EXPECT_EQ(0, theNodeLBData()->getLBData()->node_subphase_comm_.size()); + EXPECT_EQ(0, theNodeLBData()->getLBData()->user_defined_json_.size()); #endif } @@ -186,6 +188,9 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_last1) { // Go to the next phase. vt::thePhase()->nextPhaseCollective(); } + + // Check amount of phase data in the node + checkNodeLBData(1); } TEST_F(TestLBDataRetention, test_lbdata_retention_last2) { @@ -222,6 +227,9 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_last2) { // Go to the next phase. vt::thePhase()->nextPhaseCollective(); } + + // Check amount of phase data in the node + checkNodeLBData(2); } TEST_F(TestLBDataRetention, test_lbdata_retention_last4) { @@ -258,6 +266,9 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_last4) { // Go to the next phase. vt::thePhase()->nextPhaseCollective(); } + + // Check amount of phase data in the node + checkNodeLBData(4); } TEST_F(TestLBDataRetention, test_lbdata_config_retention_higher) { @@ -297,6 +308,9 @@ TEST_F(TestLBDataRetention, test_lbdata_config_retention_higher) { // Go to the next phase. vt::thePhase()->nextPhaseCollective(); } + + // Check amount of phase data in the node + checkNodeLBData(140); } TEST_F(TestLBDataRetention, test_lbdata_retention_model_switch_1) { @@ -340,7 +354,7 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_model_switch_1) { theLBManager()->setLoadModel(model_1_phase); // Check amount of phase data in the node - checkNodeLBData(2); + checkNodeLBData(1 + 1); for (uint32_t i=0; isetLoadModel(model_1_phase); // Check amount of phase data in the node - checkNodeLBData(2); + checkNodeLBData(1 + 1); // Check that amount of the retained data in TestCol is not changed and still contains 7 phases of data for (uint32_t i=0; i<10; ++i) { @@ -411,7 +425,7 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_model_switch_2) { } // Check amount of phase data in the node - checkNodeLBData(2); + checkNodeLBData(1 + 1); } }}} // end namespace vt::tests::unit diff --git a/tests/unit/collection/test_model_linear_model.nompi.cc b/tests/unit/collection/test_model_linear_model.nompi.cc index 09c37adfbf..cc79236253 100644 --- a/tests/unit/collection/test_model_linear_model.nompi.cc +++ b/tests/unit/collection/test_model_linear_model.nompi.cc @@ -95,7 +95,7 @@ struct StubModel : LoadModel { unsigned int getNumPastPhasesNeeded(unsigned int look_back = 0) const override { return look_back; } private: - std::unordered_map const* proc_load_ = nullptr; + std::map const* proc_load_ = nullptr; }; TEST_F(TestLinearModel, test_model_linear_model_1) { diff --git a/tests/unit/collection/test_model_multiple_phases.nompi.cc b/tests/unit/collection/test_model_multiple_phases.nompi.cc index 793e89099a..1e98637e85 100644 --- a/tests/unit/collection/test_model_multiple_phases.nompi.cc +++ b/tests/unit/collection/test_model_multiple_phases.nompi.cc @@ -95,12 +95,12 @@ struct StubModel : LoadModel { unsigned int getNumPastPhasesNeeded(unsigned int look_back = 0) const override { return look_back; } private: - std::unordered_map const* proc_load_ = nullptr; + std::map const* proc_load_ = nullptr; }; TEST_F(TestModelMultiplePhases, test_model_multiple_phases_1) { NodeType this_node = 0; - std::unordered_map proc_loads = { + std::map proc_loads = { {0, LoadMapType{ {ElementIDStruct{1,this_node}, {LoadType{10}, {}}}, {ElementIDStruct{2,this_node}, {LoadType{40}, {}}}}}, diff --git a/tests/unit/collection/test_model_naive_persistence.nompi.cc b/tests/unit/collection/test_model_naive_persistence.nompi.cc index 50e6d7933f..05dd392534 100644 --- a/tests/unit/collection/test_model_naive_persistence.nompi.cc +++ b/tests/unit/collection/test_model_naive_persistence.nompi.cc @@ -98,12 +98,12 @@ struct StubModel : LoadModel { unsigned int getNumPastPhasesNeeded(unsigned int look_back = 0) const override { return look_back; } private: - std::unordered_map const* proc_load_ = nullptr; + std::map const* proc_load_ = nullptr; }; TEST_F(TestModelNaivePersistence, test_model_naive_persistence_1) { NodeType this_node = 0; - std::unordered_map proc_loads = { + std::map proc_loads = { {0, LoadMapType{ {ElementIDStruct{1,this_node}, {LoadType{10}, {}}}, {ElementIDStruct{2,this_node}, {LoadType{40}, {}}}}}, 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 0107c4d251..1c378f6d39 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 @@ -95,7 +95,7 @@ struct StubModel : LoadModel { unsigned int getNumPastPhasesNeeded(unsigned int look_back = 0) const override { return look_back; } private: - std::unordered_map const* proc_load_ = nullptr; + std::map const* proc_load_ = nullptr; }; TEST_F(TestModelPersistenceMedianLastN, test_model_persistence_median_last_n_1) { @@ -105,7 +105,7 @@ TEST_F(TestModelPersistenceMedianLastN, test_model_persistence_median_last_n_1) auto test_model = std::make_shared(std::make_shared(), 4); - std::unordered_map proc_loads(num_total_phases); + std::map proc_loads; test_model->setLoads(&proc_loads, nullptr, nullptr); From d31709f0984e37a8ea1a1d167f12b155bc109a80 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 6 Jun 2023 12:19:30 +0200 Subject: [PATCH 04/82] #1934: Update UTs to better reflect which phases are kept --- .../vrt/collection/balance/lb_data_holder.h | 2 +- .../collection/balance/model/comm_overhead.h | 2 +- src/vt/vrt/collection/balance/node_lb_data.cc | 7 +-- src/vt/vrt/collection/balance/node_lb_data.h | 2 +- .../unit/collection/test_lb_data_retention.cc | 52 ++++++++++++------- .../test_model_linear_model.nompi.cc | 2 +- 6 files changed, 42 insertions(+), 25 deletions(-) diff --git a/src/vt/vrt/collection/balance/lb_data_holder.h b/src/vt/vrt/collection/balance/lb_data_holder.h index dfa094b66f..f4aa97ef02 100644 --- a/src/vt/vrt/collection/balance/lb_data_holder.h +++ b/src/vt/vrt/collection/balance/lb_data_holder.h @@ -189,7 +189,7 @@ struct LBDataHolder { std::map node_comm_; /// Node communication graph for each subphase std::map> node_subphase_comm_; - /// User-defined data from each phase + /// User-defined data from each phase for JSON output std::map >> user_defined_json_; diff --git a/src/vt/vrt/collection/balance/model/comm_overhead.h b/src/vt/vrt/collection/balance/model/comm_overhead.h index 69afe8f59f..31a284d700 100644 --- a/src/vt/vrt/collection/balance/model/comm_overhead.h +++ b/src/vt/vrt/collection/balance/model/comm_overhead.h @@ -72,7 +72,7 @@ struct CommOverhead : public ComposedModel { LoadType getModeledLoad(ElementIDStruct object, PhaseOffset when) const override; private: - std::unordered_map const* proc_comm_; /**< Underlying comm data */ + std::map const* proc_comm_; /**< Underlying comm data */ LoadType per_msg_weight_ = 0.001; /**< Cost per message */ LoadType per_byte_weight_ = 0.000001; /**< Cost per bytes */ }; // class CommOverhead diff --git a/src/vt/vrt/collection/balance/node_lb_data.cc b/src/vt/vrt/collection/balance/node_lb_data.cc index 7c0b9fd1bb..70f049603d 100644 --- a/src/vt/vrt/collection/balance/node_lb_data.cc +++ b/src/vt/vrt/collection/balance/node_lb_data.cc @@ -96,7 +96,7 @@ NodeLBData::getNodeLoad() const { return &lb_data_->node_data_; } -std::unordered_map const* +std::map const* NodeLBData::getUserData() const { return &lb_data_->user_defined_lb_info_; } @@ -146,8 +146,8 @@ void NodeLBData::startIterCleanup(PhaseType phase, unsigned int look_back) { void NodeLBData::trimLBDataHistory() { auto trim_data = [this](auto& map){ - if(map.size() > min_hist_lb_data_ + 1) { - auto target = map.lower_bound(map.rbegin()->first - min_hist_lb_data_); + if(map.size() > min_hist_lb_data_) { + auto target = map.upper_bound(map.rbegin()->first - min_hist_lb_data_); map.erase(map.begin(), target); } }; @@ -155,6 +155,7 @@ void NodeLBData::trimLBDataHistory() { trim_data(lb_data_->node_data_); trim_data(lb_data_->node_comm_); trim_data(lb_data_->node_subphase_comm_); + trim_data(lb_data_->user_defined_lb_info_); trim_data(lb_data_->user_defined_json_); NodeLBData::node_migrate_.clear(); diff --git a/src/vt/vrt/collection/balance/node_lb_data.h b/src/vt/vrt/collection/balance/node_lb_data.h index 17c47a4b12..51c6b79300 100644 --- a/src/vt/vrt/collection/balance/node_lb_data.h +++ b/src/vt/vrt/collection/balance/node_lb_data.h @@ -186,7 +186,7 @@ struct NodeLBData : runtime::component::Component { * * \return an observer pointer to the user-defined LB data */ - std::unordered_map const* getUserData() const; + std::map const* getUserData() const; /** * \internal \brief Get the user-defined attributes diff --git a/tests/unit/collection/test_lb_data_retention.cc b/tests/unit/collection/test_lb_data_retention.cc index d94f8c30a0..7139cea9dc 100644 --- a/tests/unit/collection/test_lb_data_retention.cc +++ b/tests/unit/collection/test_lb_data_retention.cc @@ -58,24 +58,40 @@ namespace vt { namespace tests { namespace unit { -void checkNodeLBData(int expected_phases_amount) { +void validatePersistedPhases(std::vector expected_phases) { #if vt_check_enabled(lblite) - EXPECT_EQ(expected_phases_amount, theNodeLBData()->getLBData()->node_comm_.size()); - EXPECT_EQ(expected_phases_amount, theNodeLBData()->getLBData()->node_data_.size()); - EXPECT_EQ(expected_phases_amount, theNodeLBData()->getLBData()->node_subphase_comm_.size()); - EXPECT_EQ(expected_phases_amount, theNodeLBData()->getLBData()->user_defined_json_.size()); + // Check maps size + EXPECT_EQ(expected_phases.size(), theNodeLBData()->getLBData()->node_comm_.size()); + EXPECT_EQ(expected_phases.size(), theNodeLBData()->getLBData()->node_data_.size()); + EXPECT_EQ(expected_phases.size(), theNodeLBData()->getLBData()->node_subphase_comm_.size()); + EXPECT_EQ(expected_phases.size(), theNodeLBData()->getLBData()->user_defined_json_.size()); + EXPECT_EQ(expected_phases.size(), theNodeLBData()->getLBData()->user_defined_lb_info_.size()); + // Check if each phase is present + for(auto&& phase : expected_phases) { + EXPECT_EQ(1, theNodeLBData()->getLBData()->node_comm_.count(phase)); + EXPECT_EQ(1, theNodeLBData()->getLBData()->node_data_.count(phase)); + EXPECT_EQ(1, theNodeLBData()->getLBData()->node_subphase_comm_.count(phase)); + EXPECT_EQ(1, theNodeLBData()->getLBData()->user_defined_json_.count(phase)); + EXPECT_EQ(1, theNodeLBData()->getLBData()->user_defined_lb_info_.count(phase)); + } #else - (void)expected_phases_amount; + (void)expected_phases; EXPECT_EQ(0, theNodeLBData()->getLBData()->node_comm_.size()); EXPECT_EQ(0, theNodeLBData()->getLBData()->node_data_.size()); EXPECT_EQ(0, theNodeLBData()->getLBData()->node_subphase_comm_.size()); EXPECT_EQ(0, theNodeLBData()->getLBData()->user_defined_json_.size()); + EXPECT_EQ(0, theNodeLBData()->getLBData()->user_defined_lb_info_.size()); #endif } struct TestCol : vt::Collection { unsigned int prev_calls_ = thePhase()->getCurrentPhase(); + TestCol() { + // Insert dummy lb info data + valInsert("foo", 10, true, true); + } + unsigned int prevCalls() { return prev_calls_++; } static void colHandler(TestCol* col) { @@ -190,13 +206,13 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_last1) { } // Check amount of phase data in the node - checkNodeLBData(1); + validatePersistedPhases({4}); } TEST_F(TestLBDataRetention, test_lbdata_retention_last2) { static constexpr int const num_phases = 6; // Minimum retention lower than the amount of phases needed by model - will be ignored - theConfig()->vt_lb_data_retention = 2; + theConfig()->vt_lb_data_retention = 1; auto range = vt::Index1D(num_elms); @@ -229,7 +245,7 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_last2) { } // Check amount of phase data in the node - checkNodeLBData(2); + validatePersistedPhases({4,5}); } TEST_F(TestLBDataRetention, test_lbdata_retention_last4) { @@ -268,12 +284,12 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_last4) { } // Check amount of phase data in the node - checkNodeLBData(4); + validatePersistedPhases({4,5,6,7}); } TEST_F(TestLBDataRetention, test_lbdata_config_retention_higher) { // Minimum retention higher than the amount of phases needed by model - theConfig()->vt_lb_data_retention = 140; + theConfig()->vt_lb_data_retention = 6; // We must have more or equal number of elements than nodes for this test to // work properly @@ -300,7 +316,7 @@ TEST_F(TestLBDataRetention, test_lbdata_config_retention_higher) { // Set the new model theLBManager()->setLoadModel(persist); - for (uint32_t i=0; ivt_lb_data_retention; ++i) { + for (uint32_t i=0; ivt_lb_data_retention * 2; ++i) { runInEpochCollective([&]{ // Do some work. proxy.broadcastCollective(); @@ -310,7 +326,7 @@ TEST_F(TestLBDataRetention, test_lbdata_config_retention_higher) { } // Check amount of phase data in the node - checkNodeLBData(140); + validatePersistedPhases({6,7,8,9,10,11}); } TEST_F(TestLBDataRetention, test_lbdata_retention_model_switch_1) { @@ -354,7 +370,7 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_model_switch_1) { theLBManager()->setLoadModel(model_1_phase); // Check amount of phase data in the node - checkNodeLBData(1 + 1); + validatePersistedPhases({10}); for (uint32_t i=0; i(base, 1U); theLBManager()->setLoadModel(model_1_phase); // Check amount of phase data in the node - checkNodeLBData(1 + 1); + validatePersistedPhases({5}); // Check that amount of the retained data in TestCol is not changed and still contains 7 phases of data for (uint32_t i=0; i<10; ++i) { @@ -425,7 +441,7 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_model_switch_2) { } // Check amount of phase data in the node - checkNodeLBData(1 + 1); + validatePersistedPhases({15}); } }}} // end namespace vt::tests::unit diff --git a/tests/unit/collection/test_model_linear_model.nompi.cc b/tests/unit/collection/test_model_linear_model.nompi.cc index cc79236253..cc04c92cf0 100644 --- a/tests/unit/collection/test_model_linear_model.nompi.cc +++ b/tests/unit/collection/test_model_linear_model.nompi.cc @@ -107,7 +107,7 @@ 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{ + std::map proc_loads{{0, LoadMapType{ {ElementIDStruct{1,this_node}, {LoadType{10}, {}}}, {ElementIDStruct{2,this_node}, {LoadType{40}, {}}} }}}; From 7de6353c8057df31ad0d74e591f16962aecf57bf Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Fri, 10 Nov 2023 10:53:02 +0100 Subject: [PATCH 05/82] #1934: Add tests for DynamicCircularBuffer --- .../test_dynamic_circular_buffer.nompi.cc | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 tests/unit/utils/test_dynamic_circular_buffer.nompi.cc diff --git a/tests/unit/utils/test_dynamic_circular_buffer.nompi.cc b/tests/unit/utils/test_dynamic_circular_buffer.nompi.cc new file mode 100644 index 0000000000..31268431bd --- /dev/null +++ b/tests/unit/utils/test_dynamic_circular_buffer.nompi.cc @@ -0,0 +1,91 @@ +#include + +#include +#include "test_harness.h" + +namespace vt { namespace tests { namespace unit { + +using TestDynamicCircularBuffer = TestHarness; + +struct Dummy { + int x; +}; + +void validatePresentPhases(util::container::DynamicCircularBuffer& buffer, std::vector expected) { + for (auto&& phase : expected) { + EXPECT_TRUE(buffer.contains(phase)); + EXPECT_EQ(phase * phase, buffer[phase]->x); + } +} + +void validateMissingPhases(util::container::DynamicCircularBuffer& buffer, std::vector expected) { + for (auto&& phase : expected) { + EXPECT_FALSE(buffer.contains(phase)); + } +} + +TEST_F(TestDynamicCircularBuffer, test_dynamic_circular_buffer_empty) { + util::container::DynamicCircularBuffer buffer{10}; + + EXPECT_FALSE(buffer.contains(3)); + EXPECT_FALSE(buffer.contains(10)); + + buffer.resize(2); + + EXPECT_FALSE(buffer.contains(3)); + EXPECT_FALSE(buffer.contains(10)); + + buffer.clear(); + + EXPECT_FALSE(buffer.contains(3)); + EXPECT_FALSE(buffer.contains(10)); +} + +TEST_F(TestDynamicCircularBuffer, test_dynamic_circular_buffer_store) { + util::container::DynamicCircularBuffer buffer{10}; + + buffer.store(2, { 2 * 2 }); + validatePresentPhases(buffer, {2}); + + // store series of elements + for (int i = 0; i < 15; i++) { + buffer.store(i, { i * i }); + } + validatePresentPhases(buffer, {5, 6, 7, 8, 9, 10, 11, 12, 13, 14}); +} + +TEST_F(TestDynamicCircularBuffer, test_dynamic_circular_buffer_resize_continuous) { + util::container::DynamicCircularBuffer buffer{1}; + + buffer.store(0, { 0 }); + validatePresentPhases(buffer, {0}); + + buffer.resize(10); + validatePresentPhases(buffer, {0}); + + for (int i = 0; i <= 15; i++) { + buffer.store(i, { i * i }); + } + validatePresentPhases(buffer, {6, 7, 8, 9, 10, 11, 12, 13, 14, 15}); + + buffer.resize(5); + validatePresentPhases(buffer, {11, 12, 13, 14, 15}); + validateMissingPhases(buffer, {6, 7, 8, 9, 10}); + + for (int i = 15; i <= 32; i++) { + buffer.store(i, { i * i }); + } + validatePresentPhases(buffer, {28, 29, 30, 31, 32}); + + buffer.resize(9); + + for (int i = 33; i <= 35; i++) { + buffer.store(i, { i * i }); + } + validatePresentPhases(buffer, {28, 29, 30, 31, 32, 33, 34, 35}); + + buffer.resize(1); + validatePresentPhases(buffer, {35}); +} + +}}} /* end namespace vt::tests::unit */ From 18cf374d704e7d8f8c660efab032218b55dc5110 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Fri, 10 Nov 2023 10:53:20 +0100 Subject: [PATCH 06/82] #1934: Add continuous dynamic circular buffer container # Conflicts: # src/vt/vrt/collection/balance/lb_data_holder.h --- .../utils/container/circular_phases_buffer.h | 188 ++++++++++++++++++ .../vrt/collection/balance/lb_data_holder.cc | 4 +- .../vrt/collection/balance/lb_data_holder.h | 8 +- .../collection/balance/model/comm_overhead.h | 2 +- .../vrt/collection/balance/model/load_model.h | 1 + .../balance/model/weighted_messages.h | 2 +- src/vt/vrt/collection/balance/node_lb_data.cc | 30 +-- src/vt/vrt/collection/balance/node_lb_data.h | 9 +- .../test_model_linear_model.nompi.cc | 4 +- .../test_model_multiple_phases.nompi.cc | 4 +- .../test_model_naive_persistence.nompi.cc | 4 +- ...t_model_persistence_median_last_n.nompi.cc | 4 +- .../test_circular_phases_buffer.nompi.cc | 134 +++++++++++++ .../test_dynamic_circular_buffer.nompi.cc | 91 --------- 14 files changed, 361 insertions(+), 124 deletions(-) create mode 100644 src/vt/utils/container/circular_phases_buffer.h create mode 100644 tests/unit/utils/test_circular_phases_buffer.nompi.cc delete mode 100644 tests/unit/utils/test_dynamic_circular_buffer.nompi.cc diff --git a/src/vt/utils/container/circular_phases_buffer.h b/src/vt/utils/container/circular_phases_buffer.h new file mode 100644 index 0000000000..096505d1a6 --- /dev/null +++ b/src/vt/utils/container/circular_phases_buffer.h @@ -0,0 +1,188 @@ +/* +//@HEADER +// ***************************************************************************** +// +// circular_phases_buffer.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_UTILS_CONTAINER_CIRCULAR_PHASES_BUFFER_H +#define INCLUDED_VT_UTILS_CONTAINER_CIRCULAR_PHASES_BUFFER_H + +#include "vt/config.h" + +namespace vt { namespace util { namespace container { + +constexpr PhaseType invalid_ = -1; + +// Circular Buffer which can store continuous phases data +template +struct CircularPhasesBuffer { + using StoredPair = std::pair; + + CircularPhasesBuffer(std::size_t capacity = 0) + : head_phase_(-1), vector_(capacity, StoredPair{invalid_, StoredType{}}) + { } + + CircularPhasesBuffer(std::initializer_list list) { + vector_.resize(list.size()); + for (auto&& pair : list) { + store(pair.first, std::move(pair.second)); + } + } + + // store, override StoredType if present on the same index + void store(const PhaseType phase, StoredType&& obj) { + vector_[phase % vector_.size()] = std::make_pair(phase, std::move(obj)); + head_phase_ = phase; + } + + // store, override StoredType if present on the same index + void store(const PhaseType phase, StoredType const& obj) { + vector_[phase % vector_.size()] = std::make_pair(phase, obj); + head_phase_ = phase; + } + + StoredType& emplace(const PhaseType phase) { + store(phase, StoredType{}); + return vector_[phase % vector_.size()].second; + } + + const StoredType* find(const PhaseType phase) const { + if (contains(phase)) { + return &vector_[phase % vector_.size()].second; + } + return nullptr; + } + + StoredType* find(const PhaseType phase) { + if (contains(phase)) { + return &vector_[phase % vector_.size()].second; + } + return nullptr; + } + + // map style operator - get reference to exsiting or newly inserted element + // const StoredType* operator[](const PhaseType phase) const { + // if (!contains(phase)) { + // store(phase, StoredType{}); + // } + // return vector_[phase % vector_.size()].second; + // } + + // map style operator - get reference to exsiting or newly inserted element + StoredType& operator[](const PhaseType phase) { + if (!contains(phase)) { + store(phase, StoredType{}); + } + return vector_[phase % vector_.size()].second; + } + + bool contains(const PhaseType phase) const { + return vector_[phase % vector_.size()].first == phase; + } + + const StoredType& at(const PhaseType phase) const { + vtAssert(contains(phase), "Buffer don't contain requested phase."); + + return vector_[phase % vector_.size()].second; + } + + StoredType& at(const PhaseType phase) { + vtAssert(contains(phase), "Buffer don't contain requested phase."); + + return vector_[phase % vector_.size()].second; + } + + std::size_t size() const { + return std::count_if(vector_.begin(), vector_.end(), [](const StoredPair& pair){ + return pair.first != invalid_; + }); + } + + void resize(std::size_t new_size) { + vtAssert(new_size != 0, "Logic error: Trying to resize buffer to size 0."); + if (new_size == vector_.size()) { return; } + + auto new_vec = std::vector(new_size, StoredPair{invalid_, StoredType{}}); + + if (new_size < vector_.size()) { + std::size_t count = 0; + std::size_t index = head_phase_ % vector_.size(); + + for(; count < new_size; index--, count++) { + auto pair = vector_[index]; + if (pair.first != invalid_) { + new_vec[pair.first % new_size] = std::move(pair); + } + + if (index == 0) { + index = vector_.size(); + } + } + } else { + for(auto pair : vector_) { + if (pair.first != invalid_) { + new_vec[pair.first % new_size] = std::move(pair); + } + } + } + + vector_.swap(new_vec); + } + + void clear() { + auto new_vec = std::vector(vector_.size(), StoredPair{invalid_, StoredType{}}); + vector_.swap(new_vec); + head_phase_ = 0; + } + + template + void serialize(SerializeT& s) { + s | head_phase_; + s | vector_; + } + +private: + PhaseType head_phase_; + std::vector vector_; +}; + +}}} /* end namespace vt::util::container */ + +#endif /* INCLUDED_VT_UTILS_CONTAINER_CIRCULAR_PHASES_BUFFER_H */ diff --git a/src/vt/vrt/collection/balance/lb_data_holder.cc b/src/vt/vrt/collection/balance/lb_data_holder.cc index e6cba201d5..e74f3e8d22 100644 --- a/src/vt/vrt/collection/balance/lb_data_holder.cc +++ b/src/vt/vrt/collection/balance/lb_data_holder.cc @@ -205,8 +205,8 @@ std::unique_ptr LBDataHolder::toJson(PhaseType phase) const { j["id"] = phase; std::size_t i = 0; - if (node_data_.find(phase) != node_data_.end()) { - for (auto&& elm : node_data_.at(phase)) { + if (node_data_.contains(phase)) { + for (auto&& elm : *node_data_.find(phase)) { ElementIDStruct id = elm.first; LoadType time = elm.second.whole_phase_load; j["tasks"][i]["resource"] = "cpu"; diff --git a/src/vt/vrt/collection/balance/lb_data_holder.h b/src/vt/vrt/collection/balance/lb_data_holder.h index f4aa97ef02..3662cee787 100644 --- a/src/vt/vrt/collection/balance/lb_data_holder.h +++ b/src/vt/vrt/collection/balance/lb_data_holder.h @@ -184,13 +184,13 @@ struct LBDataHolder { /// Node attributes for the current rank ElmUserDataType rank_attributes_; /// Node timings for each local object - std::map node_data_; + vt::util::container::CircularPhasesBuffer node_data_; /// Node communication graph for each local object - std::map node_comm_; + vt::util::container::CircularPhasesBuffer node_comm_; /// Node communication graph for each subphase - std::map> node_subphase_comm_; + vt::util::container::CircularPhasesBuffer> node_subphase_comm_; /// User-defined data from each phase for JSON output - std::map >> user_defined_json_; diff --git a/src/vt/vrt/collection/balance/model/comm_overhead.h b/src/vt/vrt/collection/balance/model/comm_overhead.h index 31a284d700..6518cdd1b4 100644 --- a/src/vt/vrt/collection/balance/model/comm_overhead.h +++ b/src/vt/vrt/collection/balance/model/comm_overhead.h @@ -72,7 +72,7 @@ struct CommOverhead : public ComposedModel { LoadType getModeledLoad(ElementIDStruct object, PhaseOffset when) const override; private: - std::map const* proc_comm_; /**< Underlying comm data */ + vt::util::container::CircularPhasesBuffer const* proc_comm_; /**< Underlying comm data */ LoadType per_msg_weight_ = 0.001; /**< Cost per message */ LoadType per_byte_weight_ = 0.000001; /**< Cost per bytes */ }; // class CommOverhead diff --git a/src/vt/vrt/collection/balance/model/load_model.h b/src/vt/vrt/collection/balance/model/load_model.h index 84b961e7fd..16b79c351d 100644 --- a/src/vt/vrt/collection/balance/model/load_model.h +++ b/src/vt/vrt/collection/balance/model/load_model.h @@ -48,6 +48,7 @@ #include "vt/timing/timing_type.h" #include "vt/vrt/collection/balance/lb_common.h" #include "vt/elm/elm_comm.h" +#include "vt/utils/container/circular_phases_buffer.h" namespace vt { namespace vrt { namespace collection { namespace balance { diff --git a/src/vt/vrt/collection/balance/model/weighted_messages.h b/src/vt/vrt/collection/balance/model/weighted_messages.h index afca6470b6..7cf5a2deda 100644 --- a/src/vt/vrt/collection/balance/model/weighted_messages.h +++ b/src/vt/vrt/collection/balance/model/weighted_messages.h @@ -77,7 +77,7 @@ struct WeightedMessages : public ComposedModel { private: // observer pointer to the underlying comm data - std::map const* proc_comm_; + vt::util::container::CircularPhasesBuffer const* proc_comm_; LoadType per_msg_weight_; LoadType per_byte_weight_; diff --git a/src/vt/vrt/collection/balance/node_lb_data.cc b/src/vt/vrt/collection/balance/node_lb_data.cc index 70f049603d..1e3d8db7a6 100644 --- a/src/vt/vrt/collection/balance/node_lb_data.cc +++ b/src/vt/vrt/collection/balance/node_lb_data.cc @@ -91,12 +91,12 @@ bool NodeLBData::migrateObjTo(ElementIDStruct obj_id, NodeType to_node) { return true; } -std::map const* +vt::util::container::CircularPhasesBuffer const* NodeLBData::getNodeLoad() const { return &lb_data_->node_data_; } -std::map const* +vt::util::container::CircularPhasesBuffer const* NodeLBData::getUserData() const { return &lb_data_->user_defined_lb_info_; } @@ -110,7 +110,7 @@ std::unordered_map const* NodeLBData::getNodeComm() cons return &lb_data_->node_comm_; } -std::map> const* NodeLBData::getNodeSubphaseComm() const { +vt::util::container::CircularPhasesBuffer> const* NodeLBData::getNodeSubphaseComm() const { return &lb_data_->node_subphase_comm_; } @@ -351,9 +351,9 @@ void NodeLBData::addNodeLBData( auto const phase = in->getPhase(); auto const& total_load = in->getLoad(phase, focused_subphase); - auto &phase_data = lb_data_->node_data_[phase]; - auto elm_iter = phase_data.find(id); - vtAssert(elm_iter == phase_data.end(), "Must not exist"); + auto phase_data = lb_data_->node_data_.find(phase); + auto elm_iter = phase_data->find(id); + vtAssert(elm_iter == phase_data->end(), "Must not exist"); auto& subphase_times = in->getSubphaseTimes(phase); @@ -364,16 +364,20 @@ void NodeLBData::addNodeLBData( ); auto const& comm = in->getComm(phase); - auto &comm_data = lb_data_->node_comm_[phase]; - for (auto&& c : comm) { - comm_data[c.first] += c.second; + auto comm_data = lb_data_->node_comm_.find(phase); + if (comm_data) { + for (auto&& c : comm) { + (*comm_data)[c.first] += c.second; + } } auto const& subphase_comm = in->getSubphaseComm(phase); - auto &subphase_comm_data = lb_data_->node_subphase_comm_[phase]; - for (SubphaseType i = 0; i < subphase_comm.size(); i++) { - for (auto& sp : subphase_comm[i]) { - subphase_comm_data[i][sp.first] += sp.second; + auto subphase_comm_data = lb_data_->node_subphase_comm_.find(phase); + if (subphase_comm_data) { + for (SubphaseType i = 0; i < subphase_comm.size(); i++) { + for (auto& sp : subphase_comm[i]) { + (*subphase_comm_data)[i][sp.first] += sp.second; + } } } diff --git a/src/vt/vrt/collection/balance/node_lb_data.h b/src/vt/vrt/collection/balance/node_lb_data.h index 51c6b79300..17f244be37 100644 --- a/src/vt/vrt/collection/balance/node_lb_data.h +++ b/src/vt/vrt/collection/balance/node_lb_data.h @@ -57,6 +57,7 @@ #include "vt/vrt/collection/balance/lb_data_holder.h" #include "vt/vrt/collection/types/storage/storable.h" #include "vt/utils/file_spec/spec.h" +#include "vt/utils/container/circular_phases_buffer.h" #include #include @@ -172,21 +173,21 @@ struct NodeLBData : runtime::component::Component { * * \return an observer pointer to the load map */ - std::map const* getNodeLoad() const; + vt::util::container::CircularPhasesBuffer const* getNodeLoad() const; /** * \internal \brief Get stored object comm graph * * \return an observer pointer to the comm graph */ - std::map const* getNodeComm() const; + vt::util::container::CircularPhasesBuffer const* getNodeComm() const; /** * \internal \brief Get the user-defined LB data * * \return an observer pointer to the user-defined LB data */ - std::map const* getUserData() const; + vt::util::container::CircularPhasesBuffer const* getUserData() const; /** * \internal \brief Get the user-defined attributes @@ -209,7 +210,7 @@ struct NodeLBData : runtime::component::Component { * * \return an observer pointer to the comm subphase graph */ - std::map> const* getNodeSubphaseComm() const; + vt::util::container::CircularPhasesBuffer> const* getNodeSubphaseComm() const; /** * \internal \brief Get stored node attributes diff --git a/tests/unit/collection/test_model_linear_model.nompi.cc b/tests/unit/collection/test_model_linear_model.nompi.cc index cc04c92cf0..ca5743ecfd 100644 --- a/tests/unit/collection/test_model_linear_model.nompi.cc +++ b/tests/unit/collection/test_model_linear_model.nompi.cc @@ -95,7 +95,7 @@ struct StubModel : LoadModel { unsigned int getNumPastPhasesNeeded(unsigned int look_back = 0) const override { return look_back; } private: - std::map const* proc_load_ = nullptr; + vt::util::container::CircularPhasesBuffer const* proc_load_ = nullptr; }; TEST_F(TestLinearModel, test_model_linear_model_1) { @@ -107,7 +107,7 @@ 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::map proc_loads{{0, LoadMapType{ + vt::util::container::CircularPhasesBuffer proc_loads{{0, LoadMapType{ {ElementIDStruct{1,this_node}, {LoadType{10}, {}}}, {ElementIDStruct{2,this_node}, {LoadType{40}, {}}} }}}; diff --git a/tests/unit/collection/test_model_multiple_phases.nompi.cc b/tests/unit/collection/test_model_multiple_phases.nompi.cc index 1e98637e85..11687b73ec 100644 --- a/tests/unit/collection/test_model_multiple_phases.nompi.cc +++ b/tests/unit/collection/test_model_multiple_phases.nompi.cc @@ -95,12 +95,12 @@ struct StubModel : LoadModel { unsigned int getNumPastPhasesNeeded(unsigned int look_back = 0) const override { return look_back; } private: - std::map const* proc_load_ = nullptr; + vt::util::container::CircularPhasesBuffer const* proc_load_ = nullptr; }; TEST_F(TestModelMultiplePhases, test_model_multiple_phases_1) { NodeType this_node = 0; - std::map proc_loads = { + vt::util::container::CircularPhasesBuffer proc_loads = { {0, LoadMapType{ {ElementIDStruct{1,this_node}, {LoadType{10}, {}}}, {ElementIDStruct{2,this_node}, {LoadType{40}, {}}}}}, diff --git a/tests/unit/collection/test_model_naive_persistence.nompi.cc b/tests/unit/collection/test_model_naive_persistence.nompi.cc index 05dd392534..10e47045f1 100644 --- a/tests/unit/collection/test_model_naive_persistence.nompi.cc +++ b/tests/unit/collection/test_model_naive_persistence.nompi.cc @@ -98,12 +98,12 @@ struct StubModel : LoadModel { unsigned int getNumPastPhasesNeeded(unsigned int look_back = 0) const override { return look_back; } private: - std::map const* proc_load_ = nullptr; + vt::util::container::CircularPhasesBuffer const* proc_load_ = nullptr; }; TEST_F(TestModelNaivePersistence, test_model_naive_persistence_1) { NodeType this_node = 0; - std::map proc_loads = { + vt::util::container::CircularPhasesBuffer proc_loads = { {0, LoadMapType{ {ElementIDStruct{1,this_node}, {LoadType{10}, {}}}, {ElementIDStruct{2,this_node}, {LoadType{40}, {}}}}}, 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 1c378f6d39..3e185aad45 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 @@ -95,7 +95,7 @@ struct StubModel : LoadModel { unsigned int getNumPastPhasesNeeded(unsigned int look_back = 0) const override { return look_back; } private: - std::map const* proc_load_ = nullptr; + vt::util::container::CircularPhasesBuffer const* proc_load_ = nullptr; }; TEST_F(TestModelPersistenceMedianLastN, test_model_persistence_median_last_n_1) { @@ -105,7 +105,7 @@ TEST_F(TestModelPersistenceMedianLastN, test_model_persistence_median_last_n_1) auto test_model = std::make_shared(std::make_shared(), 4); - std::map proc_loads; + vt::util::container::CircularPhasesBuffer proc_loads; test_model->setLoads(&proc_loads, nullptr, nullptr); diff --git a/tests/unit/utils/test_circular_phases_buffer.nompi.cc b/tests/unit/utils/test_circular_phases_buffer.nompi.cc new file mode 100644 index 0000000000..bfbc9223ca --- /dev/null +++ b/tests/unit/utils/test_circular_phases_buffer.nompi.cc @@ -0,0 +1,134 @@ +/* +//@HEADER +// ***************************************************************************** +// +// test_circular_phases_buffer.nompi.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 + +#include +#include "test_harness.h" + +namespace vt { namespace tests { namespace unit { + +using TestCircularPhasesBuffer = TestHarness; + +struct Dummy { + int x; +}; + +void validatePresentPhases(util::container::CircularPhasesBuffer& buffer, std::vector expected) { + for (auto&& phase : expected) { + EXPECT_TRUE(buffer.contains(phase)); + EXPECT_EQ(phase * phase, buffer[phase].x); + } +} + +void validateMissingPhases(util::container::CircularPhasesBuffer& buffer, std::vector expected) { + for (auto&& phase : expected) { + EXPECT_FALSE(buffer.contains(phase)); + } +} + +TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_empty) { + util::container::CircularPhasesBuffer buffer{10}; + + EXPECT_FALSE(buffer.contains(3)); + EXPECT_FALSE(buffer.contains(10)); + + buffer.resize(2); + + EXPECT_FALSE(buffer.contains(3)); + EXPECT_FALSE(buffer.contains(10)); + + buffer.clear(); + + EXPECT_FALSE(buffer.contains(3)); + EXPECT_FALSE(buffer.contains(10)); +} + +TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_store) { + util::container::CircularPhasesBuffer buffer{10}; + + buffer.store(2, { 2 * 2 }); + validatePresentPhases(buffer, {2}); + + // store series of elements + for (int i = 0; i < 15; i++) { + buffer.store(i, { i * i }); + } + validatePresentPhases(buffer, {5, 6, 7, 8, 9, 10, 11, 12, 13, 14}); +} + +TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_resize_continuous) { + util::container::CircularPhasesBuffer buffer{1}; + + buffer.store(0, { 0 }); + validatePresentPhases(buffer, {0}); + + buffer.resize(10); + validatePresentPhases(buffer, {0}); + + for (int i = 0; i <= 15; i++) { + buffer.store(i, { i * i }); + } + validatePresentPhases(buffer, {6, 7, 8, 9, 10, 11, 12, 13, 14, 15}); + + buffer.resize(5); + validatePresentPhases(buffer, {11, 12, 13, 14, 15}); + validateMissingPhases(buffer, {6, 7, 8, 9, 10}); + + for (int i = 15; i <= 32; i++) { + buffer.store(i, { i * i }); + } + validatePresentPhases(buffer, {28, 29, 30, 31, 32}); + + buffer.resize(9); + + for (int i = 33; i <= 35; i++) { + buffer.store(i, { i * i }); + } + validatePresentPhases(buffer, {28, 29, 30, 31, 32, 33, 34, 35}); + + buffer.resize(1); + validatePresentPhases(buffer, {35}); +} + +}}} /* end namespace vt::tests::unit */ diff --git a/tests/unit/utils/test_dynamic_circular_buffer.nompi.cc b/tests/unit/utils/test_dynamic_circular_buffer.nompi.cc deleted file mode 100644 index 31268431bd..0000000000 --- a/tests/unit/utils/test_dynamic_circular_buffer.nompi.cc +++ /dev/null @@ -1,91 +0,0 @@ -#include - -#include -#include "test_harness.h" - -namespace vt { namespace tests { namespace unit { - -using TestDynamicCircularBuffer = TestHarness; - -struct Dummy { - int x; -}; - -void validatePresentPhases(util::container::DynamicCircularBuffer& buffer, std::vector expected) { - for (auto&& phase : expected) { - EXPECT_TRUE(buffer.contains(phase)); - EXPECT_EQ(phase * phase, buffer[phase]->x); - } -} - -void validateMissingPhases(util::container::DynamicCircularBuffer& buffer, std::vector expected) { - for (auto&& phase : expected) { - EXPECT_FALSE(buffer.contains(phase)); - } -} - -TEST_F(TestDynamicCircularBuffer, test_dynamic_circular_buffer_empty) { - util::container::DynamicCircularBuffer buffer{10}; - - EXPECT_FALSE(buffer.contains(3)); - EXPECT_FALSE(buffer.contains(10)); - - buffer.resize(2); - - EXPECT_FALSE(buffer.contains(3)); - EXPECT_FALSE(buffer.contains(10)); - - buffer.clear(); - - EXPECT_FALSE(buffer.contains(3)); - EXPECT_FALSE(buffer.contains(10)); -} - -TEST_F(TestDynamicCircularBuffer, test_dynamic_circular_buffer_store) { - util::container::DynamicCircularBuffer buffer{10}; - - buffer.store(2, { 2 * 2 }); - validatePresentPhases(buffer, {2}); - - // store series of elements - for (int i = 0; i < 15; i++) { - buffer.store(i, { i * i }); - } - validatePresentPhases(buffer, {5, 6, 7, 8, 9, 10, 11, 12, 13, 14}); -} - -TEST_F(TestDynamicCircularBuffer, test_dynamic_circular_buffer_resize_continuous) { - util::container::DynamicCircularBuffer buffer{1}; - - buffer.store(0, { 0 }); - validatePresentPhases(buffer, {0}); - - buffer.resize(10); - validatePresentPhases(buffer, {0}); - - for (int i = 0; i <= 15; i++) { - buffer.store(i, { i * i }); - } - validatePresentPhases(buffer, {6, 7, 8, 9, 10, 11, 12, 13, 14, 15}); - - buffer.resize(5); - validatePresentPhases(buffer, {11, 12, 13, 14, 15}); - validateMissingPhases(buffer, {6, 7, 8, 9, 10}); - - for (int i = 15; i <= 32; i++) { - buffer.store(i, { i * i }); - } - validatePresentPhases(buffer, {28, 29, 30, 31, 32}); - - buffer.resize(9); - - for (int i = 33; i <= 35; i++) { - buffer.store(i, { i * i }); - } - validatePresentPhases(buffer, {28, 29, 30, 31, 32, 33, 34, 35}); - - buffer.resize(1); - validatePresentPhases(buffer, {35}); -} - -}}} /* end namespace vt::tests::unit */ From 7d496464ff03c05008abd4f0b6d1bbbab7729320 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Fri, 10 Nov 2023 19:09:58 +0100 Subject: [PATCH 07/82] #1934: Change node_data_ to new buffer type # Conflicts: # src/vt/vrt/collection/balance/lb_data_holder.cc --- .../vrt/collection/balance/lb_data_holder.cc | 7 +++-- .../vrt/collection/balance/model/raw_data.cc | 30 ++++++++++--------- src/vt/vrt/collection/balance/node_lb_data.cc | 5 ++-- src/vt/vrt/collection/balance/node_lb_data.h | 8 ++++- tests/unit/collection/test_lb_data_holder.cc | 2 +- .../unit/collection/test_lb_data_retention.cc | 6 ++-- .../test_model_comm_overhead.nompi.cc | 4 +-- .../test_model_linear_model.nompi.cc | 6 ++-- .../test_model_multiple_phases.nompi.cc | 4 +-- .../test_model_naive_persistence.nompi.cc | 6 ++-- .../unit/collection/test_model_norm.nompi.cc | 6 ++-- ...t_model_persistence_median_last_n.nompi.cc | 8 +++-- .../collection/test_model_raw_data.nompi.cc | 4 ++- .../test_model_select_subphases.nompi.cc | 16 +++++----- ...del_weighted_communication_volume.nompi.cc | 4 +-- .../test_model_weighted_messages.nompi.cc | 4 +-- tests/unit/lb/test_offlinelb.cc | 2 +- 17 files changed, 68 insertions(+), 54 deletions(-) diff --git a/src/vt/vrt/collection/balance/lb_data_holder.cc b/src/vt/vrt/collection/balance/lb_data_holder.cc index e74f3e8d22..e87905b855 100644 --- a/src/vt/vrt/collection/balance/lb_data_holder.cc +++ b/src/vt/vrt/collection/balance/lb_data_holder.cc @@ -435,11 +435,12 @@ LBDataHolder::LBDataHolder(nlohmann::json const& j) auto phases = j["phases"]; if (phases.is_array()) { + node_data_.resize(phases.size()); + for (auto const& phase : phases) { auto id = phase["id"]; auto tasks = phase["tasks"]; - this->node_data_[id]; this->node_comm_[id]; if (tasks.is_array()) { @@ -488,9 +489,9 @@ LBDataHolder::LBDataHolder(nlohmann::json const& j) vtAssertExpr(sid.is_number()); vtAssertExpr(stime.is_number()); - this->node_data_[id][elm].subphase_loads.resize( + this->node_data_.emplace(id)[elm].subphase_loads.resize( static_cast(sid) + 1); - this->node_data_[id][elm].subphase_loads[sid] = stime; + this->node_data_.emplace(id)[elm].subphase_loads[sid] = stime; } } } diff --git a/src/vt/vrt/collection/balance/model/raw_data.cc b/src/vt/vrt/collection/balance/model/raw_data.cc index d66eb9408d..b29a91215e 100644 --- a/src/vt/vrt/collection/balance/model/raw_data.cc +++ b/src/vt/vrt/collection/balance/model/raw_data.cc @@ -60,19 +60,19 @@ void RawData::setLoads(std::unordered_map const* proc_lo } ObjectIterator RawData::begin() const { - auto iter = proc_load_->find(last_completed_phase_); - if (iter != proc_load_->end()) { - return {std::make_unique(iter->second.cbegin(), - iter->second.cend())}; + auto ptr = proc_load_->find(last_completed_phase_); + if (ptr) { + return {std::make_unique(ptr->cbegin(), + ptr->cend())}; } else { return {nullptr}; } } int RawData::getNumObjects() const { - auto iter = proc_load_->find(last_completed_phase_); - if (iter != proc_load_->end()) { - return iter->second.size(); + auto ptr = proc_load_->find(last_completed_phase_); + if (ptr) { + return ptr->size(); } else { return 0; } @@ -83,14 +83,16 @@ unsigned int RawData::getNumCompletedPhases() const { } int RawData::getNumSubphases() const { - const auto& last_phase = proc_load_->at(last_completed_phase_); + const auto last_phase = proc_load_->find(last_completed_phase_); // @todo: this workaround is O(#objects) and should be removed when we finish // the new subphase API int subphases = 0; - for (auto &obj : last_phase) { - if (obj.second.subphase_loads.size() > static_cast(subphases)) { - subphases = obj.second.subphase_loads.size(); + if (last_phase) { + for (auto &obj : *last_phase) { + if (obj.second.subphase_loads.size() > static_cast(subphases)) { + subphases = obj.second.subphase_loads.size(); + } } } return subphases; @@ -105,9 +107,9 @@ LoadType RawData::getRawLoad(ElementIDStruct object, PhaseOffset offset) const { "RawData makes no predictions. Compose with NaivePersistence or some longer-range forecasting model as needed"); auto phase = getNumCompletedPhases() + offset.phases; - auto& phase_data = proc_load_->at(phase); - if (phase_data.find(object) != phase_data.end()) { - return phase_data.at(object).get(offset); + auto phase_data = proc_load_->find(phase); + if (phase_data && phase_data->find(object) != phase_data->end()) { + return phase_data->at(object).get(offset); } else { return 0.0; } diff --git a/src/vt/vrt/collection/balance/node_lb_data.cc b/src/vt/vrt/collection/balance/node_lb_data.cc index 1e3d8db7a6..64edacc60b 100644 --- a/src/vt/vrt/collection/balance/node_lb_data.cc +++ b/src/vt/vrt/collection/balance/node_lb_data.cc @@ -144,6 +144,7 @@ void NodeLBData::startIterCleanup(PhaseType phase, unsigned int look_back) { node_objgroup_lookup_.clear(); } +// later this method can be deleted void NodeLBData::trimLBDataHistory() { auto trim_data = [this](auto& map){ if(map.size() > min_hist_lb_data_) { @@ -152,7 +153,7 @@ void NodeLBData::trimLBDataHistory() { } }; - trim_data(lb_data_->node_data_); + lb_data_->node_data_.resize(min_hist_lb_data_); trim_data(lb_data_->node_comm_); trim_data(lb_data_->node_subphase_comm_); trim_data(lb_data_->user_defined_lb_info_); @@ -357,7 +358,7 @@ void NodeLBData::addNodeLBData( auto& subphase_times = in->getSubphaseTimes(phase); - phase_data.emplace( + phase_data->emplace( std::piecewise_construct, std::forward_as_tuple(id), std::forward_as_tuple(LoadSummary{total_load, subphase_times}) diff --git a/src/vt/vrt/collection/balance/node_lb_data.h b/src/vt/vrt/collection/balance/node_lb_data.h index 17f244be37..832cf837a7 100644 --- a/src/vt/vrt/collection/balance/node_lb_data.h +++ b/src/vt/vrt/collection/balance/node_lb_data.h @@ -276,7 +276,13 @@ struct NodeLBData : runtime::component::Component { * * \param[in] hist_len the minimal amount of LB data to retain */ - void setMinLBDataHistory(uint32_t hist_len) { min_hist_lb_data_ = hist_len; } + void setMinLBDataHistory(uint32_t hist_len) { + min_hist_lb_data_ = hist_len; + + if (lb_data_) { + lb_data_->node_data_.resize(min_hist_lb_data_); + } + } /** * \brief Trim the cached LB Data to it's minimum retention size diff --git a/tests/unit/collection/test_lb_data_holder.cc b/tests/unit/collection/test_lb_data_holder.cc index 09cc2ba174..8891ab143e 100644 --- a/tests/unit/collection/test_lb_data_holder.cc +++ b/tests/unit/collection/test_lb_data_holder.cc @@ -77,7 +77,7 @@ void addPhasesDataToJson(nlohmann::json& json, PhaseType amountOfPhasesToAdd, st LBDataHolder dh; for (unsigned i = 0; i < amountOfPhasesToAdd; i++) { for (auto&& elm : ids[i]) { - dh.node_data_[i][elm] = LoadSummary{3.}; + (*dh.node_data_[i])[elm] = LoadSummary{3.}; } } diff --git a/tests/unit/collection/test_lb_data_retention.cc b/tests/unit/collection/test_lb_data_retention.cc index 7139cea9dc..e22e23e559 100644 --- a/tests/unit/collection/test_lb_data_retention.cc +++ b/tests/unit/collection/test_lb_data_retention.cc @@ -62,14 +62,14 @@ void validatePersistedPhases(std::vector expected_phases) { #if vt_check_enabled(lblite) // Check maps size EXPECT_EQ(expected_phases.size(), theNodeLBData()->getLBData()->node_comm_.size()); - EXPECT_EQ(expected_phases.size(), theNodeLBData()->getLBData()->node_data_.size()); + // EXPECT_EQ(expected_phases.size(), theNodeLBData()->getLBData()->node_data_.size()); EXPECT_EQ(expected_phases.size(), theNodeLBData()->getLBData()->node_subphase_comm_.size()); EXPECT_EQ(expected_phases.size(), theNodeLBData()->getLBData()->user_defined_json_.size()); EXPECT_EQ(expected_phases.size(), theNodeLBData()->getLBData()->user_defined_lb_info_.size()); // Check if each phase is present for(auto&& phase : expected_phases) { EXPECT_EQ(1, theNodeLBData()->getLBData()->node_comm_.count(phase)); - EXPECT_EQ(1, theNodeLBData()->getLBData()->node_data_.count(phase)); + // EXPECT_EQ(1, theNodeLBData()->getLBData()->node_data_.count(phase)); EXPECT_EQ(1, theNodeLBData()->getLBData()->node_subphase_comm_.count(phase)); EXPECT_EQ(1, theNodeLBData()->getLBData()->user_defined_json_.count(phase)); EXPECT_EQ(1, theNodeLBData()->getLBData()->user_defined_lb_info_.count(phase)); @@ -77,7 +77,7 @@ void validatePersistedPhases(std::vector expected_phases) { #else (void)expected_phases; EXPECT_EQ(0, theNodeLBData()->getLBData()->node_comm_.size()); - EXPECT_EQ(0, theNodeLBData()->getLBData()->node_data_.size()); + // EXPECT_EQ(0, theNodeLBData()->getLBData()->node_data_.size()); EXPECT_EQ(0, theNodeLBData()->getLBData()->node_subphase_comm_.size()); EXPECT_EQ(0, theNodeLBData()->getLBData()->user_defined_json_.size()); EXPECT_EQ(0, theNodeLBData()->getLBData()->user_defined_lb_info_.size()); diff --git a/tests/unit/collection/test_model_comm_overhead.nompi.cc b/tests/unit/collection/test_model_comm_overhead.nompi.cc index 20d3bfc44e..a9c6690bbd 100644 --- a/tests/unit/collection/test_model_comm_overhead.nompi.cc +++ b/tests/unit/collection/test_model_comm_overhead.nompi.cc @@ -91,7 +91,7 @@ struct StubModel : LoadModel { void updateLoads(PhaseType) override {} LoadType getModeledLoad(ElementIDStruct id, PhaseOffset phase) const override { - const auto work = proc_load_->at(0).at(id).whole_phase_load; + const auto work = proc_load_->find(0)->at(id).whole_phase_load; if (phase.subphase == PhaseOffset::WHOLE_PHASE) { return work; @@ -101,7 +101,7 @@ struct StubModel : LoadModel { } ObjectIterator begin() const override { - return {std::make_unique(proc_load_->at(0).begin(), proc_load_->at(0).end())}; + return {std::make_unique(proc_load_->find(0)->begin(), proc_load_->find(0)->end())}; } unsigned int getNumCompletedPhases() const override { return num_phases; } diff --git a/tests/unit/collection/test_model_linear_model.nompi.cc b/tests/unit/collection/test_model_linear_model.nompi.cc index ca5743ecfd..b7eb866e78 100644 --- a/tests/unit/collection/test_model_linear_model.nompi.cc +++ b/tests/unit/collection/test_model_linear_model.nompi.cc @@ -83,11 +83,11 @@ struct StubModel : LoadModel { LoadType getModeledLoad(ElementIDStruct id, PhaseOffset phase) const override { // Most recent phase will be at the end of vector - return proc_load_->at(num_phases + phase.phases).at(id).whole_phase_load; + return proc_load_->find(num_phases + phase.phases)->at(id).whole_phase_load; } virtual ObjectIterator begin() const override { - return {std::make_unique(proc_load_->at(0).begin(), proc_load_->at(0).end())}; + return {std::make_unique(proc_load_->find(0)->begin(), proc_load_->find(0)->end())}; } virtual unsigned int getNumCompletedPhases() const override { return num_phases; } @@ -146,7 +146,7 @@ TEST_F(TestLinearModel, test_model_linear_model_1) { }; for (auto iter = 0; iter < num_test_interations; ++iter) { - proc_loads[num_phases] = load_holder[iter]; + proc_loads.store(num_phases, load_holder[iter]); test_model->updateLoads(num_phases); ++num_phases; diff --git a/tests/unit/collection/test_model_multiple_phases.nompi.cc b/tests/unit/collection/test_model_multiple_phases.nompi.cc index 11687b73ec..6850ac5d5b 100644 --- a/tests/unit/collection/test_model_multiple_phases.nompi.cc +++ b/tests/unit/collection/test_model_multiple_phases.nompi.cc @@ -82,11 +82,11 @@ struct StubModel : LoadModel { LoadType getModeledLoad(ElementIDStruct id, PhaseOffset phase) const override { // Here we return predicted loads for future phases // For the sake of the test we use values from the past phases - return proc_load_->at(phase.phases).at(id).whole_phase_load; + return proc_load_->find(phase.phases)->at(id).whole_phase_load; } virtual ObjectIterator begin() const override { - return {std::make_unique(proc_load_->at(3).begin(), proc_load_->at(3).end())}; + return {std::make_unique(proc_load_->find(3)->begin(), proc_load_->find(3)->end())}; } // Not used by this test diff --git a/tests/unit/collection/test_model_naive_persistence.nompi.cc b/tests/unit/collection/test_model_naive_persistence.nompi.cc index 10e47045f1..461e5f4b45 100644 --- a/tests/unit/collection/test_model_naive_persistence.nompi.cc +++ b/tests/unit/collection/test_model_naive_persistence.nompi.cc @@ -85,11 +85,11 @@ struct StubModel : LoadModel { LoadType getModeledLoad(ElementIDStruct id, PhaseOffset phase) const override { EXPECT_LE(phase.phases, -1); - return proc_load_->at(getIndexFromPhase(phase.phases)).at(id).whole_phase_load; + return proc_load_->find(getIndexFromPhase(phase.phases))->at(id).whole_phase_load; } virtual ObjectIterator begin() const override { - return {std::make_unique(proc_load_->at(3).begin(), proc_load_->at(3).end())}; + return {std::make_unique(proc_load_->find(3)->begin(), proc_load_->find(3)->end())}; } // Not used in this test @@ -127,7 +127,7 @@ TEST_F(TestModelNaivePersistence, test_model_naive_persistence_1) { auto &&obj = *it; for (auto phase : {0, -1, -2, -3, -4}) { auto work_val = test_model->getModeledLoad(obj, PhaseOffset{phase, 1}); - EXPECT_EQ(work_val, proc_loads.at(getIndexFromPhase(phase)).at(obj).whole_phase_load); + EXPECT_EQ(work_val, proc_loads.find(getIndexFromPhase(phase))->at(obj).whole_phase_load); } } } diff --git a/tests/unit/collection/test_model_norm.nompi.cc b/tests/unit/collection/test_model_norm.nompi.cc index 5d8a223ac3..af37623bc3 100644 --- a/tests/unit/collection/test_model_norm.nompi.cc +++ b/tests/unit/collection/test_model_norm.nompi.cc @@ -88,11 +88,11 @@ struct StubModel : LoadModel { void updateLoads(PhaseType) override {} LoadType getModeledLoad(ElementIDStruct id, PhaseOffset phase) const override { - return proc_load_->at(0).at(id).subphase_loads.at(phase.subphase); + return proc_load_->find(0)->at(id).subphase_loads.at(phase.subphase); } ObjectIterator begin() const override { - return {std::make_unique(proc_load_->at(0).begin(), proc_load_->at(0).end())}; + return {std::make_unique(proc_load_->find(0)->begin(), proc_load_->find(0)->end())}; } int getNumSubphases() const override { return num_subphases; } @@ -129,7 +129,7 @@ TEST_F(TestModelNorm, test_model_norm_1) { // offset.subphase != PhaseOffset::WHOLE_PHASE // expect work load value for given subphase auto work_val = test_model->getModeledLoad(obj, PhaseOffset{0, iter}); - EXPECT_EQ(work_val, proc_load[0][obj].subphase_loads[iter]); + EXPECT_EQ(work_val, (*proc_load.find(0))[obj].subphase_loads[iter]); } EXPECT_EQ(objects_seen, 2); 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 3e185aad45..df8f31440a 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 @@ -83,11 +83,11 @@ struct StubModel : LoadModel { LoadType getModeledLoad(ElementIDStruct id, PhaseOffset phase) const override { // Most recent phase will be at the end of vector - return proc_load_->at(num_phases + phase.phases).at(id).whole_phase_load; + return proc_load_->find(num_phases + phase.phases)->at(id).whole_phase_load; } virtual ObjectIterator begin() const override { - return {std::make_unique(proc_load_->at(num_phases-1).begin(), proc_load_->at(num_phases-1).end())}; + return {std::make_unique(proc_load_->find(num_phases-1)->begin(), proc_load_->find(num_phases-1)->end())}; } virtual unsigned int getNumCompletedPhases() const override { return num_phases; } @@ -144,8 +144,10 @@ TEST_F(TestModelPersistenceMedianLastN, test_model_persistence_median_last_n_1) std::make_pair(LoadType{55}, LoadType{30}) // iter 6 results }; + proc_loads.resize(num_total_phases); + for (auto iter = 0; iter < num_total_phases; ++iter) { - proc_loads[iter] = load_holder[iter]; + proc_loads.store(iter, load_holder[iter]); test_model->updateLoads(iter); ++num_phases; diff --git a/tests/unit/collection/test_model_raw_data.nompi.cc b/tests/unit/collection/test_model_raw_data.nompi.cc index 3dfca34863..8879811438 100644 --- a/tests/unit/collection/test_model_raw_data.nompi.cc +++ b/tests/unit/collection/test_model_raw_data.nompi.cc @@ -88,8 +88,10 @@ TEST_F(TestRawData, test_model_raw_data_scalar) { LoadMapType{{id1, {LoadType{100}, {LoadType{100}}}}, {id2, {LoadType{10}, {LoadType{10}}}}}, }; + proc_loads.resize(load_holder.size()); + for (size_t iter = 0; iter < load_holder.size(); ++iter) { - proc_loads[iter] = load_holder[iter]; + proc_loads.store(iter, load_holder[iter]); test_model->updateLoads(iter); EXPECT_EQ(test_model->getNumObjects(), 2); diff --git a/tests/unit/collection/test_model_select_subphases.nompi.cc b/tests/unit/collection/test_model_select_subphases.nompi.cc index fb41feacbe..4732c06233 100644 --- a/tests/unit/collection/test_model_select_subphases.nompi.cc +++ b/tests/unit/collection/test_model_select_subphases.nompi.cc @@ -87,13 +87,13 @@ struct StubModel : LoadModel { void updateLoads(PhaseType) override {} LoadType getModeledLoad(ElementIDStruct id, PhaseOffset phase) const override { - return proc_load_->at(0).at(id).subphase_loads.at(phase.subphase); + return proc_load_->find(0)->at(id).subphase_loads.at(phase.subphase); } ObjectIterator begin() const override { return { std::make_unique( - proc_load_->at(0).begin(), proc_load_->at(0).end() + proc_load_->find(0)->begin(), proc_load_->find(0)->end() ) }; } @@ -132,13 +132,13 @@ TEST_F(TestModelSelectSubphases, test_model_select_subphases_1) { std::unordered_map> expected_values = { {id1, - {proc_load[0][id1].subphase_loads[subphases[0]], - proc_load[0][id1].subphase_loads[subphases[1]], - proc_load[0][id1].subphase_loads[subphases[2]]}}, + {(*proc_load.find(0))[id1].subphase_loads[subphases[0]], + (*proc_load.find(0))[id1].subphase_loads[subphases[1]], + (*proc_load.find(0))[id1].subphase_loads[subphases[2]]}}, {id2, - {proc_load[0][id2].subphase_loads[subphases[0]], - proc_load[0][id2].subphase_loads[subphases[1]], - proc_load[0][id2].subphase_loads[subphases[2]]}}}; + {(*proc_load.find(0))[id2].subphase_loads[subphases[0]], + (*proc_load.find(0))[id2].subphase_loads[subphases[1]], + (*proc_load.find(0))[id2].subphase_loads[subphases[2]]}}}; for (unsigned int iter = 0; iter < num_subphases; ++iter) { int objects_seen = 0; diff --git a/tests/unit/collection/test_model_weighted_communication_volume.nompi.cc b/tests/unit/collection/test_model_weighted_communication_volume.nompi.cc index a7cdc11ff3..76d2d10166 100644 --- a/tests/unit/collection/test_model_weighted_communication_volume.nompi.cc +++ b/tests/unit/collection/test_model_weighted_communication_volume.nompi.cc @@ -90,7 +90,7 @@ struct StubModel : LoadModel { void updateLoads(PhaseType) override { } LoadType getModeledLoad(ElementIDStruct id, PhaseOffset phase) const override { - const auto work = proc_load_->at(0).at(id).whole_phase_load; + const auto work = proc_load_->find(0)->at(id).whole_phase_load; if (phase.subphase == PhaseOffset::WHOLE_PHASE) { return work; @@ -101,7 +101,7 @@ struct StubModel : LoadModel { ObjectIterator begin() const override { return {std::make_unique( - proc_load_->at(0).begin(), proc_load_->at(0).end() + proc_load_->find(0)->begin(), proc_load_->find(0)->end() )}; } diff --git a/tests/unit/collection/test_model_weighted_messages.nompi.cc b/tests/unit/collection/test_model_weighted_messages.nompi.cc index d08f345d0e..79e5370216 100644 --- a/tests/unit/collection/test_model_weighted_messages.nompi.cc +++ b/tests/unit/collection/test_model_weighted_messages.nompi.cc @@ -87,7 +87,7 @@ struct StubModel : LoadModel { void updateLoads(PhaseType) override { } LoadType getModeledLoad(ElementIDStruct id, PhaseOffset phase) const override { - const auto work = proc_load_->at(0).at(id).whole_phase_load; + const auto work = proc_load_->find(0)->at(id).whole_phase_load; if (phase.subphase == PhaseOffset::WHOLE_PHASE) { return work; @@ -98,7 +98,7 @@ struct StubModel : LoadModel { ObjectIterator begin() const override { return {std::make_unique( - proc_load_->at(0).begin(), proc_load_->at(0).end() + proc_load_->find(0)->begin(), proc_load_->find(0)->end() )}; } diff --git a/tests/unit/lb/test_offlinelb.cc b/tests/unit/lb/test_offlinelb.cc index b470e61f1c..599383aa03 100644 --- a/tests/unit/lb/test_offlinelb.cc +++ b/tests/unit/lb/test_offlinelb.cc @@ -128,7 +128,7 @@ TEST_F(TestOfflineLB, test_offlinelb_1) { LBDataHolder dh; for (PhaseType i = 0; i < num_phases; i++) { for (auto&& elm : ids[i]) { - dh.node_data_[i][elm] = LoadSummary{3}; + (*dh.node_data_[i])[elm] = LoadSummary{3}; } } From f801dca95d38b92f4a06692537b80f9396d44b39 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 14 Nov 2023 13:16:04 +0100 Subject: [PATCH 08/82] #1934: Use new container type in LB Data Holder --- .../vrt/collection/balance/lb_data_holder.cc | 16 ++++++------- .../balance/lb_invoke/lb_manager.cc | 19 ++++++++------- src/vt/vrt/collection/balance/node_lb_data.cc | 23 +++++++------------ tests/unit/collection/test_lb.extended.cc | 13 ++++++----- .../unit/collection/test_lb_data_retention.cc | 14 +++++------ 5 files changed, 38 insertions(+), 47 deletions(-) diff --git a/src/vt/vrt/collection/balance/lb_data_holder.cc b/src/vt/vrt/collection/balance/lb_data_holder.cc index e87905b855..f80f880e5a 100644 --- a/src/vt/vrt/collection/balance/lb_data_holder.cc +++ b/src/vt/vrt/collection/balance/lb_data_holder.cc @@ -212,13 +212,11 @@ std::unique_ptr LBDataHolder::toJson(PhaseType phase) const { j["tasks"][i]["resource"] = "cpu"; j["tasks"][i]["node"] = id.getCurrNode(); j["tasks"][i]["time"] = time; - if (user_defined_json_.find(phase) != user_defined_json_.end()) { - auto &user_def_this_phase = user_defined_json_.at(phase); - if (user_def_this_phase.find(id) != user_def_this_phase.end()) { - auto &user_def = user_def_this_phase.at(id); - if (!user_def->empty()) { - j["tasks"][i]["user_defined"] = *user_def; - } + auto user_def_this_phase = user_defined_json_.find(phase); + if (user_def_this_phase) { + auto &user_def = user_def_this_phase->at(id); + if (!user_def->empty()) { + j["tasks"][i]["user_defined"] = *user_def; } } outputEntity(j["tasks"][i]["entity"], id); @@ -550,7 +548,7 @@ LBDataHolder::LBDataHolder(nlohmann::json const& j) from_elm, to_elm, type == "Broadcast" ); CommVolume vol{bytes, messages}; - this->node_comm_[id][key] = vol; + (*this->node_comm_[id])[key] = vol; } else if ( type == "NodeToCollection" || type == "NodeToCollectionBcast" ) { @@ -568,7 +566,7 @@ LBDataHolder::LBDataHolder(nlohmann::json const& j) type == "NodeToCollectionBcast" ); CommVolume vol{bytes, messages}; - this->node_comm_[id][key] = vol; + (*this->node_comm_[id])[key] = vol; } else if ( type == "CollectionToNode" || type == "CollectionToNodeBcast" ) { 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 1569553163..e88b74bc1b 100644 --- a/src/vt/vrt/collection/balance/lb_invoke/lb_manager.cc +++ b/src/vt/vrt/collection/balance/lb_invoke/lb_manager.cc @@ -258,15 +258,15 @@ LBManager::runLB(PhaseType phase, vt::Callback cb) { elm::CommMapType const* comm = &empty_comm; auto const& node_comm = theNodeLBData()->getNodeComm(); - if (auto iter = node_comm->find(phase); iter != node_comm->end()) { - comm = &iter->second; + if (auto ptr = node_comm->find(phase)) { + comm = ptr; } balance::DataMapType empty_data_map; balance::DataMapType const* data_map = &empty_data_map; auto const& node_data_map = theNodeLBData()->getUserData(); - if (auto iter = node_data_map->find(phase); iter != node_data_map->end()) { - data_map = &iter->second; + if (auto ptr = node_data_map->find(phase)) { + data_map = ptr; } vt_debug_print(terse, lb, "LBManager: running strategy\n"); @@ -736,9 +736,8 @@ void LBManager::computeStatistics( elm::CommMapType empty_comm; elm::CommMapType const* comm_data = &empty_comm; - auto iter = theNodeLBData()->getNodeComm()->find(phase); - if (iter != theNodeLBData()->getNodeComm()->end()) { - comm_data = &iter->second; + if (auto ptr = theNodeLBData()->getNodeComm()->find(phase)) { + comm_data = ptr; } std::vector lstats; @@ -898,12 +897,12 @@ getSharedEdges(elm::CommMapType const& comm_data) { void makeGraphSymmetric( PhaseType phase, objgroup::proxy::Proxy proxy ) { - auto iter = theNodeLBData()->getNodeComm()->find(phase); - if (iter == theNodeLBData()->getNodeComm()->end()) { + auto ptr = theNodeLBData()->getNodeComm()->find(phase); + if (!ptr) { return; } - auto shared_edges = getSharedEdges(iter->second); + auto shared_edges = getSharedEdges(*ptr); for (auto&& elm : shared_edges) { proxy[elm.first].send( diff --git a/src/vt/vrt/collection/balance/node_lb_data.cc b/src/vt/vrt/collection/balance/node_lb_data.cc index 64edacc60b..12019df7c7 100644 --- a/src/vt/vrt/collection/balance/node_lb_data.cc +++ b/src/vt/vrt/collection/balance/node_lb_data.cc @@ -119,8 +119,8 @@ ElmUserDataType const* NodeLBData::getNodeAttributes() const { } CommMapType* NodeLBData::getNodeComm(PhaseType phase) { - auto iter = lb_data_->node_comm_.find(phase); - return (iter != lb_data_->node_comm_.end()) ? &iter->second : nullptr; + auto ptr = lb_data_->node_comm_.find(phase); + return (ptr != nullptr) ? ptr : nullptr; } void NodeLBData::clearLBData() { @@ -146,18 +146,11 @@ void NodeLBData::startIterCleanup(PhaseType phase, unsigned int look_back) { // later this method can be deleted void NodeLBData::trimLBDataHistory() { - auto trim_data = [this](auto& map){ - if(map.size() > min_hist_lb_data_) { - auto target = map.upper_bound(map.rbegin()->first - min_hist_lb_data_); - map.erase(map.begin(), target); - } - }; - lb_data_->node_data_.resize(min_hist_lb_data_); - trim_data(lb_data_->node_comm_); - trim_data(lb_data_->node_subphase_comm_); - trim_data(lb_data_->user_defined_lb_info_); - trim_data(lb_data_->user_defined_json_); + lb_data_->node_comm_.resize(min_hist_lb_data_); + lb_data_->node_subphase_comm_.resize(min_hist_lb_data_); + lb_data_->user_defined_lb_info_.resize(min_hist_lb_data_); + lb_data_->user_defined_json_.resize(min_hist_lb_data_); NodeLBData::node_migrate_.clear(); node_collection_lookup_.clear(); @@ -383,12 +376,12 @@ void NodeLBData::addNodeLBData( } if (storable) { - lb_data_->user_defined_json_[phase][id] = std::make_shared( + (*lb_data_->user_defined_json_[phase])[id] = std::make_shared( storable->toJson() ); storable->foreachLB( [&](std::string const& key, auto val) { - lb_data_->user_defined_lb_info_[phase][id][key] = val->toVariant(); + (*lb_data_->user_defined_lb_info_[phase])[id][key] = val->toVariant(); } ); storable->collectAttributes( diff --git a/tests/unit/collection/test_lb.extended.cc b/tests/unit/collection/test_lb.extended.cc index 8995b4b179..db6e142abd 100644 --- a/tests/unit/collection/test_lb.extended.cc +++ b/tests/unit/collection/test_lb.extended.cc @@ -563,8 +563,9 @@ TEST_F(TestRestoreLBData, test_restore_lb_data_data_1) { { PhaseType phase = write_phase; - lbdh.node_data_[phase]; - lbdh.node_comm_[phase]; + lbdh.node_data_.resize(num_elms); + lbdh.node_comm_.resize(num_elms); + lbdh.node_subphase_comm_.resize(num_elms); for (int i=0; i arr; arr.push_back(idx.x()); diff --git a/tests/unit/collection/test_lb_data_retention.cc b/tests/unit/collection/test_lb_data_retention.cc index e22e23e559..73cfd17ef4 100644 --- a/tests/unit/collection/test_lb_data_retention.cc +++ b/tests/unit/collection/test_lb_data_retention.cc @@ -62,22 +62,22 @@ void validatePersistedPhases(std::vector expected_phases) { #if vt_check_enabled(lblite) // Check maps size EXPECT_EQ(expected_phases.size(), theNodeLBData()->getLBData()->node_comm_.size()); - // EXPECT_EQ(expected_phases.size(), theNodeLBData()->getLBData()->node_data_.size()); + EXPECT_EQ(expected_phases.size(), theNodeLBData()->getLBData()->node_data_.size()); EXPECT_EQ(expected_phases.size(), theNodeLBData()->getLBData()->node_subphase_comm_.size()); EXPECT_EQ(expected_phases.size(), theNodeLBData()->getLBData()->user_defined_json_.size()); EXPECT_EQ(expected_phases.size(), theNodeLBData()->getLBData()->user_defined_lb_info_.size()); // Check if each phase is present for(auto&& phase : expected_phases) { - EXPECT_EQ(1, theNodeLBData()->getLBData()->node_comm_.count(phase)); - // EXPECT_EQ(1, theNodeLBData()->getLBData()->node_data_.count(phase)); - EXPECT_EQ(1, theNodeLBData()->getLBData()->node_subphase_comm_.count(phase)); - EXPECT_EQ(1, theNodeLBData()->getLBData()->user_defined_json_.count(phase)); - EXPECT_EQ(1, theNodeLBData()->getLBData()->user_defined_lb_info_.count(phase)); + EXPECT_TRUE(nullptr != theNodeLBData()->getLBData()->node_comm_.find(phase)); + EXPECT_TRUE(nullptr != theNodeLBData()->getLBData()->node_data_.find(phase)); + EXPECT_TRUE(nullptr != theNodeLBData()->getLBData()->node_subphase_comm_.find(phase)); + EXPECT_TRUE(nullptr != theNodeLBData()->getLBData()->user_defined_json_.find(phase)); + EXPECT_TRUE(nullptr != theNodeLBData()->getLBData()->user_defined_lb_info_.find(phase)); } #else (void)expected_phases; EXPECT_EQ(0, theNodeLBData()->getLBData()->node_comm_.size()); - // EXPECT_EQ(0, theNodeLBData()->getLBData()->node_data_.size()); + EXPECT_EQ(0, theNodeLBData()->getLBData()->node_data_.size()); EXPECT_EQ(0, theNodeLBData()->getLBData()->node_subphase_comm_.size()); EXPECT_EQ(0, theNodeLBData()->getLBData()->user_defined_json_.size()); EXPECT_EQ(0, theNodeLBData()->getLBData()->user_defined_lb_info_.size()); From b7fb70d29435c2b68afe4cdd3c3d4524caa128d8 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 14 Nov 2023 20:45:58 +0100 Subject: [PATCH 09/82] #1934: Update usage of circular buffer after change in the operator[] --- .../vrt/collection/balance/lb_data_holder.cc | 22 +++++++++---------- .../vrt/collection/balance/model/raw_data.cc | 16 ++++++-------- tests/unit/collection/test_lb_data_holder.cc | 1 + .../test_model_comm_overhead.nompi.cc | 4 ++-- .../test_model_linear_model.nompi.cc | 6 ++--- .../test_model_multiple_phases.nompi.cc | 4 ++-- .../test_model_naive_persistence.nompi.cc | 6 ++--- .../unit/collection/test_model_norm.nompi.cc | 6 ++--- ...t_model_persistence_median_last_n.nompi.cc | 10 ++++----- .../collection/test_model_raw_data.nompi.cc | 2 +- .../test_model_select_subphases.nompi.cc | 16 +++++++------- ...del_weighted_communication_volume.nompi.cc | 4 ++-- .../test_model_weighted_messages.nompi.cc | 4 ++-- 13 files changed, 49 insertions(+), 52 deletions(-) diff --git a/src/vt/vrt/collection/balance/lb_data_holder.cc b/src/vt/vrt/collection/balance/lb_data_holder.cc index f80f880e5a..589344db5e 100644 --- a/src/vt/vrt/collection/balance/lb_data_holder.cc +++ b/src/vt/vrt/collection/balance/lb_data_holder.cc @@ -206,17 +206,19 @@ std::unique_ptr LBDataHolder::toJson(PhaseType phase) const { std::size_t i = 0; if (node_data_.contains(phase)) { - for (auto&& elm : *node_data_.find(phase)) { + for (auto&& elm : node_data_.at(phase)) { ElementIDStruct id = elm.first; LoadType time = elm.second.whole_phase_load; j["tasks"][i]["resource"] = "cpu"; j["tasks"][i]["node"] = id.getCurrNode(); j["tasks"][i]["time"] = time; - auto user_def_this_phase = user_defined_json_.find(phase); - if (user_def_this_phase) { - auto &user_def = user_def_this_phase->at(id); - if (!user_def->empty()) { - j["tasks"][i]["user_defined"] = *user_def; + if (user_defined_json_.find(phase)) { + auto &user_def_this_phase = user_defined_json_.at(phase); + if (user_def_this_phase.find(id) != user_def_this_phase.end()) { + auto &user_def = user_def_this_phase.at(id); + if (!user_def->empty()) { + j["tasks"][i]["user_defined"] = *user_def; + } } } outputEntity(j["tasks"][i]["entity"], id); @@ -243,7 +245,6 @@ std::unique_ptr LBDataHolder::toJson(PhaseType phase) const { j["tasks"][i]["subphases"][s]["time"] = subphase_times[s]; } } - i++; } @@ -434,13 +435,12 @@ LBDataHolder::LBDataHolder(nlohmann::json const& j) auto phases = j["phases"]; if (phases.is_array()) { node_data_.resize(phases.size()); + node_comm_.resize(phases.size()); for (auto const& phase : phases) { auto id = phase["id"]; auto tasks = phase["tasks"]; - this->node_comm_[id]; - if (tasks.is_array()) { for (auto const& task : tasks) { auto node = task["node"]; @@ -487,9 +487,9 @@ LBDataHolder::LBDataHolder(nlohmann::json const& j) vtAssertExpr(sid.is_number()); vtAssertExpr(stime.is_number()); - this->node_data_.emplace(id)[elm].subphase_loads.resize( + this->node_data_[id][elm].subphase_loads.resize( static_cast(sid) + 1); - this->node_data_.emplace(id)[elm].subphase_loads[sid] = stime; + this->node_data_[id][elm].subphase_loads[sid] = stime; } } } diff --git a/src/vt/vrt/collection/balance/model/raw_data.cc b/src/vt/vrt/collection/balance/model/raw_data.cc index b29a91215e..179a40ff8f 100644 --- a/src/vt/vrt/collection/balance/model/raw_data.cc +++ b/src/vt/vrt/collection/balance/model/raw_data.cc @@ -83,16 +83,14 @@ unsigned int RawData::getNumCompletedPhases() const { } int RawData::getNumSubphases() const { - const auto last_phase = proc_load_->find(last_completed_phase_); + const auto& last_phase = proc_load_->at(last_completed_phase_); // @todo: this workaround is O(#objects) and should be removed when we finish // the new subphase API int subphases = 0; - if (last_phase) { - for (auto &obj : *last_phase) { - if (obj.second.subphase_loads.size() > static_cast(subphases)) { - subphases = obj.second.subphase_loads.size(); - } + for (auto &obj : last_phase) { + if (obj.second.subphase_loads.size() > static_cast(subphases)) { + subphases = obj.second.subphase_loads.size(); } } return subphases; @@ -107,9 +105,9 @@ LoadType RawData::getRawLoad(ElementIDStruct object, PhaseOffset offset) const { "RawData makes no predictions. Compose with NaivePersistence or some longer-range forecasting model as needed"); auto phase = getNumCompletedPhases() + offset.phases; - auto phase_data = proc_load_->find(phase); - if (phase_data && phase_data->find(object) != phase_data->end()) { - return phase_data->at(object).get(offset); + auto& phase_data = proc_load_->at(phase); + if (phase_data.find(object) != phase_data.end()) { + return phase_data.at(object).get(offset); } else { return 0.0; } diff --git a/tests/unit/collection/test_lb_data_holder.cc b/tests/unit/collection/test_lb_data_holder.cc index 8891ab143e..cb2a87a67b 100644 --- a/tests/unit/collection/test_lb_data_holder.cc +++ b/tests/unit/collection/test_lb_data_holder.cc @@ -75,6 +75,7 @@ void addPhasesDataToJson(nlohmann::json& json, PhaseType amountOfPhasesToAdd, st } LBDataHolder dh; + dh.node_data_.resize(amountOfPhasesToAdd); for (unsigned i = 0; i < amountOfPhasesToAdd; i++) { for (auto&& elm : ids[i]) { (*dh.node_data_[i])[elm] = LoadSummary{3.}; diff --git a/tests/unit/collection/test_model_comm_overhead.nompi.cc b/tests/unit/collection/test_model_comm_overhead.nompi.cc index a9c6690bbd..20d3bfc44e 100644 --- a/tests/unit/collection/test_model_comm_overhead.nompi.cc +++ b/tests/unit/collection/test_model_comm_overhead.nompi.cc @@ -91,7 +91,7 @@ struct StubModel : LoadModel { void updateLoads(PhaseType) override {} LoadType getModeledLoad(ElementIDStruct id, PhaseOffset phase) const override { - const auto work = proc_load_->find(0)->at(id).whole_phase_load; + const auto work = proc_load_->at(0).at(id).whole_phase_load; if (phase.subphase == PhaseOffset::WHOLE_PHASE) { return work; @@ -101,7 +101,7 @@ struct StubModel : LoadModel { } ObjectIterator begin() const override { - return {std::make_unique(proc_load_->find(0)->begin(), proc_load_->find(0)->end())}; + return {std::make_unique(proc_load_->at(0).begin(), proc_load_->at(0).end())}; } unsigned int getNumCompletedPhases() const override { return num_phases; } diff --git a/tests/unit/collection/test_model_linear_model.nompi.cc b/tests/unit/collection/test_model_linear_model.nompi.cc index b7eb866e78..ca5743ecfd 100644 --- a/tests/unit/collection/test_model_linear_model.nompi.cc +++ b/tests/unit/collection/test_model_linear_model.nompi.cc @@ -83,11 +83,11 @@ struct StubModel : LoadModel { LoadType getModeledLoad(ElementIDStruct id, PhaseOffset phase) const override { // Most recent phase will be at the end of vector - return proc_load_->find(num_phases + phase.phases)->at(id).whole_phase_load; + return proc_load_->at(num_phases + phase.phases).at(id).whole_phase_load; } virtual ObjectIterator begin() const override { - return {std::make_unique(proc_load_->find(0)->begin(), proc_load_->find(0)->end())}; + return {std::make_unique(proc_load_->at(0).begin(), proc_load_->at(0).end())}; } virtual unsigned int getNumCompletedPhases() const override { return num_phases; } @@ -146,7 +146,7 @@ TEST_F(TestLinearModel, test_model_linear_model_1) { }; for (auto iter = 0; iter < num_test_interations; ++iter) { - proc_loads.store(num_phases, load_holder[iter]); + proc_loads[num_phases] = load_holder[iter]; test_model->updateLoads(num_phases); ++num_phases; diff --git a/tests/unit/collection/test_model_multiple_phases.nompi.cc b/tests/unit/collection/test_model_multiple_phases.nompi.cc index 6850ac5d5b..11687b73ec 100644 --- a/tests/unit/collection/test_model_multiple_phases.nompi.cc +++ b/tests/unit/collection/test_model_multiple_phases.nompi.cc @@ -82,11 +82,11 @@ struct StubModel : LoadModel { LoadType getModeledLoad(ElementIDStruct id, PhaseOffset phase) const override { // Here we return predicted loads for future phases // For the sake of the test we use values from the past phases - return proc_load_->find(phase.phases)->at(id).whole_phase_load; + return proc_load_->at(phase.phases).at(id).whole_phase_load; } virtual ObjectIterator begin() const override { - return {std::make_unique(proc_load_->find(3)->begin(), proc_load_->find(3)->end())}; + return {std::make_unique(proc_load_->at(3).begin(), proc_load_->at(3).end())}; } // Not used by this test diff --git a/tests/unit/collection/test_model_naive_persistence.nompi.cc b/tests/unit/collection/test_model_naive_persistence.nompi.cc index 461e5f4b45..10e47045f1 100644 --- a/tests/unit/collection/test_model_naive_persistence.nompi.cc +++ b/tests/unit/collection/test_model_naive_persistence.nompi.cc @@ -85,11 +85,11 @@ struct StubModel : LoadModel { LoadType getModeledLoad(ElementIDStruct id, PhaseOffset phase) const override { EXPECT_LE(phase.phases, -1); - return proc_load_->find(getIndexFromPhase(phase.phases))->at(id).whole_phase_load; + return proc_load_->at(getIndexFromPhase(phase.phases)).at(id).whole_phase_load; } virtual ObjectIterator begin() const override { - return {std::make_unique(proc_load_->find(3)->begin(), proc_load_->find(3)->end())}; + return {std::make_unique(proc_load_->at(3).begin(), proc_load_->at(3).end())}; } // Not used in this test @@ -127,7 +127,7 @@ TEST_F(TestModelNaivePersistence, test_model_naive_persistence_1) { auto &&obj = *it; for (auto phase : {0, -1, -2, -3, -4}) { auto work_val = test_model->getModeledLoad(obj, PhaseOffset{phase, 1}); - EXPECT_EQ(work_val, proc_loads.find(getIndexFromPhase(phase))->at(obj).whole_phase_load); + EXPECT_EQ(work_val, proc_loads.at(getIndexFromPhase(phase)).at(obj).whole_phase_load); } } } diff --git a/tests/unit/collection/test_model_norm.nompi.cc b/tests/unit/collection/test_model_norm.nompi.cc index af37623bc3..5d8a223ac3 100644 --- a/tests/unit/collection/test_model_norm.nompi.cc +++ b/tests/unit/collection/test_model_norm.nompi.cc @@ -88,11 +88,11 @@ struct StubModel : LoadModel { void updateLoads(PhaseType) override {} LoadType getModeledLoad(ElementIDStruct id, PhaseOffset phase) const override { - return proc_load_->find(0)->at(id).subphase_loads.at(phase.subphase); + return proc_load_->at(0).at(id).subphase_loads.at(phase.subphase); } ObjectIterator begin() const override { - return {std::make_unique(proc_load_->find(0)->begin(), proc_load_->find(0)->end())}; + return {std::make_unique(proc_load_->at(0).begin(), proc_load_->at(0).end())}; } int getNumSubphases() const override { return num_subphases; } @@ -129,7 +129,7 @@ TEST_F(TestModelNorm, test_model_norm_1) { // offset.subphase != PhaseOffset::WHOLE_PHASE // expect work load value for given subphase auto work_val = test_model->getModeledLoad(obj, PhaseOffset{0, iter}); - EXPECT_EQ(work_val, (*proc_load.find(0))[obj].subphase_loads[iter]); + EXPECT_EQ(work_val, proc_load[0][obj].subphase_loads[iter]); } EXPECT_EQ(objects_seen, 2); 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 df8f31440a..11ab8f73a9 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 @@ -83,11 +83,11 @@ struct StubModel : LoadModel { LoadType getModeledLoad(ElementIDStruct id, PhaseOffset phase) const override { // Most recent phase will be at the end of vector - return proc_load_->find(num_phases + phase.phases)->at(id).whole_phase_load; + return proc_load_->at(num_phases + phase.phases).at(id).whole_phase_load; } virtual ObjectIterator begin() const override { - return {std::make_unique(proc_load_->find(num_phases-1)->begin(), proc_load_->find(num_phases-1)->end())}; + return {std::make_unique(proc_load_->at(num_phases-1).begin(), proc_load_->at(num_phases-1).end())}; } virtual unsigned int getNumCompletedPhases() const override { return num_phases; } @@ -105,7 +105,7 @@ TEST_F(TestModelPersistenceMedianLastN, test_model_persistence_median_last_n_1) auto test_model = std::make_shared(std::make_shared(), 4); - vt::util::container::CircularPhasesBuffer proc_loads; + vt::util::container::CircularPhasesBuffer proc_loads(num_total_phases); test_model->setLoads(&proc_loads, nullptr, nullptr); @@ -144,10 +144,8 @@ TEST_F(TestModelPersistenceMedianLastN, test_model_persistence_median_last_n_1) std::make_pair(LoadType{55}, LoadType{30}) // iter 6 results }; - proc_loads.resize(num_total_phases); - for (auto iter = 0; iter < num_total_phases; ++iter) { - proc_loads.store(iter, load_holder[iter]); + proc_loads[iter] = load_holder[iter]; test_model->updateLoads(iter); ++num_phases; diff --git a/tests/unit/collection/test_model_raw_data.nompi.cc b/tests/unit/collection/test_model_raw_data.nompi.cc index 8879811438..9abe8c670f 100644 --- a/tests/unit/collection/test_model_raw_data.nompi.cc +++ b/tests/unit/collection/test_model_raw_data.nompi.cc @@ -91,7 +91,7 @@ TEST_F(TestRawData, test_model_raw_data_scalar) { proc_loads.resize(load_holder.size()); for (size_t iter = 0; iter < load_holder.size(); ++iter) { - proc_loads.store(iter, load_holder[iter]); + proc_loads[iter] = load_holder[iter]; test_model->updateLoads(iter); EXPECT_EQ(test_model->getNumObjects(), 2); diff --git a/tests/unit/collection/test_model_select_subphases.nompi.cc b/tests/unit/collection/test_model_select_subphases.nompi.cc index 4732c06233..fb41feacbe 100644 --- a/tests/unit/collection/test_model_select_subphases.nompi.cc +++ b/tests/unit/collection/test_model_select_subphases.nompi.cc @@ -87,13 +87,13 @@ struct StubModel : LoadModel { void updateLoads(PhaseType) override {} LoadType getModeledLoad(ElementIDStruct id, PhaseOffset phase) const override { - return proc_load_->find(0)->at(id).subphase_loads.at(phase.subphase); + return proc_load_->at(0).at(id).subphase_loads.at(phase.subphase); } ObjectIterator begin() const override { return { std::make_unique( - proc_load_->find(0)->begin(), proc_load_->find(0)->end() + proc_load_->at(0).begin(), proc_load_->at(0).end() ) }; } @@ -132,13 +132,13 @@ TEST_F(TestModelSelectSubphases, test_model_select_subphases_1) { std::unordered_map> expected_values = { {id1, - {(*proc_load.find(0))[id1].subphase_loads[subphases[0]], - (*proc_load.find(0))[id1].subphase_loads[subphases[1]], - (*proc_load.find(0))[id1].subphase_loads[subphases[2]]}}, + {proc_load[0][id1].subphase_loads[subphases[0]], + proc_load[0][id1].subphase_loads[subphases[1]], + proc_load[0][id1].subphase_loads[subphases[2]]}}, {id2, - {(*proc_load.find(0))[id2].subphase_loads[subphases[0]], - (*proc_load.find(0))[id2].subphase_loads[subphases[1]], - (*proc_load.find(0))[id2].subphase_loads[subphases[2]]}}}; + {proc_load[0][id2].subphase_loads[subphases[0]], + proc_load[0][id2].subphase_loads[subphases[1]], + proc_load[0][id2].subphase_loads[subphases[2]]}}}; for (unsigned int iter = 0; iter < num_subphases; ++iter) { int objects_seen = 0; diff --git a/tests/unit/collection/test_model_weighted_communication_volume.nompi.cc b/tests/unit/collection/test_model_weighted_communication_volume.nompi.cc index 76d2d10166..a7cdc11ff3 100644 --- a/tests/unit/collection/test_model_weighted_communication_volume.nompi.cc +++ b/tests/unit/collection/test_model_weighted_communication_volume.nompi.cc @@ -90,7 +90,7 @@ struct StubModel : LoadModel { void updateLoads(PhaseType) override { } LoadType getModeledLoad(ElementIDStruct id, PhaseOffset phase) const override { - const auto work = proc_load_->find(0)->at(id).whole_phase_load; + const auto work = proc_load_->at(0).at(id).whole_phase_load; if (phase.subphase == PhaseOffset::WHOLE_PHASE) { return work; @@ -101,7 +101,7 @@ struct StubModel : LoadModel { ObjectIterator begin() const override { return {std::make_unique( - proc_load_->find(0)->begin(), proc_load_->find(0)->end() + proc_load_->at(0).begin(), proc_load_->at(0).end() )}; } diff --git a/tests/unit/collection/test_model_weighted_messages.nompi.cc b/tests/unit/collection/test_model_weighted_messages.nompi.cc index 79e5370216..d08f345d0e 100644 --- a/tests/unit/collection/test_model_weighted_messages.nompi.cc +++ b/tests/unit/collection/test_model_weighted_messages.nompi.cc @@ -87,7 +87,7 @@ struct StubModel : LoadModel { void updateLoads(PhaseType) override { } LoadType getModeledLoad(ElementIDStruct id, PhaseOffset phase) const override { - const auto work = proc_load_->find(0)->at(id).whole_phase_load; + const auto work = proc_load_->at(0).at(id).whole_phase_load; if (phase.subphase == PhaseOffset::WHOLE_PHASE) { return work; @@ -98,7 +98,7 @@ struct StubModel : LoadModel { ObjectIterator begin() const override { return {std::make_unique( - proc_load_->find(0)->begin(), proc_load_->find(0)->end() + proc_load_->at(0).begin(), proc_load_->at(0).end() )}; } From 374aed09e68bef8561245baf0255bbe51312c233 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 14 Nov 2023 20:47:58 +0100 Subject: [PATCH 10/82] #1934: Update implementation of setting correct buffer size in NodeLBData --- .../balance/lb_invoke/lb_manager.cc | 15 +++--- src/vt/vrt/collection/balance/node_lb_data.cc | 54 +++++++++---------- src/vt/vrt/collection/balance/node_lb_data.h | 17 ++---- 3 files changed, 36 insertions(+), 50 deletions(-) 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 e88b74bc1b..172fd29882 100644 --- a/src/vt/vrt/collection/balance/lb_invoke/lb_manager.cc +++ b/src/vt/vrt/collection/balance/lb_invoke/lb_manager.cc @@ -176,8 +176,7 @@ LBType LBManager::decideLBToRun(PhaseType phase, bool try_file) { void LBManager::setLoadModel(std::shared_ptr model) { auto nlb_data = theNodeLBData(); min_hist_lb_data_ = std::max(model->getNumPastPhasesNeeded(), theConfig()->vt_lb_data_retention); - nlb_data->setMinLBDataHistory(min_hist_lb_data_); - nlb_data->trimLBDataHistory(); + nlb_data->resizeLBDataHistory(min_hist_lb_data_); model_ = model; model_->setLoads(nlb_data->getNodeLoad(), @@ -258,15 +257,15 @@ LBManager::runLB(PhaseType phase, vt::Callback cb) { elm::CommMapType const* comm = &empty_comm; auto const& node_comm = theNodeLBData()->getNodeComm(); - if (auto ptr = node_comm->find(phase)) { - comm = ptr; + if (node_comm->contains(phase)) { + comm = &node_comm->at(phase); } balance::DataMapType empty_data_map; balance::DataMapType const* data_map = &empty_data_map; auto const& node_data_map = theNodeLBData()->getUserData(); - if (auto ptr = node_data_map->find(phase)) { - data_map = ptr; + if (node_data_map->contains(phase)) { + data_map = &node_data_map->at(phase); } vt_debug_print(terse, lb, "LBManager: running strategy\n"); @@ -736,8 +735,8 @@ void LBManager::computeStatistics( elm::CommMapType empty_comm; elm::CommMapType const* comm_data = &empty_comm; - if (auto ptr = theNodeLBData()->getNodeComm()->find(phase)) { - comm_data = ptr; + if (theNodeLBData()->getNodeComm()->contains(phase)) { + comm_data = &theNodeLBData()->getNodeComm()->at(phase); } std::vector lstats; diff --git a/src/vt/vrt/collection/balance/node_lb_data.cc b/src/vt/vrt/collection/balance/node_lb_data.cc index 12019df7c7..ea3e3222f7 100644 --- a/src/vt/vrt/collection/balance/node_lb_data.cc +++ b/src/vt/vrt/collection/balance/node_lb_data.cc @@ -119,8 +119,7 @@ ElmUserDataType const* NodeLBData::getNodeAttributes() const { } CommMapType* NodeLBData::getNodeComm(PhaseType phase) { - auto ptr = lb_data_->node_comm_.find(phase); - return (ptr != nullptr) ? ptr : nullptr; + return lb_data_->node_comm_.find(phase); } void NodeLBData::clearLBData() { @@ -144,18 +143,21 @@ void NodeLBData::startIterCleanup(PhaseType phase, unsigned int look_back) { node_objgroup_lookup_.clear(); } -// later this method can be deleted -void NodeLBData::trimLBDataHistory() { - lb_data_->node_data_.resize(min_hist_lb_data_); - lb_data_->node_comm_.resize(min_hist_lb_data_); - lb_data_->node_subphase_comm_.resize(min_hist_lb_data_); - lb_data_->user_defined_lb_info_.resize(min_hist_lb_data_); - lb_data_->user_defined_json_.resize(min_hist_lb_data_); +void NodeLBData::resizeLBDataHistory(uint32_t new_hist_len) { + min_hist_lb_data_ = new_hist_len; + + if (lb_data_) { + lb_data_->node_data_.resize(new_hist_len); + lb_data_->node_comm_.resize(new_hist_len); + lb_data_->node_subphase_comm_.resize(new_hist_len); + lb_data_->user_defined_lb_info_.resize(new_hist_len); + lb_data_->user_defined_json_.resize(new_hist_len); + } - NodeLBData::node_migrate_.clear(); - node_collection_lookup_.clear(); - node_objgroup_lookup_.clear(); -} + NodeLBData::node_migrate_.clear(); + node_collection_lookup_.clear(); + node_objgroup_lookup_.clear(); + } ElementIDType NodeLBData::getNextElm() { return next_elm_++; @@ -345,33 +347,29 @@ void NodeLBData::addNodeLBData( auto const phase = in->getPhase(); auto const& total_load = in->getLoad(phase, focused_subphase); - auto phase_data = lb_data_->node_data_.find(phase); - auto elm_iter = phase_data->find(id); - vtAssert(elm_iter == phase_data->end(), "Must not exist"); + auto& phase_data = lb_data_->node_data_[phase]; + 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( + phase_data.emplace( std::piecewise_construct, std::forward_as_tuple(id), std::forward_as_tuple(LoadSummary{total_load, subphase_times}) ); auto const& comm = in->getComm(phase); - auto comm_data = lb_data_->node_comm_.find(phase); - if (comm_data) { - for (auto&& c : comm) { - (*comm_data)[c.first] += c.second; - } + auto& comm_data = lb_data_->node_comm_[phase]; + for (auto&& c : comm) { + comm_data[c.first] += c.second; } auto const& subphase_comm = in->getSubphaseComm(phase); - auto subphase_comm_data = lb_data_->node_subphase_comm_.find(phase); - if (subphase_comm_data) { - for (SubphaseType i = 0; i < subphase_comm.size(); i++) { - for (auto& sp : subphase_comm[i]) { - (*subphase_comm_data)[i][sp.first] += sp.second; - } + auto& subphase_comm_data = lb_data_->node_subphase_comm_[phase]; + for (SubphaseType i = 0; i < subphase_comm.size(); i++) { + for (auto& sp : subphase_comm[i]) { + subphase_comm_data[i][sp.first] += sp.second; } } diff --git a/src/vt/vrt/collection/balance/node_lb_data.h b/src/vt/vrt/collection/balance/node_lb_data.h index 832cf837a7..d05bfd1161 100644 --- a/src/vt/vrt/collection/balance/node_lb_data.h +++ b/src/vt/vrt/collection/balance/node_lb_data.h @@ -272,22 +272,11 @@ struct NodeLBData : runtime::component::Component { LBDataHolder* getLBData() { return lb_data_.get(); } /** - * \brief Set the minimal amount of historical LB data which should be retained + * \brief Set the amount of historical LB data which should be retained * - * \param[in] hist_len the minimal amount of LB data to retain + * \param[in] new_hist_len the amount of LB data to retain */ - void setMinLBDataHistory(uint32_t hist_len) { - min_hist_lb_data_ = hist_len; - - if (lb_data_) { - lb_data_->node_data_.resize(min_hist_lb_data_); - } - } - - /** - * \brief Trim the cached LB Data to it's minimum retention size - */ - void trimLBDataHistory(); + void resizeLBDataHistory(uint32_t new_hist_len); template void serialize(SerializerT& s) { From cda9fd81cc30ccadf18650ce9013302cf95b9d56 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 14 Nov 2023 20:51:56 +0100 Subject: [PATCH 11/82] #1934: Remove trailing whitespaces --- .../utils/container/circular_phases_buffer.h | 12 ++------ src/vt/vrt/collection/balance/node_lb_data.cc | 28 +++++++++---------- .../test_circular_phases_buffer.nompi.cc | 2 +- 3 files changed, 17 insertions(+), 25 deletions(-) diff --git a/src/vt/utils/container/circular_phases_buffer.h b/src/vt/utils/container/circular_phases_buffer.h index 096505d1a6..6f598f8343 100644 --- a/src/vt/utils/container/circular_phases_buffer.h +++ b/src/vt/utils/container/circular_phases_buffer.h @@ -97,14 +97,6 @@ struct CircularPhasesBuffer { return nullptr; } - // map style operator - get reference to exsiting or newly inserted element - // const StoredType* operator[](const PhaseType phase) const { - // if (!contains(phase)) { - // store(phase, StoredType{}); - // } - // return vector_[phase % vector_.size()].second; - // } - // map style operator - get reference to exsiting or newly inserted element StoredType& operator[](const PhaseType phase) { if (!contains(phase)) { @@ -113,7 +105,7 @@ struct CircularPhasesBuffer { return vector_[phase % vector_.size()].second; } - bool contains(const PhaseType phase) const { + bool contains(const PhaseType phase) const { return vector_[phase % vector_.size()].first == phase; } @@ -162,7 +154,7 @@ struct CircularPhasesBuffer { } } } - + vector_.swap(new_vec); } diff --git a/src/vt/vrt/collection/balance/node_lb_data.cc b/src/vt/vrt/collection/balance/node_lb_data.cc index ea3e3222f7..20758e679f 100644 --- a/src/vt/vrt/collection/balance/node_lb_data.cc +++ b/src/vt/vrt/collection/balance/node_lb_data.cc @@ -143,22 +143,22 @@ void NodeLBData::startIterCleanup(PhaseType phase, unsigned int look_back) { node_objgroup_lookup_.clear(); } -void NodeLBData::resizeLBDataHistory(uint32_t new_hist_len) { - min_hist_lb_data_ = new_hist_len; - - if (lb_data_) { - lb_data_->node_data_.resize(new_hist_len); - lb_data_->node_comm_.resize(new_hist_len); - lb_data_->node_subphase_comm_.resize(new_hist_len); - lb_data_->user_defined_lb_info_.resize(new_hist_len); - lb_data_->user_defined_json_.resize(new_hist_len); - } - - NodeLBData::node_migrate_.clear(); - node_collection_lookup_.clear(); - node_objgroup_lookup_.clear(); +void NodeLBData::resizeLBDataHistory(uint32_t new_hist_len) { + min_hist_lb_data_ = new_hist_len; + + if (lb_data_) { + lb_data_->node_data_.resize(new_hist_len); + lb_data_->node_comm_.resize(new_hist_len); + lb_data_->node_subphase_comm_.resize(new_hist_len); + lb_data_->user_defined_lb_info_.resize(new_hist_len); + lb_data_->user_defined_json_.resize(new_hist_len); } + NodeLBData::node_migrate_.clear(); + node_collection_lookup_.clear(); + node_objgroup_lookup_.clear(); +} + ElementIDType NodeLBData::getNextElm() { return next_elm_++; } diff --git a/tests/unit/utils/test_circular_phases_buffer.nompi.cc b/tests/unit/utils/test_circular_phases_buffer.nompi.cc index bfbc9223ca..6c7ffb7c30 100644 --- a/tests/unit/utils/test_circular_phases_buffer.nompi.cc +++ b/tests/unit/utils/test_circular_phases_buffer.nompi.cc @@ -72,7 +72,7 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_empty) { EXPECT_FALSE(buffer.contains(3)); EXPECT_FALSE(buffer.contains(10)); - + buffer.resize(2); EXPECT_FALSE(buffer.contains(3)); From c6ec8305c8f8459d7fcdc276f8c12ae60294e792 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 14 Nov 2023 21:16:45 +0100 Subject: [PATCH 12/82] #1934: Add missing resize in linear model test --- tests/unit/collection/test_model_linear_model.nompi.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unit/collection/test_model_linear_model.nompi.cc b/tests/unit/collection/test_model_linear_model.nompi.cc index ca5743ecfd..d9d073d18d 100644 --- a/tests/unit/collection/test_model_linear_model.nompi.cc +++ b/tests/unit/collection/test_model_linear_model.nompi.cc @@ -100,6 +100,7 @@ struct StubModel : LoadModel { TEST_F(TestLinearModel, test_model_linear_model_1) { constexpr int32_t num_test_interations = 6; + constexpr std::size_t buffer_size = 7; NodeType this_node = 0; auto test_model = From bbb3303cee37286a03ec41d9654c4e71d4406b0f Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 14 Nov 2023 22:03:06 +0100 Subject: [PATCH 13/82] #1934: Allow contains to be called when size is zero --- src/vt/utils/container/circular_phases_buffer.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/vt/utils/container/circular_phases_buffer.h b/src/vt/utils/container/circular_phases_buffer.h index 6f598f8343..b79d8ed822 100644 --- a/src/vt/utils/container/circular_phases_buffer.h +++ b/src/vt/utils/container/circular_phases_buffer.h @@ -106,6 +106,9 @@ struct CircularPhasesBuffer { } bool contains(const PhaseType phase) const { + if (vector_.empty()) { + return false; + } return vector_[phase % vector_.size()].first == phase; } From e2bcfd7d15a1d0f7240310927405fea79987bcbb Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Wed, 22 Nov 2023 18:53:22 +0100 Subject: [PATCH 14/82] #1934: Add iterator support for buffer type --- .../utils/container/circular_phases_buffer.h | 73 ++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/src/vt/utils/container/circular_phases_buffer.h b/src/vt/utils/container/circular_phases_buffer.h index b79d8ed822..a51ec532ce 100644 --- a/src/vt/utils/container/circular_phases_buffer.h +++ b/src/vt/utils/container/circular_phases_buffer.h @@ -56,7 +56,7 @@ struct CircularPhasesBuffer { using StoredPair = std::pair; CircularPhasesBuffer(std::size_t capacity = 0) - : head_phase_(-1), vector_(capacity, StoredPair{invalid_, StoredType{}}) + : head_phase_(invalid_), vector_(capacity, StoredPair{invalid_, StoredType{}}) { } CircularPhasesBuffer(std::initializer_list list) { @@ -176,6 +176,77 @@ struct CircularPhasesBuffer { private: PhaseType head_phase_; std::vector vector_; + +public: + template + class PhaseIterator { + using ContainerType = std::vector; + + ContainerType * buffer_; + std::size_t pos_, head_; + public: + PhaseIterator(ContainerType *buff, std::size_t start_pos, std::size_t head_pos) + :buffer_(buff), pos_(start_pos), head_(head_pos) { + } + + PhaseIterator& operator++() { + // If already on the head then jump to end + if (pos_ == head_) { + pos_ = invalid_; + return *this; + } + + // find next valid phase - sparse phases or not full buffer + do { + ++pos_; + if (pos_ == buffer_->size()) { + pos_ = 0; + } + } while ((*buffer_)[pos_].first == invalid_); + + return *this; + } + + StoredPair &operator*() { + return (*buffer_)[pos_]; + } + + StoredPair *operator->() { + return &(operator*()); + } + + bool operator==(const PhaseIterator &other) const { + return pos_ == other.pos_; + } + + bool operator!=(const PhaseIterator &other) const { + return pos_ != other.pos_; + } + }; + + auto begin() { + return PhaseIterator(&vector_, firstPhase(), head_phase_ % vector_.size()); + } + + auto end() { + return PhaseIterator(&vector_, invalid_, head_phase_ % vector_.size()); + } + + // maybe better to track tail + PhaseType firstPhase() { + auto lowest_phase = head_phase_; + for(auto&& pair : vector_) { + if (pair.first < lowest_phase) { + lowest_phase = pair.first; + } + } + return lowest_phase; + } + + PhaseType lastPhase() { + return head_phase_; + } + }; }}} /* end namespace vt::util::container */ From 3182b056958a939b49da13f6c1a422b52411b868 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Thu, 23 Nov 2023 15:09:12 +0100 Subject: [PATCH 15/82] #1934: Fix failing tests related to buffers being not initialized --- src/vt/vrt/collection/balance/lb_data_holder.h | 7 +++++++ tests/unit/collection/test_lb.extended.cc | 8 ++------ tests/unit/collection/test_lb_data_holder.cc | 3 +-- tests/unit/collection/test_workload_data_migrator.cc | 6 +++--- tests/unit/lb/test_offlinelb.cc | 2 +- 5 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/vt/vrt/collection/balance/lb_data_holder.h b/src/vt/vrt/collection/balance/lb_data_holder.h index 3662cee787..ec99f5b1d2 100644 --- a/src/vt/vrt/collection/balance/lb_data_holder.h +++ b/src/vt/vrt/collection/balance/lb_data_holder.h @@ -67,6 +67,13 @@ namespace vt { namespace vrt { namespace collection { namespace balance { struct LBDataHolder { LBDataHolder() = default; + /** + * \brief Create \c LBDataHolder with specified buffers capacity + * + * \param[in] initial_buffers_size the initial size of the buffers + */ + LBDataHolder(std::size_t initial_buffers_size); + /** * \brief Create \c LBDataHolder from input JSON * diff --git a/tests/unit/collection/test_lb.extended.cc b/tests/unit/collection/test_lb.extended.cc index db6e142abd..8d31e8f7cf 100644 --- a/tests/unit/collection/test_lb.extended.cc +++ b/tests/unit/collection/test_lb.extended.cc @@ -552,7 +552,7 @@ TEST_F(TestRestoreLBData, test_restore_lb_data_data_1) { ); }); - vt::vrt::collection::balance::LBDataHolder lbdh; + vt::vrt::collection::balance::LBDataHolder lbdh(num_elms); PhaseType write_phase = 0; using CommKey = vt::elm::CommKey; @@ -563,10 +563,6 @@ TEST_F(TestRestoreLBData, test_restore_lb_data_data_1) { { PhaseType phase = write_phase; - lbdh.node_data_.resize(num_elms); - lbdh.node_comm_.resize(num_elms); - lbdh.node_subphase_comm_.resize(num_elms); - for (int i=0; i(); + auto lbdh = std::make_shared(numElements); for (auto&& elmID : myElemList) { double tval = elmID.id * 2; @@ -790,7 +790,7 @@ setupManyWorkloads( ); } - auto lbdh = std::make_shared(); + auto lbdh = std::make_shared(num_phases); PhaseType stop_phase = initial_phase + num_phases; for (PhaseType phase = initial_phase; phase < stop_phase; ++phase) { @@ -804,7 +804,7 @@ setupManyWorkloads( } } - auto scrambled_lbdh = std::make_shared(); + auto scrambled_lbdh = std::make_shared(num_phases); for (PhaseType phase = initial_phase; phase < stop_phase; ++phase) { auto base_load_model = setupBaseModel(phase, lbdh); diff --git a/tests/unit/lb/test_offlinelb.cc b/tests/unit/lb/test_offlinelb.cc index 599383aa03..bf40482479 100644 --- a/tests/unit/lb/test_offlinelb.cc +++ b/tests/unit/lb/test_offlinelb.cc @@ -125,7 +125,7 @@ TEST_F(TestOfflineLB, test_offlinelb_1) { ids[5].push_back(nid); } - LBDataHolder dh; + LBDataHolder dh(num_phases); for (PhaseType i = 0; i < num_phases; i++) { for (auto&& elm : ids[i]) { (*dh.node_data_[i])[elm] = LoadSummary{3}; From a9d4b45679d66b0ede14d740be6033a72c8e3a6b Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Fri, 24 Nov 2023 12:03:19 +0100 Subject: [PATCH 16/82] #1934: Add cosmetic changes and reverse some unneded changes --- src/vt/utils/container/circular_phases_buffer.h | 4 ++-- src/vt/vrt/collection/balance/lb_data_holder.cc | 3 ++- src/vt/vrt/collection/balance/lb_invoke/lb_manager.cc | 2 +- src/vt/vrt/collection/balance/node_lb_data.cc | 6 +++--- src/vt/vrt/collection/balance/node_lb_data.h | 2 +- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/vt/utils/container/circular_phases_buffer.h b/src/vt/utils/container/circular_phases_buffer.h index a51ec532ce..8643da4ae2 100644 --- a/src/vt/utils/container/circular_phases_buffer.h +++ b/src/vt/utils/container/circular_phases_buffer.h @@ -195,7 +195,7 @@ struct CircularPhasesBuffer { pos_ = invalid_; return *this; } - + // find next valid phase - sparse phases or not full buffer do { ++pos_; @@ -210,7 +210,7 @@ struct CircularPhasesBuffer { StoredPair &operator*() { return (*buffer_)[pos_]; } - + StoredPair *operator->() { return &(operator*()); } diff --git a/src/vt/vrt/collection/balance/lb_data_holder.cc b/src/vt/vrt/collection/balance/lb_data_holder.cc index 589344db5e..1e4db5cf08 100644 --- a/src/vt/vrt/collection/balance/lb_data_holder.cc +++ b/src/vt/vrt/collection/balance/lb_data_holder.cc @@ -212,7 +212,7 @@ std::unique_ptr LBDataHolder::toJson(PhaseType phase) const { j["tasks"][i]["resource"] = "cpu"; j["tasks"][i]["node"] = id.getCurrNode(); j["tasks"][i]["time"] = time; - if (user_defined_json_.find(phase)) { + if (user_defined_json_.contains(phase)) { auto &user_def_this_phase = user_defined_json_.at(phase); if (user_def_this_phase.find(id) != user_def_this_phase.end()) { auto &user_def = user_def_this_phase.at(id); @@ -245,6 +245,7 @@ std::unique_ptr LBDataHolder::toJson(PhaseType phase) const { j["tasks"][i]["subphases"][s]["time"] = subphase_times[s]; } } + i++; } 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 172fd29882..44a8880d41 100644 --- a/src/vt/vrt/collection/balance/lb_invoke/lb_manager.cc +++ b/src/vt/vrt/collection/balance/lb_invoke/lb_manager.cc @@ -542,7 +542,7 @@ void LBManager::finishedLB(PhaseType phase) { "finishedLB\n" ); - theNodeLBData()->startIterCleanup(phase); + theNodeLBData()->startIterCleanup(); theNodeLBData()->outputLBDataForPhase(phase); destroyLB(); diff --git a/src/vt/vrt/collection/balance/node_lb_data.cc b/src/vt/vrt/collection/balance/node_lb_data.cc index 20758e679f..03263c127e 100644 --- a/src/vt/vrt/collection/balance/node_lb_data.cc +++ b/src/vt/vrt/collection/balance/node_lb_data.cc @@ -347,7 +347,7 @@ void NodeLBData::addNodeLBData( auto const phase = in->getPhase(); auto const& total_load = in->getLoad(phase, focused_subphase); - auto& phase_data = lb_data_->node_data_[phase]; + auto &phase_data = lb_data_->node_data_[phase]; auto elm_iter = phase_data.find(id); vtAssert(elm_iter == phase_data.end(), "Must not exist"); @@ -360,13 +360,13 @@ void NodeLBData::addNodeLBData( ); auto const& comm = in->getComm(phase); - auto& comm_data = lb_data_->node_comm_[phase]; + auto &comm_data = lb_data_->node_comm_[phase]; for (auto&& c : comm) { comm_data[c.first] += c.second; } auto const& subphase_comm = in->getSubphaseComm(phase); - auto& subphase_comm_data = lb_data_->node_subphase_comm_[phase]; + auto &subphase_comm_data = lb_data_->node_subphase_comm_[phase]; for (SubphaseType i = 0; i < subphase_comm.size(); i++) { for (auto& sp : subphase_comm[i]) { subphase_comm_data[i][sp.first] += sp.second; diff --git a/src/vt/vrt/collection/balance/node_lb_data.h b/src/vt/vrt/collection/balance/node_lb_data.h index d05bfd1161..f312e92a7b 100644 --- a/src/vt/vrt/collection/balance/node_lb_data.h +++ b/src/vt/vrt/collection/balance/node_lb_data.h @@ -147,7 +147,7 @@ struct NodeLBData : runtime::component::Component { /** * \internal \brief Cleanup after LB runs */ - void startIterCleanup(PhaseType phase); + void startIterCleanup(); /** * \internal \brief Load and broadcast the LB specification file From 8070c2b84a778265a216024f593723dda4a1592f Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 28 Nov 2023 11:06:43 +0100 Subject: [PATCH 17/82] #1934: Use CircularPhasesBuffer in ElementLBData --- src/vt/elm/elm_lb_data.cc | 15 ++++++--------- src/vt/elm/elm_lb_data.h | 15 +++++++++------ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/vt/elm/elm_lb_data.cc b/src/vt/elm/elm_lb_data.cc index 4489e6bea7..5084afdafb 100644 --- a/src/vt/elm/elm_lb_data.cc +++ b/src/vt/elm/elm_lb_data.cc @@ -203,8 +203,7 @@ PhaseType ElementLBData::getPhase() const { } LoadType ElementLBData::getLoad(PhaseType const& phase) const { - auto iter = phase_timings_.find(phase); - if (iter != phase_timings_.end()) { + if (phase_timings_.contains(phase)) { auto const total_load = phase_timings_.at(phase); vt_debug_print( @@ -276,13 +275,11 @@ SubphaseType ElementLBData::getSubPhase() const { return cur_subphase_; } -void ElementLBData::releaseLBDataFromUnneededPhases(PhaseType phase, unsigned int look_back) { - if (phase >= look_back) { - phase_timings_.erase(phase - look_back); - subphase_timings_.erase(phase - look_back); - phase_comm_.erase(phase - look_back); - subphase_comm_.erase(phase - look_back); - } +void ElementLBData::setHistoryCapacity(unsigned int hist_lb_data_count) { + phase_timings_.resize(hist_lb_data_count); + subphase_timings_.resize(hist_lb_data_count); + phase_comm_.resize(hist_lb_data_count); + subphase_comm_.resize(hist_lb_data_count); } std::size_t ElementLBData::getLoadPhaseCount() const { diff --git a/src/vt/elm/elm_lb_data.h b/src/vt/elm/elm_lb_data.h index 576753250a..c6d04f996a 100644 --- a/src/vt/elm/elm_lb_data.h +++ b/src/vt/elm/elm_lb_data.h @@ -47,6 +47,7 @@ #include "vt/elm/elm_id.h" #include "vt/elm/elm_comm.h" #include "vt/timing/timing.h" +#include "vt/utils/container/circular_phases_buffer.h" namespace vt { namespace vrt { namespace collection { namespace balance { @@ -124,9 +125,11 @@ struct ElementLBData { protected: /** - * \internal \brief Release LB data from phases prior to lookback + * \internal \brief Resize internal buffers + * + * \param[in] hist_lb_data_count the requested buffers capacity */ - void releaseLBDataFromUnneededPhases(PhaseType phase, unsigned int look_back); + void setHistoryCapacity(unsigned int hist_lb_data_count); friend struct vrt::collection::balance::NodeLBData; @@ -134,12 +137,12 @@ struct ElementLBData { bool cur_time_started_ = false; TimeType cur_time_ = TimeType{0.0}; PhaseType cur_phase_ = fst_lb_phase; - std::unordered_map phase_timings_ = {}; - std::unordered_map phase_comm_ = {}; + vt::util::container::CircularPhasesBuffer phase_timings_ = {1}; // workaround for lack of initial size + vt::util::container::CircularPhasesBuffer phase_comm_ = {1}; // workaround for lack of initial size SubphaseType cur_subphase_ = 0; - std::unordered_map> subphase_timings_ = {}; - std::unordered_map> subphase_comm_ = {}; + vt::util::container::CircularPhasesBuffer> subphase_timings_ = {1}; // workaround for lack of initial size + vt::util::container::CircularPhasesBuffer> subphase_comm_ = {1}; // workaround for lack of initial size }; }} /* end namespace vt::elm */ From 0a7f8eba6b30c68020161c50bfdaa4235d143579 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 28 Nov 2023 11:12:44 +0100 Subject: [PATCH 18/82] #1934: Pass the requested retention to ElementLBData --- src/vt/vrt/collection/balance/node_lb_data.cc | 6 ++++-- src/vt/vrt/collection/balance/node_lb_data.h | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/vt/vrt/collection/balance/node_lb_data.cc b/src/vt/vrt/collection/balance/node_lb_data.cc index 03263c127e..114cba0441 100644 --- a/src/vt/vrt/collection/balance/node_lb_data.cc +++ b/src/vt/vrt/collection/balance/node_lb_data.cc @@ -144,7 +144,7 @@ void NodeLBData::startIterCleanup(PhaseType phase, unsigned int look_back) { } void NodeLBData::resizeLBDataHistory(uint32_t new_hist_len) { - min_hist_lb_data_ = new_hist_len; + hist_lb_data_size_ = new_hist_len; if (lb_data_) { lb_data_->node_data_.resize(new_hist_len); @@ -344,6 +344,9 @@ void NodeLBData::addNodeLBData( "NodeLBData::addNodeLBData: id={}\n", id ); + // Ensure that buffers can hold request amount of data + in->setHistoryCapacity(hist_lb_data_size_); + auto const phase = in->getPhase(); auto const& total_load = in->getLoad(phase, focused_subphase); @@ -390,7 +393,6 @@ void NodeLBData::addNodeLBData( } in->updatePhase(1); - in->releaseLBDataFromUnneededPhases(phase, min_hist_lb_data_); } VirtualProxyType NodeLBData::getCollectionProxyForElement( diff --git a/src/vt/vrt/collection/balance/node_lb_data.h b/src/vt/vrt/collection/balance/node_lb_data.h index f312e92a7b..3a0fe3d6a4 100644 --- a/src/vt/vrt/collection/balance/node_lb_data.h +++ b/src/vt/vrt/collection/balance/node_lb_data.h @@ -289,7 +289,7 @@ struct NodeLBData : runtime::component::Component { | created_dir_ | lb_data_writer_ | lb_data_ - | min_hist_lb_data_; + | hist_lb_data_size_; } private: @@ -322,8 +322,8 @@ struct NodeLBData : runtime::component::Component { std::unique_ptr lb_data_writer_ = nullptr; /// The struct that holds all the LB data std::unique_ptr lb_data_ = nullptr; - //// The minimal amount of historical LB data to hold - uint32_t min_hist_lb_data_ = 0; + //// The amount of historical LB data to hold + uint32_t hist_lb_data_size_ = 0; }; }}}} /* end namespace vt::vrt::collection::balance */ From 4a8ffe279f0187e39057c0eb2f91413bf58a7b30 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 28 Nov 2023 11:43:01 +0100 Subject: [PATCH 19/82] #1934: Update retention tests to expect correct amount of phases in ElementLBData --- .../unit/collection/test_lb_data_retention.cc | 43 ++++--------------- 1 file changed, 9 insertions(+), 34 deletions(-) diff --git a/tests/unit/collection/test_lb_data_retention.cc b/tests/unit/collection/test_lb_data_retention.cc index 73cfd17ef4..bab7611e8a 100644 --- a/tests/unit/collection/test_lb_data_retention.cc +++ b/tests/unit/collection/test_lb_data_retention.cc @@ -105,14 +105,12 @@ struct TestCol : vt::Collection { #if vt_check_enabled(lblite) auto phase = col->prevCalls(); auto model = theLBManager()->getLoadModel(); - auto phases_needed = std::max(model->getNumPastPhasesNeeded(), theConfig()->vt_lb_data_retention); - if (phase > phases_needed) { - // updatePhase will have caused entries to be added for the - // next phase already - EXPECT_EQ(load_phase_count, phases_needed + 1); - EXPECT_EQ(sp_load_phase_count, phases_needed + 1); - EXPECT_EQ(comm_phase_count, phases_needed + 1); - EXPECT_EQ(sp_comm_phase_count, phases_needed + 1); + auto buffers_size = std::max(model->getNumPastPhasesNeeded(), theConfig()->vt_lb_data_retention); + if (phase >= buffers_size) { + EXPECT_EQ(load_phase_count, buffers_size); + EXPECT_EQ(sp_load_phase_count, buffers_size); + EXPECT_EQ(comm_phase_count, buffers_size); + EXPECT_EQ(sp_comm_phase_count, buffers_size); } else if (phase == 0) { EXPECT_EQ(load_phase_count, phase); EXPECT_EQ(sp_load_phase_count, phase); @@ -133,29 +131,6 @@ struct TestCol : vt::Collection { EXPECT_EQ(sp_comm_phase_count, 0); #endif } - - static void expect7PhasesOfData(TestCol* col) { - auto& lb_data = col->lb_data_; - auto load_phase_count = lb_data.getLoadPhaseCount(); - auto comm_phase_count = lb_data.getCommPhaseCount(); - auto sp_load_phase_count = lb_data.getSubphaseLoadPhaseCount(); - auto sp_comm_phase_count = lb_data.getSubphaseCommPhaseCount(); - - #if vt_check_enabled(lblite) - auto phases_needed = 7; - EXPECT_EQ(load_phase_count, phases_needed); - EXPECT_EQ(sp_load_phase_count, phases_needed); - EXPECT_EQ(comm_phase_count, phases_needed); - EXPECT_EQ(sp_comm_phase_count, phases_needed); - #else - EXPECT_EQ(load_phase_count, 0); - EXPECT_EQ(sp_load_phase_count, 0); - EXPECT_EQ(comm_phase_count, 0); - EXPECT_EQ(sp_comm_phase_count, 0); - #endif - } - - static void emptyColHandler(TestCol*) { } }; static constexpr int32_t const num_elms = 16; @@ -375,7 +350,7 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_model_switch_1) { for (uint32_t i=0; i(); + proxy.broadcastCollective(); }); // Go to the next phase. vt::thePhase()->nextPhaseCollective(); @@ -430,11 +405,11 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_model_switch_2) { // Check amount of phase data in the node validatePersistedPhases({5}); - // Check that amount of the retained data in TestCol is not changed and still contains 7 phases of data + // Do another 10 phases of work for (uint32_t i=0; i<10; ++i) { runInEpochCollective([&]{ // Do some work. - proxy.broadcastCollective(); + proxy.broadcastCollective(); }); // Go to the next phase. vt::thePhase()->nextPhaseCollective(); From 03669cdd6d98a3d4e08b4e38050ebf43324da389 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 28 Nov 2023 18:21:59 +0100 Subject: [PATCH 20/82] #1934: Adjust buffers size in objs of the collection --- src/vt/elm/elm_lb_data.h | 5 +---- src/vt/vrt/collection/balance/lb_invoke/lb_manager.cc | 10 +++++++++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/vt/elm/elm_lb_data.h b/src/vt/elm/elm_lb_data.h index c6d04f996a..a3c172ac83 100644 --- a/src/vt/elm/elm_lb_data.h +++ b/src/vt/elm/elm_lb_data.h @@ -123,16 +123,13 @@ struct ElementLBData { static const constexpr SubphaseType no_subphase = std::numeric_limits::max(); -protected: /** - * \internal \brief Resize internal buffers + * \brief Resize internal buffers * * \param[in] hist_lb_data_count the requested buffers capacity */ void setHistoryCapacity(unsigned int hist_lb_data_count); - friend struct vrt::collection::balance::NodeLBData; - protected: bool cur_time_started_ = false; TimeType cur_time_ = TimeType{0.0}; 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 44a8880d41..4b822ccbb6 100644 --- a/src/vt/vrt/collection/balance/lb_invoke/lb_manager.cc +++ b/src/vt/vrt/collection/balance/lb_invoke/lb_manager.cc @@ -180,8 +180,16 @@ void LBManager::setLoadModel(std::shared_ptr model) { model_ = model; model_->setLoads(nlb_data->getNodeLoad(), - nlb_data->getNodeComm(), nlb_data->getUserData()); + nlb_data->getNodeComm()); + + // Adjust buffers size on the objs in collection + runInEpochCollective("LBManager: setLoadModel", [=] { + auto& objs = vt::objgroup::getObjs(); + for (auto& obj : objs) { + obj.second->getLBData().setHistoryCapacity(min_hist_lb_data_); + } + }); } void LBManager::defaultPostLBWork(ReassignmentMsg* msg) { From 133c88b655b0d3074c48f84bc8e45e06045f7166 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Mon, 11 Dec 2023 13:21:05 +0100 Subject: [PATCH 21/82] #1934: Reaply interface changes after rebase --- src/vt/elm/elm_lb_data.h | 2 +- src/vt/vrt/collection/balance/lb_data_holder.cc | 4 ++-- .../vrt/collection/balance/lb_invoke/lb_manager.cc | 2 +- src/vt/vrt/collection/balance/model/comm_overhead.cc | 6 +++--- src/vt/vrt/collection/balance/model/comm_overhead.h | 6 +++--- .../vrt/collection/balance/model/composed_model.cc | 6 +++--- src/vt/vrt/collection/balance/model/composed_model.h | 6 +++--- src/vt/vrt/collection/balance/model/load_model.h | 6 +++--- .../vrt/collection/balance/model/per_collection.cc | 6 +++--- src/vt/vrt/collection/balance/model/per_collection.h | 6 +++--- src/vt/vrt/collection/balance/model/raw_data.cc | 8 ++++---- src/vt/vrt/collection/balance/model/raw_data.h | 12 ++++++------ .../vrt/collection/balance/model/weighted_messages.h | 6 +++--- src/vt/vrt/collection/balance/node_lb_data.cc | 4 ++-- tests/unit/collection/test_lb.extended.cc | 8 ++++---- tests/unit/collection/test_lb_data_holder.cc | 2 +- .../collection/test_model_comm_overhead.nompi.cc | 8 ++++---- .../unit/collection/test_model_linear_model.nompi.cc | 7 +++---- .../collection/test_model_multiple_phases.nompi.cc | 6 +++--- .../collection/test_model_naive_persistence.nompi.cc | 6 +++--- tests/unit/collection/test_model_norm.nompi.cc | 8 ++++---- .../test_model_persistence_median_last_n.nompi.cc | 6 +++--- tests/unit/collection/test_model_raw_data.nompi.cc | 6 +++--- .../collection/test_model_select_subphases.nompi.cc | 8 ++++---- ...test_model_weighted_communication_volume.nompi.cc | 6 +++--- .../collection/test_model_weighted_messages.nompi.cc | 6 +++--- tests/unit/lb/test_offlinelb.cc | 2 +- 27 files changed, 79 insertions(+), 80 deletions(-) diff --git a/src/vt/elm/elm_lb_data.h b/src/vt/elm/elm_lb_data.h index a3c172ac83..3b7d55862d 100644 --- a/src/vt/elm/elm_lb_data.h +++ b/src/vt/elm/elm_lb_data.h @@ -125,7 +125,7 @@ struct ElementLBData { /** * \brief Resize internal buffers - * + * * \param[in] hist_lb_data_count the requested buffers capacity */ void setHistoryCapacity(unsigned int hist_lb_data_count); diff --git a/src/vt/vrt/collection/balance/lb_data_holder.cc b/src/vt/vrt/collection/balance/lb_data_holder.cc index 1e4db5cf08..dfbf374754 100644 --- a/src/vt/vrt/collection/balance/lb_data_holder.cc +++ b/src/vt/vrt/collection/balance/lb_data_holder.cc @@ -549,7 +549,7 @@ LBDataHolder::LBDataHolder(nlohmann::json const& j) from_elm, to_elm, type == "Broadcast" ); CommVolume vol{bytes, messages}; - (*this->node_comm_[id])[key] = vol; + this->node_comm_[id][key] = vol; } else if ( type == "NodeToCollection" || type == "NodeToCollectionBcast" ) { @@ -567,7 +567,7 @@ LBDataHolder::LBDataHolder(nlohmann::json const& j) type == "NodeToCollectionBcast" ); CommVolume vol{bytes, messages}; - (*this->node_comm_[id])[key] = vol; + this->node_comm_[id][key] = vol; } else if ( type == "CollectionToNode" || type == "CollectionToNodeBcast" ) { 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 4b822ccbb6..b239f3787a 100644 --- a/src/vt/vrt/collection/balance/lb_invoke/lb_manager.cc +++ b/src/vt/vrt/collection/balance/lb_invoke/lb_manager.cc @@ -180,8 +180,8 @@ void LBManager::setLoadModel(std::shared_ptr model) { model_ = model; model_->setLoads(nlb_data->getNodeLoad(), + nlb_data->getNodeComm(), nlb_data->getUserData()); - nlb_data->getNodeComm()); // Adjust buffers size on the objs in collection runInEpochCollective("LBManager: setLoadModel", [=] { diff --git a/src/vt/vrt/collection/balance/model/comm_overhead.cc b/src/vt/vrt/collection/balance/model/comm_overhead.cc index 8b9558f2a8..975ff98859 100644 --- a/src/vt/vrt/collection/balance/model/comm_overhead.cc +++ b/src/vt/vrt/collection/balance/model/comm_overhead.cc @@ -54,9 +54,9 @@ CommOverhead::CommOverhead( per_byte_weight_(in_per_byte_weight) { } -void CommOverhead::setLoads(std::unordered_map const* proc_load, - std::unordered_map const* proc_comm, - std::unordered_map const* user_data) { +void CommOverhead::setLoads(vt::util::container::CircularPhasesBuffer const* proc_load, + vt::util::container::CircularPhasesBuffer const* proc_comm, + vt::util::container::CircularPhasesBuffer const* user_data) { proc_comm_ = proc_comm; ComposedModel::setLoads(proc_load, proc_comm, user_data); } diff --git a/src/vt/vrt/collection/balance/model/comm_overhead.h b/src/vt/vrt/collection/balance/model/comm_overhead.h index 6518cdd1b4..d4d2420a91 100644 --- a/src/vt/vrt/collection/balance/model/comm_overhead.h +++ b/src/vt/vrt/collection/balance/model/comm_overhead.h @@ -65,9 +65,9 @@ struct CommOverhead : public ComposedModel { LoadType in_per_byte_weight ); - void setLoads(std::unordered_map const* proc_load, - std::unordered_map const* proc_comm, - std::unordered_map const* user_data) override; + void setLoads(vt::util::container::CircularPhasesBuffer const* proc_load, + vt::util::container::CircularPhasesBuffer const* proc_comm, + vt::util::container::CircularPhasesBuffer const* user_data) override; LoadType getModeledLoad(ElementIDStruct object, PhaseOffset when) const override; diff --git a/src/vt/vrt/collection/balance/model/composed_model.cc b/src/vt/vrt/collection/balance/model/composed_model.cc index c827a43af3..fd10c8e1a3 100644 --- a/src/vt/vrt/collection/balance/model/composed_model.cc +++ b/src/vt/vrt/collection/balance/model/composed_model.cc @@ -45,9 +45,9 @@ namespace vt { namespace vrt { namespace collection { namespace balance { -void ComposedModel::setLoads(std::unordered_map const* proc_load, - std::unordered_map const* proc_comm, - std::unordered_map const* user_data) { +void ComposedModel::setLoads(vt::util::container::CircularPhasesBuffer const* proc_load, + vt::util::container::CircularPhasesBuffer const* proc_comm, + vt::util::container::CircularPhasesBuffer const* user_data) { base_->setLoads(proc_load, proc_comm, user_data); } diff --git a/src/vt/vrt/collection/balance/model/composed_model.h b/src/vt/vrt/collection/balance/model/composed_model.h index a052983703..7e785b7c81 100644 --- a/src/vt/vrt/collection/balance/model/composed_model.h +++ b/src/vt/vrt/collection/balance/model/composed_model.h @@ -64,9 +64,9 @@ class ComposedModel : public LoadModel // \param[in] base must not be null explicit ComposedModel(std::shared_ptr base) : base_(base) {} - void setLoads(std::unordered_map const* proc_load, - std::unordered_map const* proc_comm, - std::unordered_map const* user_data) override; + void setLoads(vt::util::container::CircularPhasesBuffer const* proc_load, + vt::util::container::CircularPhasesBuffer const* proc_comm, + vt::util::container::CircularPhasesBuffer const* user_data) override; void updateLoads(PhaseType last_completed_phase) override; diff --git a/src/vt/vrt/collection/balance/model/load_model.h b/src/vt/vrt/collection/balance/model/load_model.h index 16b79c351d..bff7269ca5 100644 --- a/src/vt/vrt/collection/balance/model/load_model.h +++ b/src/vt/vrt/collection/balance/model/load_model.h @@ -196,9 +196,9 @@ struct LoadModel * passed a new model instance for a collection */ virtual void setLoads( - std::unordered_map const* proc_load, - std::unordered_map const* proc_comm, - std::unordered_map const* user_data + vt::util::container::CircularPhasesBuffer const* proc_load, + vt::util::container::CircularPhasesBuffer const* proc_comm, + vt::util::container::CircularPhasesBuffer const* user_data ) = 0; /** diff --git a/src/vt/vrt/collection/balance/model/per_collection.cc b/src/vt/vrt/collection/balance/model/per_collection.cc index e0ce53b6cd..f9e0b165cd 100644 --- a/src/vt/vrt/collection/balance/model/per_collection.cc +++ b/src/vt/vrt/collection/balance/model/per_collection.cc @@ -55,9 +55,9 @@ void PerCollection::addModel(CollectionID proxy, std::shared_ptr mode models_[proxy] = model; } -void PerCollection::setLoads(std::unordered_map const* proc_load, - std::unordered_map const* proc_comm, - std::unordered_map const* user_data) { +void PerCollection::setLoads(vt::util::container::CircularPhasesBuffer const* proc_load, + vt::util::container::CircularPhasesBuffer const* proc_comm, + vt::util::container::CircularPhasesBuffer const* user_data) { for (auto& m : models_) m.second->setLoads(proc_load, proc_comm, user_data); ComposedModel::setLoads(proc_load, proc_comm, user_data); diff --git a/src/vt/vrt/collection/balance/model/per_collection.h b/src/vt/vrt/collection/balance/model/per_collection.h index f32e69814e..1de2df8144 100644 --- a/src/vt/vrt/collection/balance/model/per_collection.h +++ b/src/vt/vrt/collection/balance/model/per_collection.h @@ -73,9 +73,9 @@ struct PerCollection : public ComposedModel */ void addModel(CollectionID proxy, std::shared_ptr model); - void setLoads(std::unordered_map const* proc_load, - std::unordered_map const* proc_comm, - std::unordered_map const* user_data) override; + void setLoads(vt::util::container::CircularPhasesBuffer const* proc_load, + vt::util::container::CircularPhasesBuffer const* proc_comm, + vt::util::container::CircularPhasesBuffer const* user_data) override; void updateLoads(PhaseType last_completed_phase) override; diff --git a/src/vt/vrt/collection/balance/model/raw_data.cc b/src/vt/vrt/collection/balance/model/raw_data.cc index 179a40ff8f..ea0fa44846 100644 --- a/src/vt/vrt/collection/balance/model/raw_data.cc +++ b/src/vt/vrt/collection/balance/model/raw_data.cc @@ -50,9 +50,9 @@ void RawData::updateLoads(PhaseType last_completed_phase) { last_completed_phase_ = last_completed_phase; } -void RawData::setLoads(std::unordered_map const* proc_load, - std::unordered_map const* proc_comm, - std::unordered_map const* user_data) +void RawData::setLoads(vt::util::container::CircularPhasesBuffer const* proc_load, + vt::util::container::CircularPhasesBuffer const* proc_comm, + vt::util::container::CircularPhasesBuffer const* user_data) { proc_load_ = proc_load; proc_comm_ = proc_comm; @@ -118,7 +118,7 @@ ElmUserDataType RawData::getUserData(ElementIDStruct object, PhaseOffset offset) "RawData makes no predictions. Compose with NaivePersistence or some longer-range forecasting model as needed"); auto phase = getNumCompletedPhases() + offset.phases; - if (user_data_->find(phase) != user_data_->end()) { + if (user_data_->contains(phase)) { auto& phase_data = user_data_->at(phase); if (phase_data.find(object) != phase_data.end()) { return phase_data.at(object); diff --git a/src/vt/vrt/collection/balance/model/raw_data.h b/src/vt/vrt/collection/balance/model/raw_data.h index 2eeb65d6a3..a911c2b85f 100644 --- a/src/vt/vrt/collection/balance/model/raw_data.h +++ b/src/vt/vrt/collection/balance/model/raw_data.h @@ -66,9 +66,9 @@ struct RawData : public LoadModel { ElmUserDataType getUserData(ElementIDStruct object, PhaseOffset when) const override; CommMapType getComm(PhaseOffset when) const override; - void setLoads(std::unordered_map const* proc_load, - std::unordered_map const* proc_comm, - std::unordered_map const* user_data) override; + void setLoads(vt::util::container::CircularPhasesBuffer const* proc_load, + vt::util::container::CircularPhasesBuffer const* proc_comm, + vt::util::container::CircularPhasesBuffer const* user_data) override; ObjectIterator begin() const override; @@ -78,9 +78,9 @@ struct RawData : public LoadModel { unsigned int getNumPastPhasesNeeded(unsigned int look_back) const override; // Observer pointers to the underlying data. In operation, these would be owned by NodeLBData - std::unordered_map const* proc_load_; - std::unordered_map const* proc_comm_; - std::unordered_map const* user_data_; + vt::util::container::CircularPhasesBuffer const* proc_load_; + vt::util::container::CircularPhasesBuffer const* proc_comm_; + vt::util::container::CircularPhasesBuffer const* user_data_; PhaseType last_completed_phase_ = ~0; }; // class RawData diff --git a/src/vt/vrt/collection/balance/model/weighted_messages.h b/src/vt/vrt/collection/balance/model/weighted_messages.h index 7cf5a2deda..ec2c6c16a7 100644 --- a/src/vt/vrt/collection/balance/model/weighted_messages.h +++ b/src/vt/vrt/collection/balance/model/weighted_messages.h @@ -65,9 +65,9 @@ struct WeightedMessages : public ComposedModel { per_byte_weight_(in_per_byte_weight) { } void setLoads( - std::unordered_map const* proc_load, - std::unordered_map const* proc_comm, - std::unordered_map const* user_data + vt::util::container::CircularPhasesBuffer const* proc_load, + vt::util::container::CircularPhasesBuffer const* proc_comm, + vt::util::container::CircularPhasesBuffer const* user_data ) override { proc_comm_ = proc_comm; ComposedModel::setLoads(proc_load, proc_comm, user_data); diff --git a/src/vt/vrt/collection/balance/node_lb_data.cc b/src/vt/vrt/collection/balance/node_lb_data.cc index 114cba0441..d7699c7944 100644 --- a/src/vt/vrt/collection/balance/node_lb_data.cc +++ b/src/vt/vrt/collection/balance/node_lb_data.cc @@ -377,12 +377,12 @@ void NodeLBData::addNodeLBData( } if (storable) { - (*lb_data_->user_defined_json_[phase])[id] = std::make_shared( + lb_data_->user_defined_json_[phase][id] = std::make_shared( storable->toJson() ); storable->foreachLB( [&](std::string const& key, auto val) { - (*lb_data_->user_defined_lb_info_[phase])[id][key] = val->toVariant(); + lb_data_->user_defined_lb_info_[phase][id][key] = val->toVariant(); } ); storable->collectAttributes( diff --git a/tests/unit/collection/test_lb.extended.cc b/tests/unit/collection/test_lb.extended.cc index 8d31e8f7cf..aac84b739c 100644 --- a/tests/unit/collection/test_lb.extended.cc +++ b/tests/unit/collection/test_lb.extended.cc @@ -585,15 +585,15 @@ TEST_F(TestRestoreLBData, test_restore_lb_data_data_1) { CommKey::NodeToCollectionTag{}, this_node, elm_id, false ); CommVolume ntocvol{ntoc, ntocm}; - (*lbdh.node_comm_[phase])[ntockey] = ntocvol; - (*lbdh.node_subphase_comm_[phase])[i % 2][ntockey] = ntocvol; + lbdh.node_comm_[phase][ntockey] = ntocvol; + lbdh.node_subphase_comm_[phase][i % 2][ntockey] = ntocvol; CommKey ctonkey( CommKey::CollectionToNodeTag{}, elm_id, this_node, false ); CommVolume ctonvol{cton, ctonm}; - (*lbdh.node_comm_[phase])[ctonkey] = ctonvol; - (*lbdh.node_subphase_comm_[phase])[(i + 1) % 2][ctonkey] = ctonvol; + lbdh.node_comm_[phase][ctonkey] = ctonvol; + lbdh.node_subphase_comm_[phase][(i + 1) % 2][ctonkey] = ctonvol; std::vector arr; arr.push_back(idx.x()); diff --git a/tests/unit/collection/test_lb_data_holder.cc b/tests/unit/collection/test_lb_data_holder.cc index 0f064c9007..6a12d1071c 100644 --- a/tests/unit/collection/test_lb_data_holder.cc +++ b/tests/unit/collection/test_lb_data_holder.cc @@ -77,7 +77,7 @@ void addPhasesDataToJson(nlohmann::json& json, PhaseType amountOfPhasesToAdd, st LBDataHolder dh(amountOfPhasesToAdd); for (unsigned i = 0; i < amountOfPhasesToAdd; i++) { for (auto&& elm : ids[i]) { - (*dh.node_data_[i])[elm] = LoadSummary{3.}; + dh.node_data_[i][elm] = LoadSummary{3.}; } } diff --git a/tests/unit/collection/test_model_comm_overhead.nompi.cc b/tests/unit/collection/test_model_comm_overhead.nompi.cc index 20d3bfc44e..be51b2f87d 100644 --- a/tests/unit/collection/test_model_comm_overhead.nompi.cc +++ b/tests/unit/collection/test_model_comm_overhead.nompi.cc @@ -69,10 +69,10 @@ using vt::vrt::collection::balance::SubphaseLoadMapType; using vt::vrt::collection::balance::LoadMapObjectIterator; using vt::vrt::collection::balance::DataMapType; -using ProcLoadMap = std::unordered_map; -using ProcSubphaseLoadMap = std::unordered_map; -using ProcCommMap = std::unordered_map; -using UserDataMap = std::unordered_map; +using ProcLoadMap = vt::util::container::CircularPhasesBuffer; +using ProcSubphaseLoadMap = vt::util::container::CircularPhasesBuffer; +using ProcCommMap = vt::util::container::CircularPhasesBuffer; +using UserDataMap = vt::util::container::CircularPhasesBuffer; static auto num_phases = 0; diff --git a/tests/unit/collection/test_model_linear_model.nompi.cc b/tests/unit/collection/test_model_linear_model.nompi.cc index d9d073d18d..1bdffb8a3b 100644 --- a/tests/unit/collection/test_model_linear_model.nompi.cc +++ b/tests/unit/collection/test_model_linear_model.nompi.cc @@ -73,9 +73,9 @@ struct StubModel : LoadModel { virtual ~StubModel() = default; void setLoads( - std::unordered_map const* proc_load, - std::unordered_map const*, - std::unordered_map const*) override { + vt::util::container::CircularPhasesBuffer const* proc_load, + vt::util::container::CircularPhasesBuffer const*, + vt::util::container::CircularPhasesBuffer const*) override { proc_load_ = proc_load; } @@ -100,7 +100,6 @@ struct StubModel : LoadModel { TEST_F(TestLinearModel, test_model_linear_model_1) { constexpr int32_t num_test_interations = 6; - constexpr std::size_t buffer_size = 7; NodeType this_node = 0; auto test_model = diff --git a/tests/unit/collection/test_model_multiple_phases.nompi.cc b/tests/unit/collection/test_model_multiple_phases.nompi.cc index 11687b73ec..f0e39252f9 100644 --- a/tests/unit/collection/test_model_multiple_phases.nompi.cc +++ b/tests/unit/collection/test_model_multiple_phases.nompi.cc @@ -71,9 +71,9 @@ struct StubModel : LoadModel { virtual ~StubModel() = default; void setLoads( - std::unordered_map const* proc_load, - std::unordered_map const*, - std::unordered_map const*) override { + vt::util::container::CircularPhasesBuffer const* proc_load, + vt::util::container::CircularPhasesBuffer const*, + vt::util::container::CircularPhasesBuffer const*) override { proc_load_ = proc_load; } diff --git a/tests/unit/collection/test_model_naive_persistence.nompi.cc b/tests/unit/collection/test_model_naive_persistence.nompi.cc index 10e47045f1..0f4475d797 100644 --- a/tests/unit/collection/test_model_naive_persistence.nompi.cc +++ b/tests/unit/collection/test_model_naive_persistence.nompi.cc @@ -75,9 +75,9 @@ struct StubModel : LoadModel { virtual ~StubModel() = default; void setLoads( - std::unordered_map const* proc_load, - std::unordered_map const*, - std::unordered_map const*) override { + vt::util::container::CircularPhasesBuffer const* proc_load, + vt::util::container::CircularPhasesBuffer const*, + vt::util::container::CircularPhasesBuffer const*) override { proc_load_ = proc_load; } diff --git a/tests/unit/collection/test_model_norm.nompi.cc b/tests/unit/collection/test_model_norm.nompi.cc index 5d8a223ac3..0f6e7c7164 100644 --- a/tests/unit/collection/test_model_norm.nompi.cc +++ b/tests/unit/collection/test_model_norm.nompi.cc @@ -66,10 +66,10 @@ using vt::vrt::collection::balance::SubphaseLoadMapType; using vt::vrt::collection::balance::LoadMapObjectIterator; using vt::vrt::collection::balance::DataMapType; -using ProcLoadMap = std::unordered_map; -using ProcSubphaseLoadMap = std::unordered_map; -using ProcCommMap = std::unordered_map; -using UserDataMap = std::unordered_map; +using ProcLoadMap = vt::util::container::CircularPhasesBuffer; +using ProcSubphaseLoadMap = vt::util::container::CircularPhasesBuffer; +using ProcCommMap = vt::util::container::CircularPhasesBuffer; +using UserDataMap = vt::util::container::CircularPhasesBuffer; constexpr auto num_subphases = 3; 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 11ab8f73a9..89fef63cd4 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 @@ -73,9 +73,9 @@ struct StubModel : LoadModel { virtual ~StubModel() = default; void setLoads( - std::unordered_map const* proc_load, - std::unordered_map const*, - std::unordered_map const*) override { + vt::util::container::CircularPhasesBuffer const* proc_load, + vt::util::container::CircularPhasesBuffer const*, + vt::util::container::CircularPhasesBuffer const*) override { proc_load_ = proc_load; } diff --git a/tests/unit/collection/test_model_raw_data.nompi.cc b/tests/unit/collection/test_model_raw_data.nompi.cc index 9abe8c670f..2b3caaeb62 100644 --- a/tests/unit/collection/test_model_raw_data.nompi.cc +++ b/tests/unit/collection/test_model_raw_data.nompi.cc @@ -70,7 +70,7 @@ TEST_F(TestRawData, test_model_raw_data_scalar) { auto test_model = std::make_shared(); - std::unordered_map proc_loads; + vt::util::container::CircularPhasesBuffer proc_loads; test_model->setLoads(&proc_loads, nullptr, nullptr); EXPECT_TRUE(test_model->hasRawLoad()); EXPECT_FALSE(test_model->hasUserData()); // because passed a nullptr @@ -129,8 +129,8 @@ TEST_F(TestRawData, test_model_raw_user_data) { auto test_model = std::make_shared(); - std::unordered_map proc_loads; - std::unordered_map user_data; + vt::util::container::CircularPhasesBuffer proc_loads; + vt::util::container::CircularPhasesBuffer user_data; test_model->setLoads(&proc_loads, nullptr, &user_data); EXPECT_TRUE(test_model->hasRawLoad()); EXPECT_TRUE(test_model->hasUserData()); diff --git a/tests/unit/collection/test_model_select_subphases.nompi.cc b/tests/unit/collection/test_model_select_subphases.nompi.cc index fb41feacbe..061a132d2c 100644 --- a/tests/unit/collection/test_model_select_subphases.nompi.cc +++ b/tests/unit/collection/test_model_select_subphases.nompi.cc @@ -65,10 +65,10 @@ using vt::vrt::collection::balance::SubphaseLoadMapType; using vt::vrt::collection::balance::LoadMapObjectIterator; using vt::vrt::collection::balance::DataMapType; -using ProcLoadMap = std::unordered_map; -using ProcSubphaseLoadMap = std::unordered_map; -using ProcCommMap = std::unordered_map; -using UserDataMap = std::unordered_map; +using ProcLoadMap = vt::util::container::CircularPhasesBuffer; +using ProcSubphaseLoadMap = vt::util::container::CircularPhasesBuffer; +using ProcCommMap = vt::util::container::CircularPhasesBuffer; +using UserDataMap = vt::util::container::CircularPhasesBuffer; constexpr auto num_subphases = 3; diff --git a/tests/unit/collection/test_model_weighted_communication_volume.nompi.cc b/tests/unit/collection/test_model_weighted_communication_volume.nompi.cc index a7cdc11ff3..92e01e9693 100644 --- a/tests/unit/collection/test_model_weighted_communication_volume.nompi.cc +++ b/tests/unit/collection/test_model_weighted_communication_volume.nompi.cc @@ -69,9 +69,9 @@ using vt::vrt::collection::balance::PhaseOffset; using vt::vrt::collection::balance::LoadMapObjectIterator; using vt::vrt::collection::balance::DataMapType; -using ProcLoadMap = std::unordered_map; -using ProcCommMap = std::unordered_map; -using UserDataMap = std::unordered_map; +using ProcLoadMap = vt::util::container::CircularPhasesBuffer; +using ProcCommMap = vt::util::container::CircularPhasesBuffer; +using UserDataMap = vt::util::container::CircularPhasesBuffer; static auto num_phases = 0; diff --git a/tests/unit/collection/test_model_weighted_messages.nompi.cc b/tests/unit/collection/test_model_weighted_messages.nompi.cc index d08f345d0e..fecc86a0df 100644 --- a/tests/unit/collection/test_model_weighted_messages.nompi.cc +++ b/tests/unit/collection/test_model_weighted_messages.nompi.cc @@ -67,9 +67,9 @@ using vt::vrt::collection::balance::PhaseOffset; using vt::vrt::collection::balance::LoadMapObjectIterator; using vt::vrt::collection::balance::DataMapType; -using ProcLoadMap = std::unordered_map; -using ProcCommMap = std::unordered_map; -using UserDataMap = std::unordered_map; +using ProcLoadMap = vt::util::container::CircularPhasesBuffer; +using ProcCommMap = vt::util::container::CircularPhasesBuffer; +using UserDataMap = vt::util::container::CircularPhasesBuffer; static auto num_phases = 0; diff --git a/tests/unit/lb/test_offlinelb.cc b/tests/unit/lb/test_offlinelb.cc index bf40482479..5d9bcaa5a0 100644 --- a/tests/unit/lb/test_offlinelb.cc +++ b/tests/unit/lb/test_offlinelb.cc @@ -128,7 +128,7 @@ TEST_F(TestOfflineLB, test_offlinelb_1) { LBDataHolder dh(num_phases); for (PhaseType i = 0; i < num_phases; i++) { for (auto&& elm : ids[i]) { - (*dh.node_data_[i])[elm] = LoadSummary{3}; + dh.node_data_[i][elm] = LoadSummary{3}; } } From 6b6a0e5aadc80a987d687975e17b94cf82ec3796 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 12 Dec 2023 15:39:02 +0100 Subject: [PATCH 22/82] #1934: Synchronize buffer size in TestCol before checking for persisted phases --- .../unit/collection/test_lb_data_retention.cc | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/tests/unit/collection/test_lb_data_retention.cc b/tests/unit/collection/test_lb_data_retention.cc index bab7611e8a..2c5253328b 100644 --- a/tests/unit/collection/test_lb_data_retention.cc +++ b/tests/unit/collection/test_lb_data_retention.cc @@ -180,7 +180,7 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_last1) { vt::thePhase()->nextPhaseCollective(); } - // Check amount of phase data in the node + // Check the phases persisted in the node validatePersistedPhases({4}); } @@ -219,7 +219,7 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_last2) { vt::thePhase()->nextPhaseCollective(); } - // Check amount of phase data in the node + // Check the phases persisted in the node validatePersistedPhases({4,5}); } @@ -258,7 +258,7 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_last4) { vt::thePhase()->nextPhaseCollective(); } - // Check amount of phase data in the node + // Check the phases persisted in the node validatePersistedPhases({4,5,6,7}); } @@ -300,7 +300,7 @@ TEST_F(TestLBDataRetention, test_lbdata_config_retention_higher) { vt::thePhase()->nextPhaseCollective(); } - // Check amount of phase data in the node + // Check the phases persisted in the node validatePersistedPhases({6,7,8,9,10,11}); } @@ -344,9 +344,12 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_model_switch_1) { // Set model which needs only 1 phase of data theLBManager()->setLoadModel(model_1_phase); - // Check amount of phase data in the node + // Check the phases persisted in the node validatePersistedPhases({10}); + // Go to next phase to update size of the buffers in TestCol. + vt::thePhase()->nextPhaseCollective(); + for (uint32_t i=0; inextPhaseCollective(); } - // Check amount of phase data in the node - validatePersistedPhases({21}); + // Check the phases persisted in the node + validatePersistedPhases({22}); } TEST_F(TestLBDataRetention, test_lbdata_retention_model_switch_2) { @@ -395,16 +398,19 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_model_switch_2) { vt::thePhase()->nextPhaseCollective(); } - // Check amount of phase data in the node + // Check the phases persisted in the node validatePersistedPhases({0,1,2,3,4,5}); // Set model which needs only 1 phase of data auto model_1_phase = std::make_shared(base, 1U); theLBManager()->setLoadModel(model_1_phase); - // Check amount of phase data in the node + // Check the phases persisted in the node validatePersistedPhases({5}); + // Go to next phase to update size of the buffers in TestCol. + vt::thePhase()->nextPhaseCollective(); + // Do another 10 phases of work for (uint32_t i=0; i<10; ++i) { runInEpochCollective([&]{ @@ -415,8 +421,8 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_model_switch_2) { vt::thePhase()->nextPhaseCollective(); } - // Check amount of phase data in the node - validatePersistedPhases({15}); + // Check the phases persisted in the node + validatePersistedPhases({16}); } }}} // end namespace vt::tests::unit From f88eb33e75c7fcd296ce72946751e146eb9cfad0 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 12 Dec 2023 17:36:21 +0100 Subject: [PATCH 23/82] #1934: Set initial timings buffer size to 1 --- src/vt/elm/elm_lb_data.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vt/elm/elm_lb_data.h b/src/vt/elm/elm_lb_data.h index 3b7d55862d..39387dd402 100644 --- a/src/vt/elm/elm_lb_data.h +++ b/src/vt/elm/elm_lb_data.h @@ -134,12 +134,12 @@ struct ElementLBData { bool cur_time_started_ = false; TimeType cur_time_ = TimeType{0.0}; PhaseType cur_phase_ = fst_lb_phase; - vt::util::container::CircularPhasesBuffer phase_timings_ = {1}; // workaround for lack of initial size - vt::util::container::CircularPhasesBuffer phase_comm_ = {1}; // workaround for lack of initial size + vt::util::container::CircularPhasesBuffer phase_timings_ = {1}; + vt::util::container::CircularPhasesBuffer phase_comm_ = {}; SubphaseType cur_subphase_ = 0; - vt::util::container::CircularPhasesBuffer> subphase_timings_ = {1}; // workaround for lack of initial size - vt::util::container::CircularPhasesBuffer> subphase_comm_ = {1}; // workaround for lack of initial size + vt::util::container::CircularPhasesBuffer> subphase_timings_ = {1}; + vt::util::container::CircularPhasesBuffer> subphase_comm_ = {}; }; }} /* end namespace vt::elm */ From 582052915df67e6f7dc6f6907e57ec0ca254d4fa Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 12 Dec 2023 17:39:10 +0100 Subject: [PATCH 24/82] #1934: Remove update of the buffers in the group --- src/vt/vrt/collection/balance/lb_invoke/lb_manager.cc | 8 -------- 1 file changed, 8 deletions(-) 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 b239f3787a..44a8880d41 100644 --- a/src/vt/vrt/collection/balance/lb_invoke/lb_manager.cc +++ b/src/vt/vrt/collection/balance/lb_invoke/lb_manager.cc @@ -182,14 +182,6 @@ void LBManager::setLoadModel(std::shared_ptr model) { model_->setLoads(nlb_data->getNodeLoad(), nlb_data->getNodeComm(), nlb_data->getUserData()); - - // Adjust buffers size on the objs in collection - runInEpochCollective("LBManager: setLoadModel", [=] { - auto& objs = vt::objgroup::getObjs(); - for (auto& obj : objs) { - obj.second->getLBData().setHistoryCapacity(min_hist_lb_data_); - } - }); } void LBManager::defaultPostLBWork(ReassignmentMsg* msg) { From 1c969c16c0aa1b69fb4f7a94f8b8a7c86d4f3adc Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 12 Dec 2023 18:26:52 +0100 Subject: [PATCH 25/82] #1934: Use buffer alias in models --- src/vt/elm/elm_lb_data.h | 8 ++++---- src/vt/vrt/collection/balance/lb_common.h | 4 ++++ src/vt/vrt/collection/balance/lb_data_holder.h | 8 ++++---- src/vt/vrt/collection/balance/model/comm_overhead.cc | 6 +++--- src/vt/vrt/collection/balance/model/comm_overhead.h | 8 ++++---- .../vrt/collection/balance/model/composed_model.cc | 6 +++--- src/vt/vrt/collection/balance/model/composed_model.h | 6 +++--- src/vt/vrt/collection/balance/model/load_model.h | 6 +++--- .../vrt/collection/balance/model/per_collection.cc | 6 +++--- src/vt/vrt/collection/balance/model/per_collection.h | 6 +++--- src/vt/vrt/collection/balance/model/raw_data.cc | 6 +++--- src/vt/vrt/collection/balance/model/raw_data.h | 12 ++++++------ .../vrt/collection/balance/model/weighted_messages.h | 8 ++++---- src/vt/vrt/collection/balance/node_lb_data.cc | 6 +++--- src/vt/vrt/collection/balance/node_lb_data.h | 8 ++++---- 15 files changed, 54 insertions(+), 50 deletions(-) diff --git a/src/vt/elm/elm_lb_data.h b/src/vt/elm/elm_lb_data.h index 39387dd402..b203b8dcdc 100644 --- a/src/vt/elm/elm_lb_data.h +++ b/src/vt/elm/elm_lb_data.h @@ -134,12 +134,12 @@ struct ElementLBData { bool cur_time_started_ = false; TimeType cur_time_ = TimeType{0.0}; PhaseType cur_phase_ = fst_lb_phase; - vt::util::container::CircularPhasesBuffer phase_timings_ = {1}; - vt::util::container::CircularPhasesBuffer phase_comm_ = {}; + util::container::CircularPhasesBuffer phase_timings_ = {1}; + util::container::CircularPhasesBuffer phase_comm_ = {}; SubphaseType cur_subphase_ = 0; - vt::util::container::CircularPhasesBuffer> subphase_timings_ = {1}; - vt::util::container::CircularPhasesBuffer> subphase_comm_ = {}; + util::container::CircularPhasesBuffer> subphase_timings_ = {1}; + util::container::CircularPhasesBuffer> subphase_comm_ = {}; }; }} /* end namespace vt::elm */ diff --git a/src/vt/vrt/collection/balance/lb_common.h b/src/vt/vrt/collection/balance/lb_common.h index e9e403b2de..b2fececfe3 100644 --- a/src/vt/vrt/collection/balance/lb_common.h +++ b/src/vt/vrt/collection/balance/lb_common.h @@ -49,6 +49,7 @@ #include "vt/elm/elm_comm.h" #include "vt/timing/timing_type.h" #include "vt/messaging/message/message.h" +#include "vt/utils/container/circular_phases_buffer.h" #include @@ -63,6 +64,7 @@ namespace balance { using ElementIDStruct = elm::ElementIDStruct; using ElementIDType = elm::ElementIDType; using CommMapType = elm::CommMapType; +using CommMapBufferType = util::container::CircularPhasesBuffer; static constexpr ElementIDType const no_element_id = elm::no_element_id; @@ -117,9 +119,11 @@ using UserDataValueType = std::variant; using ElmUserDataType = std::unordered_map; using LoadMapType = std::unordered_map; +using LoadMapBufferType = util::container::CircularPhasesBuffer; using SubphaseLoadMapType = std::unordered_map>; /// User-defined LB values map using DataMapType = std::unordered_map; +using DataMapBufferType = util::container::CircularPhasesBuffer; struct Reassignment { // Include the subject node so that these structures can be formed diff --git a/src/vt/vrt/collection/balance/lb_data_holder.h b/src/vt/vrt/collection/balance/lb_data_holder.h index ec99f5b1d2..715253a51c 100644 --- a/src/vt/vrt/collection/balance/lb_data_holder.h +++ b/src/vt/vrt/collection/balance/lb_data_holder.h @@ -191,13 +191,13 @@ struct LBDataHolder { /// Node attributes for the current rank ElmUserDataType rank_attributes_; /// Node timings for each local object - vt::util::container::CircularPhasesBuffer node_data_; + LoadMapBufferType node_data_; /// Node communication graph for each local object - vt::util::container::CircularPhasesBuffer node_comm_; + CommMapBufferType node_comm_; /// Node communication graph for each subphase - vt::util::container::CircularPhasesBuffer> node_subphase_comm_; + util::container::CircularPhasesBuffer> node_subphase_comm_; /// User-defined data from each phase for JSON output - vt::util::container::CircularPhasesBuffer >> user_defined_json_; diff --git a/src/vt/vrt/collection/balance/model/comm_overhead.cc b/src/vt/vrt/collection/balance/model/comm_overhead.cc index 975ff98859..d040b626d6 100644 --- a/src/vt/vrt/collection/balance/model/comm_overhead.cc +++ b/src/vt/vrt/collection/balance/model/comm_overhead.cc @@ -54,9 +54,9 @@ CommOverhead::CommOverhead( per_byte_weight_(in_per_byte_weight) { } -void CommOverhead::setLoads(vt::util::container::CircularPhasesBuffer const* proc_load, - vt::util::container::CircularPhasesBuffer const* proc_comm, - vt::util::container::CircularPhasesBuffer const* user_data) { +void CommOverhead::setLoads(LoadMapBufferType const* proc_load, + CommMapBufferType const* proc_comm, + DataMapBufferType const* user_data) { proc_comm_ = proc_comm; ComposedModel::setLoads(proc_load, proc_comm, user_data); } diff --git a/src/vt/vrt/collection/balance/model/comm_overhead.h b/src/vt/vrt/collection/balance/model/comm_overhead.h index d4d2420a91..148648ea42 100644 --- a/src/vt/vrt/collection/balance/model/comm_overhead.h +++ b/src/vt/vrt/collection/balance/model/comm_overhead.h @@ -65,14 +65,14 @@ struct CommOverhead : public ComposedModel { LoadType in_per_byte_weight ); - void setLoads(vt::util::container::CircularPhasesBuffer const* proc_load, - vt::util::container::CircularPhasesBuffer const* proc_comm, - vt::util::container::CircularPhasesBuffer const* user_data) override; + void setLoads(LoadMapBufferType const* proc_load, + CommMapBufferType const* proc_comm, + DataMapBufferType const* user_data) override; LoadType getModeledLoad(ElementIDStruct object, PhaseOffset when) const override; private: - vt::util::container::CircularPhasesBuffer const* proc_comm_; /**< Underlying comm data */ + CommMapBufferType const* proc_comm_; /**< Underlying comm data */ LoadType per_msg_weight_ = 0.001; /**< Cost per message */ LoadType per_byte_weight_ = 0.000001; /**< Cost per bytes */ }; // class CommOverhead diff --git a/src/vt/vrt/collection/balance/model/composed_model.cc b/src/vt/vrt/collection/balance/model/composed_model.cc index fd10c8e1a3..aac29b5bdf 100644 --- a/src/vt/vrt/collection/balance/model/composed_model.cc +++ b/src/vt/vrt/collection/balance/model/composed_model.cc @@ -45,9 +45,9 @@ namespace vt { namespace vrt { namespace collection { namespace balance { -void ComposedModel::setLoads(vt::util::container::CircularPhasesBuffer const* proc_load, - vt::util::container::CircularPhasesBuffer const* proc_comm, - vt::util::container::CircularPhasesBuffer const* user_data) { +void ComposedModel::setLoads(LoadMapBufferType const* proc_load, + CommMapBufferType const* proc_comm, + DataMapBufferType const* user_data) { base_->setLoads(proc_load, proc_comm, user_data); } diff --git a/src/vt/vrt/collection/balance/model/composed_model.h b/src/vt/vrt/collection/balance/model/composed_model.h index 7e785b7c81..f0e23a9a1b 100644 --- a/src/vt/vrt/collection/balance/model/composed_model.h +++ b/src/vt/vrt/collection/balance/model/composed_model.h @@ -64,9 +64,9 @@ class ComposedModel : public LoadModel // \param[in] base must not be null explicit ComposedModel(std::shared_ptr base) : base_(base) {} - void setLoads(vt::util::container::CircularPhasesBuffer const* proc_load, - vt::util::container::CircularPhasesBuffer const* proc_comm, - vt::util::container::CircularPhasesBuffer const* user_data) override; + void setLoads(LoadMapBufferType const* proc_load, + CommMapBufferType const* proc_comm, + DataMapBufferType const* user_data) override; void updateLoads(PhaseType last_completed_phase) override; diff --git a/src/vt/vrt/collection/balance/model/load_model.h b/src/vt/vrt/collection/balance/model/load_model.h index bff7269ca5..3019bbb1de 100644 --- a/src/vt/vrt/collection/balance/model/load_model.h +++ b/src/vt/vrt/collection/balance/model/load_model.h @@ -196,9 +196,9 @@ struct LoadModel * passed a new model instance for a collection */ virtual void setLoads( - vt::util::container::CircularPhasesBuffer const* proc_load, - vt::util::container::CircularPhasesBuffer const* proc_comm, - vt::util::container::CircularPhasesBuffer const* user_data + LoadMapBufferType const* proc_load, + CommMapBufferType const* proc_comm, + DataMapBufferType const* user_data ) = 0; /** diff --git a/src/vt/vrt/collection/balance/model/per_collection.cc b/src/vt/vrt/collection/balance/model/per_collection.cc index f9e0b165cd..ce94e2cf45 100644 --- a/src/vt/vrt/collection/balance/model/per_collection.cc +++ b/src/vt/vrt/collection/balance/model/per_collection.cc @@ -55,9 +55,9 @@ void PerCollection::addModel(CollectionID proxy, std::shared_ptr mode models_[proxy] = model; } -void PerCollection::setLoads(vt::util::container::CircularPhasesBuffer const* proc_load, - vt::util::container::CircularPhasesBuffer const* proc_comm, - vt::util::container::CircularPhasesBuffer const* user_data) { +void PerCollection::setLoads(LoadMapBufferType const* proc_load, + CommMapBufferType const* proc_comm, + DataMapBufferType const* user_data) { for (auto& m : models_) m.second->setLoads(proc_load, proc_comm, user_data); ComposedModel::setLoads(proc_load, proc_comm, user_data); diff --git a/src/vt/vrt/collection/balance/model/per_collection.h b/src/vt/vrt/collection/balance/model/per_collection.h index 1de2df8144..a2a57d7dcc 100644 --- a/src/vt/vrt/collection/balance/model/per_collection.h +++ b/src/vt/vrt/collection/balance/model/per_collection.h @@ -73,9 +73,9 @@ struct PerCollection : public ComposedModel */ void addModel(CollectionID proxy, std::shared_ptr model); - void setLoads(vt::util::container::CircularPhasesBuffer const* proc_load, - vt::util::container::CircularPhasesBuffer const* proc_comm, - vt::util::container::CircularPhasesBuffer const* user_data) override; + void setLoads(LoadMapBufferType const* proc_load, + CommMapBufferType const* proc_comm, + DataMapBufferType const* user_data) override; void updateLoads(PhaseType last_completed_phase) override; diff --git a/src/vt/vrt/collection/balance/model/raw_data.cc b/src/vt/vrt/collection/balance/model/raw_data.cc index ea0fa44846..15d701656b 100644 --- a/src/vt/vrt/collection/balance/model/raw_data.cc +++ b/src/vt/vrt/collection/balance/model/raw_data.cc @@ -50,9 +50,9 @@ void RawData::updateLoads(PhaseType last_completed_phase) { last_completed_phase_ = last_completed_phase; } -void RawData::setLoads(vt::util::container::CircularPhasesBuffer const* proc_load, - vt::util::container::CircularPhasesBuffer const* proc_comm, - vt::util::container::CircularPhasesBuffer const* user_data) +void RawData::setLoads(LoadMapBufferType const* proc_load, + CommMapBufferType const* proc_comm, + DataMapBufferType const* user_data) { proc_load_ = proc_load; proc_comm_ = proc_comm; diff --git a/src/vt/vrt/collection/balance/model/raw_data.h b/src/vt/vrt/collection/balance/model/raw_data.h index a911c2b85f..9d186c3168 100644 --- a/src/vt/vrt/collection/balance/model/raw_data.h +++ b/src/vt/vrt/collection/balance/model/raw_data.h @@ -66,9 +66,9 @@ struct RawData : public LoadModel { ElmUserDataType getUserData(ElementIDStruct object, PhaseOffset when) const override; CommMapType getComm(PhaseOffset when) const override; - void setLoads(vt::util::container::CircularPhasesBuffer const* proc_load, - vt::util::container::CircularPhasesBuffer const* proc_comm, - vt::util::container::CircularPhasesBuffer const* user_data) override; + void setLoads(LoadMapBufferType const* proc_load, + CommMapBufferType const* proc_comm, + DataMapBufferType const* user_data) override; ObjectIterator begin() const override; @@ -78,9 +78,9 @@ struct RawData : public LoadModel { unsigned int getNumPastPhasesNeeded(unsigned int look_back) const override; // Observer pointers to the underlying data. In operation, these would be owned by NodeLBData - vt::util::container::CircularPhasesBuffer const* proc_load_; - vt::util::container::CircularPhasesBuffer const* proc_comm_; - vt::util::container::CircularPhasesBuffer const* user_data_; + LoadMapBufferType const* proc_load_; + CommMapBufferType const* proc_comm_; + DataMapBufferType const* user_data_; PhaseType last_completed_phase_ = ~0; }; // class RawData diff --git a/src/vt/vrt/collection/balance/model/weighted_messages.h b/src/vt/vrt/collection/balance/model/weighted_messages.h index ec2c6c16a7..d787f5ef4b 100644 --- a/src/vt/vrt/collection/balance/model/weighted_messages.h +++ b/src/vt/vrt/collection/balance/model/weighted_messages.h @@ -65,9 +65,9 @@ struct WeightedMessages : public ComposedModel { per_byte_weight_(in_per_byte_weight) { } void setLoads( - vt::util::container::CircularPhasesBuffer const* proc_load, - vt::util::container::CircularPhasesBuffer const* proc_comm, - vt::util::container::CircularPhasesBuffer const* user_data + LoadMapBufferType const* proc_load, + CommMapBufferType const* proc_comm, + DataMapBufferType const* user_data ) override { proc_comm_ = proc_comm; ComposedModel::setLoads(proc_load, proc_comm, user_data); @@ -77,7 +77,7 @@ struct WeightedMessages : public ComposedModel { private: // observer pointer to the underlying comm data - vt::util::container::CircularPhasesBuffer const* proc_comm_; + CommMapBufferType const* proc_comm_; LoadType per_msg_weight_; LoadType per_byte_weight_; diff --git a/src/vt/vrt/collection/balance/node_lb_data.cc b/src/vt/vrt/collection/balance/node_lb_data.cc index d7699c7944..2422e9cccb 100644 --- a/src/vt/vrt/collection/balance/node_lb_data.cc +++ b/src/vt/vrt/collection/balance/node_lb_data.cc @@ -91,12 +91,12 @@ bool NodeLBData::migrateObjTo(ElementIDStruct obj_id, NodeType to_node) { return true; } -vt::util::container::CircularPhasesBuffer const* +LoadMapBufferType const* NodeLBData::getNodeLoad() const { return &lb_data_->node_data_; } -vt::util::container::CircularPhasesBuffer const* +DataMapBufferType const* NodeLBData::getUserData() const { return &lb_data_->user_defined_lb_info_; } @@ -110,7 +110,7 @@ std::unordered_map const* NodeLBData::getNodeComm() cons return &lb_data_->node_comm_; } -vt::util::container::CircularPhasesBuffer> const* NodeLBData::getNodeSubphaseComm() const { +util::container::CircularPhasesBuffer> const* NodeLBData::getNodeSubphaseComm() const { return &lb_data_->node_subphase_comm_; } diff --git a/src/vt/vrt/collection/balance/node_lb_data.h b/src/vt/vrt/collection/balance/node_lb_data.h index 3a0fe3d6a4..e6b18d6372 100644 --- a/src/vt/vrt/collection/balance/node_lb_data.h +++ b/src/vt/vrt/collection/balance/node_lb_data.h @@ -173,21 +173,21 @@ struct NodeLBData : runtime::component::Component { * * \return an observer pointer to the load map */ - vt::util::container::CircularPhasesBuffer const* getNodeLoad() const; + LoadMapBufferType const* getNodeLoad() const; /** * \internal \brief Get stored object comm graph * * \return an observer pointer to the comm graph */ - vt::util::container::CircularPhasesBuffer const* getNodeComm() const; + CommMapBufferType const* getNodeComm() const; /** * \internal \brief Get the user-defined LB data * * \return an observer pointer to the user-defined LB data */ - vt::util::container::CircularPhasesBuffer const* getUserData() const; + DataMapBufferType const* getUserData() const; /** * \internal \brief Get the user-defined attributes @@ -210,7 +210,7 @@ struct NodeLBData : runtime::component::Component { * * \return an observer pointer to the comm subphase graph */ - vt::util::container::CircularPhasesBuffer> const* getNodeSubphaseComm() const; + util::container::CircularPhasesBuffer> const* getNodeSubphaseComm() const; /** * \internal \brief Get stored node attributes From ebe1805c532ca9615eb906d10404cfa44b337c0d Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Fri, 15 Dec 2023 20:03:40 +0100 Subject: [PATCH 26/82] #1934: Add more tests for circular phases buffer --- .../unit/collection/test_lb_data_retention.cc | 12 ++- .../test_circular_phases_buffer.nompi.cc | 100 ++++++++++++++++-- 2 files changed, 98 insertions(+), 14 deletions(-) diff --git a/tests/unit/collection/test_lb_data_retention.cc b/tests/unit/collection/test_lb_data_retention.cc index 2c5253328b..a39108c626 100644 --- a/tests/unit/collection/test_lb_data_retention.cc +++ b/tests/unit/collection/test_lb_data_retention.cc @@ -68,11 +68,11 @@ void validatePersistedPhases(std::vector expected_phases) { EXPECT_EQ(expected_phases.size(), theNodeLBData()->getLBData()->user_defined_lb_info_.size()); // Check if each phase is present for(auto&& phase : expected_phases) { - EXPECT_TRUE(nullptr != theNodeLBData()->getLBData()->node_comm_.find(phase)); - EXPECT_TRUE(nullptr != theNodeLBData()->getLBData()->node_data_.find(phase)); - EXPECT_TRUE(nullptr != theNodeLBData()->getLBData()->node_subphase_comm_.find(phase)); - EXPECT_TRUE(nullptr != theNodeLBData()->getLBData()->user_defined_json_.find(phase)); - EXPECT_TRUE(nullptr != theNodeLBData()->getLBData()->user_defined_lb_info_.find(phase)); + EXPECT_TRUE(theNodeLBData()->getLBData()->node_comm_.contains(phase)); + EXPECT_TRUE(theNodeLBData()->getLBData()->node_data_.contains(phase)); + EXPECT_TRUE(theNodeLBData()->getLBData()->node_subphase_comm_.contains(phase)); + EXPECT_TRUE(theNodeLBData()->getLBData()->user_defined_json_.contains(phase)); + EXPECT_TRUE(theNodeLBData()->getLBData()->user_defined_lb_info_.contains(phase)); } #else (void)expected_phases; @@ -423,6 +423,8 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_model_switch_2) { // Check the phases persisted in the node validatePersistedPhases({16}); + + EXPECT_EQ(true, false); } }}} // end namespace vt::tests::unit diff --git a/tests/unit/utils/test_circular_phases_buffer.nompi.cc b/tests/unit/utils/test_circular_phases_buffer.nompi.cc index 6c7ffb7c30..14fffe9063 100644 --- a/tests/unit/utils/test_circular_phases_buffer.nompi.cc +++ b/tests/unit/utils/test_circular_phases_buffer.nompi.cc @@ -56,32 +56,55 @@ struct Dummy { void validatePresentPhases(util::container::CircularPhasesBuffer& buffer, std::vector expected) { for (auto&& phase : expected) { - EXPECT_TRUE(buffer.contains(phase)); - EXPECT_EQ(phase * phase, buffer[phase].x); + EXPECT_TRUE(buffer.contains(phase)) << "phase: " << phase; + EXPECT_EQ(phase * phase, buffer[phase].x) << "phase: " << phase; } } void validateMissingPhases(util::container::CircularPhasesBuffer& buffer, std::vector expected) { for (auto&& phase : expected) { - EXPECT_FALSE(buffer.contains(phase)); + EXPECT_FALSE(buffer.contains(phase)) << "phase: " << phase; } } TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_empty) { - util::container::CircularPhasesBuffer buffer{10}; + util::container::CircularPhasesBuffer buffer; + EXPECT_FALSE(buffer.isInitialized()); + EXPECT_EQ(std::size_t{0}, buffer.capacity()); EXPECT_FALSE(buffer.contains(3)); EXPECT_FALSE(buffer.contains(10)); + EXPECT_EQ(std::size_t{0}, buffer.size()); buffer.resize(2); + EXPECT_TRUE(buffer.isInitialized()); + EXPECT_EQ(std::size_t{2}, buffer.capacity()); EXPECT_FALSE(buffer.contains(3)); EXPECT_FALSE(buffer.contains(10)); + EXPECT_EQ(std::size_t{0}, buffer.size()); buffer.clear(); + EXPECT_TRUE(buffer.isInitialized()); + EXPECT_EQ(std::size_t{2}, buffer.capacity()); EXPECT_FALSE(buffer.contains(3)); EXPECT_FALSE(buffer.contains(10)); + EXPECT_EQ(std::size_t{0}, buffer.size()); + + buffer.resize(0); + + EXPECT_FALSE(buffer.isInitialized()); + EXPECT_EQ(std::size_t{0}, buffer.capacity()); + EXPECT_FALSE(buffer.contains(3)); + EXPECT_FALSE(buffer.contains(10)); + EXPECT_EQ(std::size_t{0}, buffer.size()); + + for(auto&& ele : buffer) { + // This will never be called. + EXPECT_EQ(true, false); + (void)ele; + } } TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_store) { @@ -94,20 +117,28 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_store) { for (int i = 0; i < 15; i++) { buffer.store(i, { i * i }); } - validatePresentPhases(buffer, {5, 6, 7, 8, 9, 10, 11, 12, 13, 14}); + std::vector finalOutput = {5, 6, 7, 8, 9, 10, 11, 12, 13, 14}; + validatePresentPhases(buffer, finalOutput); + + std::vector visited; + for(auto&& ele : buffer) { + visited.push_back(ele.first); + EXPECT_EQ(ele.first * ele.first, ele.second.x) << "phase: " << ele.first; + } + EXPECT_TRUE(std::equal(visited.begin(), visited.end(), finalOutput.begin())); } TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_resize_continuous) { util::container::CircularPhasesBuffer buffer{1}; - buffer.store(0, { 0 }); + buffer[0] = { 0 }; validatePresentPhases(buffer, {0}); buffer.resize(10); validatePresentPhases(buffer, {0}); for (int i = 0; i <= 15; i++) { - buffer.store(i, { i * i }); + buffer[i] = { i * i }; } validatePresentPhases(buffer, {6, 7, 8, 9, 10, 11, 12, 13, 14, 15}); @@ -116,14 +147,14 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_resize_continuous) validateMissingPhases(buffer, {6, 7, 8, 9, 10}); for (int i = 15; i <= 32; i++) { - buffer.store(i, { i * i }); + buffer[i] = { i * i }; } validatePresentPhases(buffer, {28, 29, 30, 31, 32}); buffer.resize(9); for (int i = 33; i <= 35; i++) { - buffer.store(i, { i * i }); + buffer[i] = { i * i }; } validatePresentPhases(buffer, {28, 29, 30, 31, 32, 33, 34, 35}); @@ -131,4 +162,55 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_resize_continuous) validatePresentPhases(buffer, {35}); } +TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_resize_sparse) { + util::container::CircularPhasesBuffer buffer{10}; + + buffer[1] = { 1 }; + buffer[4] = { 16 }; + buffer[7] = { 49 }; + + { + std::vector expected = {1, 4, 7}; + validatePresentPhases(buffer, expected); + + std::vector visited; + for(auto&& ele : buffer) { + visited.push_back(ele.first); + EXPECT_EQ(ele.first * ele.first, ele.second.x); + } + EXPECT_TRUE(std::equal(visited.begin(), visited.end(), expected.begin())); + } + + buffer.resize(4); + + { + std::vector expected = {1, 4, 7}; + validatePresentPhases(buffer, expected); + + std::vector visited; + for(auto&& ele : buffer) { + visited.push_back(ele.first); + EXPECT_EQ(ele.first * ele.first, ele.second.x); + } + EXPECT_TRUE(std::equal(visited.begin(), visited.end(), expected.begin())); + } + + // All of the elements will have the same % result. Expect only the last one + buffer.resize(3); + + { + std::vector expected = {7}; + validatePresentPhases(buffer, expected); + + std::vector visited; + for(auto&& ele : buffer) { + visited.push_back(ele.first); + EXPECT_EQ(ele.first * ele.first, ele.second.x); + } + EXPECT_TRUE(std::equal(visited.begin(), visited.end(), expected.begin())); + } + + EXPECT_EQ(true, false); +} + }}} /* end namespace vt::tests::unit */ From 529659f39858d135190bc478d7e27f67c7cad04b Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 19 Dec 2023 12:29:04 +0100 Subject: [PATCH 27/82] #1934: Add more test cases for CircularPhasesBuffer --- .../unit/collection/test_lb_data_retention.cc | 2 - .../test_circular_phases_buffer.nompi.cc | 270 ++++++++++-------- 2 files changed, 145 insertions(+), 127 deletions(-) diff --git a/tests/unit/collection/test_lb_data_retention.cc b/tests/unit/collection/test_lb_data_retention.cc index a39108c626..e4bbeb0df6 100644 --- a/tests/unit/collection/test_lb_data_retention.cc +++ b/tests/unit/collection/test_lb_data_retention.cc @@ -423,8 +423,6 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_model_switch_2) { // Check the phases persisted in the node validatePersistedPhases({16}); - - EXPECT_EQ(true, false); } }}} // end namespace vt::tests::unit diff --git a/tests/unit/utils/test_circular_phases_buffer.nompi.cc b/tests/unit/utils/test_circular_phases_buffer.nompi.cc index 14fffe9063..fbb1d4a06f 100644 --- a/tests/unit/utils/test_circular_phases_buffer.nompi.cc +++ b/tests/unit/utils/test_circular_phases_buffer.nompi.cc @@ -51,166 +51,186 @@ namespace vt { namespace tests { namespace unit { using TestCircularPhasesBuffer = TestHarness; struct Dummy { - int x; + int x; }; -void validatePresentPhases(util::container::CircularPhasesBuffer& buffer, std::vector expected) { - for (auto&& phase : expected) { - EXPECT_TRUE(buffer.contains(phase)) << "phase: " << phase; - EXPECT_EQ(phase * phase, buffer[phase].x) << "phase: " << phase; - } +void validatePresentPhases( + util::container::CircularPhasesBuffer& buffer, + std::vector expected) { + for (auto&& phase : expected) { + EXPECT_TRUE(buffer.contains(phase)) << "phase: " << phase; + EXPECT_EQ(phase * phase, buffer[phase].x) << "phase: " << phase; + } } -void validateMissingPhases(util::container::CircularPhasesBuffer& buffer, std::vector expected) { - for (auto&& phase : expected) { - EXPECT_FALSE(buffer.contains(phase)) << "phase: " << phase; - } +void validateMissingPhases( + util::container::CircularPhasesBuffer& buffer, + std::vector expected) { + for (auto&& phase : expected) { + EXPECT_FALSE(buffer.contains(phase)) << "phase: " << phase; + } } TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_empty) { - util::container::CircularPhasesBuffer buffer; - - EXPECT_FALSE(buffer.isInitialized()); - EXPECT_EQ(std::size_t{0}, buffer.capacity()); - EXPECT_FALSE(buffer.contains(3)); - EXPECT_FALSE(buffer.contains(10)); - EXPECT_EQ(std::size_t{0}, buffer.size()); - - buffer.resize(2); - - EXPECT_TRUE(buffer.isInitialized()); - EXPECT_EQ(std::size_t{2}, buffer.capacity()); - EXPECT_FALSE(buffer.contains(3)); - EXPECT_FALSE(buffer.contains(10)); - EXPECT_EQ(std::size_t{0}, buffer.size()); - - buffer.clear(); - - EXPECT_TRUE(buffer.isInitialized()); - EXPECT_EQ(std::size_t{2}, buffer.capacity()); - EXPECT_FALSE(buffer.contains(3)); - EXPECT_FALSE(buffer.contains(10)); - EXPECT_EQ(std::size_t{0}, buffer.size()); - - buffer.resize(0); - - EXPECT_FALSE(buffer.isInitialized()); - EXPECT_EQ(std::size_t{0}, buffer.capacity()); - EXPECT_FALSE(buffer.contains(3)); - EXPECT_FALSE(buffer.contains(10)); - EXPECT_EQ(std::size_t{0}, buffer.size()); - - for(auto&& ele : buffer) { - // This will never be called. - EXPECT_EQ(true, false); - (void)ele; - } -} + util::container::CircularPhasesBuffer buffer; -TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_store) { - util::container::CircularPhasesBuffer buffer{10}; + EXPECT_FALSE(buffer.isInitialized()); + EXPECT_EQ(std::size_t{0}, buffer.capacity()); + EXPECT_FALSE(buffer.contains(3)); + EXPECT_FALSE(buffer.contains(10)); + EXPECT_EQ(std::size_t{0}, buffer.size()); - buffer.store(2, { 2 * 2 }); - validatePresentPhases(buffer, {2}); + buffer.resize(2); - // store series of elements - for (int i = 0; i < 15; i++) { - buffer.store(i, { i * i }); - } - std::vector finalOutput = {5, 6, 7, 8, 9, 10, 11, 12, 13, 14}; - validatePresentPhases(buffer, finalOutput); + EXPECT_TRUE(buffer.isInitialized()); + EXPECT_EQ(std::size_t{2}, buffer.capacity()); + EXPECT_FALSE(buffer.contains(3)); + EXPECT_FALSE(buffer.contains(10)); + EXPECT_EQ(std::size_t{0}, buffer.size()); - std::vector visited; - for(auto&& ele : buffer) { - visited.push_back(ele.first); - EXPECT_EQ(ele.first * ele.first, ele.second.x) << "phase: " << ele.first; - } - EXPECT_TRUE(std::equal(visited.begin(), visited.end(), finalOutput.begin())); + buffer.clear(); + + EXPECT_TRUE(buffer.isInitialized()); + EXPECT_EQ(std::size_t{2}, buffer.capacity()); + EXPECT_FALSE(buffer.contains(3)); + EXPECT_FALSE(buffer.contains(10)); + EXPECT_EQ(std::size_t{0}, buffer.size()); + + buffer.resize(0); + + EXPECT_FALSE(buffer.isInitialized()); + EXPECT_EQ(std::size_t{0}, buffer.capacity()); + EXPECT_FALSE(buffer.contains(3)); + EXPECT_FALSE(buffer.contains(10)); + EXPECT_EQ(std::size_t{0}, buffer.size()); } -TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_resize_continuous) { - util::container::CircularPhasesBuffer buffer{1}; +TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_store) { + util::container::CircularPhasesBuffer buffer{10}; + + buffer.store(2, {2 * 2}); + validatePresentPhases(buffer, {2}); + + // store series of elements + for (int i = 0; i < 15; i++) { + buffer.store(i, {i * i}); + } + std::vector finalOutput = {5, 6, 7, 8, 9, 10, 11, 12, 13, 14}; + validatePresentPhases(buffer, finalOutput); + + std::vector visited; + for (auto&& ele : buffer) { + visited.push_back(ele.first); + EXPECT_EQ(ele.first * ele.first, ele.second.x) << "phase: " << ele.first; + } + EXPECT_TRUE(std::equal(visited.begin(), visited.end(), finalOutput.begin())); +} - buffer[0] = { 0 }; - validatePresentPhases(buffer, {0}); +TEST_F( + TestCircularPhasesBuffer, test_circular_phases_buffer_resize_continuous) { + util::container::CircularPhasesBuffer buffer{1}; - buffer.resize(10); - validatePresentPhases(buffer, {0}); + buffer[0] = {0}; + validatePresentPhases(buffer, {0}); - for (int i = 0; i <= 15; i++) { - buffer[i] = { i * i }; - } - validatePresentPhases(buffer, {6, 7, 8, 9, 10, 11, 12, 13, 14, 15}); + buffer.resize(10); + validatePresentPhases(buffer, {0}); - buffer.resize(5); - validatePresentPhases(buffer, {11, 12, 13, 14, 15}); - validateMissingPhases(buffer, {6, 7, 8, 9, 10}); + for (int i = 0; i <= 15; i++) { + buffer[i] = {i * i}; + } + validatePresentPhases(buffer, {6, 7, 8, 9, 10, 11, 12, 13, 14, 15}); - for (int i = 15; i <= 32; i++) { - buffer[i] = { i * i }; - } - validatePresentPhases(buffer, {28, 29, 30, 31, 32}); + buffer.resize(5); + validatePresentPhases(buffer, {11, 12, 13, 14, 15}); + validateMissingPhases(buffer, {6, 7, 8, 9, 10}); - buffer.resize(9); + for (int i = 15; i <= 32; i++) { + buffer[i] = {i * i}; + } + validatePresentPhases(buffer, {28, 29, 30, 31, 32}); + validateMissingPhases(buffer, {11, 12, 13, 14, 15}); - for (int i = 33; i <= 35; i++) { - buffer[i] = { i * i }; - } - validatePresentPhases(buffer, {28, 29, 30, 31, 32, 33, 34, 35}); + buffer.resize(9); - buffer.resize(1); - validatePresentPhases(buffer, {35}); + for (int i = 33; i <= 35; i++) { + buffer[i] = {i * i}; + } + validatePresentPhases(buffer, {28, 29, 30, 31, 32, 33, 34, 35}); + + buffer.resize(1); + validatePresentPhases(buffer, {35}); + validateMissingPhases(buffer, {28, 29, 30, 31, 32, 33, 34, 35}); } -TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_resize_sparse) { - util::container::CircularPhasesBuffer buffer{10}; +TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_forward_iter) { + util::container::CircularPhasesBuffer buffer; + + for (auto&& ele : buffer) { + // This will never be called. + EXPECT_EQ(true, false) << "Unexpected phase: " << ele.first; + } + + buffer.resize(4); - buffer[1] = { 1 }; - buffer[4] = { 16 }; - buffer[7] = { 49 }; + for (auto&& ele : buffer) { + // This will never be called. + EXPECT_EQ(true, false) << "Unexpected phase: " << ele.first; + } - { - std::vector expected = {1, 4, 7}; - validatePresentPhases(buffer, expected); + buffer[0] = {0}; + buffer[1] = {1}; + buffer[2] = {4}; - std::vector visited; - for(auto&& ele : buffer) { - visited.push_back(ele.first); - EXPECT_EQ(ele.first * ele.first, ele.second.x); - } - EXPECT_TRUE(std::equal(visited.begin(), visited.end(), expected.begin())); + { + std::vector expected = {0, 1, 2}; + std::vector visited; + for (auto&& ele : buffer) { + visited.push_back(ele.first); + EXPECT_EQ(ele.first * ele.first, ele.second.x); } + EXPECT_TRUE(std::equal(visited.begin(), visited.end(), expected.begin())); + } + + buffer[3] = {9}; - buffer.resize(4); + { + std::vector expected = {0, 1, 2, 3}; + std::vector visited; + for (auto&& ele : buffer) { + visited.push_back(ele.first); + EXPECT_EQ(ele.first * ele.first, ele.second.x); + } + EXPECT_TRUE(std::equal(visited.begin(), visited.end(), expected.begin())); + } - { - std::vector expected = {1, 4, 7}; - validatePresentPhases(buffer, expected); + buffer[4] = {16}; + buffer[5] = {25}; + buffer[6] = {36}; - std::vector visited; - for(auto&& ele : buffer) { - visited.push_back(ele.first); - EXPECT_EQ(ele.first * ele.first, ele.second.x); - } - EXPECT_TRUE(std::equal(visited.begin(), visited.end(), expected.begin())); + { + std::vector expected = {3, 4, 5, 6}; + std::vector visited; + for (auto&& ele : buffer) { + visited.push_back(ele.first); + EXPECT_EQ(ele.first * ele.first, ele.second.x); } + EXPECT_TRUE(std::equal(visited.begin(), visited.end(), expected.begin())); + } - // All of the elements will have the same % result. Expect only the last one - buffer.resize(3); + buffer.clear(); - { - std::vector expected = {7}; - validatePresentPhases(buffer, expected); + for (auto&& ele : buffer) { + // This will never be called. + EXPECT_EQ(true, false) << "Unexpected phase: " << ele.first; + } - std::vector visited; - for(auto&& ele : buffer) { - visited.push_back(ele.first); - EXPECT_EQ(ele.first * ele.first, ele.second.x); - } - EXPECT_TRUE(std::equal(visited.begin(), visited.end(), expected.begin())); - } + buffer.resize(0); - EXPECT_EQ(true, false); + for (auto&& ele : buffer) { + // This will never be called. + EXPECT_EQ(true, false) << "Unexpected phase: " << ele.first; + } } }}} /* end namespace vt::tests::unit */ From 86c60dea78bd558bea187de9aaaa4a2bc2eca1c2 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 19 Dec 2023 13:26:18 +0100 Subject: [PATCH 28/82] #1934: Avoid crashing when container was not resized yet --- src/vt/elm/elm_lb_data.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vt/elm/elm_lb_data.h b/src/vt/elm/elm_lb_data.h index b203b8dcdc..d28fc95697 100644 --- a/src/vt/elm/elm_lb_data.h +++ b/src/vt/elm/elm_lb_data.h @@ -135,11 +135,11 @@ struct ElementLBData { TimeType cur_time_ = TimeType{0.0}; PhaseType cur_phase_ = fst_lb_phase; util::container::CircularPhasesBuffer phase_timings_ = {1}; - util::container::CircularPhasesBuffer phase_comm_ = {}; + util::container::CircularPhasesBuffer phase_comm_ = {1}; SubphaseType cur_subphase_ = 0; util::container::CircularPhasesBuffer> subphase_timings_ = {1}; - util::container::CircularPhasesBuffer> subphase_comm_ = {}; + util::container::CircularPhasesBuffer> subphase_comm_ = {1}; }; }} /* end namespace vt::elm */ From 76a65ec739e3ee84ced3fca701e7a3ddd73a9ffa Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 19 Dec 2023 13:26:44 +0100 Subject: [PATCH 29/82] #1934: Finish first version of the CirculaPhasesBuffer --- .../utils/container/circular_phases_buffer.h | 70 +++++++++++-------- 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/src/vt/utils/container/circular_phases_buffer.h b/src/vt/utils/container/circular_phases_buffer.h index 8643da4ae2..7eed660c2d 100644 --- a/src/vt/utils/container/circular_phases_buffer.h +++ b/src/vt/utils/container/circular_phases_buffer.h @@ -48,9 +48,6 @@ namespace vt { namespace util { namespace container { -constexpr PhaseType invalid_ = -1; - -// Circular Buffer which can store continuous phases data template struct CircularPhasesBuffer { using StoredPair = std::pair; @@ -106,7 +103,7 @@ struct CircularPhasesBuffer { } bool contains(const PhaseType phase) const { - if (vector_.empty()) { + if (!isInitialized()) { return false; } return vector_[phase % vector_.size()].first == phase; @@ -130,41 +127,52 @@ struct CircularPhasesBuffer { }); } + std::size_t capacity() const { + return vector_.size(); + } + + bool isInitialized() const { + return vector_.size() > 0; + } + void resize(std::size_t new_size) { - vtAssert(new_size != 0, "Logic error: Trying to resize buffer to size 0."); - if (new_size == vector_.size()) { return; } + if (new_size == 0) { + head_phase_ = invalid_; + } - auto new_vec = std::vector(new_size, StoredPair{invalid_, StoredType{}}); + if (new_size != vector_.size()) { + auto new_vec = std::vector(new_size, StoredPair{invalid_, StoredType{}}); - if (new_size < vector_.size()) { - std::size_t count = 0; - std::size_t index = head_phase_ % vector_.size(); + if (new_size < size()) { + std::size_t count = 0; + std::size_t index = head_phase_ % vector_.size(); - for(; count < new_size; index--, count++) { - auto pair = vector_[index]; - if (pair.first != invalid_) { - new_vec[pair.first % new_size] = std::move(pair); - } + for(; count < new_size; index--, count++) { + auto pair = vector_[index]; + if (pair.first != invalid_) { + new_vec[pair.first % new_size] = std::move(pair); + } - if (index == 0) { - index = vector_.size(); + if (index == 0) { + index = vector_.size(); + } } - } - } else { - for(auto pair : vector_) { - if (pair.first != invalid_) { - new_vec[pair.first % new_size] = std::move(pair); + } else { + for(auto pair : vector_) { + if (pair.first != invalid_) { + new_vec[pair.first % new_size] = std::move(pair); + } } } - } - vector_.swap(new_vec); + vector_.swap(new_vec); + } } void clear() { auto new_vec = std::vector(vector_.size(), StoredPair{invalid_, StoredType{}}); vector_.swap(new_vec); - head_phase_ = 0; + head_phase_ = invalid_; } template @@ -177,6 +185,8 @@ struct CircularPhasesBuffer { PhaseType head_phase_; std::vector vector_; + static const constexpr PhaseType invalid_ = std::numeric_limits::max(); + public: template class PhaseIterator { @@ -192,7 +202,7 @@ struct CircularPhasesBuffer { PhaseIterator& operator++() { // If already on the head then jump to end if (pos_ == head_) { - pos_ = invalid_; + pos_ = buffer_->size(); return *this; } @@ -225,11 +235,15 @@ struct CircularPhasesBuffer { }; auto begin() { - return PhaseIterator(&vector_, firstPhase(), head_phase_ % vector_.size()); + if (head_phase_ != invalid_) { + return PhaseIterator(&vector_, firstPhase() % vector_.size(), head_phase_ % vector_.size()); + } else { + return end(); + } } auto end() { - return PhaseIterator(&vector_, invalid_, head_phase_ % vector_.size()); + return PhaseIterator(&vector_, vector_.size(), head_phase_ % vector_.size()); } // maybe better to track tail From c5772d9ac9add300b917cdd38a1dde1f2ab56510 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Wed, 20 Dec 2023 21:09:39 +0100 Subject: [PATCH 30/82] #1934: Update tests for CircularPhasesBuffer --- .../test_model_linear_model.nompi.cc | 1 + .../collection/test_model_raw_data.nompi.cc | 12 ++-- .../test_circular_phases_buffer.nompi.cc | 62 ++++++++++++------- 3 files changed, 48 insertions(+), 27 deletions(-) diff --git a/tests/unit/collection/test_model_linear_model.nompi.cc b/tests/unit/collection/test_model_linear_model.nompi.cc index 1bdffb8a3b..7b603b045b 100644 --- a/tests/unit/collection/test_model_linear_model.nompi.cc +++ b/tests/unit/collection/test_model_linear_model.nompi.cc @@ -111,6 +111,7 @@ TEST_F(TestLinearModel, test_model_linear_model_1) { {ElementIDStruct{1,this_node}, {LoadType{10}, {}}}, {ElementIDStruct{2,this_node}, {LoadType{40}, {}}} }}}; + proc_loads.resize(num_test_interations + 1); test_model->setLoads(&proc_loads, nullptr, nullptr); test_model->updateLoads(0); diff --git a/tests/unit/collection/test_model_raw_data.nompi.cc b/tests/unit/collection/test_model_raw_data.nompi.cc index 2b3caaeb62..cf181bf2df 100644 --- a/tests/unit/collection/test_model_raw_data.nompi.cc +++ b/tests/unit/collection/test_model_raw_data.nompi.cc @@ -129,12 +129,6 @@ TEST_F(TestRawData, test_model_raw_user_data) { auto test_model = std::make_shared(); - vt::util::container::CircularPhasesBuffer proc_loads; - vt::util::container::CircularPhasesBuffer user_data; - test_model->setLoads(&proc_loads, nullptr, &user_data); - EXPECT_TRUE(test_model->hasRawLoad()); - EXPECT_TRUE(test_model->hasUserData()); - ElementIDStruct id1{1,this_node}; ElementIDStruct id2{2,this_node}; @@ -156,6 +150,12 @@ TEST_F(TestRawData, test_model_raw_user_data) { DataMapType{{id2, ElmUserDataType{{"x", 1}, {"y", 2}}}} }; + vt::util::container::CircularPhasesBuffer proc_loads{load_holder.size()}; + vt::util::container::CircularPhasesBuffer user_data{user_holder.size()}; + test_model->setLoads(&proc_loads, nullptr, &user_data); + EXPECT_TRUE(test_model->hasRawLoad()); + EXPECT_TRUE(test_model->hasUserData()); + for (size_t iter = 0; iter < load_holder.size(); ++iter) { proc_loads[iter] = load_holder[iter]; user_data[iter] = user_holder[iter]; diff --git a/tests/unit/utils/test_circular_phases_buffer.nompi.cc b/tests/unit/utils/test_circular_phases_buffer.nompi.cc index fbb1d4a06f..1bfdddd514 100644 --- a/tests/unit/utils/test_circular_phases_buffer.nompi.cc +++ b/tests/unit/utils/test_circular_phases_buffer.nompi.cc @@ -58,8 +58,8 @@ void validatePresentPhases( util::container::CircularPhasesBuffer& buffer, std::vector expected) { for (auto&& phase : expected) { - EXPECT_TRUE(buffer.contains(phase)) << "phase: " << phase; - EXPECT_EQ(phase * phase, buffer[phase].x) << "phase: " << phase; + EXPECT_TRUE(buffer.contains(phase)) << "Phase: " << phase; + EXPECT_EQ(phase * phase, buffer[phase].x) << "Phase: " << phase; } } @@ -67,7 +67,7 @@ void validateMissingPhases( util::container::CircularPhasesBuffer& buffer, std::vector expected) { for (auto&& phase : expected) { - EXPECT_FALSE(buffer.contains(phase)) << "phase: " << phase; + EXPECT_FALSE(buffer.contains(phase)) << "Phase: " << phase; } } @@ -76,33 +76,61 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_empty) { EXPECT_FALSE(buffer.isInitialized()); EXPECT_EQ(std::size_t{0}, buffer.capacity()); - EXPECT_FALSE(buffer.contains(3)); - EXPECT_FALSE(buffer.contains(10)); + EXPECT_FALSE(buffer.contains(0)); EXPECT_EQ(std::size_t{0}, buffer.size()); + EXPECT_EQ(std::size_t{0}, buffer.numFree()); + EXPECT_TRUE(buffer.empty()); buffer.resize(2); EXPECT_TRUE(buffer.isInitialized()); EXPECT_EQ(std::size_t{2}, buffer.capacity()); - EXPECT_FALSE(buffer.contains(3)); - EXPECT_FALSE(buffer.contains(10)); + EXPECT_FALSE(buffer.contains(0)); EXPECT_EQ(std::size_t{0}, buffer.size()); + EXPECT_EQ(std::size_t{2}, buffer.numFree()); + EXPECT_TRUE(buffer.empty()); buffer.clear(); EXPECT_TRUE(buffer.isInitialized()); EXPECT_EQ(std::size_t{2}, buffer.capacity()); - EXPECT_FALSE(buffer.contains(3)); - EXPECT_FALSE(buffer.contains(10)); + EXPECT_FALSE(buffer.contains(1)); EXPECT_EQ(std::size_t{0}, buffer.size()); + EXPECT_EQ(std::size_t{2}, buffer.numFree()); + EXPECT_TRUE(buffer.empty()); buffer.resize(0); EXPECT_FALSE(buffer.isInitialized()); EXPECT_EQ(std::size_t{0}, buffer.capacity()); - EXPECT_FALSE(buffer.contains(3)); - EXPECT_FALSE(buffer.contains(10)); + EXPECT_FALSE(buffer.contains(1)); EXPECT_EQ(std::size_t{0}, buffer.size()); + EXPECT_EQ(std::size_t{0}, buffer.numFree()); + EXPECT_TRUE(buffer.empty()); + + buffer.resize(4); + buffer[0] = {0}; + + // head_ > tail_ + EXPECT_TRUE(buffer.isInitialized()); + EXPECT_EQ(std::size_t{4}, buffer.capacity()); + EXPECT_TRUE(buffer.contains(0)); + EXPECT_EQ(std::size_t{1}, buffer.size()); + EXPECT_EQ(std::size_t{3}, buffer.numFree()); + EXPECT_FALSE(buffer.empty()); + + buffer[1] = {1}; + buffer[2] = {4}; + buffer[3] = {6}; + buffer[4] = {8}; + + // head_ < tail_ + EXPECT_TRUE(buffer.isInitialized()); + EXPECT_EQ(std::size_t{4}, buffer.capacity()); + EXPECT_TRUE(buffer.contains(1)); + EXPECT_EQ(std::size_t{4}, buffer.size()); + EXPECT_EQ(std::size_t{0}, buffer.numFree()); + EXPECT_FALSE(buffer.empty()); } TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_store) { @@ -117,17 +145,9 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_store) { } std::vector finalOutput = {5, 6, 7, 8, 9, 10, 11, 12, 13, 14}; validatePresentPhases(buffer, finalOutput); - - std::vector visited; - for (auto&& ele : buffer) { - visited.push_back(ele.first); - EXPECT_EQ(ele.first * ele.first, ele.second.x) << "phase: " << ele.first; - } - EXPECT_TRUE(std::equal(visited.begin(), visited.end(), finalOutput.begin())); } -TEST_F( - TestCircularPhasesBuffer, test_circular_phases_buffer_resize_continuous) { +TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_resize_continuous) { util::container::CircularPhasesBuffer buffer{1}; buffer[0] = {0}; @@ -160,7 +180,7 @@ TEST_F( buffer.resize(1); validatePresentPhases(buffer, {35}); - validateMissingPhases(buffer, {28, 29, 30, 31, 32, 33, 34, 35}); + validateMissingPhases(buffer, {28, 29, 30, 31, 32, 33, 34}); } TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_forward_iter) { From 2c2db3de7856bc7b6124f7192dba184e7fa9af71 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Wed, 20 Dec 2023 21:23:55 +0100 Subject: [PATCH 31/82] #1934: Update implementation of CirculaPhasesBuffer --- .../utils/container/circular_phases_buffer.h | 201 ++++++++++-------- 1 file changed, 111 insertions(+), 90 deletions(-) diff --git a/src/vt/utils/container/circular_phases_buffer.h b/src/vt/utils/container/circular_phases_buffer.h index 7eed660c2d..556afa5fbf 100644 --- a/src/vt/utils/container/circular_phases_buffer.h +++ b/src/vt/utils/container/circular_phases_buffer.h @@ -53,7 +53,7 @@ struct CircularPhasesBuffer { using StoredPair = std::pair; CircularPhasesBuffer(std::size_t capacity = 0) - : head_phase_(invalid_), vector_(capacity, StoredPair{invalid_, StoredType{}}) + : vector_(capacity, StoredPair{invalid_, StoredType{}}) { } CircularPhasesBuffer(std::initializer_list list) { @@ -65,127 +65,169 @@ struct CircularPhasesBuffer { // store, override StoredType if present on the same index void store(const PhaseType phase, StoredType&& obj) { - vector_[phase % vector_.size()] = std::make_pair(phase, std::move(obj)); - head_phase_ = phase; + moveHeadAndTail(); + vector_[head_] = std::make_pair(phase, std::move(obj)); } // store, override StoredType if present on the same index void store(const PhaseType phase, StoredType const& obj) { - vector_[phase % vector_.size()] = std::make_pair(phase, obj); - head_phase_ = phase; + moveHeadAndTail(); + vector_[head_] = std::make_pair(phase, obj); } - StoredType& emplace(const PhaseType phase) { - store(phase, StoredType{}); - return vector_[phase % vector_.size()].second; + bool contains(const PhaseType phase) const { + return !empty() && phase <= vector_[head_].first && phase >= vector_[tail_].first; + } + + // map style operator - get reference to exsiting or newly inserted element + StoredType& operator[](const PhaseType phase) { + if (!contains(phase)) { + store(phase, StoredType{}); + } + return vector_[phaseToPos(phase)].second; } const StoredType* find(const PhaseType phase) const { if (contains(phase)) { - return &vector_[phase % vector_.size()].second; + return &vector_[phaseToPos(phase)].second; } return nullptr; } StoredType* find(const PhaseType phase) { if (contains(phase)) { - return &vector_[phase % vector_.size()].second; + return &vector_[phaseToPos(phase)].second; } return nullptr; } - // map style operator - get reference to exsiting or newly inserted element - StoredType& operator[](const PhaseType phase) { - if (!contains(phase)) { - store(phase, StoredType{}); - } - return vector_[phase % vector_.size()].second; - } - - bool contains(const PhaseType phase) const { - if (!isInitialized()) { - return false; - } - return vector_[phase % vector_.size()].first == phase; - } - const StoredType& at(const PhaseType phase) const { vtAssert(contains(phase), "Buffer don't contain requested phase."); - return vector_[phase % vector_.size()].second; + return vector_[phaseToPos(phase)].second; } StoredType& at(const PhaseType phase) { vtAssert(contains(phase), "Buffer don't contain requested phase."); - return vector_[phase % vector_.size()].second; - } - - std::size_t size() const { - return std::count_if(vector_.begin(), vector_.end(), [](const StoredPair& pair){ - return pair.first != invalid_; - }); - } - - std::size_t capacity() const { - return vector_.size(); - } - - bool isInitialized() const { - return vector_.size() > 0; + return vector_[phaseToPos(phase)].second; } void resize(std::size_t new_size) { if (new_size == 0) { - head_phase_ = invalid_; + resetIndexes(); } if (new_size != vector_.size()) { auto new_vec = std::vector(new_size, StoredPair{invalid_, StoredType{}}); if (new_size < size()) { - std::size_t count = 0; - std::size_t index = head_phase_ % vector_.size(); - - for(; count < new_size; index--, count++) { - auto pair = vector_[index]; - if (pair.first != invalid_) { - new_vec[pair.first % new_size] = std::move(pair); - } - - if (index == 0) { - index = vector_.size(); - } + auto tmp_tail = head_ - new_size + 1; + if (tmp_tail < 0) { + tmp_tail += size(); } - } else { - for(auto pair : vector_) { - if (pair.first != invalid_) { - new_vec[pair.first % new_size] = std::move(pair); - } + + for(int i = 0; tmp_tail != getNextEntry(head_);) { + new_vec[i++] = std::move(vector_[tmp_tail]); + tmp_tail = getNextEntry(tmp_tail); } + + head_ = new_size - 1; + tail_ = 0; + + } else if (!empty()) { + int i = 0; + for(auto&& pair : *this) { + new_vec[i++] = std::move(pair); + } + + head_ = --i; + tail_ = 0; } vector_.swap(new_vec); } } + std::size_t size() const { + return capacity() - numFree(); + } + + int numFree() const { + if (empty()) { + return capacity(); + } else if (head_ == tail_) { + return capacity() - 1; + } else if (head_ < tail_) { + return tail_ - head_ - 1; + } else { + return capacity() + tail_ - head_ - 1; + } + } + + bool empty() const { + return head_ == invalid_index_ && tail_ == invalid_index_; + } + + std::size_t capacity() const { + return vector_.size(); + } + + bool isInitialized() const { + return capacity() > 0; + } + void clear() { auto new_vec = std::vector(vector_.size(), StoredPair{invalid_, StoredType{}}); vector_.swap(new_vec); - head_phase_ = invalid_; + resetIndexes(); } template void serialize(SerializeT& s) { - s | head_phase_; + s | head_; + s | tail_; s | vector_; } private: - PhaseType head_phase_; + inline std::size_t phaseToPos(PhaseType phase) const { + auto go_back = vector_[head_].first - phase; + if (go_back > head_) { + return vector_.size() - (go_back - head_); + } + return head_ - go_back; + } + + inline std::size_t getNextEntry(std::size_t index) const { + auto next_entry = index + 1; + if (next_entry == capacity()) { + next_entry = 0; + } + return next_entry; + } + + inline void moveHeadAndTail() { + head_ = getNextEntry(head_); + if (head_ == tail_) { + tail_ = getNextEntry(tail_); + } else if (tail_ == invalid_index_) { + tail_ = 0; + } + } + + inline void resetIndexes() { + head_ = invalid_index_; + tail_ = invalid_index_; + } + +private: + std::size_t head_ = invalid_index_; + std::size_t tail_ = invalid_index_; std::vector vector_; static const constexpr PhaseType invalid_ = std::numeric_limits::max(); + static const constexpr std::size_t invalid_index_ = std::numeric_limits::max(); public: template @@ -200,19 +242,15 @@ struct CircularPhasesBuffer { } PhaseIterator& operator++() { - // If already on the head then jump to end if (pos_ == head_) { pos_ = buffer_->size(); return *this; } - // find next valid phase - sparse phases or not full buffer - do { - ++pos_; - if (pos_ == buffer_->size()) { - pos_ = 0; - } - } while ((*buffer_)[pos_].first == invalid_); + ++pos_; + if (pos_ == buffer_->size()) { + pos_ = 0; + } return *this; } @@ -235,32 +273,15 @@ struct CircularPhasesBuffer { }; auto begin() { - if (head_phase_ != invalid_) { - return PhaseIterator(&vector_, firstPhase() % vector_.size(), head_phase_ % vector_.size()); - } else { + if (empty()) { return end(); } + return PhaseIterator(&vector_, tail_, head_); } auto end() { - return PhaseIterator(&vector_, vector_.size(), head_phase_ % vector_.size()); + return PhaseIterator(&vector_, vector_.size(), vector_.size()); } - - // maybe better to track tail - PhaseType firstPhase() { - auto lowest_phase = head_phase_; - for(auto&& pair : vector_) { - if (pair.first < lowest_phase) { - lowest_phase = pair.first; - } - } - return lowest_phase; - } - - PhaseType lastPhase() { - return head_phase_; - } - }; }}} /* end namespace vt::util::container */ From 0be51a43cff48daf24e17083bd919069ddfbc6ff Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Wed, 20 Dec 2023 22:11:16 +0100 Subject: [PATCH 32/82] #1934: Add documentation for CirculalPhasesBuffer --- .../utils/container/circular_phases_buffer.h | 516 +++++++++++------- 1 file changed, 318 insertions(+), 198 deletions(-) diff --git a/src/vt/utils/container/circular_phases_buffer.h b/src/vt/utils/container/circular_phases_buffer.h index 556afa5fbf..2e659b6593 100644 --- a/src/vt/utils/container/circular_phases_buffer.h +++ b/src/vt/utils/container/circular_phases_buffer.h @@ -48,240 +48,360 @@ namespace vt { namespace util { namespace container { -template +/** + * \struct CircularPhasesBuffer + * + * \brief The circular buffer which holds data related to a continuous set of phases. + * PhaseType is used as a key when storing or retrieving data. + */ +template struct CircularPhasesBuffer { - using StoredPair = std::pair; - - CircularPhasesBuffer(std::size_t capacity = 0) - : vector_(capacity, StoredPair{invalid_, StoredType{}}) - { } - - CircularPhasesBuffer(std::initializer_list list) { - vector_.resize(list.size()); - for (auto&& pair : list) { - store(pair.first, std::move(pair.second)); - } + using StoredPair = std::pair; + + /** + * \brief Construct a CircularPhasesBuffer + * + * \param[in] capacity the requested capacity of the buffer + */ + CircularPhasesBuffer(std::size_t capacity = 0) + : vector_(capacity, StoredPair{invalid_, StoredType{}}) { } + + /** + * \brief Construct a CircularPhasesBuffer. The size of buffer will be equal to the size of the list + * + * \param[in] list the initializer list with elements to be put into the buffer + */ + CircularPhasesBuffer(std::initializer_list list) { + vector_.resize(list.size()); + for (auto&& pair : list) { + store(pair.first, std::move(pair.second)); } - - // store, override StoredType if present on the same index - void store(const PhaseType phase, StoredType&& obj) { - moveHeadAndTail(); - vector_[head_] = std::make_pair(phase, std::move(obj)); + } + + /** + * \brief Store data in the buffer + * + * \param[in] phase the phase for which data will be stored + * \param[in] obj the data to store + */ + void store(const PhaseType phase, StoredType&& obj) { + moveHeadAndTail(); + vector_[head_] = std::make_pair(phase, std::move(obj)); + } + + /** + * \brief Store data in the buffer + * + * \param[in] phase the phase for which data will be stored + * \param[in] obj the data to store + */ + void store(const PhaseType phase, StoredType const& obj) { + moveHeadAndTail(); + vector_[head_] = std::make_pair(phase, obj); + } + + /** + * \brief Check if phase is present in the buffer + * + * \param[in] phase the phase to look for + * + * \return whether buffer contains the phase or not + */ + bool contains(const PhaseType phase) const { + return !empty() && phase <= vector_[head_].first && + phase >= vector_[tail_].first; + } + + /** + * \brief Get data related to the phase. Insert new data if phase is not present in the buffer. + * + * \param[in] phase the phase to look for + * + * \return reference to the stored data + */ + StoredType& operator[](const PhaseType phase) { + if (!contains(phase)) { + store(phase, StoredType{}); } - - // store, override StoredType if present on the same index - void store(const PhaseType phase, StoredType const& obj) { - moveHeadAndTail(); - vector_[head_] = std::make_pair(phase, obj); + return vector_[phaseToPos(phase)].second; + } + + /** + * \brief Find data related to the phase. + * + * \param[in] phase the phase to look for + * + * \return pointer to the stored data or null if not present + */ + const StoredType* find(const PhaseType phase) const { + if (contains(phase)) { + return &vector_[phaseToPos(phase)].second; } - - bool contains(const PhaseType phase) const { - return !empty() && phase <= vector_[head_].first && phase >= vector_[tail_].first; + return nullptr; + } + + /** + * \brief Find data related to the phase. + * + * \param[in] phase the phase to look for + * + * \return pointer to the stored data or null if not present + */ + StoredType* find(const PhaseType phase) { + if (contains(phase)) { + return &vector_[phaseToPos(phase)].second; } - - // map style operator - get reference to exsiting or newly inserted element - StoredType& operator[](const PhaseType phase) { - if (!contains(phase)) { - store(phase, StoredType{}); - } - return vector_[phaseToPos(phase)].second; + return nullptr; + } + + /** + * \brief Get data related to the phase. Throws and exception if phase is not present. + * + * \param[in] phase the phase to look for + * + * \return reference to the stored data + */ + const StoredType& at(const PhaseType phase) const { + vtAssert(contains(phase), "Buffer don't contain requested phase."); + + return vector_[phaseToPos(phase)].second; + } + + /** + * \brief Get data related to the phase. Throws and exception if phase is not present. + * + * \param[in] phase the phase to look for + * + * \return reference to the stored data + */ + StoredType& at(const PhaseType phase) { + vtAssert(contains(phase), "Buffer don't contain requested phase."); + + return vector_[phaseToPos(phase)].second; + } + + /** + * \brief Resize buffer to the requested new_size + * + * \param[in] new_size the requested new size of the buffer + */ + void resize(std::size_t new_size) { + if (new_size == 0) { + resetIndexes(); } - const StoredType* find(const PhaseType phase) const { - if (contains(phase)) { - return &vector_[phaseToPos(phase)].second; - } - return nullptr; - } + if (new_size != vector_.size()) { + auto new_vec = + std::vector(new_size, StoredPair{invalid_, StoredType{}}); - StoredType* find(const PhaseType phase) { - if (contains(phase)) { - return &vector_[phaseToPos(phase)].second; + if (new_size < size()) { + auto tmp_tail = head_ - new_size + 1; + if (tmp_tail < 0) { + tmp_tail += size(); } - return nullptr; - } - - const StoredType& at(const PhaseType phase) const { - vtAssert(contains(phase), "Buffer don't contain requested phase."); - - return vector_[phaseToPos(phase)].second; - } - StoredType& at(const PhaseType phase) { - vtAssert(contains(phase), "Buffer don't contain requested phase."); - - return vector_[phaseToPos(phase)].second; - } - - void resize(std::size_t new_size) { - if (new_size == 0) { - resetIndexes(); + for (int i = 0; tmp_tail != getNextEntry(head_);) { + new_vec[i++] = std::move(vector_[tmp_tail]); + tmp_tail = getNextEntry(tmp_tail); } - if (new_size != vector_.size()) { - auto new_vec = std::vector(new_size, StoredPair{invalid_, StoredType{}}); - - if (new_size < size()) { - auto tmp_tail = head_ - new_size + 1; - if (tmp_tail < 0) { - tmp_tail += size(); - } - - for(int i = 0; tmp_tail != getNextEntry(head_);) { - new_vec[i++] = std::move(vector_[tmp_tail]); - tmp_tail = getNextEntry(tmp_tail); - } - - head_ = new_size - 1; - tail_ = 0; - - } else if (!empty()) { - int i = 0; - for(auto&& pair : *this) { - new_vec[i++] = std::move(pair); - } - - head_ = --i; - tail_ = 0; - } - - vector_.swap(new_vec); - } - } - - std::size_t size() const { - return capacity() - numFree(); - } + head_ = new_size - 1; + tail_ = 0; - int numFree() const { - if (empty()) { - return capacity(); - } else if (head_ == tail_) { - return capacity() - 1; - } else if (head_ < tail_) { - return tail_ - head_ - 1; - } else { - return capacity() + tail_ - head_ - 1; + } else if (!empty()) { + int i = 0; + for (auto&& pair : *this) { + new_vec[i++] = std::move(pair); } - } - - bool empty() const { - return head_ == invalid_index_ && tail_ == invalid_index_; - } - std::size_t capacity() const { - return vector_.size(); - } + head_ = --i; + tail_ = 0; + } - bool isInitialized() const { - return capacity() > 0; + vector_.swap(new_vec); } - - void clear() { - auto new_vec = std::vector(vector_.size(), StoredPair{invalid_, StoredType{}}); - vector_.swap(new_vec); - resetIndexes(); - } - - template - void serialize(SerializeT& s) { - s | head_; - s | tail_; - s | vector_; + } + + /** + * \brief Get current size of the buffer + * + * \return the current size + */ + std::size_t size() const { return capacity() - numFree(); } + + /** + * \brief Get number of free spaces in the buffer + * + * \return the number free spaces in the buffer + */ + int numFree() const { + if (empty()) { + return capacity(); + } else if (head_ == tail_) { + return capacity() - 1; + } else if (head_ < tail_) { + return tail_ - head_ - 1; + } else { + return capacity() + tail_ - head_ - 1; } + } + + /** + * \brief Check if the buffer is empty + * + * \return whetever the buffer is empty or not + */ + bool empty() const { + return head_ == invalid_index_ && tail_ == invalid_index_; + } + + /** + * \brief Get the maximum number of phases which can be stored + * + * \return the maximum number of phases + */ + std::size_t capacity() const { return vector_.size(); } + + /** + * \brief Check if the buffer is initialized + * + * \return whenever the buffer is initialized or not + */ + bool isInitialized() const { return capacity() > 0; } + + /** + * \brief Clears content of the buffer including phases and related data. Does not change the buffer maximum capacity. + */ + void clear() { + auto new_vec = std::vector( + vector_.size(), StoredPair{invalid_, StoredType{}}); + vector_.swap(new_vec); + resetIndexes(); + } + + template + void serialize(SerializeT& s) { + s | head_; + s | tail_; + s | vector_; + } private: - inline std::size_t phaseToPos(PhaseType phase) const { - auto go_back = vector_[head_].first - phase; - if (go_back > head_) { - return vector_.size() - (go_back - head_); - } - return head_ - go_back; + /** + * \brief Convert the phase number to related index in the buffer + * + * \param[in] phase the phase to convert + * + * \return the index to the phase data + */ + inline std::size_t phaseToPos(PhaseType phase) const { + auto go_back = vector_[head_].first - phase; + if (go_back > head_) { + return vector_.size() - (go_back - head_); } - - inline std::size_t getNextEntry(std::size_t index) const { - auto next_entry = index + 1; - if (next_entry == capacity()) { - next_entry = 0; - } - return next_entry; + return head_ - go_back; + } + + /** + * \brief Calculates next valid index in the buffer after the passed index + * + * \param[in] index the index to be incremented + * + * \return the incremented index + */ + inline std::size_t getNextEntry(std::size_t index) const { + auto next_entry = index + 1; + if (next_entry == capacity()) { + next_entry = 0; } - - inline void moveHeadAndTail() { - head_ = getNextEntry(head_); - if (head_ == tail_) { - tail_ = getNextEntry(tail_); - } else if (tail_ == invalid_index_) { - tail_ = 0; - } + return next_entry; + } + + /** + * \brief Update internal indexes to point to the correct spots in the buffer after inserting new element + */ + inline void moveHeadAndTail() { + head_ = getNextEntry(head_); + if (head_ == tail_) { + tail_ = getNextEntry(tail_); + } else if (tail_ == invalid_index_) { + tail_ = 0; } + } - inline void resetIndexes() { - head_ = invalid_index_; - tail_ = invalid_index_; - } + /** + * \brief Resets internal indexes to their default position + */ + inline void resetIndexes() { + head_ = invalid_index_; + tail_ = invalid_index_; + } private: - std::size_t head_ = invalid_index_; - std::size_t tail_ = invalid_index_; - std::vector vector_; + std::size_t head_ = invalid_index_; + std::size_t tail_ = invalid_index_; + std::vector vector_; - static const constexpr PhaseType invalid_ = std::numeric_limits::max(); - static const constexpr std::size_t invalid_index_ = std::numeric_limits::max(); + static const constexpr PhaseType invalid_ = + std::numeric_limits::max(); + static const constexpr std::size_t invalid_index_ = + std::numeric_limits::max(); public: - template - class PhaseIterator { - using ContainerType = std::vector; - - ContainerType * buffer_; - std::size_t pos_, head_; - public: - PhaseIterator(ContainerType *buff, std::size_t start_pos, std::size_t head_pos) - :buffer_(buff), pos_(start_pos), head_(head_pos) { - } - - PhaseIterator& operator++() { - if (pos_ == head_) { - pos_ = buffer_->size(); - return *this; - } - - ++pos_; - if (pos_ == buffer_->size()) { - pos_ = 0; - } - - return *this; - } + /** + * \struct PhaseIterator + * + * \brief The iterator for CircularPhasesBuffer. + */ + template + class PhaseIterator { + using ContainerType = std::vector; + + ContainerType* buffer_; + std::size_t pos_, head_; + + public: + PhaseIterator( + ContainerType* buff, std::size_t start_pos, std::size_t head_pos) + : buffer_(buff), + pos_(start_pos), + head_(head_pos) { } + + PhaseIterator& operator++() { + if (pos_ == head_) { + pos_ = buffer_->size(); + return *this; + } + + ++pos_; + if (pos_ == buffer_->size()) { + pos_ = 0; + } + + return *this; + } - StoredPair &operator*() { - return (*buffer_)[pos_]; - } + StoredPair& operator*() { return (*buffer_)[pos_]; } - StoredPair *operator->() { - return &(operator*()); - } + StoredPair* operator->() { return &(operator*()); } - bool operator==(const PhaseIterator &other) const { - return pos_ == other.pos_; - } - - bool operator!=(const PhaseIterator &other) const { - return pos_ != other.pos_; - } - }; + bool operator==(const PhaseIterator& other) const { + return pos_ == other.pos_; + } - auto begin() { - if (empty()) { - return end(); - } - return PhaseIterator(&vector_, tail_, head_); + bool operator!=(const PhaseIterator& other) const { + return pos_ != other.pos_; } + }; - auto end() { - return PhaseIterator(&vector_, vector_.size(), vector_.size()); + auto begin() { + if (empty()) { + return end(); } + return PhaseIterator(&vector_, tail_, head_); + } + + auto end() { return PhaseIterator(&vector_, vector_.size(), vector_.size()); } }; }}} /* end namespace vt::util::container */ From 79d8a1080c3586ff6435205c8fead1b6f50cf73e Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Thu, 21 Dec 2023 11:17:08 +0100 Subject: [PATCH 33/82] #1934: Fix compilation issue on Apple Clang --- .../utils/container/circular_phases_buffer.h | 36 ++++++++++--------- .../test_circular_phases_buffer.nompi.cc | 3 +- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/vt/utils/container/circular_phases_buffer.h b/src/vt/utils/container/circular_phases_buffer.h index 2e659b6593..0be70d3a97 100644 --- a/src/vt/utils/container/circular_phases_buffer.h +++ b/src/vt/utils/container/circular_phases_buffer.h @@ -162,7 +162,7 @@ struct CircularPhasesBuffer { * \return reference to the stored data */ const StoredType& at(const PhaseType phase) const { - vtAssert(contains(phase), "Buffer don't contain requested phase."); + vtAssert(contains(phase), "Buffer don't contain the requested phase."); return vector_[phaseToPos(phase)].second; } @@ -175,7 +175,7 @@ struct CircularPhasesBuffer { * \return reference to the stored data */ StoredType& at(const PhaseType phase) { - vtAssert(contains(phase), "Buffer don't contain requested phase."); + vtAssert(contains(phase), "Buffer don't contain the requested phase."); return vector_[phaseToPos(phase)].second; } @@ -185,15 +185,15 @@ struct CircularPhasesBuffer { * * \param[in] new_size the requested new size of the buffer */ - void resize(std::size_t new_size) { - if (new_size == 0) { - resetIndexes(); + void resize(const std::size_t new_size) { + if (new_size == vector_.size()) { + return; } - if (new_size != vector_.size()) { - auto new_vec = - std::vector(new_size, StoredPair{invalid_, StoredType{}}); + auto new_vec = + std::vector(new_size, StoredPair{invalid_, StoredType{}}); + if (new_size > 0) { if (new_size < size()) { auto tmp_tail = head_ - new_size + 1; if (tmp_tail < 0) { @@ -217,9 +217,11 @@ struct CircularPhasesBuffer { head_ = --i; tail_ = 0; } - - vector_.swap(new_vec); + } else { + resetIndexes(); } + + vector_.swap(new_vec); } /** @@ -234,7 +236,7 @@ struct CircularPhasesBuffer { * * \return the number free spaces in the buffer */ - int numFree() const { + std::size_t numFree() const { if (empty()) { return capacity(); } else if (head_ == tail_) { @@ -249,7 +251,7 @@ struct CircularPhasesBuffer { /** * \brief Check if the buffer is empty * - * \return whetever the buffer is empty or not + * \return whether the buffer is empty or not */ bool empty() const { return head_ == invalid_index_ && tail_ == invalid_index_; @@ -265,7 +267,7 @@ struct CircularPhasesBuffer { /** * \brief Check if the buffer is initialized * - * \return whenever the buffer is initialized or not + * \return whether the buffer is initialized or not */ bool isInitialized() const { return capacity() > 0; } @@ -294,7 +296,7 @@ struct CircularPhasesBuffer { * * \return the index to the phase data */ - inline std::size_t phaseToPos(PhaseType phase) const { + inline std::size_t phaseToPos(const PhaseType phase) const { auto go_back = vector_[head_].first - phase; if (go_back > head_) { return vector_.size() - (go_back - head_); @@ -309,7 +311,7 @@ struct CircularPhasesBuffer { * * \return the incremented index */ - inline std::size_t getNextEntry(std::size_t index) const { + inline std::size_t getNextEntry(const std::size_t index) const { auto next_entry = index + 1; if (next_entry == capacity()) { next_entry = 0; @@ -398,10 +400,10 @@ struct CircularPhasesBuffer { if (empty()) { return end(); } - return PhaseIterator(&vector_, tail_, head_); + return PhaseIterator(&vector_, tail_, head_); } - auto end() { return PhaseIterator(&vector_, vector_.size(), vector_.size()); } + auto end() { return PhaseIterator(&vector_, vector_.size(), vector_.size()); } }; }}} /* end namespace vt::util::container */ diff --git a/tests/unit/utils/test_circular_phases_buffer.nompi.cc b/tests/unit/utils/test_circular_phases_buffer.nompi.cc index 1bfdddd514..25e2133ef1 100644 --- a/tests/unit/utils/test_circular_phases_buffer.nompi.cc +++ b/tests/unit/utils/test_circular_phases_buffer.nompi.cc @@ -138,9 +138,10 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_store) { buffer.store(2, {2 * 2}); validatePresentPhases(buffer, {2}); + validateMissingPhases(buffer, {0, 1}); // store series of elements - for (int i = 0; i < 15; i++) { + for (int i = 3; i < 15; i++) { buffer.store(i, {i * i}); } std::vector finalOutput = {5, 6, 7, 8, 9, 10, 11, 12, 13, 14}; From e473ec9a326214630ca76737a85923a79962047d Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Fri, 29 Dec 2023 15:04:25 +0100 Subject: [PATCH 34/82] #1934: Fix NVCC warning related to unsigned variable --- src/vt/utils/container/circular_phases_buffer.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/vt/utils/container/circular_phases_buffer.h b/src/vt/utils/container/circular_phases_buffer.h index 0be70d3a97..61d0da9370 100644 --- a/src/vt/utils/container/circular_phases_buffer.h +++ b/src/vt/utils/container/circular_phases_buffer.h @@ -195,11 +195,12 @@ struct CircularPhasesBuffer { if (new_size > 0) { if (new_size < size()) { - auto tmp_tail = head_ - new_size + 1; - if (tmp_tail < 0) { - tmp_tail += size(); + int tmp = head_ - new_size + 1; + if (tmp < 0) { + tmp += size(); } + std::size_t tmp_tail = static_cast(tmp); for (int i = 0; tmp_tail != getNextEntry(head_);) { new_vec[i++] = std::move(vector_[tmp_tail]); tmp_tail = getNextEntry(tmp_tail); From 34cf664c44455dcf573281e9fc959ca93fe4c916 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 23 Apr 2024 18:01:50 +0200 Subject: [PATCH 35/82] #1934: Update implementation after resolving conflicts --- src/vt/vrt/collection/balance/lb_data_holder.h | 2 +- src/vt/vrt/collection/balance/node_lb_data.cc | 13 +++---------- tests/unit/collection/test_lb_data_retention.cc | 6 +++--- 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/src/vt/vrt/collection/balance/lb_data_holder.h b/src/vt/vrt/collection/balance/lb_data_holder.h index 715253a51c..dfdd1fa6cd 100644 --- a/src/vt/vrt/collection/balance/lb_data_holder.h +++ b/src/vt/vrt/collection/balance/lb_data_holder.h @@ -203,7 +203,7 @@ struct LBDataHolder { std::unordered_map> user_per_phase_json_; /// User-defined data from each phase for LB - std::unordered_map user_defined_lb_info_; + DataMapBufferType user_defined_lb_info_; /// User-defined attributes from each phase std::unordered_map node_user_attributes_; /// Node indices for each ID along with the proxy ID diff --git a/src/vt/vrt/collection/balance/node_lb_data.cc b/src/vt/vrt/collection/balance/node_lb_data.cc index 2422e9cccb..c38bd9246f 100644 --- a/src/vt/vrt/collection/balance/node_lb_data.cc +++ b/src/vt/vrt/collection/balance/node_lb_data.cc @@ -106,7 +106,8 @@ NodeLBData::getPhaseAttributes() const { return &lb_data_->node_user_attributes_; } -std::unordered_map const* NodeLBData::getNodeComm() const { +CommMapBufferType const* +NodeLBData::getNodeComm() const { return &lb_data_->node_comm_; } @@ -128,15 +129,7 @@ void NodeLBData::clearLBData() { next_elm_ = 1; } -void NodeLBData::startIterCleanup(PhaseType phase, unsigned int look_back) { - if (phase >= look_back) { - lb_data_->node_data_.erase(phase - look_back); - lb_data_->node_comm_.erase(phase - look_back); - lb_data_->node_subphase_comm_.erase(phase - look_back); - lb_data_->user_defined_lb_info_.erase(phase - look_back); - lb_data_->node_user_attributes_.erase(phase - look_back); - } - +void NodeLBData::startIterCleanup() { // Clear migrate lambdas and proxy lookup since LB is complete NodeLBData::node_migrate_.clear(); node_collection_lookup_.clear(); diff --git a/tests/unit/collection/test_lb_data_retention.cc b/tests/unit/collection/test_lb_data_retention.cc index e4bbeb0df6..27a7d68b42 100644 --- a/tests/unit/collection/test_lb_data_retention.cc +++ b/tests/unit/collection/test_lb_data_retention.cc @@ -65,14 +65,14 @@ void validatePersistedPhases(std::vector expected_phases) { EXPECT_EQ(expected_phases.size(), theNodeLBData()->getLBData()->node_data_.size()); EXPECT_EQ(expected_phases.size(), theNodeLBData()->getLBData()->node_subphase_comm_.size()); EXPECT_EQ(expected_phases.size(), theNodeLBData()->getLBData()->user_defined_json_.size()); - EXPECT_EQ(expected_phases.size(), theNodeLBData()->getLBData()->user_defined_lb_info_.size()); + // EXPECT_EQ(expected_phases.size(), theNodeLBData()->getLBData()->user_defined_lb_info_.size()); // Check if each phase is present for(auto&& phase : expected_phases) { EXPECT_TRUE(theNodeLBData()->getLBData()->node_comm_.contains(phase)); EXPECT_TRUE(theNodeLBData()->getLBData()->node_data_.contains(phase)); EXPECT_TRUE(theNodeLBData()->getLBData()->node_subphase_comm_.contains(phase)); EXPECT_TRUE(theNodeLBData()->getLBData()->user_defined_json_.contains(phase)); - EXPECT_TRUE(theNodeLBData()->getLBData()->user_defined_lb_info_.contains(phase)); + // EXPECT_TRUE(theNodeLBData()->getLBData()->user_defined_lb_info_.contains(phase)); } #else (void)expected_phases; @@ -89,7 +89,7 @@ struct TestCol : vt::Collection { TestCol() { // Insert dummy lb info data - valInsert("foo", 10, true, true); + valInsert("foo", 10, true, true, true); } unsigned int prevCalls() { return prev_calls_++; } From 96373a8b0658e13adfac554cf818bafd9236afa0 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 30 Apr 2024 17:52:44 +0200 Subject: [PATCH 36/82] #1934: Refactor of the CircularPhasesBuffer to be dynamic in size until specific size is requested --- .../utils/container/circular_phases_buffer.h | 278 +++++------------- .../test_circular_phases_buffer.nompi.cc | 65 +--- 2 files changed, 83 insertions(+), 260 deletions(-) diff --git a/src/vt/utils/container/circular_phases_buffer.h b/src/vt/utils/container/circular_phases_buffer.h index 61d0da9370..0eae63f43d 100644 --- a/src/vt/utils/container/circular_phases_buffer.h +++ b/src/vt/utils/container/circular_phases_buffer.h @@ -45,14 +45,15 @@ #define INCLUDED_VT_UTILS_CONTAINER_CIRCULAR_PHASES_BUFFER_H #include "vt/config.h" +#include namespace vt { namespace util { namespace container { /** * \struct CircularPhasesBuffer * - * \brief The circular buffer which holds data related to a continuous set of phases. - * PhaseType is used as a key when storing or retrieving data. + * \brief The circular buffer which holds data related to a set of phases. + * PhaseType is used as a key when storing or retrieving data. If capacity was not specified then buffer is allow to grow without limit. */ template struct CircularPhasesBuffer { @@ -63,18 +64,22 @@ struct CircularPhasesBuffer { * * \param[in] capacity the requested capacity of the buffer */ - CircularPhasesBuffer(std::size_t capacity = 0) - : vector_(capacity, StoredPair{invalid_, StoredType{}}) { } + CircularPhasesBuffer(std::size_t capacity = 0) { + m_requested_capacity = capacity; + m_buffer.reserve(capacity); + } /** - * \brief Construct a CircularPhasesBuffer. The size of buffer will be equal to the size of the list + * \brief Construct a CircularPhasesBuffer. The max size of buffer will be equal to the size of the list * * \param[in] list the initializer list with elements to be put into the buffer */ CircularPhasesBuffer(std::initializer_list list) { - vector_.resize(list.size()); + m_requested_capacity = list.size(); + m_buffer.reserve(list.size()); + for (auto&& pair : list) { - store(pair.first, std::move(pair.second)); + addToCache(std::make_pair(pair.first, pair.second)); } } @@ -85,8 +90,7 @@ struct CircularPhasesBuffer { * \param[in] obj the data to store */ void store(const PhaseType phase, StoredType&& obj) { - moveHeadAndTail(); - vector_[head_] = std::make_pair(phase, std::move(obj)); + addToCache(std::make_pair(phase, std::move(obj))); } /** @@ -96,8 +100,7 @@ struct CircularPhasesBuffer { * \param[in] obj the data to store */ void store(const PhaseType phase, StoredType const& obj) { - moveHeadAndTail(); - vector_[head_] = std::make_pair(phase, obj); + addToCache(std::make_pair(phase, obj)); } /** @@ -108,8 +111,7 @@ struct CircularPhasesBuffer { * \return whether buffer contains the phase or not */ bool contains(const PhaseType phase) const { - return !empty() && phase <= vector_[head_].first && - phase >= vector_[tail_].first; + return m_buffer.find(phase) != m_buffer.end(); } /** @@ -121,9 +123,9 @@ struct CircularPhasesBuffer { */ StoredType& operator[](const PhaseType phase) { if (!contains(phase)) { - store(phase, StoredType{}); + addToCache(std::make_pair(phase, StoredType{})); } - return vector_[phaseToPos(phase)].second; + return m_buffer[phase]; } /** @@ -134,8 +136,9 @@ struct CircularPhasesBuffer { * \return pointer to the stored data or null if not present */ const StoredType* find(const PhaseType phase) const { - if (contains(phase)) { - return &vector_[phaseToPos(phase)].second; + auto iter = m_buffer.find(phase); + if (iter != m_buffer.end()) { + return &iter->second; } return nullptr; } @@ -148,81 +151,47 @@ struct CircularPhasesBuffer { * \return pointer to the stored data or null if not present */ StoredType* find(const PhaseType phase) { - if (contains(phase)) { - return &vector_[phaseToPos(phase)].second; + auto iter = m_buffer.find(phase); + if (iter != m_buffer.end()) { + return &iter->second; } return nullptr; } /** - * \brief Get data related to the phase. Throws and exception if phase is not present. + * \brief Get data related to the phase. * * \param[in] phase the phase to look for * * \return reference to the stored data */ const StoredType& at(const PhaseType phase) const { - vtAssert(contains(phase), "Buffer don't contain the requested phase."); - - return vector_[phaseToPos(phase)].second; + return m_buffer.at(phase); } /** - * \brief Get data related to the phase. Throws and exception if phase is not present. + * \brief Get data related to the phase. * * \param[in] phase the phase to look for * * \return reference to the stored data */ - StoredType& at(const PhaseType phase) { - vtAssert(contains(phase), "Buffer don't contain the requested phase."); - - return vector_[phaseToPos(phase)].second; - } + StoredType& at(const PhaseType phase) { return m_buffer.at(phase); } /** - * \brief Resize buffer to the requested new_size + * \brief Resize buffer to the requested size * * \param[in] new_size the requested new size of the buffer */ void resize(const std::size_t new_size) { - if (new_size == vector_.size()) { - return; - } - - auto new_vec = - std::vector(new_size, StoredPair{invalid_, StoredType{}}); - - if (new_size > 0) { - if (new_size < size()) { - int tmp = head_ - new_size + 1; - if (tmp < 0) { - tmp += size(); - } - - std::size_t tmp_tail = static_cast(tmp); - for (int i = 0; tmp_tail != getNextEntry(head_);) { - new_vec[i++] = std::move(vector_[tmp_tail]); - tmp_tail = getNextEntry(tmp_tail); - } - - head_ = new_size - 1; - tail_ = 0; - - } else if (!empty()) { - int i = 0; - for (auto&& pair : *this) { - new_vec[i++] = std::move(pair); - } - - head_ = --i; - tail_ = 0; + if (new_size < m_buffer.size()) { + std::size_t remove_last = m_buffer.size() - new_size; + for (std::size_t i = 0; i < remove_last; i++) { + removeOldest(); } - } else { - resetIndexes(); } - vector_.swap(new_vec); + m_requested_capacity = new_size; } /** @@ -230,181 +199,80 @@ struct CircularPhasesBuffer { * * \return the current size */ - std::size_t size() const { return capacity() - numFree(); } - - /** - * \brief Get number of free spaces in the buffer - * - * \return the number free spaces in the buffer - */ - std::size_t numFree() const { - if (empty()) { - return capacity(); - } else if (head_ == tail_) { - return capacity() - 1; - } else if (head_ < tail_) { - return tail_ - head_ - 1; - } else { - return capacity() + tail_ - head_ - 1; - } - } + std::size_t size() const { return m_buffer.size(); } /** * \brief Check if the buffer is empty * * \return whether the buffer is empty or not */ - bool empty() const { - return head_ == invalid_index_ && tail_ == invalid_index_; - } + bool empty() const { return m_buffer.empty(); } /** - * \brief Get the maximum number of phases which can be stored - * - * \return the maximum number of phases + * \brief Clears content of the buffer. Does not change the buffer maximum capacity. */ - std::size_t capacity() const { return vector_.size(); } - - /** - * \brief Check if the buffer is initialized - * - * \return whether the buffer is initialized or not - */ - bool isInitialized() const { return capacity() > 0; } + void clear() { + std::queue empty; + m_indexes.swap(empty); + m_buffer.clear(); + } /** - * \brief Clears content of the buffer including phases and related data. Does not change the buffer maximum capacity. + * @brief Clears content of the buffer and allow the buffer maximum capacity to grow */ - void clear() { - auto new_vec = std::vector( - vector_.size(), StoredPair{invalid_, StoredType{}}); - vector_.swap(new_vec); - resetIndexes(); + void reset() { + m_requested_capacity = 0; + clear(); } template void serialize(SerializeT& s) { - s | head_; - s | tail_; - s | vector_; + s | m_requested_capacity; + // TODO: Checkpoint is not supporting the queue + // s | m_indexes; + s | m_buffer; } -private: /** - * \brief Convert the phase number to related index in the buffer - * - * \param[in] phase the phase to convert - * - * \return the index to the phase data + * @brief Get iterator to the begging of the buffer + * + * @return auto the begin iterator */ - inline std::size_t phaseToPos(const PhaseType phase) const { - auto go_back = vector_[head_].first - phase; - if (go_back > head_) { - return vector_.size() - (go_back - head_); - } - return head_ - go_back; - } + auto begin() { return m_buffer.begin(); } /** - * \brief Calculates next valid index in the buffer after the passed index - * - * \param[in] index the index to be incremented - * - * \return the incremented index + * @brief Get iterator to the space after buffer + * + * @return auto the end iterator */ - inline std::size_t getNextEntry(const std::size_t index) const { - auto next_entry = index + 1; - if (next_entry == capacity()) { - next_entry = 0; - } - return next_entry; - } + auto end() { return m_buffer.end(); } +private: /** - * \brief Update internal indexes to point to the correct spots in the buffer after inserting new element + * @brief Add new phase to the cache and remove oldest one if buffer exceeds requested size + * + * @param pair the pair to be stored */ - inline void moveHeadAndTail() { - head_ = getNextEntry(head_); - if (head_ == tail_) { - tail_ = getNextEntry(tail_); - } else if (tail_ == invalid_index_) { - tail_ = 0; + void addToCache(StoredPair&& pair) { + if (m_requested_capacity > 0 && m_buffer.size() >= m_requested_capacity) { + removeOldest(); } + m_indexes.push(pair.first); + m_buffer[pair.first] = std::move(pair.second); } /** - * \brief Resets internal indexes to their default position + * @brief Remove oldest phase from cache */ - inline void resetIndexes() { - head_ = invalid_index_; - tail_ = invalid_index_; + void removeOldest() { + m_buffer.erase(m_indexes.front()); + m_indexes.pop(); } private: - std::size_t head_ = invalid_index_; - std::size_t tail_ = invalid_index_; - std::vector vector_; - - static const constexpr PhaseType invalid_ = - std::numeric_limits::max(); - static const constexpr std::size_t invalid_index_ = - std::numeric_limits::max(); - -public: - /** - * \struct PhaseIterator - * - * \brief The iterator for CircularPhasesBuffer. - */ - template - class PhaseIterator { - using ContainerType = std::vector; - - ContainerType* buffer_; - std::size_t pos_, head_; - - public: - PhaseIterator( - ContainerType* buff, std::size_t start_pos, std::size_t head_pos) - : buffer_(buff), - pos_(start_pos), - head_(head_pos) { } - - PhaseIterator& operator++() { - if (pos_ == head_) { - pos_ = buffer_->size(); - return *this; - } - - ++pos_; - if (pos_ == buffer_->size()) { - pos_ = 0; - } - - return *this; - } - - StoredPair& operator*() { return (*buffer_)[pos_]; } - - StoredPair* operator->() { return &(operator*()); } - - bool operator==(const PhaseIterator& other) const { - return pos_ == other.pos_; - } - - bool operator!=(const PhaseIterator& other) const { - return pos_ != other.pos_; - } - }; - - auto begin() { - if (empty()) { - return end(); - } - return PhaseIterator(&vector_, tail_, head_); - } - - auto end() { return PhaseIterator(&vector_, vector_.size(), vector_.size()); } + std::size_t m_requested_capacity; + std::queue m_indexes; + std::unordered_map m_buffer; }; }}} /* end namespace vt::util::container */ diff --git a/tests/unit/utils/test_circular_phases_buffer.nompi.cc b/tests/unit/utils/test_circular_phases_buffer.nompi.cc index 25e2133ef1..9003f6c070 100644 --- a/tests/unit/utils/test_circular_phases_buffer.nompi.cc +++ b/tests/unit/utils/test_circular_phases_buffer.nompi.cc @@ -59,7 +59,7 @@ void validatePresentPhases( std::vector expected) { for (auto&& phase : expected) { EXPECT_TRUE(buffer.contains(phase)) << "Phase: " << phase; - EXPECT_EQ(phase * phase, buffer[phase].x) << "Phase: " << phase; + EXPECT_EQ(phase * phase, buffer.at(phase).x) << "Phase: " << phase; } } @@ -74,49 +74,33 @@ void validateMissingPhases( TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_empty) { util::container::CircularPhasesBuffer buffer; - EXPECT_FALSE(buffer.isInitialized()); - EXPECT_EQ(std::size_t{0}, buffer.capacity()); EXPECT_FALSE(buffer.contains(0)); EXPECT_EQ(std::size_t{0}, buffer.size()); - EXPECT_EQ(std::size_t{0}, buffer.numFree()); EXPECT_TRUE(buffer.empty()); buffer.resize(2); - EXPECT_TRUE(buffer.isInitialized()); - EXPECT_EQ(std::size_t{2}, buffer.capacity()); EXPECT_FALSE(buffer.contains(0)); EXPECT_EQ(std::size_t{0}, buffer.size()); - EXPECT_EQ(std::size_t{2}, buffer.numFree()); EXPECT_TRUE(buffer.empty()); buffer.clear(); - EXPECT_TRUE(buffer.isInitialized()); - EXPECT_EQ(std::size_t{2}, buffer.capacity()); EXPECT_FALSE(buffer.contains(1)); EXPECT_EQ(std::size_t{0}, buffer.size()); - EXPECT_EQ(std::size_t{2}, buffer.numFree()); EXPECT_TRUE(buffer.empty()); buffer.resize(0); - EXPECT_FALSE(buffer.isInitialized()); - EXPECT_EQ(std::size_t{0}, buffer.capacity()); EXPECT_FALSE(buffer.contains(1)); EXPECT_EQ(std::size_t{0}, buffer.size()); - EXPECT_EQ(std::size_t{0}, buffer.numFree()); EXPECT_TRUE(buffer.empty()); buffer.resize(4); buffer[0] = {0}; - // head_ > tail_ - EXPECT_TRUE(buffer.isInitialized()); - EXPECT_EQ(std::size_t{4}, buffer.capacity()); EXPECT_TRUE(buffer.contains(0)); EXPECT_EQ(std::size_t{1}, buffer.size()); - EXPECT_EQ(std::size_t{3}, buffer.numFree()); EXPECT_FALSE(buffer.empty()); buffer[1] = {1}; @@ -124,13 +108,15 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_empty) { buffer[3] = {6}; buffer[4] = {8}; - // head_ < tail_ - EXPECT_TRUE(buffer.isInitialized()); - EXPECT_EQ(std::size_t{4}, buffer.capacity()); EXPECT_TRUE(buffer.contains(1)); EXPECT_EQ(std::size_t{4}, buffer.size()); - EXPECT_EQ(std::size_t{0}, buffer.numFree()); EXPECT_FALSE(buffer.empty()); + + buffer.reset(); + + EXPECT_FALSE(buffer.contains(0)); + EXPECT_EQ(std::size_t{0}, buffer.size()); + EXPECT_TRUE(buffer.empty()); } TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_store) { @@ -192,52 +178,21 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_forward_iter) { EXPECT_EQ(true, false) << "Unexpected phase: " << ele.first; } - buffer.resize(4); - - for (auto&& ele : buffer) { - // This will never be called. - EXPECT_EQ(true, false) << "Unexpected phase: " << ele.first; - } - buffer[0] = {0}; buffer[1] = {1}; buffer[2] = {4}; - { - std::vector expected = {0, 1, 2}; - std::vector visited; - for (auto&& ele : buffer) { - visited.push_back(ele.first); - EXPECT_EQ(ele.first * ele.first, ele.second.x); - } - EXPECT_TRUE(std::equal(visited.begin(), visited.end(), expected.begin())); - } + validatePresentPhases(buffer, {0, 1, 2}); buffer[3] = {9}; - { - std::vector expected = {0, 1, 2, 3}; - std::vector visited; - for (auto&& ele : buffer) { - visited.push_back(ele.first); - EXPECT_EQ(ele.first * ele.first, ele.second.x); - } - EXPECT_TRUE(std::equal(visited.begin(), visited.end(), expected.begin())); - } + validatePresentPhases(buffer, {0, 1, 2, 3}); buffer[4] = {16}; buffer[5] = {25}; buffer[6] = {36}; - { - std::vector expected = {3, 4, 5, 6}; - std::vector visited; - for (auto&& ele : buffer) { - visited.push_back(ele.first); - EXPECT_EQ(ele.first * ele.first, ele.second.x); - } - EXPECT_TRUE(std::equal(visited.begin(), visited.end(), expected.begin())); - } + validatePresentPhases(buffer, {0, 1, 2, 3, 4, 5, 6}); buffer.clear(); From e0eb2bc06c29b3b1a8f2c43d4a17fe14501c1ba4 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 30 Apr 2024 17:54:48 +0200 Subject: [PATCH 37/82] #1934: Remove unnecessary resizes --- src/vt/elm/elm_lb_data.h | 8 ++++---- src/vt/vrt/collection/balance/lb_data_holder.cc | 2 +- src/vt/vrt/collection/balance/lb_data_holder.h | 9 +-------- tests/unit/collection/test_workload_data_migrator.cc | 6 +++--- 4 files changed, 9 insertions(+), 16 deletions(-) diff --git a/src/vt/elm/elm_lb_data.h b/src/vt/elm/elm_lb_data.h index d28fc95697..360f450e7d 100644 --- a/src/vt/elm/elm_lb_data.h +++ b/src/vt/elm/elm_lb_data.h @@ -134,12 +134,12 @@ struct ElementLBData { bool cur_time_started_ = false; TimeType cur_time_ = TimeType{0.0}; PhaseType cur_phase_ = fst_lb_phase; - util::container::CircularPhasesBuffer phase_timings_ = {1}; - util::container::CircularPhasesBuffer phase_comm_ = {1}; + util::container::CircularPhasesBuffer phase_timings_; + util::container::CircularPhasesBuffer phase_comm_; SubphaseType cur_subphase_ = 0; - util::container::CircularPhasesBuffer> subphase_timings_ = {1}; - util::container::CircularPhasesBuffer> subphase_comm_ = {1}; + util::container::CircularPhasesBuffer> subphase_timings_; + util::container::CircularPhasesBuffer> subphase_comm_; }; }} /* end namespace vt::elm */ diff --git a/src/vt/vrt/collection/balance/lb_data_holder.cc b/src/vt/vrt/collection/balance/lb_data_holder.cc index dfbf374754..aead88b562 100644 --- a/src/vt/vrt/collection/balance/lb_data_holder.cc +++ b/src/vt/vrt/collection/balance/lb_data_holder.cc @@ -223,7 +223,7 @@ std::unique_ptr LBDataHolder::toJson(PhaseType phase) const { } outputEntity(j["tasks"][i]["entity"], id); - if (node_user_attributes_.find(phase) != node_user_attributes_.end()) { + if (node_user_attributes_.contains(phase)) { if (node_user_attributes_.at(phase).find(id) != node_user_attributes_.at(phase).end()) { for (auto const& [key, value] : node_user_attributes_.at(phase).at(id)) { if (std::holds_alternative(value)) { diff --git a/src/vt/vrt/collection/balance/lb_data_holder.h b/src/vt/vrt/collection/balance/lb_data_holder.h index dfdd1fa6cd..fd8b0cf149 100644 --- a/src/vt/vrt/collection/balance/lb_data_holder.h +++ b/src/vt/vrt/collection/balance/lb_data_holder.h @@ -67,13 +67,6 @@ namespace vt { namespace vrt { namespace collection { namespace balance { struct LBDataHolder { LBDataHolder() = default; - /** - * \brief Create \c LBDataHolder with specified buffers capacity - * - * \param[in] initial_buffers_size the initial size of the buffers - */ - LBDataHolder(std::size_t initial_buffers_size); - /** * \brief Create \c LBDataHolder from input JSON * @@ -205,7 +198,7 @@ struct LBDataHolder { /// User-defined data from each phase for LB DataMapBufferType user_defined_lb_info_; /// User-defined attributes from each phase - std::unordered_map node_user_attributes_; + DataMapBufferType node_user_attributes_; /// Node indices for each ID along with the proxy ID std::unordered_map>> node_idx_; /// Map from id to objgroup proxy diff --git a/tests/unit/collection/test_workload_data_migrator.cc b/tests/unit/collection/test_workload_data_migrator.cc index 250f19d749..f034b30909 100644 --- a/tests/unit/collection/test_workload_data_migrator.cc +++ b/tests/unit/collection/test_workload_data_migrator.cc @@ -93,7 +93,7 @@ setupWorkloads(PhaseType phase, size_t numElements) { ); } - auto lbdh = std::make_shared(numElements); + auto lbdh = std::make_shared(); for (auto&& elmID : myElemList) { double tval = elmID.id * 2; @@ -790,7 +790,7 @@ setupManyWorkloads( ); } - auto lbdh = std::make_shared(num_phases); + auto lbdh = std::make_shared(); PhaseType stop_phase = initial_phase + num_phases; for (PhaseType phase = initial_phase; phase < stop_phase; ++phase) { @@ -804,7 +804,7 @@ setupManyWorkloads( } } - auto scrambled_lbdh = std::make_shared(num_phases); + auto scrambled_lbdh = std::make_shared(); for (PhaseType phase = initial_phase; phase < stop_phase; ++phase) { auto base_load_model = setupBaseModel(phase, lbdh); From 7a43e69c91590f711d7162f5808002228764f4c6 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 30 Apr 2024 17:55:38 +0200 Subject: [PATCH 38/82] #1934: Update unit tests to check all relevant fields in NodeLBData --- src/vt/vrt/collection/balance/node_lb_data.cc | 3 ++- src/vt/vrt/collection/balance/node_lb_data.h | 2 +- tests/unit/collection/test_lb_data_holder.cc | 2 +- .../unit/collection/test_lb_data_retention.cc | 25 +++++++++++++------ 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/vt/vrt/collection/balance/node_lb_data.cc b/src/vt/vrt/collection/balance/node_lb_data.cc index c38bd9246f..f197770163 100644 --- a/src/vt/vrt/collection/balance/node_lb_data.cc +++ b/src/vt/vrt/collection/balance/node_lb_data.cc @@ -101,7 +101,7 @@ NodeLBData::getUserData() const { return &lb_data_->user_defined_lb_info_; } -std::unordered_map const* +DataMapBufferType const* NodeLBData::getPhaseAttributes() const { return &lb_data_->node_user_attributes_; } @@ -145,6 +145,7 @@ void NodeLBData::resizeLBDataHistory(uint32_t new_hist_len) { lb_data_->node_subphase_comm_.resize(new_hist_len); lb_data_->user_defined_lb_info_.resize(new_hist_len); lb_data_->user_defined_json_.resize(new_hist_len); + lb_data_->node_user_attributes_.resize(new_hist_len); } NodeLBData::node_migrate_.clear(); diff --git a/src/vt/vrt/collection/balance/node_lb_data.h b/src/vt/vrt/collection/balance/node_lb_data.h index e6b18d6372..c39753d0cb 100644 --- a/src/vt/vrt/collection/balance/node_lb_data.h +++ b/src/vt/vrt/collection/balance/node_lb_data.h @@ -194,7 +194,7 @@ struct NodeLBData : runtime::component::Component { * * \return an observer pointer to the user-defined attributes */ - std::unordered_map const* getPhaseAttributes() const; + DataMapBufferType const* getPhaseAttributes() const; /** * \internal \brief Get stored object comm data for a specific phase diff --git a/tests/unit/collection/test_lb_data_holder.cc b/tests/unit/collection/test_lb_data_holder.cc index 6a12d1071c..dee8295a58 100644 --- a/tests/unit/collection/test_lb_data_holder.cc +++ b/tests/unit/collection/test_lb_data_holder.cc @@ -370,7 +370,7 @@ TEST_F(TestLBDataHolder, test_lb_entity_attributes) { auto id = vt::vrt::collection::balance::ElementIDStruct{524291, 0}; LBDataHolder testObj(json); - EXPECT_TRUE(testObj.node_user_attributes_.find(0) != testObj.node_user_attributes_.end()); + EXPECT_TRUE(testObj.node_user_attributes_.contains(0)); EXPECT_TRUE(testObj.node_user_attributes_[0].find(id) != testObj.node_user_attributes_[0].end()); auto attributes = testObj.node_user_attributes_[0][id]; EXPECT_EQ(123, std::get(attributes["intSample"])); diff --git a/tests/unit/collection/test_lb_data_retention.cc b/tests/unit/collection/test_lb_data_retention.cc index 27a7d68b42..e93bc710a8 100644 --- a/tests/unit/collection/test_lb_data_retention.cc +++ b/tests/unit/collection/test_lb_data_retention.cc @@ -65,14 +65,16 @@ void validatePersistedPhases(std::vector expected_phases) { EXPECT_EQ(expected_phases.size(), theNodeLBData()->getLBData()->node_data_.size()); EXPECT_EQ(expected_phases.size(), theNodeLBData()->getLBData()->node_subphase_comm_.size()); EXPECT_EQ(expected_phases.size(), theNodeLBData()->getLBData()->user_defined_json_.size()); - // EXPECT_EQ(expected_phases.size(), theNodeLBData()->getLBData()->user_defined_lb_info_.size()); + EXPECT_EQ(expected_phases.size(), theNodeLBData()->getLBData()->user_defined_lb_info_.size()); + EXPECT_EQ(expected_phases.size(), theNodeLBData()->getLBData()->node_user_attributes_.size()); // Check if each phase is present for(auto&& phase : expected_phases) { EXPECT_TRUE(theNodeLBData()->getLBData()->node_comm_.contains(phase)); EXPECT_TRUE(theNodeLBData()->getLBData()->node_data_.contains(phase)); EXPECT_TRUE(theNodeLBData()->getLBData()->node_subphase_comm_.contains(phase)); EXPECT_TRUE(theNodeLBData()->getLBData()->user_defined_json_.contains(phase)); - // EXPECT_TRUE(theNodeLBData()->getLBData()->user_defined_lb_info_.contains(phase)); + EXPECT_TRUE(theNodeLBData()->getLBData()->user_defined_lb_info_.contains(phase)); + EXPECT_TRUE(theNodeLBData()->getLBData()->node_user_attributes_.contains(phase)); } #else (void)expected_phases; @@ -81,21 +83,20 @@ void validatePersistedPhases(std::vector expected_phases) { EXPECT_EQ(0, theNodeLBData()->getLBData()->node_subphase_comm_.size()); EXPECT_EQ(0, theNodeLBData()->getLBData()->user_defined_json_.size()); EXPECT_EQ(0, theNodeLBData()->getLBData()->user_defined_lb_info_.size()); + EXPECT_EQ(0, theNodeLBData()->getLBData()->node_user_attributes_.size()); #endif } struct TestCol : vt::Collection { unsigned int prev_calls_ = thePhase()->getCurrentPhase(); - TestCol() { - // Insert dummy lb info data - valInsert("foo", 10, true, true, true); - } - unsigned int prevCalls() { return prev_calls_++; } - static void colHandler(TestCol* col) { + static void insertValue(TestCol* col) { + col->valInsert("foo", 10, true, true, true); + } + static void colHandler(TestCol* col) { auto& lb_data = col->lb_data_; auto load_phase_count = lb_data.getLoadPhaseCount(); auto comm_phase_count = lb_data.getCommPhaseCount(); @@ -174,6 +175,7 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_last1) { for (int i=0; i(); proxy.broadcastCollective(); }); // Go to the next phase. @@ -213,6 +215,7 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_last2) { for (int i=0; i(); proxy.broadcastCollective(); }); // Go to the next phase. @@ -252,6 +255,7 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_last4) { for (int i=0; i(); proxy.broadcastCollective(); }); // Go to the next phase. @@ -294,6 +298,7 @@ TEST_F(TestLBDataRetention, test_lbdata_config_retention_higher) { for (uint32_t i=0; ivt_lb_data_retention * 2; ++i) { runInEpochCollective([&]{ // Do some work. + proxy.broadcastCollective(); proxy.broadcastCollective(); }); // Go to the next phase. @@ -335,6 +340,7 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_model_switch_1) { for (uint32_t i=0; i(); proxy.broadcastCollective(); }); // Go to the next phase. @@ -353,6 +359,7 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_model_switch_1) { for (uint32_t i=0; i(); proxy.broadcastCollective(); }); // Go to the next phase. @@ -392,6 +399,7 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_model_switch_2) { for (uint32_t i=0; i(); proxy.broadcastCollective(); }); // Go to the next phase. @@ -415,6 +423,7 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_model_switch_2) { for (uint32_t i=0; i<10; ++i) { runInEpochCollective([&]{ // Do some work. + proxy.broadcastCollective(); proxy.broadcastCollective(); }); // Go to the next phase. From 376c516361017b448314cd95eac9a0bc0895ab2a Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 30 Apr 2024 17:58:47 +0200 Subject: [PATCH 39/82] #1934: Remove trailing whitespaces --- src/vt/utils/container/circular_phases_buffer.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vt/utils/container/circular_phases_buffer.h b/src/vt/utils/container/circular_phases_buffer.h index 0eae63f43d..21a96c53bb 100644 --- a/src/vt/utils/container/circular_phases_buffer.h +++ b/src/vt/utils/container/circular_phases_buffer.h @@ -235,14 +235,14 @@ struct CircularPhasesBuffer { /** * @brief Get iterator to the begging of the buffer - * + * * @return auto the begin iterator */ auto begin() { return m_buffer.begin(); } /** * @brief Get iterator to the space after buffer - * + * * @return auto the end iterator */ auto end() { return m_buffer.end(); } @@ -250,7 +250,7 @@ struct CircularPhasesBuffer { private: /** * @brief Add new phase to the cache and remove oldest one if buffer exceeds requested size - * + * * @param pair the pair to be stored */ void addToCache(StoredPair&& pair) { From 0b1fb5645f278200c53667c51e6407f7d1b218dc Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Mon, 6 May 2024 14:12:33 +0200 Subject: [PATCH 40/82] #1934: Remove usage of old LBDataHolder constructor --- tests/unit/collection/test_lb.extended.cc | 4 ++-- tests/unit/collection/test_lb_data_holder.cc | 2 +- tests/unit/lb/test_offlinelb.cc | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/unit/collection/test_lb.extended.cc b/tests/unit/collection/test_lb.extended.cc index aac84b739c..20c2f38616 100644 --- a/tests/unit/collection/test_lb.extended.cc +++ b/tests/unit/collection/test_lb.extended.cc @@ -552,7 +552,7 @@ TEST_F(TestRestoreLBData, test_restore_lb_data_data_1) { ); }); - vt::vrt::collection::balance::LBDataHolder lbdh(num_elms); + vt::vrt::collection::balance::LBDataHolder lbdh; PhaseType write_phase = 0; using CommKey = vt::elm::CommKey; @@ -747,7 +747,7 @@ TEST_P(TestDumpUserdefinedData, test_dump_userdefined_json) { ); }); - vt::vrt::collection::balance::LBDataHolder lbdh(1); + vt::vrt::collection::balance::LBDataHolder lbdh; PhaseType write_phase = 0; { diff --git a/tests/unit/collection/test_lb_data_holder.cc b/tests/unit/collection/test_lb_data_holder.cc index dee8295a58..1f3d2bdc7e 100644 --- a/tests/unit/collection/test_lb_data_holder.cc +++ b/tests/unit/collection/test_lb_data_holder.cc @@ -74,7 +74,7 @@ void addPhasesDataToJson(nlohmann::json& json, PhaseType amountOfPhasesToAdd, st } } - LBDataHolder dh(amountOfPhasesToAdd); + LBDataHolder dh; for (unsigned i = 0; i < amountOfPhasesToAdd; i++) { for (auto&& elm : ids[i]) { dh.node_data_[i][elm] = LoadSummary{3.}; diff --git a/tests/unit/lb/test_offlinelb.cc b/tests/unit/lb/test_offlinelb.cc index 5d9bcaa5a0..b470e61f1c 100644 --- a/tests/unit/lb/test_offlinelb.cc +++ b/tests/unit/lb/test_offlinelb.cc @@ -125,7 +125,7 @@ TEST_F(TestOfflineLB, test_offlinelb_1) { ids[5].push_back(nid); } - LBDataHolder dh(num_phases); + LBDataHolder dh; for (PhaseType i = 0; i < num_phases; i++) { for (auto&& elm : ids[i]) { dh.node_data_[i][elm] = LoadSummary{3}; From 899cd3e9a20dc86998e2a76694b9c7accf0d45b0 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Thu, 6 Jun 2024 11:36:12 +0200 Subject: [PATCH 41/82] #1934: Enable serialization of queue in CircularPhasesBuffer --- src/vt/utils/container/circular_phases_buffer.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/vt/utils/container/circular_phases_buffer.h b/src/vt/utils/container/circular_phases_buffer.h index 21a96c53bb..636bb81074 100644 --- a/src/vt/utils/container/circular_phases_buffer.h +++ b/src/vt/utils/container/circular_phases_buffer.h @@ -228,8 +228,7 @@ struct CircularPhasesBuffer { template void serialize(SerializeT& s) { s | m_requested_capacity; - // TODO: Checkpoint is not supporting the queue - // s | m_indexes; + s | m_indexes; s | m_buffer; } From f7e26ff01f2fb69aad5b41bc2aa080254d2fe004 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Thu, 6 Jun 2024 12:18:26 +0200 Subject: [PATCH 42/82] #1934: Add missing include with unordered_map --- src/vt/utils/container/circular_phases_buffer.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vt/utils/container/circular_phases_buffer.h b/src/vt/utils/container/circular_phases_buffer.h index 636bb81074..b056345b0e 100644 --- a/src/vt/utils/container/circular_phases_buffer.h +++ b/src/vt/utils/container/circular_phases_buffer.h @@ -45,6 +45,7 @@ #define INCLUDED_VT_UTILS_CONTAINER_CIRCULAR_PHASES_BUFFER_H #include "vt/config.h" +#include #include namespace vt { namespace util { namespace container { From 9b066bc26f4c8bd70d21d4d9d2eb47833aad19fa Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 11 Jun 2024 13:41:22 +0200 Subject: [PATCH 43/82] #1934: Update units tests to fix CI failure --- tests/unit/collection/test_lb_data_retention.cc | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/unit/collection/test_lb_data_retention.cc b/tests/unit/collection/test_lb_data_retention.cc index e93bc710a8..b8970045e6 100644 --- a/tests/unit/collection/test_lb_data_retention.cc +++ b/tests/unit/collection/test_lb_data_retention.cc @@ -112,11 +112,6 @@ struct TestCol : vt::Collection { EXPECT_EQ(sp_load_phase_count, buffers_size); EXPECT_EQ(comm_phase_count, buffers_size); EXPECT_EQ(sp_comm_phase_count, buffers_size); - } else if (phase == 0) { - EXPECT_EQ(load_phase_count, phase); - EXPECT_EQ(sp_load_phase_count, phase); - EXPECT_EQ(comm_phase_count, phase); - EXPECT_EQ(sp_comm_phase_count, phase); } else { // updatePhase will have caused entries to be added for the // next phase already From 6ffedd8fe3dbbd44b26a14bdf4834ea72ab819cd Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 11 Jun 2024 15:20:43 +0200 Subject: [PATCH 44/82] #1934: Use common types in tests --- .../test_model_comm_overhead.nompi.cc | 20 ++++++++--------- .../test_model_linear_model.nompi.cc | 13 ++++++----- .../test_model_multiple_phases.nompi.cc | 13 ++++++----- .../test_model_naive_persistence.nompi.cc | 13 ++++++----- .../unit/collection/test_model_norm.nompi.cc | 22 +++++++++---------- ...t_model_persistence_median_last_n.nompi.cc | 13 ++++++----- .../test_model_select_subphases.nompi.cc | 20 ++++++++--------- ...del_weighted_communication_volume.nompi.cc | 21 +++++++++--------- .../test_model_weighted_messages.nompi.cc | 19 ++++++++-------- 9 files changed, 79 insertions(+), 75 deletions(-) diff --git a/tests/unit/collection/test_model_comm_overhead.nompi.cc b/tests/unit/collection/test_model_comm_overhead.nompi.cc index be51b2f87d..cea0d70e58 100644 --- a/tests/unit/collection/test_model_comm_overhead.nompi.cc +++ b/tests/unit/collection/test_model_comm_overhead.nompi.cc @@ -68,11 +68,9 @@ using vt::vrt::collection::balance::PhaseOffset; using vt::vrt::collection::balance::SubphaseLoadMapType; using vt::vrt::collection::balance::LoadMapObjectIterator; using vt::vrt::collection::balance::DataMapType; - -using ProcLoadMap = vt::util::container::CircularPhasesBuffer; -using ProcSubphaseLoadMap = vt::util::container::CircularPhasesBuffer; -using ProcCommMap = vt::util::container::CircularPhasesBuffer; -using UserDataMap = vt::util::container::CircularPhasesBuffer; +using vt::vrt::collection::balance::LoadMapBufferType; +using vt::vrt::collection::balance::CommMapBufferType; +using vt::vrt::collection::balance::DataMapBufferType; static auto num_phases = 0; @@ -82,9 +80,9 @@ struct StubModel : LoadModel { virtual ~StubModel() = default; void setLoads( - ProcLoadMap const* proc_load, - ProcCommMap const*, - UserDataMap const*) override { + LoadMapBufferType const* proc_load, + CommMapBufferType const*, + DataMapBufferType const*) override { proc_load_ = proc_load; } @@ -111,7 +109,7 @@ struct StubModel : LoadModel { unsigned int getNumPastPhasesNeeded(unsigned int look_back = 0) const override { return look_back; } private: - ProcLoadMap const* proc_load_ = nullptr; + LoadMapBufferType const* proc_load_ = nullptr; }; TEST_F(TestModelCommOverhead, test_model_comm_overhead_1) { @@ -126,9 +124,9 @@ TEST_F(TestModelCommOverhead, test_model_comm_overhead_1) { // Element 3 (home node == 3) ElementIDStruct const elem3 = {3, 3}; - ProcLoadMap proc_load = {{0, LoadMapType{{elem2, {LoadType{150}, {}}}}}}; + LoadMapBufferType proc_load = {{0, LoadMapType{{elem2, {LoadType{150}, {}}}}}}; - ProcCommMap proc_comm = { + CommMapBufferType proc_comm = { {0, CommMapType{// Node 1 -> Node 2 {{CommKeyType::CollectionTag{}, elem1, elem2, false}, diff --git a/tests/unit/collection/test_model_linear_model.nompi.cc b/tests/unit/collection/test_model_linear_model.nompi.cc index 7b603b045b..91460dc3e2 100644 --- a/tests/unit/collection/test_model_linear_model.nompi.cc +++ b/tests/unit/collection/test_model_linear_model.nompi.cc @@ -66,6 +66,9 @@ using vt::vrt::collection::balance::PhaseOffset; using vt::vrt::collection::balance::SubphaseLoadMapType; using vt::vrt::collection::balance::LoadMapObjectIterator; using vt::vrt::collection::balance::DataMapType; +using vt::vrt::collection::balance::LoadMapBufferType; +using vt::vrt::collection::balance::CommMapBufferType; +using vt::vrt::collection::balance::DataMapBufferType; struct StubModel : LoadModel { @@ -73,9 +76,9 @@ struct StubModel : LoadModel { virtual ~StubModel() = default; void setLoads( - vt::util::container::CircularPhasesBuffer const* proc_load, - vt::util::container::CircularPhasesBuffer const*, - vt::util::container::CircularPhasesBuffer const*) override { + LoadMapBufferType const* proc_load, + CommMapBufferType const*, + DataMapBufferType const*) override { proc_load_ = proc_load; } @@ -95,7 +98,7 @@ struct StubModel : LoadModel { unsigned int getNumPastPhasesNeeded(unsigned int look_back = 0) const override { return look_back; } private: - vt::util::container::CircularPhasesBuffer const* proc_load_ = nullptr; + LoadMapBufferType const* proc_load_ = nullptr; }; TEST_F(TestLinearModel, test_model_linear_model_1) { @@ -107,7 +110,7 @@ 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 - vt::util::container::CircularPhasesBuffer proc_loads{{0, LoadMapType{ + LoadMapBufferType proc_loads{{0, LoadMapType{ {ElementIDStruct{1,this_node}, {LoadType{10}, {}}}, {ElementIDStruct{2,this_node}, {LoadType{40}, {}}} }}}; diff --git a/tests/unit/collection/test_model_multiple_phases.nompi.cc b/tests/unit/collection/test_model_multiple_phases.nompi.cc index f0e39252f9..5266885eb9 100644 --- a/tests/unit/collection/test_model_multiple_phases.nompi.cc +++ b/tests/unit/collection/test_model_multiple_phases.nompi.cc @@ -64,6 +64,9 @@ using vt::vrt::collection::balance::CommMapType; using vt::vrt::collection::balance::ObjectIterator; using vt::vrt::collection::balance::LoadMapObjectIterator; using vt::vrt::collection::balance::DataMapType; +using vt::vrt::collection::balance::LoadMapBufferType; +using vt::vrt::collection::balance::CommMapBufferType; +using vt::vrt::collection::balance::DataMapBufferType; struct StubModel : LoadModel { @@ -71,9 +74,9 @@ struct StubModel : LoadModel { virtual ~StubModel() = default; void setLoads( - vt::util::container::CircularPhasesBuffer const* proc_load, - vt::util::container::CircularPhasesBuffer const*, - vt::util::container::CircularPhasesBuffer const*) override { + LoadMapBufferType const* proc_load, + CommMapBufferType const*, + DataMapBufferType const*) override { proc_load_ = proc_load; } @@ -95,12 +98,12 @@ struct StubModel : LoadModel { unsigned int getNumPastPhasesNeeded(unsigned int look_back = 0) const override { return look_back; } private: - vt::util::container::CircularPhasesBuffer const* proc_load_ = nullptr; + LoadMapBufferType const* proc_load_ = nullptr; }; TEST_F(TestModelMultiplePhases, test_model_multiple_phases_1) { NodeType this_node = 0; - vt::util::container::CircularPhasesBuffer proc_loads = { + LoadMapBufferType proc_loads = { {0, LoadMapType{ {ElementIDStruct{1,this_node}, {LoadType{10}, {}}}, {ElementIDStruct{2,this_node}, {LoadType{40}, {}}}}}, diff --git a/tests/unit/collection/test_model_naive_persistence.nompi.cc b/tests/unit/collection/test_model_naive_persistence.nompi.cc index 0f4475d797..25ec9fd3f0 100644 --- a/tests/unit/collection/test_model_naive_persistence.nompi.cc +++ b/tests/unit/collection/test_model_naive_persistence.nompi.cc @@ -64,6 +64,9 @@ using vt::vrt::collection::balance::CommMapType; using vt::vrt::collection::balance::ObjectIterator; using vt::vrt::collection::balance::LoadMapObjectIterator; using vt::vrt::collection::balance::DataMapType; +using vt::vrt::collection::balance::LoadMapBufferType; +using vt::vrt::collection::balance::CommMapBufferType; +using vt::vrt::collection::balance::DataMapBufferType; static int32_t getIndexFromPhase(int32_t phase) { return std::max(0, -1 * phase - 1); @@ -75,9 +78,9 @@ struct StubModel : LoadModel { virtual ~StubModel() = default; void setLoads( - vt::util::container::CircularPhasesBuffer const* proc_load, - vt::util::container::CircularPhasesBuffer const*, - vt::util::container::CircularPhasesBuffer const*) override { + LoadMapBufferType const* proc_load, + CommMapBufferType const*, + DataMapBufferType const*) override { proc_load_ = proc_load; } @@ -98,12 +101,12 @@ struct StubModel : LoadModel { unsigned int getNumPastPhasesNeeded(unsigned int look_back = 0) const override { return look_back; } private: - vt::util::container::CircularPhasesBuffer const* proc_load_ = nullptr; + LoadMapBufferType const* proc_load_ = nullptr; }; TEST_F(TestModelNaivePersistence, test_model_naive_persistence_1) { NodeType this_node = 0; - vt::util::container::CircularPhasesBuffer proc_loads = { + LoadMapBufferType proc_loads = { {0, LoadMapType{ {ElementIDStruct{1,this_node}, {LoadType{10}, {}}}, {ElementIDStruct{2,this_node}, {LoadType{40}, {}}}}}, diff --git a/tests/unit/collection/test_model_norm.nompi.cc b/tests/unit/collection/test_model_norm.nompi.cc index 0f6e7c7164..ac12570e8c 100644 --- a/tests/unit/collection/test_model_norm.nompi.cc +++ b/tests/unit/collection/test_model_norm.nompi.cc @@ -65,11 +65,9 @@ using vt::vrt::collection::balance::PhaseOffset; using vt::vrt::collection::balance::SubphaseLoadMapType; using vt::vrt::collection::balance::LoadMapObjectIterator; using vt::vrt::collection::balance::DataMapType; - -using ProcLoadMap = vt::util::container::CircularPhasesBuffer; -using ProcSubphaseLoadMap = vt::util::container::CircularPhasesBuffer; -using ProcCommMap = vt::util::container::CircularPhasesBuffer; -using UserDataMap = vt::util::container::CircularPhasesBuffer; +using vt::vrt::collection::balance::LoadMapBufferType; +using vt::vrt::collection::balance::CommMapBufferType; +using vt::vrt::collection::balance::DataMapBufferType; constexpr auto num_subphases = 3; @@ -79,9 +77,9 @@ struct StubModel : LoadModel { virtual ~StubModel() = default; void setLoads( - ProcLoadMap const* proc_load, - ProcCommMap const*, - UserDataMap const*) override { + LoadMapBufferType const* proc_load, + CommMapBufferType const*, + DataMapBufferType const*) override { proc_load_ = proc_load; } @@ -102,12 +100,12 @@ struct StubModel : LoadModel { unsigned int getNumPastPhasesNeeded(unsigned int look_back = 0) const override { return look_back; } private: - ProcLoadMap const* proc_load_ = nullptr; + LoadMapBufferType const* proc_load_ = nullptr; }; TEST_F(TestModelNorm, test_model_norm_1) { NodeType this_node = 0; - ProcLoadMap proc_load = { + LoadMapBufferType proc_load = { {0, LoadMapType{ {ElementIDStruct{1,this_node}, {LoadType{60}, {LoadType{10}, LoadType{20}, LoadType{30}}}}, @@ -138,7 +136,7 @@ TEST_F(TestModelNorm, test_model_norm_1) { TEST_F(TestModelNorm, test_model_norm_2) { NodeType this_node = 0; - ProcLoadMap proc_load = { + LoadMapBufferType proc_load = { {0, LoadMapType{ {ElementIDStruct{1,this_node}, {LoadType{60}, {LoadType{10}, LoadType{20}, LoadType{30}}}}, @@ -167,7 +165,7 @@ TEST_F(TestModelNorm, test_model_norm_2) { TEST_F(TestModelNorm, test_model_norm_3) { NodeType this_node = 0; - ProcLoadMap proc_load = { + LoadMapBufferType proc_load = { {0, LoadMapType{ {ElementIDStruct{1,this_node}, {LoadType{60}, {LoadType{10}, LoadType{20}, LoadType{30}}}}, 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 89fef63cd4..fe1eeb90fe 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 @@ -66,6 +66,9 @@ using vt::vrt::collection::balance::CommMapType; using vt::vrt::collection::balance::ObjectIterator; using vt::vrt::collection::balance::LoadMapObjectIterator; using vt::vrt::collection::balance::DataMapType; +using vt::vrt::collection::balance::LoadMapBufferType; +using vt::vrt::collection::balance::CommMapBufferType; +using vt::vrt::collection::balance::DataMapBufferType; struct StubModel : LoadModel { @@ -73,9 +76,9 @@ struct StubModel : LoadModel { virtual ~StubModel() = default; void setLoads( - vt::util::container::CircularPhasesBuffer const* proc_load, - vt::util::container::CircularPhasesBuffer const*, - vt::util::container::CircularPhasesBuffer const*) override { + LoadMapBufferType const* proc_load, + CommMapBufferType const*, + DataMapBufferType const*) override { proc_load_ = proc_load; } @@ -95,7 +98,7 @@ struct StubModel : LoadModel { unsigned int getNumPastPhasesNeeded(unsigned int look_back = 0) const override { return look_back; } private: - vt::util::container::CircularPhasesBuffer const* proc_load_ = nullptr; + LoadMapBufferType const* proc_load_ = nullptr; }; TEST_F(TestModelPersistenceMedianLastN, test_model_persistence_median_last_n_1) { @@ -105,7 +108,7 @@ TEST_F(TestModelPersistenceMedianLastN, test_model_persistence_median_last_n_1) auto test_model = std::make_shared(std::make_shared(), 4); - vt::util::container::CircularPhasesBuffer proc_loads(num_total_phases); + LoadMapBufferType proc_loads(num_total_phases); test_model->setLoads(&proc_loads, nullptr, nullptr); diff --git a/tests/unit/collection/test_model_select_subphases.nompi.cc b/tests/unit/collection/test_model_select_subphases.nompi.cc index 061a132d2c..fe558a2236 100644 --- a/tests/unit/collection/test_model_select_subphases.nompi.cc +++ b/tests/unit/collection/test_model_select_subphases.nompi.cc @@ -64,11 +64,9 @@ using vt::vrt::collection::balance::SelectSubphases; using vt::vrt::collection::balance::SubphaseLoadMapType; using vt::vrt::collection::balance::LoadMapObjectIterator; using vt::vrt::collection::balance::DataMapType; - -using ProcLoadMap = vt::util::container::CircularPhasesBuffer; -using ProcSubphaseLoadMap = vt::util::container::CircularPhasesBuffer; -using ProcCommMap = vt::util::container::CircularPhasesBuffer; -using UserDataMap = vt::util::container::CircularPhasesBuffer; +using vt::vrt::collection::balance::LoadMapBufferType; +using vt::vrt::collection::balance::CommMapBufferType; +using vt::vrt::collection::balance::DataMapBufferType; constexpr auto num_subphases = 3; @@ -78,9 +76,9 @@ struct StubModel : LoadModel { virtual ~StubModel() = default; void setLoads( - ProcLoadMap const* proc_load, - ProcCommMap const*, - UserDataMap const*) override { + LoadMapBufferType const* proc_load, + CommMapBufferType const*, + DataMapBufferType const*) override { proc_load_ = proc_load; } @@ -107,7 +105,7 @@ struct StubModel : LoadModel { } private: - ProcLoadMap const* proc_load_ = nullptr; + LoadMapBufferType const* proc_load_ = nullptr; }; TEST_F(TestModelSelectSubphases, test_model_select_subphases_1) { @@ -115,7 +113,7 @@ TEST_F(TestModelSelectSubphases, test_model_select_subphases_1) { ElementIDStruct id1{1,this_node}; ElementIDStruct id2{2,this_node}; - ProcLoadMap proc_load = { + LoadMapBufferType proc_load = { {0, LoadMapType{ {id1, {LoadType{60}, {LoadType{10}, LoadType{20}, LoadType{30}}}}, @@ -159,7 +157,7 @@ TEST_F(TestModelSelectSubphases, test_model_select_subphases_1) { TEST_F(TestModelSelectSubphases, test_model_select_subphases_2) { NodeType this_node = 0; - ProcLoadMap proc_load = { + LoadMapBufferType proc_load = { {0, LoadMapType{ {ElementIDStruct{1,this_node}, diff --git a/tests/unit/collection/test_model_weighted_communication_volume.nompi.cc b/tests/unit/collection/test_model_weighted_communication_volume.nompi.cc index 92e01e9693..6527f63565 100644 --- a/tests/unit/collection/test_model_weighted_communication_volume.nompi.cc +++ b/tests/unit/collection/test_model_weighted_communication_volume.nompi.cc @@ -68,10 +68,9 @@ using vt::vrt::collection::balance::ObjectIterator; using vt::vrt::collection::balance::PhaseOffset; using vt::vrt::collection::balance::LoadMapObjectIterator; using vt::vrt::collection::balance::DataMapType; - -using ProcLoadMap = vt::util::container::CircularPhasesBuffer; -using ProcCommMap = vt::util::container::CircularPhasesBuffer; -using UserDataMap = vt::util::container::CircularPhasesBuffer; +using vt::vrt::collection::balance::LoadMapBufferType; +using vt::vrt::collection::balance::CommMapBufferType; +using vt::vrt::collection::balance::DataMapBufferType; static auto num_phases = 0; @@ -80,9 +79,9 @@ struct StubModel : LoadModel { virtual ~StubModel() = default; void setLoads( - ProcLoadMap const* proc_load, - ProcCommMap const* proc_comm, - UserDataMap const*) override { + LoadMapBufferType const* proc_load, + CommMapBufferType const* proc_comm, + DataMapBufferType const*) override { proc_load_ = proc_load; proc_comm_ = proc_comm; } @@ -114,8 +113,8 @@ struct StubModel : LoadModel { } private: - ProcLoadMap const* proc_load_ = nullptr; - ProcCommMap const* proc_comm_ = nullptr; + LoadMapBufferType const* proc_load_ = nullptr; + CommMapBufferType const* proc_comm_ = nullptr; }; TEST_F(TestModelWeightedCommunicationVolume, test_model) { @@ -129,9 +128,9 @@ TEST_F(TestModelWeightedCommunicationVolume, test_model) { // Element 3 (home node == 3) ElementIDStruct const elem3 = {3, 3}; - ProcLoadMap proc_load = {{0, LoadMapType{{elem2, {LoadType{150}, {}}}}}}; + LoadMapBufferType proc_load = {{0, LoadMapType{{elem2, {LoadType{150}, {}}}}}}; - ProcCommMap proc_comm = { + CommMapBufferType proc_comm = { {0, CommMapType{// Node 1 -> Node 2 {{CommKeyType::CollectionTag{}, elem1, elem2, false}, diff --git a/tests/unit/collection/test_model_weighted_messages.nompi.cc b/tests/unit/collection/test_model_weighted_messages.nompi.cc index fecc86a0df..37b8a48f82 100644 --- a/tests/unit/collection/test_model_weighted_messages.nompi.cc +++ b/tests/unit/collection/test_model_weighted_messages.nompi.cc @@ -66,10 +66,9 @@ using vt::vrt::collection::balance::ObjectIterator; using vt::vrt::collection::balance::PhaseOffset; using vt::vrt::collection::balance::LoadMapObjectIterator; using vt::vrt::collection::balance::DataMapType; - -using ProcLoadMap = vt::util::container::CircularPhasesBuffer; -using ProcCommMap = vt::util::container::CircularPhasesBuffer; -using UserDataMap = vt::util::container::CircularPhasesBuffer; +using vt::vrt::collection::balance::LoadMapBufferType; +using vt::vrt::collection::balance::CommMapBufferType; +using vt::vrt::collection::balance::DataMapBufferType; static auto num_phases = 0; @@ -78,9 +77,9 @@ struct StubModel : LoadModel { virtual ~StubModel() = default; void setLoads( - ProcLoadMap const* proc_load, - ProcCommMap const*, - UserDataMap const*) override { + LoadMapBufferType const* proc_load, + CommMapBufferType const*, + DataMapBufferType const*) override { proc_load_ = proc_load; } @@ -111,7 +110,7 @@ struct StubModel : LoadModel { } private: - ProcLoadMap const* proc_load_ = nullptr; + LoadMapBufferType const* proc_load_ = nullptr; }; TEST_F(TestModelWeightedMessages, test_model) { @@ -125,9 +124,9 @@ TEST_F(TestModelWeightedMessages, test_model) { // Element 3 (home node == 3) ElementIDStruct const elem3 = {3, 3}; - ProcLoadMap proc_load = {{0, LoadMapType{{elem2, {LoadType{150}, {}}}}}}; + LoadMapBufferType proc_load = {{0, LoadMapType{{elem2, {LoadType{150}, {}}}}}}; - ProcCommMap proc_comm = { + CommMapBufferType proc_comm = { {0, CommMapType{// Node 1 -> Node 2 {{CommKeyType::CollectionTag{}, elem1, elem2, false}, From 5ca4a62a3e3b40a7a26bef13ef2ae8c9c80a7b50 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 11 Jun 2024 15:35:46 +0200 Subject: [PATCH 45/82] #1934: Undo not needed changes --- .../vrt/collection/balance/lb_data_holder.cc | 6 +++--- .../collection/test_model_raw_data.nompi.cc | 18 +++++++++--------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/vt/vrt/collection/balance/lb_data_holder.cc b/src/vt/vrt/collection/balance/lb_data_holder.cc index aead88b562..8a8629f1ea 100644 --- a/src/vt/vrt/collection/balance/lb_data_holder.cc +++ b/src/vt/vrt/collection/balance/lb_data_holder.cc @@ -435,13 +435,13 @@ LBDataHolder::LBDataHolder(nlohmann::json const& j) auto phases = j["phases"]; if (phases.is_array()) { - node_data_.resize(phases.size()); - node_comm_.resize(phases.size()); - for (auto const& phase : phases) { auto id = phase["id"]; auto tasks = phase["tasks"]; + this->node_data_[id]; + this->node_comm_[id]; + if (tasks.is_array()) { for (auto const& task : tasks) { auto node = task["node"]; diff --git a/tests/unit/collection/test_model_raw_data.nompi.cc b/tests/unit/collection/test_model_raw_data.nompi.cc index cf181bf2df..63dd8fdfb0 100644 --- a/tests/unit/collection/test_model_raw_data.nompi.cc +++ b/tests/unit/collection/test_model_raw_data.nompi.cc @@ -64,13 +64,15 @@ using vt::vrt::collection::balance::PhaseOffset; using vt::vrt::collection::balance::SubphaseLoadMapType; using vt::vrt::collection::balance::ElmUserDataType; using vt::vrt::collection::balance::DataMapType; +using vt::vrt::collection::balance::LoadMapBufferType; +using vt::vrt::collection::balance::DataMapBufferType; TEST_F(TestRawData, test_model_raw_data_scalar) { NodeType this_node = 0; auto test_model = std::make_shared(); - vt::util::container::CircularPhasesBuffer proc_loads; + LoadMapBufferType proc_loads; test_model->setLoads(&proc_loads, nullptr, nullptr); EXPECT_TRUE(test_model->hasRawLoad()); EXPECT_FALSE(test_model->hasUserData()); // because passed a nullptr @@ -88,8 +90,6 @@ TEST_F(TestRawData, test_model_raw_data_scalar) { LoadMapType{{id1, {LoadType{100}, {LoadType{100}}}}, {id2, {LoadType{10}, {LoadType{10}}}}}, }; - proc_loads.resize(load_holder.size()); - for (size_t iter = 0; iter < load_holder.size(); ++iter) { proc_loads[iter] = load_holder[iter]; test_model->updateLoads(iter); @@ -129,6 +129,12 @@ TEST_F(TestRawData, test_model_raw_user_data) { auto test_model = std::make_shared(); + LoadMapBufferType proc_loads; + DataMapBufferType user_data; + test_model->setLoads(&proc_loads, nullptr, &user_data); + EXPECT_TRUE(test_model->hasRawLoad()); + EXPECT_TRUE(test_model->hasUserData()); + ElementIDStruct id1{1,this_node}; ElementIDStruct id2{2,this_node}; @@ -150,12 +156,6 @@ TEST_F(TestRawData, test_model_raw_user_data) { DataMapType{{id2, ElmUserDataType{{"x", 1}, {"y", 2}}}} }; - vt::util::container::CircularPhasesBuffer proc_loads{load_holder.size()}; - vt::util::container::CircularPhasesBuffer user_data{user_holder.size()}; - test_model->setLoads(&proc_loads, nullptr, &user_data); - EXPECT_TRUE(test_model->hasRawLoad()); - EXPECT_TRUE(test_model->hasUserData()); - for (size_t iter = 0; iter < load_holder.size(); ++iter) { proc_loads[iter] = load_holder[iter]; user_data[iter] = user_holder[iter]; From 3658c6ab1bb08abfac816fa05a2c8dbe829e7ae5 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 11 Jun 2024 16:14:14 +0200 Subject: [PATCH 46/82] #1934: Make CircularBuffer interface more like a map --- .../utils/container/circular_phases_buffer.h | 86 ++++++++++++------- .../balance/lb_invoke/lb_manager.cc | 19 ++-- .../vrt/collection/balance/model/raw_data.cc | 14 +-- src/vt/vrt/collection/balance/node_lb_data.cc | 3 +- 4 files changed, 72 insertions(+), 50 deletions(-) diff --git a/src/vt/utils/container/circular_phases_buffer.h b/src/vt/utils/container/circular_phases_buffer.h index b056345b0e..d51f06d7d0 100644 --- a/src/vt/utils/container/circular_phases_buffer.h +++ b/src/vt/utils/container/circular_phases_buffer.h @@ -105,79 +105,71 @@ struct CircularPhasesBuffer { } /** - * \brief Check if phase is present in the buffer + * \brief Get data related to the phase. * * \param[in] phase the phase to look for * - * \return whether buffer contains the phase or not + * \return reference to the stored data */ - bool contains(const PhaseType phase) const { - return m_buffer.find(phase) != m_buffer.end(); + const StoredType& at(const PhaseType phase) const { + return m_buffer.at(phase); } /** - * \brief Get data related to the phase. Insert new data if phase is not present in the buffer. + * \brief Get data related to the phase. * * \param[in] phase the phase to look for * * \return reference to the stored data */ - StoredType& operator[](const PhaseType phase) { - if (!contains(phase)) { - addToCache(std::make_pair(phase, StoredType{})); - } - return m_buffer[phase]; - } + StoredType& at(const PhaseType phase) { return m_buffer.at(phase); } /** - * \brief Find data related to the phase. + * \brief Get data related to the phase. Insert new data if phase is not present in the buffer. * * \param[in] phase the phase to look for * - * \return pointer to the stored data or null if not present + * \return reference to the stored data */ - const StoredType* find(const PhaseType phase) const { - auto iter = m_buffer.find(phase); - if (iter != m_buffer.end()) { - return &iter->second; + StoredType& operator[](const PhaseType phase) { + if (!contains(phase)) { + addToCache(std::make_pair(phase, StoredType{})); } - return nullptr; + return m_buffer[phase]; } /** - * \brief Find data related to the phase. + * \brief Find an element for passed phase. * * \param[in] phase the phase to look for * - * \return pointer to the stored data or null if not present + * \return iterator to the requested element. */ - StoredType* find(const PhaseType phase) { - auto iter = m_buffer.find(phase); - if (iter != m_buffer.end()) { - return &iter->second; - } - return nullptr; + auto find(const PhaseType& phase) { + return m_buffer.find(phase); } /** - * \brief Get data related to the phase. + * \brief Find an element for passed phase. * * \param[in] phase the phase to look for * - * \return reference to the stored data + * \return const iterator to the requested element. */ - const StoredType& at(const PhaseType phase) const { - return m_buffer.at(phase); + auto find(const PhaseType& phase) const { + return m_buffer.find(phase); } /** - * \brief Get data related to the phase. + * \brief Check if phase is present in the buffer * * \param[in] phase the phase to look for * - * \return reference to the stored data + * \return whether buffer contains the phase or not */ - StoredType& at(const PhaseType phase) { return m_buffer.at(phase); } + bool contains(const PhaseType phase) const { + return m_buffer.find(phase) != m_buffer.end(); + } /** * \brief Resize buffer to the requested size @@ -240,6 +232,20 @@ struct CircularPhasesBuffer { */ auto begin() { return m_buffer.begin(); } + /** + * @brief Get const iterator to the begging of the buffer + * + * @return auto the const begin iterator + */ + auto begin() const { return m_buffer.begin(); } + + /** + * @brief Get const iterator to the begging of the buffer + * + * @return auto the const begin iterator + */ + auto cbegin() const { return m_buffer.cbegin(); } + /** * @brief Get iterator to the space after buffer * @@ -247,6 +253,20 @@ struct CircularPhasesBuffer { */ auto end() { return m_buffer.end(); } + /** + * @brief Get const iterator to the space after buffer + * + * @return auto the const end iterator + */ + auto end() const { return m_buffer.end(); } + + /** + * @brief Get const iterator to the space after buffer + * + * @return auto the const end iterator + */ + auto cend() const { return m_buffer.cend(); } + private: /** * @brief Add new phase to the cache and remove oldest one if buffer exceeds requested size 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 44a8880d41..af5497e2bc 100644 --- a/src/vt/vrt/collection/balance/lb_invoke/lb_manager.cc +++ b/src/vt/vrt/collection/balance/lb_invoke/lb_manager.cc @@ -257,15 +257,15 @@ LBManager::runLB(PhaseType phase, vt::Callback cb) { elm::CommMapType const* comm = &empty_comm; auto const& node_comm = theNodeLBData()->getNodeComm(); - if (node_comm->contains(phase)) { - comm = &node_comm->at(phase); + if (auto iter = node_comm->find(phase); iter != node_comm->end()) { + comm = &iter->second; } balance::DataMapType empty_data_map; balance::DataMapType const* data_map = &empty_data_map; auto const& node_data_map = theNodeLBData()->getUserData(); - if (node_data_map->contains(phase)) { - data_map = &node_data_map->at(phase); + if (auto iter = node_data_map->find(phase); iter != node_data_map->end()) { + data_map = &iter->second; } vt_debug_print(terse, lb, "LBManager: running strategy\n"); @@ -735,8 +735,9 @@ void LBManager::computeStatistics( elm::CommMapType empty_comm; elm::CommMapType const* comm_data = &empty_comm; - if (theNodeLBData()->getNodeComm()->contains(phase)) { - comm_data = &theNodeLBData()->getNodeComm()->at(phase); + auto iter = theNodeLBData()->getNodeComm()->find(phase); + if (iter != theNodeLBData()->getNodeComm()->end()) { + comm_data = &iter->second; } std::vector lstats; @@ -896,12 +897,12 @@ getSharedEdges(elm::CommMapType const& comm_data) { void makeGraphSymmetric( PhaseType phase, objgroup::proxy::Proxy proxy ) { - auto ptr = theNodeLBData()->getNodeComm()->find(phase); - if (!ptr) { + auto iter = theNodeLBData()->getNodeComm()->find(phase); + if (iter == theNodeLBData()->getNodeComm()->end()) { return; } - auto shared_edges = getSharedEdges(*ptr); + auto shared_edges = getSharedEdges(iter->second); for (auto&& elm : shared_edges) { proxy[elm.first].send( diff --git a/src/vt/vrt/collection/balance/model/raw_data.cc b/src/vt/vrt/collection/balance/model/raw_data.cc index 15d701656b..18c8edd2b3 100644 --- a/src/vt/vrt/collection/balance/model/raw_data.cc +++ b/src/vt/vrt/collection/balance/model/raw_data.cc @@ -60,19 +60,19 @@ void RawData::setLoads(LoadMapBufferType const* proc_load, } ObjectIterator RawData::begin() const { - auto ptr = proc_load_->find(last_completed_phase_); - if (ptr) { - return {std::make_unique(ptr->cbegin(), - ptr->cend())}; + auto iter = proc_load_->find(last_completed_phase_); + if (iter != proc_load_->end()) { + return {std::make_unique(iter->second.cbegin(), + iter->second.cend())}; } else { return {nullptr}; } } int RawData::getNumObjects() const { - auto ptr = proc_load_->find(last_completed_phase_); - if (ptr) { - return ptr->size(); + auto iter = proc_load_->find(last_completed_phase_); + if (iter != proc_load_->end()) { + return iter->second.size(); } else { return 0; } diff --git a/src/vt/vrt/collection/balance/node_lb_data.cc b/src/vt/vrt/collection/balance/node_lb_data.cc index f197770163..c7e625914d 100644 --- a/src/vt/vrt/collection/balance/node_lb_data.cc +++ b/src/vt/vrt/collection/balance/node_lb_data.cc @@ -120,7 +120,8 @@ ElmUserDataType const* NodeLBData::getNodeAttributes() const { } CommMapType* NodeLBData::getNodeComm(PhaseType phase) { - return lb_data_->node_comm_.find(phase); + auto iter = lb_data_->node_comm_.find(phase); + return (iter != lb_data_->node_comm_.end()) ? &iter->second : nullptr; } void NodeLBData::clearLBData() { From 8ec8fe2a8134b0c724f125660c82421d1f042960 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 11 Jun 2024 16:46:46 +0200 Subject: [PATCH 47/82] #1934: Update collection creation in tests #1934: Update retention unit tests check for phase 0 #1934: Add namespaces for the tests containing similiar TestCol Object #1934: Remove redundant methods from TestCol --- .../utils/container/circular_phases_buffer.h | 2 +- src/vt/vrt/collection/balance/node_lb_data.cc | 4 +-- .../collection/test_collection_manager.cc | 6 +++-- .../unit/collection/test_lb_data_retention.cc | 26 +++++++++++-------- 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/vt/utils/container/circular_phases_buffer.h b/src/vt/utils/container/circular_phases_buffer.h index d51f06d7d0..855b0fee28 100644 --- a/src/vt/utils/container/circular_phases_buffer.h +++ b/src/vt/utils/container/circular_phases_buffer.h @@ -297,4 +297,4 @@ struct CircularPhasesBuffer { }}} /* end namespace vt::util::container */ -#endif /* INCLUDED_VT_UTILS_CONTAINER_CIRCULAR_PHASES_BUFFER_H */ +#endif /*INCLUDED_VT_UTILS_CONTAINER_CIRCULAR_PHASES_BUFFER_H*/ diff --git a/src/vt/vrt/collection/balance/node_lb_data.cc b/src/vt/vrt/collection/balance/node_lb_data.cc index c7e625914d..5ece1545ed 100644 --- a/src/vt/vrt/collection/balance/node_lb_data.cc +++ b/src/vt/vrt/collection/balance/node_lb_data.cc @@ -149,9 +149,7 @@ void NodeLBData::resizeLBDataHistory(uint32_t new_hist_len) { lb_data_->node_user_attributes_.resize(new_hist_len); } - NodeLBData::node_migrate_.clear(); - node_collection_lookup_.clear(); - node_objgroup_lookup_.clear(); + startIterCleanup(); } ElementIDType NodeLBData::getNextElm() { diff --git a/tests/unit/collection/test_collection_manager.cc b/tests/unit/collection/test_collection_manager.cc index d086a079d3..0183e1be42 100644 --- a/tests/unit/collection/test_collection_manager.cc +++ b/tests/unit/collection/test_collection_manager.cc @@ -52,7 +52,9 @@ namespace vt { namespace tests { namespace unit { -struct TestCollectionManager : TestParallelHarness {}; +namespace TestCollectionManager { + +struct TestCollectionManager : TestParallelHarness { }; struct TestCol : vt::Collection { static void colHandler(TestCol*) {} @@ -89,4 +91,4 @@ TEST_F(TestCollectionManager, test_collection_manager_proxy_deletion) { } } -}}} // end namespace vt::tests::unit +}}}} // end namespace vt::tests::unit::TestCollectionManager diff --git a/tests/unit/collection/test_lb_data_retention.cc b/tests/unit/collection/test_lb_data_retention.cc index b8970045e6..7cd091e34c 100644 --- a/tests/unit/collection/test_lb_data_retention.cc +++ b/tests/unit/collection/test_lb_data_retention.cc @@ -58,6 +58,8 @@ namespace vt { namespace tests { namespace unit { +namespace TestLBDataRetention { + void validatePersistedPhases(std::vector expected_phases) { #if vt_check_enabled(lblite) // Check maps size @@ -88,9 +90,6 @@ void validatePersistedPhases(std::vector expected_phases) { } struct TestCol : vt::Collection { - unsigned int prev_calls_ = thePhase()->getCurrentPhase(); - - unsigned int prevCalls() { return prev_calls_++; } static void insertValue(TestCol* col) { col->valInsert("foo", 10, true, true, true); @@ -104,7 +103,7 @@ struct TestCol : vt::Collection { auto sp_comm_phase_count = lb_data.getSubphaseCommPhaseCount(); #if vt_check_enabled(lblite) - auto phase = col->prevCalls(); + auto phase = thePhase()->getCurrentPhase(); auto model = theLBManager()->getLoadModel(); auto buffers_size = std::max(model->getNumPastPhasesNeeded(), theConfig()->vt_lb_data_retention); if (phase >= buffers_size) { @@ -112,6 +111,11 @@ struct TestCol : vt::Collection { EXPECT_EQ(sp_load_phase_count, buffers_size); EXPECT_EQ(comm_phase_count, buffers_size); EXPECT_EQ(sp_comm_phase_count, buffers_size); + } else if (phase == 0) { + EXPECT_EQ(load_phase_count, 1); + EXPECT_EQ(sp_load_phase_count, 1); + EXPECT_EQ(comm_phase_count, 0); + EXPECT_EQ(sp_comm_phase_count, 0); } else { // updatePhase will have caused entries to be added for the // next phase already @@ -155,6 +159,7 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_last1) { proxy = vt::theCollection()->constructCollective( range, "test_lbstats_retention_last1" ); + proxy.broadcastCollective(); }); // Get the base model, assert it's valid @@ -170,7 +175,6 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_last1) { for (int i=0; i(); proxy.broadcastCollective(); }); // Go to the next phase. @@ -195,6 +199,7 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_last2) { proxy = vt::theCollection()->constructCollective( range, "test_lbstats_retention_last2" ); + proxy.broadcastCollective(); }); // Get the base model, assert it's valid @@ -210,7 +215,6 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_last2) { for (int i=0; i(); proxy.broadcastCollective(); }); // Go to the next phase. @@ -235,6 +239,7 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_last4) { proxy = vt::theCollection()->constructCollective( range, "test_lbstats_retention_last4" ); + proxy.broadcastCollective(); }); // Get the base model, assert it's valid @@ -250,7 +255,6 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_last4) { for (int i=0; i(); proxy.broadcastCollective(); }); // Go to the next phase. @@ -278,6 +282,7 @@ TEST_F(TestLBDataRetention, test_lbdata_config_retention_higher) { proxy = vt::theCollection()->constructCollective( range, "test_lbdata_config_retention_higher" ); + proxy.broadcastCollective(); }); // Get the base model, assert it's valid @@ -293,7 +298,6 @@ TEST_F(TestLBDataRetention, test_lbdata_config_retention_higher) { for (uint32_t i=0; ivt_lb_data_retention * 2; ++i) { runInEpochCollective([&]{ // Do some work. - proxy.broadcastCollective(); proxy.broadcastCollective(); }); // Go to the next phase. @@ -319,6 +323,7 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_model_switch_1) { proxy = vt::theCollection()->constructCollective( range, "test_lbdata_retention_model_switch_1" ); + proxy.broadcastCollective(); }); // Get the base model, assert it's valid @@ -335,7 +340,6 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_model_switch_1) { for (uint32_t i=0; i(); proxy.broadcastCollective(); }); // Go to the next phase. @@ -380,6 +384,7 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_model_switch_2) { proxy = vt::theCollection()->constructCollective( range, "test_lbdata_retention_model_switch_2" ); + proxy.broadcastCollective(); }); // Get the base model, assert it's valid @@ -394,7 +399,6 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_model_switch_2) { for (uint32_t i=0; i(); proxy.broadcastCollective(); }); // Go to the next phase. @@ -429,4 +433,4 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_model_switch_2) { validatePersistedPhases({16}); } -}}} // end namespace vt::tests::unit +}}}} // end namespace vt::tests::unit::TestLBDataRetention From e225d2b68daf274d348c03de78f977c069c387cf Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Thu, 4 Jul 2024 18:22:09 +0200 Subject: [PATCH 48/82] #1934: Remove small changes --- src/vt/elm/elm_lb_data.h | 8 ++++---- tests/unit/collection/test_lb.extended.cc | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/vt/elm/elm_lb_data.h b/src/vt/elm/elm_lb_data.h index 360f450e7d..40908c9feb 100644 --- a/src/vt/elm/elm_lb_data.h +++ b/src/vt/elm/elm_lb_data.h @@ -134,12 +134,12 @@ struct ElementLBData { bool cur_time_started_ = false; TimeType cur_time_ = TimeType{0.0}; PhaseType cur_phase_ = fst_lb_phase; - util::container::CircularPhasesBuffer phase_timings_; - util::container::CircularPhasesBuffer phase_comm_; + util::container::CircularPhasesBuffer phase_timings_ = {}; + util::container::CircularPhasesBuffer phase_comm_ = {}; SubphaseType cur_subphase_ = 0; - util::container::CircularPhasesBuffer> subphase_timings_; - util::container::CircularPhasesBuffer> subphase_comm_; + util::container::CircularPhasesBuffer> subphase_timings_ = {}; + util::container::CircularPhasesBuffer> subphase_comm_ = {}; }; }} /* end namespace vt::elm */ diff --git a/tests/unit/collection/test_lb.extended.cc b/tests/unit/collection/test_lb.extended.cc index 20c2f38616..8995b4b179 100644 --- a/tests/unit/collection/test_lb.extended.cc +++ b/tests/unit/collection/test_lb.extended.cc @@ -563,6 +563,9 @@ TEST_F(TestRestoreLBData, test_restore_lb_data_data_1) { { PhaseType phase = write_phase; + lbdh.node_data_[phase]; + lbdh.node_comm_[phase]; + for (int i=0; i Date: Mon, 15 Jul 2024 15:39:40 +0200 Subject: [PATCH 49/82] #1934: Update CircularPhasesBuffer to follow vt style of naming variables --- .../utils/container/circular_phases_buffer.h | 99 ++++++++++--------- 1 file changed, 50 insertions(+), 49 deletions(-) diff --git a/src/vt/utils/container/circular_phases_buffer.h b/src/vt/utils/container/circular_phases_buffer.h index 855b0fee28..61992f9b4a 100644 --- a/src/vt/utils/container/circular_phases_buffer.h +++ b/src/vt/utils/container/circular_phases_buffer.h @@ -63,24 +63,24 @@ struct CircularPhasesBuffer { /** * \brief Construct a CircularPhasesBuffer * - * \param[in] capacity the requested capacity of the buffer + * \param[in] in_capacity the requested capacity of the buffer */ - CircularPhasesBuffer(std::size_t capacity = 0) { - m_requested_capacity = capacity; - m_buffer.reserve(capacity); + CircularPhasesBuffer(std::size_t in_capacity = 0) { + requested_capacity_ = in_capacity; + buffer_.reserve(in_capacity); } /** * \brief Construct a CircularPhasesBuffer. The max size of buffer will be equal to the size of the list * - * \param[in] list the initializer list with elements to be put into the buffer + * \param[in] in_list the initializer list with elements to be put into the buffer */ - CircularPhasesBuffer(std::initializer_list list) { - m_requested_capacity = list.size(); - m_buffer.reserve(list.size()); + CircularPhasesBuffer(std::initializer_list in_list) { + requested_capacity_ = in_list.size(); + buffer_.reserve(in_list.size()); - for (auto&& pair : list) { - addToCache(std::make_pair(pair.first, pair.second)); + for (auto&& pair : in_list) { + addToCache(pair.first, pair.second); } } @@ -91,7 +91,7 @@ struct CircularPhasesBuffer { * \param[in] obj the data to store */ void store(const PhaseType phase, StoredType&& obj) { - addToCache(std::make_pair(phase, std::move(obj))); + addToCache(phase, std::move(obj)); } /** @@ -101,7 +101,7 @@ struct CircularPhasesBuffer { * \param[in] obj the data to store */ void store(const PhaseType phase, StoredType const& obj) { - addToCache(std::make_pair(phase, obj)); + addToCache(phase, obj); } /** @@ -112,7 +112,7 @@ struct CircularPhasesBuffer { * \return reference to the stored data */ const StoredType& at(const PhaseType phase) const { - return m_buffer.at(phase); + return buffer_.at(phase); } /** @@ -122,7 +122,7 @@ struct CircularPhasesBuffer { * * \return reference to the stored data */ - StoredType& at(const PhaseType phase) { return m_buffer.at(phase); } + StoredType& at(const PhaseType phase) { return buffer_.at(phase); } /** * \brief Get data related to the phase. Insert new data if phase is not present in the buffer. @@ -133,9 +133,9 @@ struct CircularPhasesBuffer { */ StoredType& operator[](const PhaseType phase) { if (!contains(phase)) { - addToCache(std::make_pair(phase, StoredType{})); + addToCache(phase, StoredType{}); } - return m_buffer[phase]; + return buffer_[phase]; } /** @@ -146,7 +146,7 @@ struct CircularPhasesBuffer { * \return iterator to the requested element. */ auto find(const PhaseType& phase) { - return m_buffer.find(phase); + return buffer_.find(phase); } /** @@ -157,7 +157,7 @@ struct CircularPhasesBuffer { * \return const iterator to the requested element. */ auto find(const PhaseType& phase) const { - return m_buffer.find(phase); + return buffer_.find(phase); } /** @@ -168,7 +168,7 @@ struct CircularPhasesBuffer { * \return whether buffer contains the phase or not */ bool contains(const PhaseType phase) const { - return m_buffer.find(phase) != m_buffer.end(); + return buffer_.find(phase) != buffer_.end(); } /** @@ -177,14 +177,14 @@ struct CircularPhasesBuffer { * \param[in] new_size the requested new size of the buffer */ void resize(const std::size_t new_size) { - if (new_size < m_buffer.size()) { - std::size_t remove_last = m_buffer.size() - new_size; + if (new_size < buffer_.size()) { + std::size_t remove_last = buffer_.size() - new_size; for (std::size_t i = 0; i < remove_last; i++) { removeOldest(); } } - m_requested_capacity = new_size; + requested_capacity_ = new_size; } /** @@ -192,107 +192,108 @@ struct CircularPhasesBuffer { * * \return the current size */ - std::size_t size() const { return m_buffer.size(); } + std::size_t size() const { return buffer_.size(); } /** * \brief Check if the buffer is empty * * \return whether the buffer is empty or not */ - bool empty() const { return m_buffer.empty(); } + bool empty() const { return buffer_.empty(); } /** * \brief Clears content of the buffer. Does not change the buffer maximum capacity. */ void clear() { std::queue empty; - m_indexes.swap(empty); - m_buffer.clear(); + indexes_.swap(empty); + buffer_.clear(); } /** * @brief Clears content of the buffer and allow the buffer maximum capacity to grow */ void reset() { - m_requested_capacity = 0; + requested_capacity_ = 0; clear(); } template void serialize(SerializeT& s) { - s | m_requested_capacity; - s | m_indexes; - s | m_buffer; + s | requested_capacity_; + s | indexes_; + s | buffer_; } /** - * @brief Get iterator to the begging of the buffer + * @brief Get iterator to the beginning of the buffer * * @return auto the begin iterator */ - auto begin() { return m_buffer.begin(); } + auto begin() { return buffer_.begin(); } /** - * @brief Get const iterator to the begging of the buffer + * @brief Get const iterator to the beginning of the buffer * * @return auto the const begin iterator */ - auto begin() const { return m_buffer.begin(); } + auto begin() const { return buffer_.begin(); } /** - * @brief Get const iterator to the begging of the buffer + * @brief Get const iterator to the beginning of the buffer * * @return auto the const begin iterator */ - auto cbegin() const { return m_buffer.cbegin(); } + auto cbegin() const { return buffer_.cbegin(); } /** * @brief Get iterator to the space after buffer * * @return auto the end iterator */ - auto end() { return m_buffer.end(); } + auto end() { return buffer_.end(); } /** * @brief Get const iterator to the space after buffer * * @return auto the const end iterator */ - auto end() const { return m_buffer.end(); } + auto end() const { return buffer_.end(); } /** * @brief Get const iterator to the space after buffer * * @return auto the const end iterator */ - auto cend() const { return m_buffer.cend(); } + auto cend() const { return buffer_.cend(); } private: /** * @brief Add new phase to the cache and remove oldest one if buffer exceeds requested size * - * @param pair the pair to be stored + * \param[in] phase the phase for which data will be stored + * \param[in] data the data to store */ - void addToCache(StoredPair&& pair) { - if (m_requested_capacity > 0 && m_buffer.size() >= m_requested_capacity) { + void addToCache(const PhaseType phase, StoredType const& data) { + if (requested_capacity_ > 0 && buffer_.size() >= requested_capacity_) { removeOldest(); } - m_indexes.push(pair.first); - m_buffer[pair.first] = std::move(pair.second); + indexes_.push(phase); + buffer_.emplace(phase, data); } /** * @brief Remove oldest phase from cache */ void removeOldest() { - m_buffer.erase(m_indexes.front()); - m_indexes.pop(); + buffer_.erase(indexes_.front()); + indexes_.pop(); } private: - std::size_t m_requested_capacity; - std::queue m_indexes; - std::unordered_map m_buffer; + std::size_t requested_capacity_; + std::queue indexes_; + std::unordered_map buffer_; }; }}} /* end namespace vt::util::container */ From 3942cada4a4a297654e20de0c2837ec5945d3d71 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Wed, 17 Jul 2024 15:24:56 +0200 Subject: [PATCH 50/82] #1934: Avoid unnecessary copies of data when adding it to cache --- src/vt/utils/container/circular_phases_buffer.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vt/utils/container/circular_phases_buffer.h b/src/vt/utils/container/circular_phases_buffer.h index 61992f9b4a..c342340244 100644 --- a/src/vt/utils/container/circular_phases_buffer.h +++ b/src/vt/utils/container/circular_phases_buffer.h @@ -79,8 +79,8 @@ struct CircularPhasesBuffer { requested_capacity_ = in_list.size(); buffer_.reserve(in_list.size()); - for (auto&& pair : in_list) { - addToCache(pair.first, pair.second); + for (const auto& pair : in_list) { + addToCache(pair.first, std::move(pair.second)); } } @@ -274,12 +274,12 @@ struct CircularPhasesBuffer { * \param[in] phase the phase for which data will be stored * \param[in] data the data to store */ - void addToCache(const PhaseType phase, StoredType const& data) { + void addToCache(const PhaseType& phase, const StoredType&& data) { if (requested_capacity_ > 0 && buffer_.size() >= requested_capacity_) { removeOldest(); } indexes_.push(phase); - buffer_.emplace(phase, data); + buffer_.emplace(phase, std::move(data)); } /** From 5e2d8a78f862c3562d553f988f024ac99836deda Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Thu, 18 Jul 2024 12:28:18 +0200 Subject: [PATCH 51/82] #1934: Remove const from addToCache data parameter --- src/vt/utils/container/circular_phases_buffer.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vt/utils/container/circular_phases_buffer.h b/src/vt/utils/container/circular_phases_buffer.h index c342340244..00ebbc3c95 100644 --- a/src/vt/utils/container/circular_phases_buffer.h +++ b/src/vt/utils/container/circular_phases_buffer.h @@ -79,7 +79,7 @@ struct CircularPhasesBuffer { requested_capacity_ = in_list.size(); buffer_.reserve(in_list.size()); - for (const auto& pair : in_list) { + for (auto pair : in_list) { addToCache(pair.first, std::move(pair.second)); } } @@ -274,7 +274,7 @@ struct CircularPhasesBuffer { * \param[in] phase the phase for which data will be stored * \param[in] data the data to store */ - void addToCache(const PhaseType& phase, const StoredType&& data) { + void addToCache(const PhaseType& phase, StoredType&& data) { if (requested_capacity_ > 0 && buffer_.size() >= requested_capacity_) { removeOldest(); } From 9c86660554b04cc05a44bbbcfeb2978a9b2df459 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Thu, 22 Aug 2024 15:52:48 +0200 Subject: [PATCH 52/82] #1934: Update unit tests to work with new implementation of the buffer --- .../test_circular_phases_buffer.nompi.cc | 120 ++++++++++-------- 1 file changed, 68 insertions(+), 52 deletions(-) diff --git a/tests/unit/utils/test_circular_phases_buffer.nompi.cc b/tests/unit/utils/test_circular_phases_buffer.nompi.cc index 9003f6c070..3e55538f2c 100644 --- a/tests/unit/utils/test_circular_phases_buffer.nompi.cc +++ b/tests/unit/utils/test_circular_phases_buffer.nompi.cc @@ -54,25 +54,23 @@ struct Dummy { int x; }; -void validatePresentPhases( - util::container::CircularPhasesBuffer& buffer, - std::vector expected) { +using CircularBufferType = util::container::CircularPhasesBuffer; + +void validatePresentPhases(CircularBufferType& buffer, std::vector expected) { for (auto&& phase : expected) { EXPECT_TRUE(buffer.contains(phase)) << "Phase: " << phase; - EXPECT_EQ(phase * phase, buffer.at(phase).x) << "Phase: " << phase; + EXPECT_EQ(phase, buffer.at(phase).x) << "Phase: " << phase; } } -void validateMissingPhases( - util::container::CircularPhasesBuffer& buffer, - std::vector expected) { +void validateMissingPhases(CircularBufferType& buffer, std::vector expected) { for (auto&& phase : expected) { EXPECT_FALSE(buffer.contains(phase)) << "Phase: " << phase; } } TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_empty) { - util::container::CircularPhasesBuffer buffer; + CircularBufferType buffer; EXPECT_FALSE(buffer.contains(0)); EXPECT_EQ(std::size_t{0}, buffer.size()); @@ -112,39 +110,65 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_empty) { EXPECT_EQ(std::size_t{4}, buffer.size()); EXPECT_FALSE(buffer.empty()); - buffer.reset(); + buffer.clear(); EXPECT_FALSE(buffer.contains(0)); EXPECT_EQ(std::size_t{0}, buffer.size()); EXPECT_TRUE(buffer.empty()); } +TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_single_element) { + CircularBufferType buffer{1}; + + EXPECT_EQ(false, buffer.contains(0)); + + for (int i = 0; i < 5; i++) { + buffer.store(i, {i}); + EXPECT_EQ(i == 0, buffer.contains(0)); + EXPECT_EQ(i == 1, buffer.contains(1)); + EXPECT_EQ(i == 2, buffer.contains(2)); + EXPECT_EQ(i == 3, buffer.contains(3)); + EXPECT_EQ(i == 4, buffer.contains(4)); + EXPECT_EQ(i == 5, buffer.contains(5)); + EXPECT_EQ(i == 6, buffer.contains(5)); + } +} + +TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_multi_elements) { + CircularBufferType buffer{5}; + + for (int i = 0; i < 15; i++) { + buffer.store(i, {i}); + } + std::vector finalOutput = {10, 11, 12, 13, 14}; + validatePresentPhases(buffer, finalOutput); +} + TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_store) { - util::container::CircularPhasesBuffer buffer{10}; + CircularBufferType buffer; + + buffer.store(2, {2}); + validatePresentPhases(buffer, {2}); + validateMissingPhases(buffer, {0, 1}); + + buffer.resize(10); - buffer.store(2, {2 * 2}); validatePresentPhases(buffer, {2}); validateMissingPhases(buffer, {0, 1}); // store series of elements for (int i = 3; i < 15; i++) { - buffer.store(i, {i * i}); + buffer.store(i, {i}); } std::vector finalOutput = {5, 6, 7, 8, 9, 10, 11, 12, 13, 14}; validatePresentPhases(buffer, finalOutput); } -TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_resize_continuous) { - util::container::CircularPhasesBuffer buffer{1}; - - buffer[0] = {0}; - validatePresentPhases(buffer, {0}); - - buffer.resize(10); - validatePresentPhases(buffer, {0}); +TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_resize) { + CircularBufferType buffer{10}; for (int i = 0; i <= 15; i++) { - buffer[i] = {i * i}; + buffer[i] = {i}; } validatePresentPhases(buffer, {6, 7, 8, 9, 10, 11, 12, 13, 14, 15}); @@ -153,7 +177,7 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_resize_continuous) validateMissingPhases(buffer, {6, 7, 8, 9, 10}); for (int i = 15; i <= 32; i++) { - buffer[i] = {i * i}; + buffer[i] = {i}; } validatePresentPhases(buffer, {28, 29, 30, 31, 32}); validateMissingPhases(buffer, {11, 12, 13, 14, 15}); @@ -161,51 +185,43 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_resize_continuous) buffer.resize(9); for (int i = 33; i <= 35; i++) { - buffer[i] = {i * i}; + buffer[i] = {i}; } validatePresentPhases(buffer, {28, 29, 30, 31, 32, 33, 34, 35}); buffer.resize(1); validatePresentPhases(buffer, {35}); validateMissingPhases(buffer, {28, 29, 30, 31, 32, 33, 34}); + + buffer.resize(0); + validateMissingPhases(buffer, {35}); } TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_forward_iter) { - util::container::CircularPhasesBuffer buffer; + CircularBufferType buffer{0}; - for (auto&& ele : buffer) { - // This will never be called. - EXPECT_EQ(true, false) << "Unexpected phase: " << ele.first; - } + for (auto& ele : buffer) { EXPECT_EQ(123, ele.x); } + for (auto&& ele : buffer) { EXPECT_EQ(123, ele.x); } + buffer.resize(3); buffer[0] = {0}; buffer[1] = {1}; - buffer[2] = {4}; - - validatePresentPhases(buffer, {0, 1, 2}); - - buffer[3] = {9}; - - validatePresentPhases(buffer, {0, 1, 2, 3}); - - buffer[4] = {16}; - buffer[5] = {25}; - buffer[6] = {36}; - - validatePresentPhases(buffer, {0, 1, 2, 3, 4, 5, 6}); - - buffer.clear(); - - for (auto&& ele : buffer) { - // This will never be called. - EXPECT_EQ(true, false) << "Unexpected phase: " << ele.first; + buffer[2] = {2}; + + { + int iter = 0; + for (auto&& ele : buffer) { + EXPECT_EQ(iter, ele.x); + iter++; + } } - buffer.resize(0); - - for (auto&& ele : buffer) { - // This will never be called. - EXPECT_EQ(true, false) << "Unexpected phase: " << ele.first; + { + int iter = 0; + for (auto& ele : buffer) { + EXPECT_EQ(iter, ele.x); + iter++; + } } } From ff860c8341a73ad14fb0c90fa7bf9a8fe12dcc6c Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Thu, 22 Aug 2024 15:54:01 +0200 Subject: [PATCH 53/82] #1934: Update implementation of the circular buffer to use std::vector --- .../utils/container/circular_phases_buffer.h | 295 +++++++++++------- 1 file changed, 181 insertions(+), 114 deletions(-) diff --git a/src/vt/utils/container/circular_phases_buffer.h b/src/vt/utils/container/circular_phases_buffer.h index 00ebbc3c95..7272b15725 100644 --- a/src/vt/utils/container/circular_phases_buffer.h +++ b/src/vt/utils/container/circular_phases_buffer.h @@ -47,6 +47,7 @@ #include "vt/config.h" #include #include +#include namespace vt { namespace util { namespace container { @@ -54,65 +55,62 @@ namespace vt { namespace util { namespace container { * \struct CircularPhasesBuffer * * \brief The circular buffer which holds data related to a set of phases. - * PhaseType is used as a key when storing or retrieving data. If capacity was not specified then buffer is allow to grow without limit. */ template -struct CircularPhasesBuffer { +class CircularPhasesBuffer { using StoredPair = std::pair; + static const auto no_pos = std::numeric_limits::max(); + +public: + /** * \brief Construct a CircularPhasesBuffer * - * \param[in] in_capacity the requested capacity of the buffer + * \param[in] in_capacity the requested size of the buffer */ - CircularPhasesBuffer(std::size_t in_capacity = 0) { - requested_capacity_ = in_capacity; - buffer_.reserve(in_capacity); - } + CircularPhasesBuffer(std::size_t size_in = 1) + : buffer_(size_in) + { } /** - * \brief Construct a CircularPhasesBuffer. The max size of buffer will be equal to the size of the list + * \brief Construct a CircularPhasesBuffer. + * The max size of buffer will be equal to the size of the list. * * \param[in] in_list the initializer list with elements to be put into the buffer */ - CircularPhasesBuffer(std::initializer_list in_list) { - requested_capacity_ = in_list.size(); - buffer_.reserve(in_list.size()); + CircularPhasesBuffer(std::initializer_list in_list) + : buffer_(in_list.size()) { for (auto pair : in_list) { - addToCache(pair.first, std::move(pair.second)); + store(pair.first, pair.second); } } /** - * \brief Store data in the buffer + * \brief Check if phase is present in the buffer. * - * \param[in] phase the phase for which data will be stored - * \param[in] obj the data to store - */ - void store(const PhaseType phase, StoredType&& obj) { - addToCache(phase, std::move(obj)); - } - - /** - * \brief Store data in the buffer + * \param[in] phase the phase to look for * - * \param[in] phase the phase for which data will be stored - * \param[in] obj the data to store + * \return whether buffer contains the phase or not */ - void store(const PhaseType phase, StoredType const& obj) { - addToCache(phase, obj); + bool contains(const PhaseType& phase) const { + return phase < head_phase_ && phase >= (head_phase_ - size()); } /** * \brief Get data related to the phase. + * Insert new data if phase is not present in the buffer. * * \param[in] phase the phase to look for * * \return reference to the stored data */ - const StoredType& at(const PhaseType phase) const { - return buffer_.at(phase); + StoredType& operator[](const PhaseType phase) { + if (!contains(phase)) { + store(phase, StoredType{}); + } + return at(phase); } /** @@ -122,106 +120,121 @@ struct CircularPhasesBuffer { * * \return reference to the stored data */ - StoredType& at(const PhaseType phase) { return buffer_.at(phase); } + StoredType& at(const PhaseType phase) { + return buffer_.at(phaseToIndex(phase)); + } /** - * \brief Get data related to the phase. Insert new data if phase is not present in the buffer. + * \brief Get data related to the phase. * * \param[in] phase the phase to look for * * \return reference to the stored data */ - StoredType& operator[](const PhaseType phase) { - if (!contains(phase)) { - addToCache(phase, StoredType{}); - } - return buffer_[phase]; + const StoredType& at(const PhaseType phase) const { + return buffer_.at(phaseToIndex(phase)); } /** - * \brief Find an element for passed phase. + * \brief Find data for a phase. * * \param[in] phase the phase to look for * - * \return iterator to the requested element. + * \return pointer to phase data, nullptr otherwise. */ - auto find(const PhaseType& phase) { - return buffer_.find(phase); + StoredType* find(const PhaseType& phase) { + if (contains(phase)) { + return &buffer_[phaseToIndex(phase)]; + } + return nullptr; } /** - * \brief Find an element for passed phase. + * \brief Find data for a phase. * * \param[in] phase the phase to look for * - * \return const iterator to the requested element. + * \return pointer to phase data, nullptr otherwise. */ - auto find(const PhaseType& phase) const { - return buffer_.find(phase); + const StoredType* find(const PhaseType& phase) const { + if (contains(phase)) { + return &buffer_[phaseToIndex(phase)]; + } + return nullptr; } /** - * \brief Check if phase is present in the buffer + * \brief Store data in the buffer. * - * \param[in] phase the phase to look for - * - * \return whether buffer contains the phase or not + * \param[in] phase the phase for which data will be stored + * \param[in] obj the data to store */ - bool contains(const PhaseType phase) const { - return buffer_.find(phase) != buffer_.end(); + void store(const PhaseType& phase, StoredType data) { + buffer_[head_] = std::move(data); + head_ = getNextIndex(); + head_phase_ = phase + 1; + inserted_ = inserted_ + 1; } /** - * \brief Resize buffer to the requested size + * \brief Resize buffer to the requested size. * * \param[in] new_size the requested new size of the buffer */ void resize(const std::size_t new_size) { - if (new_size < buffer_.size()) { - std::size_t remove_last = buffer_.size() - new_size; - for (std::size_t i = 0; i < remove_last; i++) { - removeOldest(); - } + if (new_size == buffer_.size()) { + return; + } + // temporary vector to copy the elements to retain + std::vector tmp(new_size); + // number of elements to copy + auto num = std::min(new_size, size()); + + // copy + auto to_copy = head_; + for(std::size_t it = num; it > 0; it--) { + to_copy = getPrevIndex(to_copy); + tmp[it - 1] = buffer_[to_copy]; } - requested_capacity_ = new_size; + buffer_.swap(tmp); + inserted_ = num; + head_ = getNextIndex(num - 1); } /** - * \brief Get current size of the buffer + * \brief Get number of elements in the buffer. * - * \return the current size + * \return the number of elements */ - std::size_t size() const { return buffer_.size(); } + std::size_t size() const { + return std::min(inserted_, buffer_.size()); + } /** - * \brief Check if the buffer is empty + * \brief Check if the buffer is empty. * * \return whether the buffer is empty or not */ - bool empty() const { return buffer_.empty(); } - - /** - * \brief Clears content of the buffer. Does not change the buffer maximum capacity. - */ - void clear() { - std::queue empty; - indexes_.swap(empty); - buffer_.clear(); + bool empty() const { + return inserted_ == 0; } /** - * @brief Clears content of the buffer and allow the buffer maximum capacity to grow + * \brief Clears content of the buffer. */ - void reset() { - requested_capacity_ = 0; - clear(); + void clear() { + head_ = 0; + inserted_ = 0; + head_phase_ = 0; + buffer_.assign(buffer_.size(), StoredType{}); } template void serialize(SerializeT& s) { - s | requested_capacity_; - s | indexes_; + s | head_; + s | inserted_; + s | head_phase_; s | buffer_; } @@ -230,70 +243,124 @@ struct CircularPhasesBuffer { * * @return auto the begin iterator */ - auto begin() { return buffer_.begin(); } - - /** - * @brief Get const iterator to the beginning of the buffer - * - * @return auto the const begin iterator - */ - auto begin() const { return buffer_.begin(); } + auto begin() { return ForwardIterator(head_, findTail(), &buffer_); } /** * @brief Get const iterator to the beginning of the buffer * * @return auto the const begin iterator */ - auto cbegin() const { return buffer_.cbegin(); } + auto begin() const { return ForwardIterator(head_, findTail(), &buffer_); } /** * @brief Get iterator to the space after buffer * * @return auto the end iterator */ - auto end() { return buffer_.end(); } + auto end() { return ForwardIterator(); } /** * @brief Get const iterator to the space after buffer * * @return auto the const end iterator */ - auto end() const { return buffer_.end(); } + auto end() const { return ForwardIterator(); } +private: + std::size_t findTail() const { + if (inserted_ == 0) { + return no_pos; + } else if (head_ == inserted_) { + return 0; + } + return head_; + } - /** - * @brief Get const iterator to the space after buffer - * - * @return auto the const end iterator - */ - auto cend() const { return buffer_.cend(); } + std::size_t phaseToIndex(const PhaseType phase) const { + std::size_t go_back = head_phase_ - phase; + if (go_back > head_) { + return size() - (go_back - head_); + } else { + return head_ - go_back; + } + } -private: - /** - * @brief Add new phase to the cache and remove oldest one if buffer exceeds requested size - * - * \param[in] phase the phase for which data will be stored - * \param[in] data the data to store - */ - void addToCache(const PhaseType& phase, StoredType&& data) { - if (requested_capacity_ > 0 && buffer_.size() >= requested_capacity_) { - removeOldest(); + std::size_t getPrevIndex(std::size_t index) const { + std::size_t prev = index - 1; + if (prev > buffer_.size()) { + prev = buffer_.size() - 1; } - indexes_.push(phase); - buffer_.emplace(phase, std::move(data)); + return prev; } - /** - * @brief Remove oldest phase from cache - */ - void removeOldest() { - buffer_.erase(indexes_.front()); - indexes_.pop(); + std::size_t getNextIndex() const { + std::size_t next = head_ + 1; + if (next >= buffer_.size()) { + next = 0; + } + return next; } -private: - std::size_t requested_capacity_; - std::queue indexes_; - std::unordered_map buffer_; + std::size_t getNextIndex(std::size_t index) const { + std::size_t next = index + 1; + if (next >= buffer_.size()) { + next = 0; + } + return next; + } + + // Number of the next index in buffer + std::size_t head_ = 0; + // Counter for inserted phases + std::size_t inserted_ = 0; + // Number of the next phase + PhaseType head_phase_ = 0; + + std::vector buffer_; + +public: + // TODO: Change iterator to return a pair of phase and reference to data + struct ForwardIterator { + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = StoredType; + using reference = StoredType&; + + ForwardIterator(std::size_t head, std::size_t index, const std::vector* buffer) + : head_(head), index_(index), buffer_(buffer) {} + + ForwardIterator() + : head_(no_pos), index_(no_pos), buffer_(nullptr) {} + + reference operator*() { return &buffer_->at(index_); } + + ForwardIterator& operator++() { + advance(); + return *this; + } + ForwardIterator operator++(int) { + ForwardIterator tmp = *this; + ++(*this); + return tmp; + } + + bool operator== (const ForwardIterator& it) { return index_ == it.index_; }; + bool operator!= (const ForwardIterator& it) { return index_ != it.index_; }; + + private: + void advance() { + index_++; + if (index_ >= buffer_->size()) { + index_ = 0; + } + if (index_ == head_) { + index_ = no_pos; + } + } + + std::size_t head_; + std::size_t index_; + const std::vector* buffer_; + }; }; }}} /* end namespace vt::util::container */ From 0fc17787f3198cb54e243d16afaa84641bfd21cc Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Mon, 26 Aug 2024 20:10:19 +0200 Subject: [PATCH 54/82] #1934: Add front and back methods to CircularPhasesBuffer --- .../utils/container/circular_phases_buffer.h | 55 ++++++++++++++----- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/src/vt/utils/container/circular_phases_buffer.h b/src/vt/utils/container/circular_phases_buffer.h index 7272b15725..f3301a56fb 100644 --- a/src/vt/utils/container/circular_phases_buffer.h +++ b/src/vt/utils/container/circular_phases_buffer.h @@ -239,32 +239,58 @@ class CircularPhasesBuffer { } /** - * @brief Get iterator to the beginning of the buffer + * \brief Get const iterator to the beginning of the buffer * - * @return auto the begin iterator + * \return the const begin iterator */ - auto begin() { return ForwardIterator(head_, findTail(), &buffer_); } + auto begin() const { return ForwardIterator(head_, findTail(), &buffer_); } /** - * @brief Get const iterator to the beginning of the buffer + * \brief Get const iterator to the space after buffer * - * @return auto the const begin iterator + * \return the const end iterator */ - auto begin() const { return ForwardIterator(head_, findTail(), &buffer_); } + auto end() const { return ForwardIterator(); } /** - * @brief Get iterator to the space after buffer + * \brief Finds the newest phase in the buffer. * - * @return auto the end iterator + * \return the newest phase in the buffer. */ - auto end() { return ForwardIterator(); } + PhaseType frontPhase() const { + return inserted_ == 0 ? 0 : head_phase_ - 1; + } /** - * @brief Get const iterator to the space after buffer + * \brief Get the newest element in buffer. * - * @return auto the const end iterator + * \return the reference to the newest element. */ - auto end() const { return ForwardIterator(); } + StoredType& front() { + return buffer_.at(getPrevIndex(head_)); + } + + /** + * \brief Finds the oldest phase in the buffer. + * + * \return the oldest phase in the buffer. + */ + PhaseType backPhase() const { + if (head_ == inserted_) { + return 0; + } + return head_phase_ - buffer_.size(); + } + + /** + * \brief Get the oldest element in buffer. + * + * \return the reference to the oldest element. + */ + StoredType& back() { + return buffer_.at(findTail()); + } + private: std::size_t findTail() const { if (inserted_ == 0) { @@ -318,12 +344,11 @@ class CircularPhasesBuffer { std::vector buffer_; public: - // TODO: Change iterator to return a pair of phase and reference to data struct ForwardIterator { using iterator_category = std::forward_iterator_tag; using difference_type = std::ptrdiff_t; using value_type = StoredType; - using reference = StoredType&; + using reference = const StoredType&; ForwardIterator(std::size_t head, std::size_t index, const std::vector* buffer) : head_(head), index_(index), buffer_(buffer) {} @@ -331,7 +356,7 @@ class CircularPhasesBuffer { ForwardIterator() : head_(no_pos), index_(no_pos), buffer_(nullptr) {} - reference operator*() { return &buffer_->at(index_); } + reference operator*() { return (*buffer_)[index_]; } ForwardIterator& operator++() { advance(); From 4af903fbdfa753975ec4e9638aa396521eed9fc5 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Mon, 26 Aug 2024 20:10:45 +0200 Subject: [PATCH 55/82] #1934: Add tests for front and back methods --- .../utils/test_circular_phases_buffer.nompi.cc | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/unit/utils/test_circular_phases_buffer.nompi.cc b/tests/unit/utils/test_circular_phases_buffer.nompi.cc index 3e55538f2c..5c28e7c0ac 100644 --- a/tests/unit/utils/test_circular_phases_buffer.nompi.cc +++ b/tests/unit/utils/test_circular_phases_buffer.nompi.cc @@ -75,24 +75,32 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_empty) { EXPECT_FALSE(buffer.contains(0)); EXPECT_EQ(std::size_t{0}, buffer.size()); EXPECT_TRUE(buffer.empty()); + EXPECT_EQ(0, buffer.backPhase()); + EXPECT_EQ(0, buffer.frontPhase()); buffer.resize(2); EXPECT_FALSE(buffer.contains(0)); EXPECT_EQ(std::size_t{0}, buffer.size()); EXPECT_TRUE(buffer.empty()); + EXPECT_EQ(0, buffer.backPhase()); + EXPECT_EQ(0, buffer.frontPhase()); buffer.clear(); EXPECT_FALSE(buffer.contains(1)); EXPECT_EQ(std::size_t{0}, buffer.size()); EXPECT_TRUE(buffer.empty()); + EXPECT_EQ(0, buffer.backPhase()); + EXPECT_EQ(0, buffer.frontPhase()); buffer.resize(0); EXPECT_FALSE(buffer.contains(1)); EXPECT_EQ(std::size_t{0}, buffer.size()); EXPECT_TRUE(buffer.empty()); + EXPECT_EQ(0, buffer.backPhase()); + EXPECT_EQ(0, buffer.frontPhase()); buffer.resize(4); buffer[0] = {0}; @@ -100,6 +108,10 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_empty) { EXPECT_TRUE(buffer.contains(0)); EXPECT_EQ(std::size_t{1}, buffer.size()); EXPECT_FALSE(buffer.empty()); + EXPECT_EQ(0, buffer.backPhase()); + EXPECT_EQ(0, buffer.frontPhase()); + EXPECT_EQ(0, buffer.back().x); + EXPECT_EQ(0, buffer.front().x); buffer[1] = {1}; buffer[2] = {4}; @@ -109,12 +121,18 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_empty) { EXPECT_TRUE(buffer.contains(1)); EXPECT_EQ(std::size_t{4}, buffer.size()); EXPECT_FALSE(buffer.empty()); + EXPECT_EQ(1, buffer.backPhase()); + EXPECT_EQ(4, buffer.frontPhase()); + EXPECT_EQ(1, buffer.back().x); + EXPECT_EQ(8, buffer.front().x); buffer.clear(); EXPECT_FALSE(buffer.contains(0)); EXPECT_EQ(std::size_t{0}, buffer.size()); EXPECT_TRUE(buffer.empty()); + EXPECT_EQ(0, buffer.backPhase()); + EXPECT_EQ(0, buffer.frontPhase()); } TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_single_element) { From 1822f20dfab93ce6e40712d1ace7a8b53bc7842f Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Mon, 26 Aug 2024 20:27:47 +0200 Subject: [PATCH 56/82] #1934: Update usage of circular phases buffer --- .../balance/lb_data_restart_reader.cc | 10 +++------- .../collection/balance/lb_invoke/lb_manager.cc | 18 ++++++++---------- .../vrt/collection/balance/model/raw_data.cc | 13 ++++++------- src/vt/vrt/collection/balance/node_lb_data.cc | 3 +-- .../vrt/collection/balance/workload_replay.cc | 8 ++++---- tests/unit/collection/test_lb.extended.cc | 9 ++++----- tests/unit/lb/test_lb_data_comm.cc | 18 +++++++++--------- 7 files changed, 35 insertions(+), 44 deletions(-) diff --git a/src/vt/vrt/collection/balance/lb_data_restart_reader.cc b/src/vt/vrt/collection/balance/lb_data_restart_reader.cc index be21ad319b..cf89a7bb22 100644 --- a/src/vt/vrt/collection/balance/lb_data_restart_reader.cc +++ b/src/vt/vrt/collection/balance/lb_data_restart_reader.cc @@ -83,10 +83,7 @@ void LBDataRestartReader::readHistory(LBDataHolder const& lbdh) { if (lbdh.node_data_.empty()) { return 0; } - return std::max_element( - lbdh.node_data_.begin(), lbdh.node_data_.end(), - [](const auto& p1, const auto& p2) { return p1.first < p2.first; }) - ->first; + return lbdh.node_data_.frontPhase(); }; // Find last phase number @@ -100,10 +97,9 @@ void LBDataRestartReader::readHistory(LBDataHolder const& lbdh) { PhaseType last_found_phase = 0; for (PhaseType phase = 0; phase < num_phases_; phase++) { - auto iter = lbdh.node_data_.find(phase); - if (iter != lbdh.node_data_.end()) { + if (lbdh.node_data_.contains(phase)) { last_found_phase = phase; - for (auto const& obj : iter->second) { + for (auto const& obj : lbdh.node_data_.at(phase)) { if (obj.first.isMigratable()) { if (history_[phase] == nullptr) { history_[phase] = std::make_shared>(); 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 af5497e2bc..3d0dcc3890 100644 --- a/src/vt/vrt/collection/balance/lb_invoke/lb_manager.cc +++ b/src/vt/vrt/collection/balance/lb_invoke/lb_manager.cc @@ -257,15 +257,15 @@ LBManager::runLB(PhaseType phase, vt::Callback cb) { elm::CommMapType const* comm = &empty_comm; auto const& node_comm = theNodeLBData()->getNodeComm(); - if (auto iter = node_comm->find(phase); iter != node_comm->end()) { - comm = &iter->second; + if (node_comm->contains(phase)) { + comm = &node_comm->at(phase); } balance::DataMapType empty_data_map; balance::DataMapType const* data_map = &empty_data_map; auto const& node_data_map = theNodeLBData()->getUserData(); - if (auto iter = node_data_map->find(phase); iter != node_data_map->end()) { - data_map = &iter->second; + if (node_data_map->contains(phase)) { + data_map = &node_data_map->at(phase); } vt_debug_print(terse, lb, "LBManager: running strategy\n"); @@ -735,9 +735,8 @@ void LBManager::computeStatistics( elm::CommMapType empty_comm; elm::CommMapType const* comm_data = &empty_comm; - auto iter = theNodeLBData()->getNodeComm()->find(phase); - if (iter != theNodeLBData()->getNodeComm()->end()) { - comm_data = &iter->second; + if (theNodeLBData()->getNodeComm()->contains(phase)) { + comm_data = &theNodeLBData()->getNodeComm()->at(phase); } std::vector lstats; @@ -897,12 +896,11 @@ getSharedEdges(elm::CommMapType const& comm_data) { void makeGraphSymmetric( PhaseType phase, objgroup::proxy::Proxy proxy ) { - auto iter = theNodeLBData()->getNodeComm()->find(phase); - if (iter == theNodeLBData()->getNodeComm()->end()) { + if (!theNodeLBData()->getNodeComm()->contains(phase)) { return; } - auto shared_edges = getSharedEdges(iter->second); + auto shared_edges = getSharedEdges(theNodeLBData()->getNodeComm()->at(phase)); for (auto&& elm : shared_edges) { proxy[elm.first].send( diff --git a/src/vt/vrt/collection/balance/model/raw_data.cc b/src/vt/vrt/collection/balance/model/raw_data.cc index 18c8edd2b3..729774f7f4 100644 --- a/src/vt/vrt/collection/balance/model/raw_data.cc +++ b/src/vt/vrt/collection/balance/model/raw_data.cc @@ -60,19 +60,18 @@ void RawData::setLoads(LoadMapBufferType const* proc_load, } ObjectIterator RawData::begin() const { - auto iter = proc_load_->find(last_completed_phase_); - if (iter != proc_load_->end()) { - return {std::make_unique(iter->second.cbegin(), - iter->second.cend())}; + if (proc_load_->contains(last_completed_phase_)) { + auto ptr = proc_load_->find(last_completed_phase_); + return {std::make_unique(ptr->cbegin(), + ptr->cend())}; } else { return {nullptr}; } } int RawData::getNumObjects() const { - auto iter = proc_load_->find(last_completed_phase_); - if (iter != proc_load_->end()) { - return iter->second.size(); + if (proc_load_->contains(last_completed_phase_)) { + return proc_load_->at(last_completed_phase_).size(); } else { return 0; } diff --git a/src/vt/vrt/collection/balance/node_lb_data.cc b/src/vt/vrt/collection/balance/node_lb_data.cc index 5ece1545ed..a8e6203370 100644 --- a/src/vt/vrt/collection/balance/node_lb_data.cc +++ b/src/vt/vrt/collection/balance/node_lb_data.cc @@ -120,8 +120,7 @@ ElmUserDataType const* NodeLBData::getNodeAttributes() const { } CommMapType* NodeLBData::getNodeComm(PhaseType phase) { - auto iter = lb_data_->node_comm_.find(phase); - return (iter != lb_data_->node_comm_.end()) ? &iter->second : nullptr; + return lb_data_->node_comm_.find(phase); } void NodeLBData::clearLBData() { diff --git a/src/vt/vrt/collection/balance/workload_replay.cc b/src/vt/vrt/collection/balance/workload_replay.cc index 975e3ae515..0017905b56 100644 --- a/src/vt/vrt/collection/balance/workload_replay.cc +++ b/src/vt/vrt/collection/balance/workload_replay.cc @@ -249,19 +249,19 @@ readInWorkloads(const std::string &filename) { auto json = r.readFile(); auto sd = std::make_shared(*json); - for (auto &phase_data : sd->node_data_) { + for (auto phase = sd->node_data_.backPhase(); phase <= sd->node_data_.frontPhase(); phase++) { vt_debug_print( normal, replay, "found {} loads for phase {}\n", - phase_data.second.size(), phase_data.first + sd->node_data_[phase].size(), phase ); } - for (auto &phase_data : sd->node_comm_) { + for (auto phase = sd->node_comm_.backPhase(); phase <= sd->node_comm_.frontPhase(); phase++) { vt_debug_print( normal, replay, "found {} comms for phase {}\n", - phase_data.second.size(), phase_data.first + sd->node_comm_[phase].size(), phase ); } diff --git a/tests/unit/collection/test_lb.extended.cc b/tests/unit/collection/test_lb.extended.cc index 8995b4b179..c6c1c6a3b2 100644 --- a/tests/unit/collection/test_lb.extended.cc +++ b/tests/unit/collection/test_lb.extended.cc @@ -616,17 +616,16 @@ TEST_F(TestRestoreLBData, test_restore_lb_data_data_1) { ); } else { // compare the whole-phase load data in detail - for (auto &phase_data : lbdh.node_data_) { - auto phase = phase_data.first; - EXPECT_FALSE(lbdh_read.node_data_.find(phase) == lbdh_read.node_data_.end()); - if (lbdh_read.node_data_.find(phase) == lbdh_read.node_data_.end()) { + for (auto phase = lbdh.node_data_.backPhase(); phase <= lbdh.node_data_.frontPhase(); phase++) { + EXPECT_TRUE(lbdh_read.node_data_.contains(phase)); + if (!lbdh_read.node_data_.contains(phase)) { fmt::print( "Phase {} in whole-phase loads were not read in", phase ); } else { auto &read_load_map = lbdh_read.node_data_[phase]; - auto &orig_load_map = phase_data.second; + auto &orig_load_map = lbdh.node_data_[phase]; for (auto &entry : read_load_map) { auto read_elm_id = entry.first; if ((read_elm_id.id == vt::elm::no_element_id) diff --git a/tests/unit/lb/test_lb_data_comm.cc b/tests/unit/lb/test_lb_data_comm.cc index c314068847..fd3379887e 100644 --- a/tests/unit/lb/test_lb_data_comm.cc +++ b/tests/unit/lb/test_lb_data_comm.cc @@ -294,7 +294,7 @@ TEST_F(TestLBDataComm, test_lb_data_comm_col_to_col_send) { if (proxy(i).tryGetLocalPtr()) { bool found = false; for (auto&& x : comm) { - for (auto&& y : x.second) { + for (auto&& y : x) { auto key = y.first; auto vol = y.second; if (key.to_.id == idxToElmID(idx)) { @@ -358,7 +358,7 @@ TEST_F(TestLBDataComm, test_lb_data_comm_col_to_objgroup_send) { bool found = false; auto idb = vt::elm::ElmIDBits::createObjGroup(op, next).id; for (auto&& x : comm) { - for (auto&& y : x.second) { + for (auto&& y : x) { auto key = y.first; auto vol = y.second; if (key.from_.id == idxToElmID(idx) /*and key.to_.id == idb*/) { @@ -421,7 +421,7 @@ TEST_F(TestLBDataComm, test_lb_data_comm_objgroup_to_col_send) { if (proxy(i).tryGetLocalPtr()) { bool found = false; for (auto&& x : comm) { - for (auto&& y : x.second) { + for (auto&& y : x) { auto key = y.first; auto vol = y.second; if (key.to_.id == idxToElmID(idx)) { @@ -475,7 +475,7 @@ TEST_F(TestLBDataComm, test_lb_data_comm_objgroup_to_objgroup_send) { // Check that communication exists on the send side as expected bool found = false; for (auto&& x : comm) { - for (auto&& y : x.second) { + for (auto&& y : x) { auto key = y.first; auto vol = y.second; if (key.from_.id == ida /*and key.to_.id == idb*/) { @@ -532,7 +532,7 @@ TEST_F(TestLBDataComm, test_lb_data_comm_handler_to_col_send) { if (proxy(i).tryGetLocalPtr()) { bool found = false; for (auto&& x : comm) { - for (auto&& y : x.second) { + for (auto&& y : x) { auto key = y.first; auto vol = y.second; if (key.to_.id == idxToElmID(idx)) { @@ -592,7 +592,7 @@ TEST_F(TestLBDataComm, test_lb_data_comm_col_to_handler_send) { if (proxy(i).tryGetLocalPtr()) { bool found = false; for (auto&& x : comm) { - for (auto&& y : x.second) { + for (auto&& y : x) { auto key = y.first; auto vol = y.second; fmt::print("from={}, to={}\n", key.from_, key.to_); @@ -641,7 +641,7 @@ TEST_F(TestLBDataComm, test_lb_data_comm_objgroup_to_handler_send) { // Check that communication exists on the send side as expected bool found = false; for (auto&& x : comm) { - for (auto&& y : x.second) { + for (auto&& y : x) { auto key = y.first; auto vol = y.second; if (key.from_.id == ida) { @@ -686,7 +686,7 @@ TEST_F(TestLBDataComm, test_lb_data_comm_handler_to_objgroup_send) { // Check that communication exists on the send side as expected bool found = false; for (auto&& x : comm) { - for (auto&& y : x.second) { + for (auto&& y : x) { auto key = y.first; auto vol = y.second; if (key.to_.id == ida) { @@ -727,7 +727,7 @@ TEST_F(TestLBDataComm, test_lb_data_comm_handler_to_handler_send) { // Check that communication exists on the send side as expected bool found = false; for (auto&& x : comm) { - for (auto&& y : x.second) { + for (auto&& y : x) { auto key = y.first; auto vol = y.second; if (key.to_.id == ida and key.from_.id == idb) { From f252c536dfc94e8c6a6347fe0205e755b97a24dd Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 27 Aug 2024 09:23:51 +0200 Subject: [PATCH 57/82] #1934: Add resizing functionality to LBDataHolder buffers --- src/vt/vrt/collection/balance/lb_data_holder.cc | 5 ++--- src/vt/vrt/collection/balance/lb_data_holder.h | 14 +++++++++++++- src/vt/vrt/collection/balance/node_lb_data.cc | 2 +- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/vt/vrt/collection/balance/lb_data_holder.cc b/src/vt/vrt/collection/balance/lb_data_holder.cc index 8a8629f1ea..f2f4c91e0b 100644 --- a/src/vt/vrt/collection/balance/lb_data_holder.cc +++ b/src/vt/vrt/collection/balance/lb_data_holder.cc @@ -435,13 +435,12 @@ LBDataHolder::LBDataHolder(nlohmann::json const& j) auto phases = j["phases"]; if (phases.is_array()) { + resizeHistory(phases.size()); + for (auto const& phase : phases) { auto id = phase["id"]; auto tasks = phase["tasks"]; - this->node_data_[id]; - this->node_comm_[id]; - if (tasks.is_array()) { for (auto const& task : tasks) { auto node = task["node"]; diff --git a/src/vt/vrt/collection/balance/lb_data_holder.h b/src/vt/vrt/collection/balance/lb_data_holder.h index fd8b0cf149..f890a6979f 100644 --- a/src/vt/vrt/collection/balance/lb_data_holder.h +++ b/src/vt/vrt/collection/balance/lb_data_holder.h @@ -65,7 +65,12 @@ namespace vt { namespace vrt { namespace collection { namespace balance { * output them as JSON. */ struct LBDataHolder { - LBDataHolder() = default; + /** + * \brief Construct a new \c LBDataHolder with specified history length. + * + * \param[in] phases_history_num the number of phases to retain + */ + LBDataHolder(std::size_t phases_history_num); /** * \brief Create \c LBDataHolder from input JSON @@ -137,6 +142,13 @@ struct LBDataHolder { */ void clear(); + /** + * \brief Resize internal buffers to hold specified amount of phases. + * + * \param[in] num_to_retain the number of phases to retain + */ + void resizeHistory(std::size_t num_to_retain); + private: /** * \brief Output an entity to json diff --git a/src/vt/vrt/collection/balance/node_lb_data.cc b/src/vt/vrt/collection/balance/node_lb_data.cc index a8e6203370..0004c40064 100644 --- a/src/vt/vrt/collection/balance/node_lb_data.cc +++ b/src/vt/vrt/collection/balance/node_lb_data.cc @@ -156,7 +156,7 @@ ElementIDType NodeLBData::getNextElm() { } void NodeLBData::initialize() { - lb_data_ = std::make_unique(); + lb_data_ = std::make_unique(hist_lb_data_size_); #if vt_check_enabled(lblite) if (theConfig()->vt_lb_data) { From f519dca81ee19cf1df922363dab7f3223d37fff6 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 27 Aug 2024 09:29:48 +0200 Subject: [PATCH 58/82] #1934: Update unit tests to use new constructor of LBDataHolder --- tests/unit/collection/test_lb.extended.cc | 6 +++--- tests/unit/collection/test_lb_data_holder.cc | 2 +- tests/unit/collection/test_workload_data_migrator.cc | 6 +++--- tests/unit/lb/test_offlinelb.cc | 4 ++-- tests/unit/runtime/test_initialization.cc | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/unit/collection/test_lb.extended.cc b/tests/unit/collection/test_lb.extended.cc index c6c1c6a3b2..514a155c35 100644 --- a/tests/unit/collection/test_lb.extended.cc +++ b/tests/unit/collection/test_lb.extended.cc @@ -552,7 +552,7 @@ TEST_F(TestRestoreLBData, test_restore_lb_data_data_1) { ); }); - vt::vrt::collection::balance::LBDataHolder lbdh; + vt::vrt::collection::balance::LBDataHolder lbdh(num_phases); PhaseType write_phase = 0; using CommKey = vt::elm::CommKey; @@ -749,7 +749,7 @@ TEST_P(TestDumpUserdefinedData, test_dump_userdefined_json) { ); }); - vt::vrt::collection::balance::LBDataHolder lbdh; + vt::vrt::collection::balance::LBDataHolder lbdh(num_phases); PhaseType write_phase = 0; { @@ -812,7 +812,7 @@ TEST_P(TestDumpAttributesFieldData, test_dump_attributes_json) { ); }); - vt::vrt::collection::balance::LBDataHolder lbdh; + vt::vrt::collection::balance::LBDataHolder lbdh(num_phases); PhaseType phase = 0; { diff --git a/tests/unit/collection/test_lb_data_holder.cc b/tests/unit/collection/test_lb_data_holder.cc index 1f3d2bdc7e..dee8295a58 100644 --- a/tests/unit/collection/test_lb_data_holder.cc +++ b/tests/unit/collection/test_lb_data_holder.cc @@ -74,7 +74,7 @@ void addPhasesDataToJson(nlohmann::json& json, PhaseType amountOfPhasesToAdd, st } } - LBDataHolder dh; + LBDataHolder dh(amountOfPhasesToAdd); for (unsigned i = 0; i < amountOfPhasesToAdd; i++) { for (auto&& elm : ids[i]) { dh.node_data_[i][elm] = LoadSummary{3.}; diff --git a/tests/unit/collection/test_workload_data_migrator.cc b/tests/unit/collection/test_workload_data_migrator.cc index f034b30909..fac8d4c666 100644 --- a/tests/unit/collection/test_workload_data_migrator.cc +++ b/tests/unit/collection/test_workload_data_migrator.cc @@ -93,7 +93,7 @@ setupWorkloads(PhaseType phase, size_t numElements) { ); } - auto lbdh = std::make_shared(); + auto lbdh = std::make_shared(1); for (auto&& elmID : myElemList) { double tval = elmID.id * 2; @@ -790,7 +790,7 @@ setupManyWorkloads( ); } - auto lbdh = std::make_shared(); + auto lbdh = std::make_shared(num_phases); PhaseType stop_phase = initial_phase + num_phases; for (PhaseType phase = initial_phase; phase < stop_phase; ++phase) { @@ -804,7 +804,7 @@ setupManyWorkloads( } } - auto scrambled_lbdh = std::make_shared(); + auto scrambled_lbdh = std::make_shared(num_phases); for (PhaseType phase = initial_phase; phase < stop_phase; ++phase) { auto base_load_model = setupBaseModel(phase, lbdh); diff --git a/tests/unit/lb/test_offlinelb.cc b/tests/unit/lb/test_offlinelb.cc index b470e61f1c..622d863c7f 100644 --- a/tests/unit/lb/test_offlinelb.cc +++ b/tests/unit/lb/test_offlinelb.cc @@ -125,7 +125,7 @@ TEST_F(TestOfflineLB, test_offlinelb_1) { ids[5].push_back(nid); } - LBDataHolder dh; + LBDataHolder dh(num_phases); for (PhaseType i = 0; i < num_phases; i++) { for (auto&& elm : ids[i]) { dh.node_data_[i][elm] = LoadSummary{3}; @@ -196,7 +196,7 @@ TEST_F(TestOfflineLB, test_offlinelb_2) { ids[7].push_back(nid); } - LBDataHolder dh; + LBDataHolder dh(num_phases); for (PhaseType i = 0; i < num_phases; i++) { if (i != 1 and i != 2 and i != 5 and i != 8 and i != 9) { auto& elms = ids[i]; diff --git a/tests/unit/runtime/test_initialization.cc b/tests/unit/runtime/test_initialization.cc index 132321fe2e..265d1eced0 100644 --- a/tests/unit/runtime/test_initialization.cc +++ b/tests/unit/runtime/test_initialization.cc @@ -543,7 +543,7 @@ void prepareLBDataFiles(const std::string file_name_without_ext) { ids[5].push_back(nid); } - LBDataHolder dh; + LBDataHolder dh(num_phases); for (PhaseType i = 0; i < num_phases; i++) { for (auto&& elm : ids[i]) { dh.node_data_[i][elm] = LoadSummary{3}; From fef230b527affc70c631fc1b6dae9ea6f7af9281 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Wed, 28 Aug 2024 19:27:43 +0200 Subject: [PATCH 59/82] #1934: Disable resizing of the buffer to zero --- src/vt/utils/container/circular_phases_buffer.h | 2 +- tests/unit/utils/test_circular_phases_buffer.nompi.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vt/utils/container/circular_phases_buffer.h b/src/vt/utils/container/circular_phases_buffer.h index f3301a56fb..c42f263279 100644 --- a/src/vt/utils/container/circular_phases_buffer.h +++ b/src/vt/utils/container/circular_phases_buffer.h @@ -182,7 +182,7 @@ class CircularPhasesBuffer { * \param[in] new_size the requested new size of the buffer */ void resize(const std::size_t new_size) { - if (new_size == buffer_.size()) { + if (new_size == buffer_.size() || new_size == 0) { return; } // temporary vector to copy the elements to retain diff --git a/tests/unit/utils/test_circular_phases_buffer.nompi.cc b/tests/unit/utils/test_circular_phases_buffer.nompi.cc index 5c28e7c0ac..105090a688 100644 --- a/tests/unit/utils/test_circular_phases_buffer.nompi.cc +++ b/tests/unit/utils/test_circular_phases_buffer.nompi.cc @@ -212,7 +212,7 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_resize) { validateMissingPhases(buffer, {28, 29, 30, 31, 32, 33, 34}); buffer.resize(0); - validateMissingPhases(buffer, {35}); + validatePresentPhases(buffer, {35}); } TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_forward_iter) { From 35fc7711641f5f4aa45a513f82148ab8c1751330 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Wed, 28 Aug 2024 19:32:54 +0200 Subject: [PATCH 60/82] #1934: Update tests to work correctly with the new buffer type --- .../utils/container/circular_phases_buffer.h | 4 +-- .../vrt/collection/balance/lb_data_holder.cc | 34 +++++++++++++++++-- .../vrt/collection/balance/lb_data_holder.h | 4 ++- .../balance/lb_data_restart_reader.cc | 11 ++---- src/vt/vrt/collection/balance/node_lb_data.cc | 1 - tests/unit/lb/test_offlinelb.cc | 4 +++ 6 files changed, 41 insertions(+), 17 deletions(-) diff --git a/src/vt/utils/container/circular_phases_buffer.h b/src/vt/utils/container/circular_phases_buffer.h index c42f263279..fdb00a7696 100644 --- a/src/vt/utils/container/circular_phases_buffer.h +++ b/src/vt/utils/container/circular_phases_buffer.h @@ -45,9 +45,7 @@ #define INCLUDED_VT_UTILS_CONTAINER_CIRCULAR_PHASES_BUFFER_H #include "vt/config.h" -#include -#include -#include +#include namespace vt { namespace util { namespace container { diff --git a/src/vt/vrt/collection/balance/lb_data_holder.cc b/src/vt/vrt/collection/balance/lb_data_holder.cc index f2f4c91e0b..4a167dff10 100644 --- a/src/vt/vrt/collection/balance/lb_data_holder.cc +++ b/src/vt/vrt/collection/balance/lb_data_holder.cc @@ -431,11 +431,31 @@ LBDataHolder::LBDataHolder(nlohmann::json const& j) this_node_ = theContext()->getNode(); // read metadata for skipped and identical phases - readMetadata(j); + auto num_phases = readMetadata(j); + auto largest_identical = identical_phases_.size() > 0 ? *identical_phases_.rbegin() : 0; + auto largest_skipped = skipped_phases_.size() > 0 ? *skipped_phases_.rbegin() : 0; + PhaseType max_phase = std::max(largest_identical, largest_skipped); auto phases = j["phases"]; if (phases.is_array()) { - resizeHistory(phases.size()); + num_phases = std::max(num_phases, phases.size()); + + for(auto const& phase: phases) { + auto id = phase["id"]; + if (id > max_phase) { + max_phase = id; + } + } + resizeHistory(num_phases); + // create entries in buffer for each phase + PhaseType min_phase = 0; + if (max_phase > num_phases) { + min_phase = max_phase - num_phases; + } + for (auto i = min_phase; i <= max_phase; i++) { + this->node_data_[i]; + this->node_comm_[i]; + } for (auto const& phase : phases) { auto id = phase["id"]; @@ -630,11 +650,17 @@ LBDataHolder::LBDataHolder(nlohmann::json const& j) // right now, so it will be ignored } -void LBDataHolder::readMetadata(nlohmann::json const& j) { +std::size_t LBDataHolder::readMetadata(nlohmann::json const& j) { + std::size_t num_phases = 0; if (j.find("metadata") != j.end()) { auto metadata = j["metadata"]; if (metadata.find("phases") != metadata.end()) { auto phases = metadata["phases"]; + // read the number of phases + if (phases.find("count") != phases.end()) { + num_phases = phases["count"]; + } + // load all skipped phases auto sl = phases["skipped"]["list"]; if(sl.is_array()) { @@ -681,6 +707,8 @@ void LBDataHolder::readMetadata(nlohmann::json const& j) { } } } + + return num_phases; } void LBDataHolder::clear() { diff --git a/src/vt/vrt/collection/balance/lb_data_holder.h b/src/vt/vrt/collection/balance/lb_data_holder.h index f890a6979f..ce77afb7d8 100644 --- a/src/vt/vrt/collection/balance/lb_data_holder.h +++ b/src/vt/vrt/collection/balance/lb_data_holder.h @@ -187,8 +187,10 @@ struct LBDataHolder { * \brief Read the LB phase's metadata * * \param[in] j the json + * + * \return the number of phases in the json's metadata */ - void readMetadata(nlohmann::json const& j); + std::size_t readMetadata(nlohmann::json const& j); public: /// The current node diff --git a/src/vt/vrt/collection/balance/lb_data_restart_reader.cc b/src/vt/vrt/collection/balance/lb_data_restart_reader.cc index cf89a7bb22..6d175881c8 100644 --- a/src/vt/vrt/collection/balance/lb_data_restart_reader.cc +++ b/src/vt/vrt/collection/balance/lb_data_restart_reader.cc @@ -79,15 +79,8 @@ void LBDataRestartReader::startup() { } void LBDataRestartReader::readHistory(LBDataHolder const& lbdh) { - auto find_max_data_phase = [&]() -> PhaseType { - if (lbdh.node_data_.empty()) { - return 0; - } - return lbdh.node_data_.frontPhase(); - }; - // Find last phase number - auto largest_data = find_max_data_phase(); + auto largest_data = lbdh.node_data_.frontPhase(); auto largest_identical = lbdh.identical_phases_.size() > 0 ? *lbdh.identical_phases_.rbegin() : 0; auto largest_skipped = @@ -97,7 +90,7 @@ void LBDataRestartReader::readHistory(LBDataHolder const& lbdh) { PhaseType last_found_phase = 0; for (PhaseType phase = 0; phase < num_phases_; phase++) { - if (lbdh.node_data_.contains(phase)) { + if (lbdh.node_data_.contains(phase) && lbdh.node_data_.at(phase).size() > 0) { last_found_phase = phase; for (auto const& obj : lbdh.node_data_.at(phase)) { if (obj.first.isMigratable()) { diff --git a/src/vt/vrt/collection/balance/node_lb_data.cc b/src/vt/vrt/collection/balance/node_lb_data.cc index 0004c40064..549e8b5723 100644 --- a/src/vt/vrt/collection/balance/node_lb_data.cc +++ b/src/vt/vrt/collection/balance/node_lb_data.cc @@ -57,7 +57,6 @@ #include #include #include -#include namespace vt { namespace vrt { namespace collection { namespace balance { diff --git a/tests/unit/lb/test_offlinelb.cc b/tests/unit/lb/test_offlinelb.cc index 622d863c7f..88e95c76f8 100644 --- a/tests/unit/lb/test_offlinelb.cc +++ b/tests/unit/lb/test_offlinelb.cc @@ -204,6 +204,10 @@ TEST_F(TestOfflineLB, test_offlinelb_2) { dh.node_data_[i][elms[j]] = LoadSummary{ static_cast(i + j) + 3}; } } + else { + // add empty element - circular buffer expects continuous phases + dh.node_data_[i]; + } } using JSONAppender = util::json::Appender; From 5c3479012f142ad8d0fd4be923bfffbe8dc1a26a Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 17 Sep 2024 16:41:28 +0200 Subject: [PATCH 61/82] #1934: Update implementation of circular buffer to work based on modulo operation --- .../utils/container/circular_phases_buffer.h | 343 +++++++++--------- 1 file changed, 179 insertions(+), 164 deletions(-) diff --git a/src/vt/utils/container/circular_phases_buffer.h b/src/vt/utils/container/circular_phases_buffer.h index fdb00a7696..f5fd1b95a3 100644 --- a/src/vt/utils/container/circular_phases_buffer.h +++ b/src/vt/utils/container/circular_phases_buffer.h @@ -58,30 +58,41 @@ template class CircularPhasesBuffer { using StoredPair = std::pair; - static const auto no_pos = std::numeric_limits::max(); + constexpr static auto no_phase = std::numeric_limits::max(); + constexpr static auto no_index = std::numeric_limits::max(); + + static StoredPair makeEmptyPair(const PhaseType& phase = no_phase) { + return std::make_pair(phase, StoredType{}); + } public: /** * \brief Construct a CircularPhasesBuffer * - * \param[in] in_capacity the requested size of the buffer + * \param[in] size_in the requested size of the buffer */ CircularPhasesBuffer(std::size_t size_in = 1) - : buffer_(size_in) - { } + : buffer_(size_in, makeEmptyPair()) + { + vtAssert(size_in > 0, "Size of circular phases buffer needs to be greather than zero."); + } /** * \brief Construct a CircularPhasesBuffer. - * The max size of buffer will be equal to the size of the list. * * \param[in] in_list the initializer list with elements to be put into the buffer */ - CircularPhasesBuffer(std::initializer_list in_list) - : buffer_(in_list.size()) { + CircularPhasesBuffer(std::initializer_list in_list) { + const auto& [min, max] = std::minmax(in_list, [](const StoredPair& lhs, const StoredPair& rhs) { + return lhs.first < rhs.first; + }); + // Calcuate the size of the buffer to hold all phases including the missing ones + buffer_.resize((max.first - min.first) + 1, makeEmptyPair()); for (auto pair : in_list) { - store(pair.first, pair.second); + buffer_[phaseToIndex(pair.first)] = pair; + updateHead(pair.first); } } @@ -93,22 +104,37 @@ class CircularPhasesBuffer { * \return whether buffer contains the phase or not */ bool contains(const PhaseType& phase) const { - return phase < head_phase_ && phase >= (head_phase_ - size()); + return buffer_[phaseToIndex(phase)].first == phase; } /** - * \brief Get data related to the phase. - * Insert new data if phase is not present in the buffer. + * \brief Get or set data for the phase. * * \param[in] phase the phase to look for * * \return reference to the stored data */ StoredType& operator[](const PhaseType phase) { - if (!contains(phase)) { + auto& pair = buffer_[phaseToIndex(phase)]; + // Create empty data for new phase + if (pair.first != phase) { store(phase, StoredType{}); } - return at(phase); + return pair.second; + } + + /** + * \brief Store data in the buffer. + * + * \param[in] phase the phase for which data will be stored + * \param[in] obj the data to store + */ + // probably best to get phase and data and store it when it is within valid range of phases + void store(const PhaseType& phase, StoredType data) { + vtAssert(canBeStored(phase), "Phase is out of valid range"); + + buffer_[phaseToIndex(phase)] = std::make_pair(phase, data); + updateHead(phase); } /** @@ -119,7 +145,8 @@ class CircularPhasesBuffer { * \return reference to the stored data */ StoredType& at(const PhaseType phase) { - return buffer_.at(phaseToIndex(phase)); + vtAssert(contains(phase), "Phase is not stored in the buffer."); + return buffer_[phaseToIndex(phase)].second; } /** @@ -130,229 +157,218 @@ class CircularPhasesBuffer { * \return reference to the stored data */ const StoredType& at(const PhaseType phase) const { - return buffer_.at(phaseToIndex(phase)); + vtAssert(contains(phase), "Phase is not stored in the buffer."); + return buffer_[phaseToIndex(phase)].second; } /** - * \brief Find data for a phase. - * - * \param[in] phase the phase to look for + * \brief Resize buffer to the requested size. + * The minimal size of the buffer is 1. * - * \return pointer to phase data, nullptr otherwise. + * \param[in] new_size_in the requested new size of the buffer */ - StoredType* find(const PhaseType& phase) { - if (contains(phase)) { - return &buffer_[phaseToIndex(phase)]; + void resize(const std::size_t new_size_in) { + vtAssert(new_size_in > 0, "Size of circular phases buffer needs to be greather than zero."); + if (new_size_in == buffer_.size()) { + return; } - return nullptr; + + // temporary vector to copy the elements to retain + std::vector tmp(new_size_in, makeEmptyPair()); + // number of elements to copy + auto num = std::min(new_size_in, buffer_.size() - numFree()); + + // copy num phases + auto to_copy = head_phase_; + while(num > 0 && to_copy != no_phase) { + if (contains(to_copy)) { + tmp[calcIndex(to_copy, tmp)] = buffer_[phaseToIndex(to_copy)]; + num--; + } + to_copy--; + } + + buffer_.swap(tmp); } /** - * \brief Find data for a phase. - * - * \param[in] phase the phase to look for + * \brief Check if the buffer is empty. * - * \return pointer to phase data, nullptr otherwise. + * \return whether the buffer is empty or not */ - const StoredType* find(const PhaseType& phase) const { - if (contains(phase)) { - return &buffer_[phaseToIndex(phase)]; - } - return nullptr; + bool empty() const { + return head_phase_ == no_phase; } /** - * \brief Store data in the buffer. + * \brief Get the number of valid elements in the buffer * - * \param[in] phase the phase for which data will be stored - * \param[in] obj the data to store + * \return the number of valid elements */ - void store(const PhaseType& phase, StoredType data) { - buffer_[head_] = std::move(data); - head_ = getNextIndex(); - head_phase_ = phase + 1; - inserted_ = inserted_ + 1; + std::size_t size() const { + return buffer_.size() - numFree(); } /** - * \brief Resize buffer to the requested size. + * \brief Returns the current capacity of the buffer * - * \param[in] new_size the requested new size of the buffer + * \return the buffer capacity */ - void resize(const std::size_t new_size) { - if (new_size == buffer_.size() || new_size == 0) { - return; - } - // temporary vector to copy the elements to retain - std::vector tmp(new_size); - // number of elements to copy - auto num = std::min(new_size, size()); - - // copy - auto to_copy = head_; - for(std::size_t it = num; it > 0; it--) { - to_copy = getPrevIndex(to_copy); - tmp[it - 1] = buffer_[to_copy]; - } + std::size_t capacity() const { + return buffer_.size(); + } - buffer_.swap(tmp); - inserted_ = num; - head_ = getNextIndex(num - 1); + /** + * \brief Clears content of the buffer. + */ + void clear() { + head_phase_ = no_phase; + buffer_.assign(buffer_.size(), makeEmptyPair()); } /** - * \brief Get number of elements in the buffer. + * \brief Get the latest phase * - * \return the number of elements + * \return the latest phase */ - std::size_t size() const { - return std::min(inserted_, buffer_.size()); + PhaseType frontPhase() const { + return head_phase_; } /** - * \brief Check if the buffer is empty. + * \brief Get the data for the latest phase * - * \return whether the buffer is empty or not + * \return the reference to the latest data */ - bool empty() const { - return inserted_ == 0; + StoredType& frontData() { + return at(head_phase_); } /** - * \brief Clears content of the buffer. + * \brief Find data for a phase. + * + * \param[in] phase the phase to look for + * + * \return pointer to phase data, nullptr otherwise. */ - void clear() { - head_ = 0; - inserted_ = 0; - head_phase_ = 0; - buffer_.assign(buffer_.size(), StoredType{}); + StoredType* find(const PhaseType& phase) { + if (contains(phase)) { + return &buffer_[phaseToIndex(phase)].second; + } + return nullptr; } - template - void serialize(SerializeT& s) { - s | head_; - s | inserted_; - s | head_phase_; - s | buffer_; + /** + * \brief Find data for a phase. + * + * \param[in] phase the phase to look for + * + * \return pointer to phase data, nullptr otherwise. + */ + const StoredType* find(const PhaseType& phase) const { + if (contains(phase)) { + return &buffer_[phaseToIndex(phase)].second; + } + return nullptr; } /** - * \brief Get const iterator to the beginning of the buffer + * \brief Get const iterator to the first valid element in the buffer * - * \return the const begin iterator + * \return the const iterator */ - auto begin() const { return ForwardIterator(head_, findTail(), &buffer_); } + auto begin() const { return ++ForwardIterator(&buffer_, no_index); } /** - * \brief Get const iterator to the space after buffer + * \brief Get iterator to the first valid element in the buffer * - * \return the const end iterator + * \return the iterator */ - auto end() const { return ForwardIterator(); } + auto begin() { return ++ForwardIterator(&buffer_, no_index); } /** - * \brief Finds the newest phase in the buffer. + * \brief Get const iterator to the space after the buffer * - * \return the newest phase in the buffer. + * \return the const end iterator */ - PhaseType frontPhase() const { - return inserted_ == 0 ? 0 : head_phase_ - 1; - } + auto end() const { return ForwardIterator(&buffer_, buffer_.size()); } /** - * \brief Get the newest element in buffer. + * \brief Get iterator to the space after the buffer * - * \return the reference to the newest element. + * \return the end iterator */ - StoredType& front() { - return buffer_.at(getPrevIndex(head_)); + auto end() { return ForwardIterator(&buffer_, buffer_.size()); } + + template + void serialize(SerializeT& s) { + s | head_phase_; + s | buffer_; } +private: /** - * \brief Finds the oldest phase in the buffer. + * \brief Converts the phase to the index in the buffer * - * \return the oldest phase in the buffer. + * \param phase - the phase to be converted + * \return the position of the data container in the buffer */ - PhaseType backPhase() const { - if (head_ == inserted_) { - return 0; - } - return head_phase_ - buffer_.size(); + std::size_t phaseToIndex(const PhaseType& phase) const { + return phase % buffer_.size(); } /** - * \brief Get the oldest element in buffer. + * \brief Converts the phase to the index in the temporary buffer * - * \return the reference to the oldest element. + * @param phase - the phase to be converted + * @param vector - the buffer to return index for + * @return the position of the data container in the buffer */ - StoredType& back() { - return buffer_.at(findTail()); + std::size_t calcIndex(const PhaseType& phase, const std::vector& vector) const { + return phase % vector.size(); } -private: - std::size_t findTail() const { - if (inserted_ == 0) { - return no_pos; - } else if (head_ == inserted_) { - return 0; - } - return head_; - } - - std::size_t phaseToIndex(const PhaseType phase) const { - std::size_t go_back = head_phase_ - phase; - if (go_back > head_) { - return size() - (go_back - head_); - } else { - return head_ - go_back; - } - } - - std::size_t getPrevIndex(std::size_t index) const { - std::size_t prev = index - 1; - if (prev > buffer_.size()) { - prev = buffer_.size() - 1; - } - return prev; + /** + * \brief Counts spots in the buffer without a valid phase assigned. + * + * @return the number of empty spots + */ + std::size_t numFree() const { + return std::count_if(buffer_.begin(), buffer_.end(), + [](const StoredPair& pair){ return pair.first == no_phase; } + ); } - std::size_t getNextIndex() const { - std::size_t next = head_ + 1; - if (next >= buffer_.size()) { - next = 0; + /** + * \brief Update the head phase stored in the buffer if necessary + * + * \param phase - the phase to compare to \c head_phase_ + */ + void updateHead(const PhaseType& phase) { + if (head_phase_ == no_phase || phase > head_phase_) { + head_phase_ = phase; } - return next; } - std::size_t getNextIndex(std::size_t index) const { - std::size_t next = index + 1; - if (next >= buffer_.size()) { - next = 0; + bool canBeStored(const PhaseType& phase) const { + if (!empty() && head_phase_ > buffer_.size()) { + return phase > head_phase_ - buffer_.size(); } - return next; + return true; } - // Number of the next index in buffer - std::size_t head_ = 0; - // Counter for inserted phases - std::size_t inserted_ = 0; - // Number of the next phase - PhaseType head_phase_ = 0; - - std::vector buffer_; + PhaseType head_phase_ = no_phase; + std::vector buffer_; public: struct ForwardIterator { using iterator_category = std::forward_iterator_tag; using difference_type = std::ptrdiff_t; - using value_type = StoredType; - using reference = const StoredType&; - - ForwardIterator(std::size_t head, std::size_t index, const std::vector* buffer) - : head_(head), index_(index), buffer_(buffer) {} + using value_type = StoredPair; + using reference = StoredPair&; - ForwardIterator() - : head_(no_pos), index_(no_pos), buffer_(nullptr) {} + ForwardIterator(std::vector* buffer, std::size_t index) + : index_(index), buffer_(buffer) { } reference operator*() { return (*buffer_)[index_]; } @@ -366,23 +382,22 @@ class CircularPhasesBuffer { return tmp; } - bool operator== (const ForwardIterator& it) { return index_ == it.index_; }; - bool operator!= (const ForwardIterator& it) { return index_ != it.index_; }; + bool operator== (const ForwardIterator& it) const { return index_ == it.index_; }; + bool operator!= (const ForwardIterator& it) const { return index_ != it.index_; }; private: void advance() { index_++; - if (index_ >= buffer_->size()) { - index_ = 0; + if (index_ == buffer_->size()) { + return; } - if (index_ == head_) { - index_ = no_pos; + if ((*buffer_)[index_].first == no_phase) { + advance(); } } - std::size_t head_; std::size_t index_; - const std::vector* buffer_; + std::vector* buffer_; }; }; From 14c17f3884cf8405e06bd9e22a09016e67aac7c8 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 17 Sep 2024 16:41:55 +0200 Subject: [PATCH 62/82] #1934: Update tests for circular buffer to support the new implementation --- .../test_circular_phases_buffer.nompi.cc | 160 +++++++++++++----- 1 file changed, 118 insertions(+), 42 deletions(-) diff --git a/tests/unit/utils/test_circular_phases_buffer.nompi.cc b/tests/unit/utils/test_circular_phases_buffer.nompi.cc index 105090a688..dfbf1aa857 100644 --- a/tests/unit/utils/test_circular_phases_buffer.nompi.cc +++ b/tests/unit/utils/test_circular_phases_buffer.nompi.cc @@ -58,14 +58,17 @@ using CircularBufferType = util::container::CircularPhasesBuffer; void validatePresentPhases(CircularBufferType& buffer, std::vector expected) { for (auto&& phase : expected) { - EXPECT_TRUE(buffer.contains(phase)) << "Phase: " << phase; - EXPECT_EQ(phase, buffer.at(phase).x) << "Phase: " << phase; + EXPECT_TRUE(buffer.contains(phase)) << " Phase: " << phase; + EXPECT_EQ(phase, buffer.at(phase).x) << " Phase: " << phase; + EXPECT_EQ(phase, buffer[phase].x) << " Phase: " << phase; + EXPECT_EQ(phase, buffer.find(phase)->x) << " Phase: " << phase; } } void validateMissingPhases(CircularBufferType& buffer, std::vector expected) { for (auto&& phase : expected) { - EXPECT_FALSE(buffer.contains(phase)) << "Phase: " << phase; + EXPECT_FALSE(buffer.contains(phase)) << " Phase: " << phase; + EXPECT_EQ(nullptr, buffer.find(phase)) << " Phase: " << phase; } } @@ -75,32 +78,24 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_empty) { EXPECT_FALSE(buffer.contains(0)); EXPECT_EQ(std::size_t{0}, buffer.size()); EXPECT_TRUE(buffer.empty()); - EXPECT_EQ(0, buffer.backPhase()); - EXPECT_EQ(0, buffer.frontPhase()); + EXPECT_EQ(std::numeric_limits::max(), buffer.frontPhase()); + EXPECT_EQ(nullptr, buffer.find(0)); buffer.resize(2); EXPECT_FALSE(buffer.contains(0)); EXPECT_EQ(std::size_t{0}, buffer.size()); EXPECT_TRUE(buffer.empty()); - EXPECT_EQ(0, buffer.backPhase()); - EXPECT_EQ(0, buffer.frontPhase()); + EXPECT_EQ(std::numeric_limits::max(), buffer.frontPhase()); + EXPECT_EQ(nullptr, buffer.find(0)); buffer.clear(); EXPECT_FALSE(buffer.contains(1)); EXPECT_EQ(std::size_t{0}, buffer.size()); EXPECT_TRUE(buffer.empty()); - EXPECT_EQ(0, buffer.backPhase()); - EXPECT_EQ(0, buffer.frontPhase()); - - buffer.resize(0); - - EXPECT_FALSE(buffer.contains(1)); - EXPECT_EQ(std::size_t{0}, buffer.size()); - EXPECT_TRUE(buffer.empty()); - EXPECT_EQ(0, buffer.backPhase()); - EXPECT_EQ(0, buffer.frontPhase()); + EXPECT_EQ(std::numeric_limits::max(), buffer.frontPhase()); + EXPECT_EQ(nullptr, buffer.find(0)); buffer.resize(4); buffer[0] = {0}; @@ -108,10 +103,9 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_empty) { EXPECT_TRUE(buffer.contains(0)); EXPECT_EQ(std::size_t{1}, buffer.size()); EXPECT_FALSE(buffer.empty()); - EXPECT_EQ(0, buffer.backPhase()); EXPECT_EQ(0, buffer.frontPhase()); - EXPECT_EQ(0, buffer.back().x); - EXPECT_EQ(0, buffer.front().x); + EXPECT_EQ(0, buffer.frontData().x); + EXPECT_NE(nullptr, buffer.find(0)); buffer[1] = {1}; buffer[2] = {4}; @@ -121,18 +115,18 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_empty) { EXPECT_TRUE(buffer.contains(1)); EXPECT_EQ(std::size_t{4}, buffer.size()); EXPECT_FALSE(buffer.empty()); - EXPECT_EQ(1, buffer.backPhase()); EXPECT_EQ(4, buffer.frontPhase()); - EXPECT_EQ(1, buffer.back().x); - EXPECT_EQ(8, buffer.front().x); + EXPECT_EQ(8, buffer.frontData().x); + EXPECT_EQ(nullptr, buffer.find(0)); + EXPECT_NE(nullptr, buffer.find(3)); buffer.clear(); EXPECT_FALSE(buffer.contains(0)); EXPECT_EQ(std::size_t{0}, buffer.size()); EXPECT_TRUE(buffer.empty()); - EXPECT_EQ(0, buffer.backPhase()); - EXPECT_EQ(0, buffer.frontPhase()); + EXPECT_EQ(std::numeric_limits::max(), buffer.frontPhase()); + EXPECT_EQ(nullptr, buffer.find(0)); } TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_single_element) { @@ -148,7 +142,12 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_single_element) { EXPECT_EQ(i == 3, buffer.contains(3)); EXPECT_EQ(i == 4, buffer.contains(4)); EXPECT_EQ(i == 5, buffer.contains(5)); - EXPECT_EQ(i == 6, buffer.contains(5)); + EXPECT_EQ(i == 6, buffer.contains(6)); + + EXPECT_EQ(i, buffer.frontPhase()); + EXPECT_EQ(i, buffer.frontData().x); + EXPECT_NE(nullptr, buffer.find(i)); + EXPECT_NO_THROW(buffer.at(i)); } } @@ -157,6 +156,11 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_multi_elements) { for (int i = 0; i < 15; i++) { buffer.store(i, {i}); + + EXPECT_EQ(i, buffer.frontPhase()); + EXPECT_EQ(i, buffer.frontData().x); + EXPECT_NE(nullptr, buffer.find(i)); + EXPECT_NO_THROW(buffer.at(i)); } std::vector finalOutput = {10, 11, 12, 13, 14}; validatePresentPhases(buffer, finalOutput); @@ -172,12 +176,14 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_store) { buffer.resize(10); validatePresentPhases(buffer, {2}); - validateMissingPhases(buffer, {0, 1}); + validateMissingPhases(buffer, {0, 1, 3, 4, 5, 6, 7, 8, 9}); // store series of elements for (int i = 3; i < 15; i++) { buffer.store(i, {i}); } + + validateMissingPhases(buffer, {0, 1, 2, 3, 4}); std::vector finalOutput = {5, 6, 7, 8, 9, 10, 11, 12, 13, 14}; validatePresentPhases(buffer, finalOutput); } @@ -202,6 +208,8 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_resize) { buffer.resize(9); + validatePresentPhases(buffer, {28, 29, 30, 31, 32}); + for (int i = 33; i <= 35; i++) { buffer[i] = {i}; } @@ -210,36 +218,104 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_resize) { buffer.resize(1); validatePresentPhases(buffer, {35}); validateMissingPhases(buffer, {28, 29, 30, 31, 32, 33, 34}); - - buffer.resize(0); - validatePresentPhases(buffer, {35}); } TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_forward_iter) { - CircularBufferType buffer{0}; + CircularBufferType buffer; - for (auto& ele : buffer) { EXPECT_EQ(123, ele.x); } - for (auto&& ele : buffer) { EXPECT_EQ(123, ele.x); } + for (auto& ele: buffer) { + EXPECT_EQ(true, false) << " Phase: " << ele.first; + } + for (auto&& ele : buffer) { + EXPECT_EQ(true, false) << " Phase: " << ele.first; + } - buffer.resize(3); + buffer.resize(9); buffer[0] = {0}; - buffer[1] = {1}; - buffer[2] = {2}; + buffer[3] = {3}; + buffer[7] = {7}; { - int iter = 0; + std::vector visited; for (auto&& ele : buffer) { - EXPECT_EQ(iter, ele.x); - iter++; + visited.push_back(ele.first); } + validatePresentPhases(buffer, visited); + EXPECT_EQ(visited.size(), buffer.size()); } { - int iter = 0; + std::vector visited; for (auto& ele : buffer) { - EXPECT_EQ(iter, ele.x); - iter++; + visited.push_back(ele.first); } + validatePresentPhases(buffer, visited); + EXPECT_EQ(visited.size(), buffer.size()); + } + + for (int i = 0; i <= 15; i++) { + buffer[i] = {i}; + } + + { + std::vector visited; + for (auto&& ele : buffer) { + visited.push_back(ele.first); + } + validatePresentPhases(buffer, visited); + EXPECT_EQ(visited.size(), buffer.size()); + } + + { + std::vector visited; + for (auto& ele : buffer) { + visited.push_back(ele.first); + } + validatePresentPhases(buffer, visited); + EXPECT_EQ(visited.size(), buffer.size()); + } +} + +TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_list_init) { + { + CircularBufferType buffer{}; + + EXPECT_EQ(true, buffer.empty()); + EXPECT_EQ(0, buffer.size()); + EXPECT_EQ(1, buffer.capacity()); + } + + { + CircularBufferType buffer{{0, {0}}, {1, {1}}, {2, {2}}}; + + EXPECT_EQ(false, buffer.empty()); + EXPECT_EQ(3, buffer.size()); + EXPECT_EQ(3, buffer.capacity()); + validatePresentPhases(buffer, {0, 1, 2}); + EXPECT_EQ(2, buffer.frontPhase()); + EXPECT_EQ(2, buffer.frontData().x); + } + + { + CircularBufferType buffer{{4, {4}}, {9, {9}}, {0, {0}}}; + + EXPECT_EQ(false, buffer.empty()); + EXPECT_EQ(3, buffer.size()); + EXPECT_EQ(10, buffer.capacity()); + validatePresentPhases(buffer, {0, 4, 9}); + EXPECT_EQ(9, buffer.frontPhase()); + EXPECT_EQ(9, buffer.frontData().x); + } + + { + CircularBufferType buffer{{9, {9}}, {4, {4}}, {12, {12}}}; + + EXPECT_EQ(false, buffer.empty()); + EXPECT_EQ(3, buffer.size()); + EXPECT_EQ(9, buffer.capacity()); + validatePresentPhases(buffer, {12, 4, 9}); + EXPECT_EQ(12, buffer.frontPhase()); + EXPECT_EQ(12, buffer.frontData().x); } } From 5a94672c8ebfdfb150c6cb90156741086c03102a Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 17 Sep 2024 16:42:22 +0200 Subject: [PATCH 63/82] #1934: Update usage of the buffer in the codebase --- .../vrt/collection/balance/workload_replay.cc | 8 ++++---- tests/unit/collection/test_lb.extended.cc | 7 ++++--- tests/unit/lb/test_lb_data_comm.cc | 18 +++++++++--------- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/vt/vrt/collection/balance/workload_replay.cc b/src/vt/vrt/collection/balance/workload_replay.cc index 0017905b56..975e3ae515 100644 --- a/src/vt/vrt/collection/balance/workload_replay.cc +++ b/src/vt/vrt/collection/balance/workload_replay.cc @@ -249,19 +249,19 @@ readInWorkloads(const std::string &filename) { auto json = r.readFile(); auto sd = std::make_shared(*json); - for (auto phase = sd->node_data_.backPhase(); phase <= sd->node_data_.frontPhase(); phase++) { + for (auto &phase_data : sd->node_data_) { vt_debug_print( normal, replay, "found {} loads for phase {}\n", - sd->node_data_[phase].size(), phase + phase_data.second.size(), phase_data.first ); } - for (auto phase = sd->node_comm_.backPhase(); phase <= sd->node_comm_.frontPhase(); phase++) { + for (auto &phase_data : sd->node_comm_) { vt_debug_print( normal, replay, "found {} comms for phase {}\n", - sd->node_comm_[phase].size(), phase + phase_data.second.size(), phase_data.first ); } diff --git a/tests/unit/collection/test_lb.extended.cc b/tests/unit/collection/test_lb.extended.cc index 514a155c35..3ad7604913 100644 --- a/tests/unit/collection/test_lb.extended.cc +++ b/tests/unit/collection/test_lb.extended.cc @@ -616,8 +616,9 @@ TEST_F(TestRestoreLBData, test_restore_lb_data_data_1) { ); } else { // compare the whole-phase load data in detail - for (auto phase = lbdh.node_data_.backPhase(); phase <= lbdh.node_data_.frontPhase(); phase++) { - EXPECT_TRUE(lbdh_read.node_data_.contains(phase)); + for (auto &phase_data : lbdh.node_data_) { + auto phase = phase_data.first; + EXPECT_FALSE(!lbdh_read.node_data_.contains(phase)); if (!lbdh_read.node_data_.contains(phase)) { fmt::print( "Phase {} in whole-phase loads were not read in", @@ -625,7 +626,7 @@ TEST_F(TestRestoreLBData, test_restore_lb_data_data_1) { ); } else { auto &read_load_map = lbdh_read.node_data_[phase]; - auto &orig_load_map = lbdh.node_data_[phase]; + auto &orig_load_map = phase_data.second; for (auto &entry : read_load_map) { auto read_elm_id = entry.first; if ((read_elm_id.id == vt::elm::no_element_id) diff --git a/tests/unit/lb/test_lb_data_comm.cc b/tests/unit/lb/test_lb_data_comm.cc index fd3379887e..c314068847 100644 --- a/tests/unit/lb/test_lb_data_comm.cc +++ b/tests/unit/lb/test_lb_data_comm.cc @@ -294,7 +294,7 @@ TEST_F(TestLBDataComm, test_lb_data_comm_col_to_col_send) { if (proxy(i).tryGetLocalPtr()) { bool found = false; for (auto&& x : comm) { - for (auto&& y : x) { + for (auto&& y : x.second) { auto key = y.first; auto vol = y.second; if (key.to_.id == idxToElmID(idx)) { @@ -358,7 +358,7 @@ TEST_F(TestLBDataComm, test_lb_data_comm_col_to_objgroup_send) { bool found = false; auto idb = vt::elm::ElmIDBits::createObjGroup(op, next).id; for (auto&& x : comm) { - for (auto&& y : x) { + for (auto&& y : x.second) { auto key = y.first; auto vol = y.second; if (key.from_.id == idxToElmID(idx) /*and key.to_.id == idb*/) { @@ -421,7 +421,7 @@ TEST_F(TestLBDataComm, test_lb_data_comm_objgroup_to_col_send) { if (proxy(i).tryGetLocalPtr()) { bool found = false; for (auto&& x : comm) { - for (auto&& y : x) { + for (auto&& y : x.second) { auto key = y.first; auto vol = y.second; if (key.to_.id == idxToElmID(idx)) { @@ -475,7 +475,7 @@ TEST_F(TestLBDataComm, test_lb_data_comm_objgroup_to_objgroup_send) { // Check that communication exists on the send side as expected bool found = false; for (auto&& x : comm) { - for (auto&& y : x) { + for (auto&& y : x.second) { auto key = y.first; auto vol = y.second; if (key.from_.id == ida /*and key.to_.id == idb*/) { @@ -532,7 +532,7 @@ TEST_F(TestLBDataComm, test_lb_data_comm_handler_to_col_send) { if (proxy(i).tryGetLocalPtr()) { bool found = false; for (auto&& x : comm) { - for (auto&& y : x) { + for (auto&& y : x.second) { auto key = y.first; auto vol = y.second; if (key.to_.id == idxToElmID(idx)) { @@ -592,7 +592,7 @@ TEST_F(TestLBDataComm, test_lb_data_comm_col_to_handler_send) { if (proxy(i).tryGetLocalPtr()) { bool found = false; for (auto&& x : comm) { - for (auto&& y : x) { + for (auto&& y : x.second) { auto key = y.first; auto vol = y.second; fmt::print("from={}, to={}\n", key.from_, key.to_); @@ -641,7 +641,7 @@ TEST_F(TestLBDataComm, test_lb_data_comm_objgroup_to_handler_send) { // Check that communication exists on the send side as expected bool found = false; for (auto&& x : comm) { - for (auto&& y : x) { + for (auto&& y : x.second) { auto key = y.first; auto vol = y.second; if (key.from_.id == ida) { @@ -686,7 +686,7 @@ TEST_F(TestLBDataComm, test_lb_data_comm_handler_to_objgroup_send) { // Check that communication exists on the send side as expected bool found = false; for (auto&& x : comm) { - for (auto&& y : x) { + for (auto&& y : x.second) { auto key = y.first; auto vol = y.second; if (key.to_.id == ida) { @@ -727,7 +727,7 @@ TEST_F(TestLBDataComm, test_lb_data_comm_handler_to_handler_send) { // Check that communication exists on the send side as expected bool found = false; for (auto&& x : comm) { - for (auto&& y : x) { + for (auto&& y : x.second) { auto key = y.first; auto vol = y.second; if (key.to_.id == ida and key.from_.id == idb) { From 1d828ae7a16cc161455dd6642e00dbca3f5f9fbf Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 17 Sep 2024 17:13:47 +0200 Subject: [PATCH 64/82] #1934: Update LBDataHolder to use default constructor --- src/vt/vrt/collection/balance/lb_data_holder.cc | 2 ++ src/vt/vrt/collection/balance/lb_data_holder.h | 7 +------ src/vt/vrt/collection/balance/node_lb_data.cc | 10 +++------- tests/unit/collection/test_workload_data_migrator.cc | 9 ++++++--- 4 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/vt/vrt/collection/balance/lb_data_holder.cc b/src/vt/vrt/collection/balance/lb_data_holder.cc index 4a167dff10..c81484f8ba 100644 --- a/src/vt/vrt/collection/balance/lb_data_holder.cc +++ b/src/vt/vrt/collection/balance/lb_data_holder.cc @@ -51,6 +51,8 @@ #include +#include + namespace vt { namespace vrt { namespace collection { namespace balance { void LBDataHolder::getObjectFromJsonField_( diff --git a/src/vt/vrt/collection/balance/lb_data_holder.h b/src/vt/vrt/collection/balance/lb_data_holder.h index ce77afb7d8..5bd2b10835 100644 --- a/src/vt/vrt/collection/balance/lb_data_holder.h +++ b/src/vt/vrt/collection/balance/lb_data_holder.h @@ -65,12 +65,7 @@ namespace vt { namespace vrt { namespace collection { namespace balance { * output them as JSON. */ struct LBDataHolder { - /** - * \brief Construct a new \c LBDataHolder with specified history length. - * - * \param[in] phases_history_num the number of phases to retain - */ - LBDataHolder(std::size_t phases_history_num); + LBDataHolder() = default; /** * \brief Create \c LBDataHolder from input JSON diff --git a/src/vt/vrt/collection/balance/node_lb_data.cc b/src/vt/vrt/collection/balance/node_lb_data.cc index 549e8b5723..8a69373817 100644 --- a/src/vt/vrt/collection/balance/node_lb_data.cc +++ b/src/vt/vrt/collection/balance/node_lb_data.cc @@ -139,12 +139,7 @@ void NodeLBData::resizeLBDataHistory(uint32_t new_hist_len) { hist_lb_data_size_ = new_hist_len; if (lb_data_) { - lb_data_->node_data_.resize(new_hist_len); - lb_data_->node_comm_.resize(new_hist_len); - lb_data_->node_subphase_comm_.resize(new_hist_len); - lb_data_->user_defined_lb_info_.resize(new_hist_len); - lb_data_->user_defined_json_.resize(new_hist_len); - lb_data_->node_user_attributes_.resize(new_hist_len); + lb_data_->resizeHistory(hist_lb_data_size_); } startIterCleanup(); @@ -155,7 +150,8 @@ ElementIDType NodeLBData::getNextElm() { } void NodeLBData::initialize() { - lb_data_ = std::make_unique(hist_lb_data_size_); + lb_data_ = std::make_unique(); + lb_data_->resizeHistory(hist_lb_data_size_); #if vt_check_enabled(lblite) if (theConfig()->vt_lb_data) { diff --git a/tests/unit/collection/test_workload_data_migrator.cc b/tests/unit/collection/test_workload_data_migrator.cc index fac8d4c666..f6e7c1f752 100644 --- a/tests/unit/collection/test_workload_data_migrator.cc +++ b/tests/unit/collection/test_workload_data_migrator.cc @@ -93,7 +93,8 @@ setupWorkloads(PhaseType phase, size_t numElements) { ); } - auto lbdh = std::make_shared(1); + auto lbdh = std::make_shared(); + lbdh->resizeHistory(1); for (auto&& elmID : myElemList) { double tval = elmID.id * 2; @@ -790,7 +791,8 @@ setupManyWorkloads( ); } - auto lbdh = std::make_shared(num_phases); + auto lbdh = std::make_shared(); + lbdh->resizeHistory(num_phases); PhaseType stop_phase = initial_phase + num_phases; for (PhaseType phase = initial_phase; phase < stop_phase; ++phase) { @@ -804,7 +806,8 @@ setupManyWorkloads( } } - auto scrambled_lbdh = std::make_shared(num_phases); + auto scrambled_lbdh = std::make_shared(); + scrambled_lbdh->resizeHistory(num_phases); for (PhaseType phase = initial_phase; phase < stop_phase; ++phase) { auto base_load_model = setupBaseModel(phase, lbdh); From 13b5d7fa418763424243078e33ee88be80273e52 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Thu, 19 Sep 2024 14:28:44 +0200 Subject: [PATCH 65/82] #1934: Remove list initializer constructor --- .../utils/container/circular_phases_buffer.h | 37 ++++++---------- .../test_circular_phases_buffer.nompi.cc | 43 ------------------- 2 files changed, 13 insertions(+), 67 deletions(-) diff --git a/src/vt/utils/container/circular_phases_buffer.h b/src/vt/utils/container/circular_phases_buffer.h index f5fd1b95a3..fd3d901d67 100644 --- a/src/vt/utils/container/circular_phases_buffer.h +++ b/src/vt/utils/container/circular_phases_buffer.h @@ -46,6 +46,7 @@ #include "vt/config.h" #include +#include namespace vt { namespace util { namespace container { @@ -61,6 +62,12 @@ class CircularPhasesBuffer { constexpr static auto no_phase = std::numeric_limits::max(); constexpr static auto no_index = std::numeric_limits::max(); + /** + * \brief Creates a new pair to be stored in the buffer + * + * \param phase - the phase to be assigned, \c no_phase otherwise + * \return the new pair + */ static StoredPair makeEmptyPair(const PhaseType& phase = no_phase) { return std::make_pair(phase, StoredType{}); } @@ -75,33 +82,16 @@ class CircularPhasesBuffer { CircularPhasesBuffer(std::size_t size_in = 1) : buffer_(size_in, makeEmptyPair()) { - vtAssert(size_in > 0, "Size of circular phases buffer needs to be greather than zero."); + vtAssert(size_in > 0, "Size of CircularPhasesBuffer needs to be greather than zero."); } - /** - * \brief Construct a CircularPhasesBuffer. - * - * \param[in] in_list the initializer list with elements to be put into the buffer - */ - CircularPhasesBuffer(std::initializer_list in_list) { - const auto& [min, max] = std::minmax(in_list, [](const StoredPair& lhs, const StoredPair& rhs) { - return lhs.first < rhs.first; - }); - // Calcuate the size of the buffer to hold all phases including the missing ones - buffer_.resize((max.first - min.first) + 1, makeEmptyPair()); - - for (auto pair : in_list) { - buffer_[phaseToIndex(pair.first)] = pair; - updateHead(pair.first); - } - } /** * \brief Check if phase is present in the buffer. * * \param[in] phase the phase to look for * - * \return whether buffer contains the phase or not + * \return whenever the buffer contains the phase or not */ bool contains(const PhaseType& phase) const { return buffer_[phaseToIndex(phase)].first == phase; @@ -129,7 +119,6 @@ class CircularPhasesBuffer { * \param[in] phase the phase for which data will be stored * \param[in] obj the data to store */ - // probably best to get phase and data and store it when it is within valid range of phases void store(const PhaseType& phase, StoredType data) { vtAssert(canBeStored(phase), "Phase is out of valid range"); @@ -168,15 +157,15 @@ class CircularPhasesBuffer { * \param[in] new_size_in the requested new size of the buffer */ void resize(const std::size_t new_size_in) { - vtAssert(new_size_in > 0, "Size of circular phases buffer needs to be greather than zero."); - if (new_size_in == buffer_.size()) { + auto new_size = std::max(std::size_t{1}, new_size_in); + if (new_size == buffer_.size()) { return; } // temporary vector to copy the elements to retain - std::vector tmp(new_size_in, makeEmptyPair()); + std::vector tmp(new_size, makeEmptyPair()); // number of elements to copy - auto num = std::min(new_size_in, buffer_.size() - numFree()); + auto num = std::min(new_size, buffer_.size() - numFree()); // copy num phases auto to_copy = head_phase_; diff --git a/tests/unit/utils/test_circular_phases_buffer.nompi.cc b/tests/unit/utils/test_circular_phases_buffer.nompi.cc index dfbf1aa857..27d5289dee 100644 --- a/tests/unit/utils/test_circular_phases_buffer.nompi.cc +++ b/tests/unit/utils/test_circular_phases_buffer.nompi.cc @@ -276,47 +276,4 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_forward_iter) { } } -TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_list_init) { - { - CircularBufferType buffer{}; - - EXPECT_EQ(true, buffer.empty()); - EXPECT_EQ(0, buffer.size()); - EXPECT_EQ(1, buffer.capacity()); - } - - { - CircularBufferType buffer{{0, {0}}, {1, {1}}, {2, {2}}}; - - EXPECT_EQ(false, buffer.empty()); - EXPECT_EQ(3, buffer.size()); - EXPECT_EQ(3, buffer.capacity()); - validatePresentPhases(buffer, {0, 1, 2}); - EXPECT_EQ(2, buffer.frontPhase()); - EXPECT_EQ(2, buffer.frontData().x); - } - - { - CircularBufferType buffer{{4, {4}}, {9, {9}}, {0, {0}}}; - - EXPECT_EQ(false, buffer.empty()); - EXPECT_EQ(3, buffer.size()); - EXPECT_EQ(10, buffer.capacity()); - validatePresentPhases(buffer, {0, 4, 9}); - EXPECT_EQ(9, buffer.frontPhase()); - EXPECT_EQ(9, buffer.frontData().x); - } - - { - CircularBufferType buffer{{9, {9}}, {4, {4}}, {12, {12}}}; - - EXPECT_EQ(false, buffer.empty()); - EXPECT_EQ(3, buffer.size()); - EXPECT_EQ(9, buffer.capacity()); - validatePresentPhases(buffer, {12, 4, 9}); - EXPECT_EQ(12, buffer.frontPhase()); - EXPECT_EQ(12, buffer.frontData().x); - } -} - }}} /* end namespace vt::tests::unit */ From b36b93376502eb61bf10b5a1abcf9701c55a2ed6 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Thu, 19 Sep 2024 14:30:10 +0200 Subject: [PATCH 66/82] #1934: Update LBDataHolder to resize containers when reading data from json --- .../vrt/collection/balance/lb_data_holder.cc | 58 +++++++++++-------- .../vrt/collection/balance/lb_data_holder.h | 4 +- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/src/vt/vrt/collection/balance/lb_data_holder.cc b/src/vt/vrt/collection/balance/lb_data_holder.cc index c81484f8ba..2c3eb5f0aa 100644 --- a/src/vt/vrt/collection/balance/lb_data_holder.cc +++ b/src/vt/vrt/collection/balance/lb_data_holder.cc @@ -433,32 +433,10 @@ LBDataHolder::LBDataHolder(nlohmann::json const& j) this_node_ = theContext()->getNode(); // read metadata for skipped and identical phases - auto num_phases = readMetadata(j); - auto largest_identical = identical_phases_.size() > 0 ? *identical_phases_.rbegin() : 0; - auto largest_skipped = skipped_phases_.size() > 0 ? *skipped_phases_.rbegin() : 0; - PhaseType max_phase = std::max(largest_identical, largest_skipped); + readMetadata(j); auto phases = j["phases"]; if (phases.is_array()) { - num_phases = std::max(num_phases, phases.size()); - - for(auto const& phase: phases) { - auto id = phase["id"]; - if (id > max_phase) { - max_phase = id; - } - } - resizeHistory(num_phases); - // create entries in buffer for each phase - PhaseType min_phase = 0; - if (max_phase > num_phases) { - min_phase = max_phase - num_phases; - } - for (auto i = min_phase; i <= max_phase; i++) { - this->node_data_[i]; - this->node_comm_[i]; - } - for (auto const& phase : phases) { auto id = phase["id"]; auto tasks = phase["tasks"]; @@ -652,7 +630,7 @@ LBDataHolder::LBDataHolder(nlohmann::json const& j) // right now, so it will be ignored } -std::size_t LBDataHolder::readMetadata(nlohmann::json const& j) { +void LBDataHolder::readMetadata(nlohmann::json const& j) { std::size_t num_phases = 0; if (j.find("metadata") != j.end()) { auto metadata = j["metadata"]; @@ -710,7 +688,37 @@ std::size_t LBDataHolder::readMetadata(nlohmann::json const& j) { } } - return num_phases; + // Adjust the capacity of the data containers + if (num_phases > 0) { + resizeHistory(num_phases); + } else { + // find min and max phase + PhaseType min = std::numeric_limits::max(); + PhaseType max = 0; + + if (identical_phases_.size() > 0) { + min = std::min(min, *identical_phases_.begin()); + max = std::max(max, *identical_phases_.rbegin()); + } + if (skipped_phases_.size() > 0) { + min = std::min(min, *skipped_phases_.begin()); + max = std::max(max, *skipped_phases_.rbegin()); + } + + auto phases = j["phases"]; + if (phases.is_array()) { + for (auto const& phase : phases) { + auto id = phase["id"]; + if (id < min) { + min = id; + } else if (id > max) { + max = id; + } + } + } + + resizeHistory((max - min) + 1); + } } void LBDataHolder::clear() { diff --git a/src/vt/vrt/collection/balance/lb_data_holder.h b/src/vt/vrt/collection/balance/lb_data_holder.h index 5bd2b10835..4451bfc94c 100644 --- a/src/vt/vrt/collection/balance/lb_data_holder.h +++ b/src/vt/vrt/collection/balance/lb_data_holder.h @@ -182,10 +182,8 @@ struct LBDataHolder { * \brief Read the LB phase's metadata * * \param[in] j the json - * - * \return the number of phases in the json's metadata */ - std::size_t readMetadata(nlohmann::json const& j); + void readMetadata(nlohmann::json const& j); public: /// The current node From 7f3f0e1d01d47b4e660ef751e79be46e7f7d24bf Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Thu, 19 Sep 2024 14:36:07 +0200 Subject: [PATCH 67/82] #1934: Update tests to not use the removed constructor --- tests/unit/collection/test_lb_data_holder.cc | 3 +- .../test_model_comm_overhead.nompi.cc | 41 ++++++++----------- .../test_model_linear_model.nompi.cc | 7 ++-- .../test_model_multiple_phases.nompi.cc | 18 ++++---- .../test_model_naive_persistence.nompi.cc | 26 ++++++------ .../unit/collection/test_model_norm.nompi.cc | 29 ++++++------- .../test_model_select_subphases.nompi.cc | 23 ++++------- ...del_weighted_communication_volume.nompi.cc | 36 ++++++++-------- .../test_model_weighted_messages.nompi.cc | 36 ++++++++-------- 9 files changed, 101 insertions(+), 118 deletions(-) diff --git a/tests/unit/collection/test_lb_data_holder.cc b/tests/unit/collection/test_lb_data_holder.cc index dee8295a58..df8bf9248f 100644 --- a/tests/unit/collection/test_lb_data_holder.cc +++ b/tests/unit/collection/test_lb_data_holder.cc @@ -74,7 +74,8 @@ void addPhasesDataToJson(nlohmann::json& json, PhaseType amountOfPhasesToAdd, st } } - LBDataHolder dh(amountOfPhasesToAdd); + LBDataHolder dh; + dh.resizeHistory(amountOfPhasesToAdd); for (unsigned i = 0; i < amountOfPhasesToAdd; i++) { for (auto&& elm : ids[i]) { dh.node_data_[i][elm] = LoadSummary{3.}; diff --git a/tests/unit/collection/test_model_comm_overhead.nompi.cc b/tests/unit/collection/test_model_comm_overhead.nompi.cc index cea0d70e58..3e1f338796 100644 --- a/tests/unit/collection/test_model_comm_overhead.nompi.cc +++ b/tests/unit/collection/test_model_comm_overhead.nompi.cc @@ -124,29 +124,24 @@ TEST_F(TestModelCommOverhead, test_model_comm_overhead_1) { // Element 3 (home node == 3) ElementIDStruct const elem3 = {3, 3}; - LoadMapBufferType proc_load = {{0, LoadMapType{{elem2, {LoadType{150}, {}}}}}}; - - CommMapBufferType proc_comm = { - {0, - CommMapType{// Node 1 -> Node 2 - {{CommKeyType::CollectionTag{}, elem1, elem2, false}, - CommVolume{20.0, 2}}, - - // Node 3 -> Node 2 - {{CommKeyType::CollectionTag{}, elem3, elem2, false}, - CommVolume{5.0, 5}}} - }, - {1, - CommMapType{ - // Node 3 -> Node 2 - {{CommKeyType::CollectionTag{}, elem3, elem2, false}, - CommVolume{500.0, 50}}, - - // Node 1 -> Node 2 - {{CommKeyType::CollectionTag{}, elem1, elem2, false}, - CommVolume{25.0, 10}}} - } - }; + LoadMapBufferType proc_load(1); + proc_load[0] = LoadMapType{{elem2, {LoadType{150}, {}}}}; + + CommMapBufferType proc_comm(2); + proc_comm[0] = CommMapType{ + // Node 1 -> Node 2 + {{CommKeyType::CollectionTag{}, elem1, elem2, false}, CommVolume{20.0, 2}}, + + // Node 3 -> Node 2 + {{CommKeyType::CollectionTag{}, elem3, elem2, false}, CommVolume{5.0, 5}}}; + proc_comm[1] = + CommMapType{// Node 3 -> Node 2 + {{CommKeyType::CollectionTag{}, elem3, elem2, false}, + CommVolume{500.0, 50}}, + + // Node 1 -> Node 2 + {{CommKeyType::CollectionTag{}, elem1, elem2, false}, + CommVolume{25.0, 10}}}; constexpr auto per_msg_weight = 3.0; constexpr auto per_byte_weight = 5.0; diff --git a/tests/unit/collection/test_model_linear_model.nompi.cc b/tests/unit/collection/test_model_linear_model.nompi.cc index 91460dc3e2..a6152f4720 100644 --- a/tests/unit/collection/test_model_linear_model.nompi.cc +++ b/tests/unit/collection/test_model_linear_model.nompi.cc @@ -110,11 +110,10 @@ 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 - LoadMapBufferType proc_loads{{0, LoadMapType{ + LoadMapBufferType proc_loads(num_test_interations + 1); + proc_loads[0] = LoadMapType{ {ElementIDStruct{1,this_node}, {LoadType{10}, {}}}, - {ElementIDStruct{2,this_node}, {LoadType{40}, {}}} - }}}; - proc_loads.resize(num_test_interations + 1); + {ElementIDStruct{2,this_node}, {LoadType{40}, {}}}}; test_model->setLoads(&proc_loads, nullptr, nullptr); test_model->updateLoads(0); diff --git a/tests/unit/collection/test_model_multiple_phases.nompi.cc b/tests/unit/collection/test_model_multiple_phases.nompi.cc index 5266885eb9..e9e280a87c 100644 --- a/tests/unit/collection/test_model_multiple_phases.nompi.cc +++ b/tests/unit/collection/test_model_multiple_phases.nompi.cc @@ -103,19 +103,19 @@ struct StubModel : LoadModel { TEST_F(TestModelMultiplePhases, test_model_multiple_phases_1) { NodeType this_node = 0; - LoadMapBufferType proc_loads = { - {0, LoadMapType{ + LoadMapBufferType proc_loads(4); + proc_loads[0] = LoadMapType{ {ElementIDStruct{1,this_node}, {LoadType{10}, {}}}, - {ElementIDStruct{2,this_node}, {LoadType{40}, {}}}}}, - {1, LoadMapType{ + {ElementIDStruct{2,this_node}, {LoadType{40}, {}}}}; + proc_loads[1] = LoadMapType{ {ElementIDStruct{1,this_node}, {LoadType{20}, {}}}, - {ElementIDStruct{2,this_node}, {LoadType{30}, {}}}}}, - {2, LoadMapType{ + {ElementIDStruct{2,this_node}, {LoadType{30}, {}}}}; + proc_loads[2] = LoadMapType{ {ElementIDStruct{1,this_node}, {LoadType{30}, {}}}, - {ElementIDStruct{2,this_node}, {LoadType{10}, {}}}}}, - {3, LoadMapType{ + {ElementIDStruct{2,this_node}, {LoadType{10}, {}}}}; + proc_loads[3] = LoadMapType{ {ElementIDStruct{1,this_node}, {LoadType{40}, {}}}, - {ElementIDStruct{2,this_node}, {LoadType{5}, {}}}}}}; + {ElementIDStruct{2,this_node}, {LoadType{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 25ec9fd3f0..e29fd903af 100644 --- a/tests/unit/collection/test_model_naive_persistence.nompi.cc +++ b/tests/unit/collection/test_model_naive_persistence.nompi.cc @@ -106,19 +106,19 @@ struct StubModel : LoadModel { TEST_F(TestModelNaivePersistence, test_model_naive_persistence_1) { NodeType this_node = 0; - LoadMapBufferType proc_loads = { - {0, LoadMapType{ - {ElementIDStruct{1,this_node}, {LoadType{10}, {}}}, - {ElementIDStruct{2,this_node}, {LoadType{40}, {}}}}}, - {1, LoadMapType{ - {ElementIDStruct{1,this_node}, {LoadType{4}, {}}}, - {ElementIDStruct{2,this_node}, {LoadType{10}, {}}}}}, - {2, LoadMapType{ - {ElementIDStruct{1,this_node}, {LoadType{20}, {}}}, - {ElementIDStruct{2,this_node}, {LoadType{50}, {}}}}}, - {3, LoadMapType{ - {ElementIDStruct{1,this_node}, {LoadType{40}, {}}}, - {ElementIDStruct{2,this_node}, {LoadType{100}, {}}}}}}; + LoadMapBufferType proc_loads(4); + proc_loads[0] = LoadMapType{ + {ElementIDStruct{1, this_node}, {LoadType{10}, {}}}, + {ElementIDStruct{2, this_node}, {LoadType{40}, {}}}}; + proc_loads[1] = LoadMapType{ + {ElementIDStruct{1, this_node}, {LoadType{4}, {}}}, + {ElementIDStruct{2, this_node}, {LoadType{10}, {}}}}; + proc_loads[2] = LoadMapType{ + {ElementIDStruct{1, this_node}, {LoadType{20}, {}}}, + {ElementIDStruct{2, this_node}, {LoadType{50}, {}}}}; + proc_loads[3] = LoadMapType{ + {ElementIDStruct{1, this_node}, {LoadType{40}, {}}}, + {ElementIDStruct{2, this_node}, {LoadType{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 ac12570e8c..21a99ac910 100644 --- a/tests/unit/collection/test_model_norm.nompi.cc +++ b/tests/unit/collection/test_model_norm.nompi.cc @@ -105,11 +105,12 @@ struct StubModel : LoadModel { TEST_F(TestModelNorm, test_model_norm_1) { NodeType this_node = 0; - LoadMapBufferType proc_load = { - {0, - LoadMapType{ - {ElementIDStruct{1,this_node}, {LoadType{60}, {LoadType{10}, LoadType{20}, LoadType{30}}}}, - {ElementIDStruct{2,this_node}, {LoadType{150}, {LoadType{40}, LoadType{50}, LoadType{60}}}}}}}; + LoadMapBufferType proc_load(1); + proc_load[0] = LoadMapType{ + {ElementIDStruct{1, this_node}, + {LoadType{60}, {LoadType{10}, LoadType{20}, LoadType{30}}}}, + {ElementIDStruct{2, this_node}, + {LoadType{150}, {LoadType{40}, LoadType{50}, LoadType{60}}}}}; auto test_model = std::make_shared(std::make_shared(), 3.0); test_model->setLoads(&proc_load, nullptr, nullptr); @@ -136,11 +137,12 @@ TEST_F(TestModelNorm, test_model_norm_1) { TEST_F(TestModelNorm, test_model_norm_2) { NodeType this_node = 0; - LoadMapBufferType proc_load = { - {0, - LoadMapType{ - {ElementIDStruct{1,this_node}, {LoadType{60}, {LoadType{10}, LoadType{20}, LoadType{30}}}}, - {ElementIDStruct{2,this_node}, {LoadType{150}, {LoadType{40}, LoadType{50}, LoadType{60}}}}}}}; + LoadMapBufferType proc_load(1); + proc_load[0] = LoadMapType{ + {ElementIDStruct{1, this_node}, + {LoadType{60}, {LoadType{10}, LoadType{20}, LoadType{30}}}}, + {ElementIDStruct{2, this_node}, + {LoadType{150}, {LoadType{40}, LoadType{50}, LoadType{60}}}}}; // finite 'power' value auto test_model = std::make_shared(std::make_shared(), 3.0); @@ -165,11 +167,10 @@ TEST_F(TestModelNorm, test_model_norm_2) { TEST_F(TestModelNorm, test_model_norm_3) { NodeType this_node = 0; - LoadMapBufferType proc_load = { - {0, - LoadMapType{ + LoadMapBufferType proc_load(1); + proc_load[0] = LoadMapType{ {ElementIDStruct{1,this_node}, {LoadType{60}, {LoadType{10}, LoadType{20}, LoadType{30}}}}, - {ElementIDStruct{2,this_node}, {LoadType{150}, {LoadType{40}, LoadType{50}, LoadType{60}}}}}}}; + {ElementIDStruct{2,this_node}, {LoadType{150}, {LoadType{40}, LoadType{50}, LoadType{60}}}}}; // infinite 'power' value auto test_model = std::make_shared( diff --git a/tests/unit/collection/test_model_select_subphases.nompi.cc b/tests/unit/collection/test_model_select_subphases.nompi.cc index fe558a2236..57648bcca1 100644 --- a/tests/unit/collection/test_model_select_subphases.nompi.cc +++ b/tests/unit/collection/test_model_select_subphases.nompi.cc @@ -113,11 +113,10 @@ TEST_F(TestModelSelectSubphases, test_model_select_subphases_1) { ElementIDStruct id1{1,this_node}; ElementIDStruct id2{2,this_node}; - LoadMapBufferType proc_load = { - {0, - LoadMapType{ + LoadMapBufferType proc_load(1); + proc_load[0] = LoadMapType{ {id1, {LoadType{60}, {LoadType{10}, LoadType{20}, LoadType{30}}}}, - {id2, {LoadType{150}, {LoadType{40}, LoadType{50}, LoadType{60}}}}}}}; + {id2, {LoadType{150}, {LoadType{40}, LoadType{50}, LoadType{60}}}}}; std::vector subphases{2, 0, 1}; auto test_model = @@ -157,16 +156,12 @@ TEST_F(TestModelSelectSubphases, test_model_select_subphases_1) { TEST_F(TestModelSelectSubphases, test_model_select_subphases_2) { NodeType this_node = 0; - LoadMapBufferType proc_load = { - {0, - LoadMapType{ - {ElementIDStruct{1,this_node}, - {LoadType{60}, {LoadType{10}, LoadType{20}, LoadType{30}}}}, - {ElementIDStruct{2,this_node}, - {LoadType{150}, {LoadType{40}, LoadType{50}, LoadType{60}}}} - } - } - }; + LoadMapBufferType proc_load(1); + proc_load[0] = LoadMapType{ + {ElementIDStruct{1, this_node}, + {LoadType{60}, {LoadType{10}, LoadType{20}, LoadType{30}}}}, + {ElementIDStruct{2, this_node}, + {LoadType{150}, {LoadType{40}, LoadType{50}, LoadType{60}}}}}; std::vector subphases{2, 1}; auto test_model = diff --git a/tests/unit/collection/test_model_weighted_communication_volume.nompi.cc b/tests/unit/collection/test_model_weighted_communication_volume.nompi.cc index 6527f63565..f11c197ff2 100644 --- a/tests/unit/collection/test_model_weighted_communication_volume.nompi.cc +++ b/tests/unit/collection/test_model_weighted_communication_volume.nompi.cc @@ -128,26 +128,22 @@ TEST_F(TestModelWeightedCommunicationVolume, test_model) { // Element 3 (home node == 3) ElementIDStruct const elem3 = {3, 3}; - LoadMapBufferType proc_load = {{0, LoadMapType{{elem2, {LoadType{150}, {}}}}}}; - - CommMapBufferType proc_comm = { - {0, - CommMapType{// Node 1 -> Node 2 - {{CommKeyType::CollectionTag{}, elem1, elem2, false}, - CommVolume{20.0, 2}}, - // Node 3 -> Node 2 - {{CommKeyType::CollectionTag{}, elem3, elem2, false}, - CommVolume{5.0, 5}}} - }, - {1, - CommMapType{// Node 3 -> Node 2 - {{CommKeyType::CollectionTag{}, elem3, elem2, false}, - CommVolume{500.0, 50}}, - // Node 1 -> Node 2 - {{CommKeyType::CollectionTag{}, elem1, elem2, false}, - CommVolume{25.0, 10}}} - } - }; + LoadMapBufferType proc_load(1); + proc_load[0] = LoadMapType{{elem2, {LoadType{150}, {}}}}; + + CommMapBufferType proc_comm(2); + proc_comm[0] = CommMapType{ + // Node 1 -> Node 2 + {{CommKeyType::CollectionTag{}, elem1, elem2, false}, CommVolume{20.0, 2}}, + // Node 3 -> Node 2 + {{CommKeyType::CollectionTag{}, elem3, elem2, false}, CommVolume{5.0, 5}}}; + proc_comm[1] = + CommMapType{// Node 3 -> Node 2 + {{CommKeyType::CollectionTag{}, elem3, elem2, false}, + CommVolume{500.0, 50}}, + // Node 1 -> Node 2 + {{CommKeyType::CollectionTag{}, elem1, elem2, false}, + CommVolume{25.0, 10}}}; constexpr auto alpha = 0.8; constexpr auto beta = 0.2; diff --git a/tests/unit/collection/test_model_weighted_messages.nompi.cc b/tests/unit/collection/test_model_weighted_messages.nompi.cc index 37b8a48f82..63cc7bb2d6 100644 --- a/tests/unit/collection/test_model_weighted_messages.nompi.cc +++ b/tests/unit/collection/test_model_weighted_messages.nompi.cc @@ -124,26 +124,22 @@ TEST_F(TestModelWeightedMessages, test_model) { // Element 3 (home node == 3) ElementIDStruct const elem3 = {3, 3}; - LoadMapBufferType proc_load = {{0, LoadMapType{{elem2, {LoadType{150}, {}}}}}}; - - CommMapBufferType proc_comm = { - {0, - CommMapType{// Node 1 -> Node 2 - {{CommKeyType::CollectionTag{}, elem1, elem2, false}, - CommVolume{20.0, 2}}, - // Node 3 -> Node 2 - {{CommKeyType::CollectionTag{}, elem3, elem2, false}, - CommVolume{5.0, 5}}} - }, - {1, - CommMapType{// Node 3 -> Node 2 - {{CommKeyType::CollectionTag{}, elem3, elem2, false}, - CommVolume{500.0, 50}}, - // Node 1 -> Node 2 - {{CommKeyType::CollectionTag{}, elem1, elem2, false}, - CommVolume{25.0, 10}}} - } - }; + LoadMapBufferType proc_load(1); + proc_load[0] = LoadMapType{{elem2, {LoadType{150}, {}}}}; + + CommMapBufferType proc_comm(2); + proc_comm[0] = CommMapType{ + // Node 1 -> Node 2 + {{CommKeyType::CollectionTag{}, elem1, elem2, false}, CommVolume{20.0, 2}}, + // Node 3 -> Node 2 + {{CommKeyType::CollectionTag{}, elem3, elem2, false}, CommVolume{5.0, 5}}}; + proc_comm[1] = + CommMapType{// Node 3 -> Node 2 + {{CommKeyType::CollectionTag{}, elem3, elem2, false}, + CommVolume{500.0, 50}}, + // Node 1 -> Node 2 + {{CommKeyType::CollectionTag{}, elem1, elem2, false}, + CommVolume{25.0, 10}}}; constexpr auto per_msg_weight = 3.0; constexpr auto per_byte_weight = 5.0; From 77b8fb9239c72098d0769444b69cf78ac4d541be Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Thu, 19 Sep 2024 15:09:36 +0200 Subject: [PATCH 68/82] #1934: Update usage of LBDataHolder in the codebase --- tests/unit/collection/test_lb.extended.cc | 6 ++++-- tests/unit/lb/test_offlinelb.cc | 6 ++++-- tests/unit/runtime/test_initialization.cc | 3 ++- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/tests/unit/collection/test_lb.extended.cc b/tests/unit/collection/test_lb.extended.cc index 3ad7604913..3f94ba4785 100644 --- a/tests/unit/collection/test_lb.extended.cc +++ b/tests/unit/collection/test_lb.extended.cc @@ -750,7 +750,8 @@ TEST_P(TestDumpUserdefinedData, test_dump_userdefined_json) { ); }); - vt::vrt::collection::balance::LBDataHolder lbdh(num_phases); + vt::vrt::collection::balance::LBDataHolder lbdh; + lbdh.resizeHistory(num_phases); PhaseType write_phase = 0; { @@ -813,7 +814,8 @@ TEST_P(TestDumpAttributesFieldData, test_dump_attributes_json) { ); }); - vt::vrt::collection::balance::LBDataHolder lbdh(num_phases); + vt::vrt::collection::balance::LBDataHolder lbdh; + lbdh.resizeHistory(num_phases); PhaseType phase = 0; { diff --git a/tests/unit/lb/test_offlinelb.cc b/tests/unit/lb/test_offlinelb.cc index 88e95c76f8..beb946465d 100644 --- a/tests/unit/lb/test_offlinelb.cc +++ b/tests/unit/lb/test_offlinelb.cc @@ -125,7 +125,8 @@ TEST_F(TestOfflineLB, test_offlinelb_1) { ids[5].push_back(nid); } - LBDataHolder dh(num_phases); + LBDataHolder dh; + dh.resizeHistory(num_phases); for (PhaseType i = 0; i < num_phases; i++) { for (auto&& elm : ids[i]) { dh.node_data_[i][elm] = LoadSummary{3}; @@ -196,7 +197,8 @@ TEST_F(TestOfflineLB, test_offlinelb_2) { ids[7].push_back(nid); } - LBDataHolder dh(num_phases); + LBDataHolder dh; + dh.resizeHistory(num_phases); for (PhaseType i = 0; i < num_phases; i++) { if (i != 1 and i != 2 and i != 5 and i != 8 and i != 9) { auto& elms = ids[i]; diff --git a/tests/unit/runtime/test_initialization.cc b/tests/unit/runtime/test_initialization.cc index 265d1eced0..2e0e04e7a1 100644 --- a/tests/unit/runtime/test_initialization.cc +++ b/tests/unit/runtime/test_initialization.cc @@ -543,7 +543,8 @@ void prepareLBDataFiles(const std::string file_name_without_ext) { ids[5].push_back(nid); } - LBDataHolder dh(num_phases); + LBDataHolder dh; + dh.resizeHistory(num_phases); for (PhaseType i = 0; i < num_phases; i++) { for (auto&& elm : ids[i]) { dh.node_data_[i][elm] = LoadSummary{3}; From 3bc5550bb429d8a5c01446abf5cd2d542f60f206 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Thu, 19 Sep 2024 15:19:55 +0200 Subject: [PATCH 69/82] #1934: Fix compilation issues after the PR rebase --- src/vt/vrt/collection/balance/lb_data_holder.cc | 2 +- src/vt/vrt/collection/balance/model/raw_data.cc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vt/vrt/collection/balance/lb_data_holder.cc b/src/vt/vrt/collection/balance/lb_data_holder.cc index 2c3eb5f0aa..35773ab10f 100644 --- a/src/vt/vrt/collection/balance/lb_data_holder.cc +++ b/src/vt/vrt/collection/balance/lb_data_holder.cc @@ -257,7 +257,7 @@ std::unique_ptr LBDataHolder::toJson(PhaseType phase) const { } i = 0; - if (node_comm_.find(phase) != node_comm_.end()) { + if (node_comm_.contains(phase)) { for (auto const& [key, volume] : node_comm_.at(phase)) { j["communications"][i]["bytes"] = volume.bytes; j["communications"][i]["messages"] = volume.messages; diff --git a/src/vt/vrt/collection/balance/model/raw_data.cc b/src/vt/vrt/collection/balance/model/raw_data.cc index 729774f7f4..f6dac5ca45 100644 --- a/src/vt/vrt/collection/balance/model/raw_data.cc +++ b/src/vt/vrt/collection/balance/model/raw_data.cc @@ -131,8 +131,8 @@ ElmUserDataType RawData::getUserData(ElementIDStruct object, PhaseOffset offset) CommMapType RawData::getComm(PhaseOffset offset) const { auto phase = getNumCompletedPhases() + offset.phases; - if (auto it = proc_comm_->find(phase); it != proc_comm_->end()) { - return it->second; + if (auto it = proc_comm_->find(phase); it != nullptr) { + return *it; } else { return CommMapType{}; } From f4ce66b3c0b18a5b894c7861eb3a8d30bac29488 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Thu, 19 Sep 2024 16:30:49 +0200 Subject: [PATCH 70/82] #1934: Reset ElementLBData containers after resetting the current phase --- src/vt/elm/elm_lb_data.cc | 5 +++++ tests/unit/collection/test_lb.extended.cc | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/vt/elm/elm_lb_data.cc b/src/vt/elm/elm_lb_data.cc index 5084afdafb..04af3c93a7 100644 --- a/src/vt/elm/elm_lb_data.cc +++ b/src/vt/elm/elm_lb_data.cc @@ -196,6 +196,11 @@ void ElementLBData::updatePhase(PhaseType const& inc) { void ElementLBData::resetPhase() { cur_phase_ = fst_lb_phase; + // Reset containers after resetting the current phase + phase_timings_.clear(); + subphase_timings_.clear(); + phase_comm_.clear(); + subphase_comm_.clear(); } PhaseType ElementLBData::getPhase() const { diff --git a/tests/unit/collection/test_lb.extended.cc b/tests/unit/collection/test_lb.extended.cc index 3f94ba4785..5548b797e3 100644 --- a/tests/unit/collection/test_lb.extended.cc +++ b/tests/unit/collection/test_lb.extended.cc @@ -552,7 +552,8 @@ TEST_F(TestRestoreLBData, test_restore_lb_data_data_1) { ); }); - vt::vrt::collection::balance::LBDataHolder lbdh(num_phases); + vt::vrt::collection::balance::LBDataHolder lbdh; + lbdh.resizeHistory(num_phases); PhaseType write_phase = 0; using CommKey = vt::elm::CommKey; From c9c65e63e43efbdfe55de84af881a917a001c35e Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Thu, 19 Sep 2024 17:01:43 +0200 Subject: [PATCH 71/82] #1934: Remove leftovers from previous implementation of the circular buffer --- src/vt/vrt/collection/balance/lb_data_holder.cc | 4 ---- src/vt/vrt/collection/balance/lb_data_restart_reader.cc | 2 +- tests/unit/lb/test_offlinelb.cc | 4 ---- 3 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/vt/vrt/collection/balance/lb_data_holder.cc b/src/vt/vrt/collection/balance/lb_data_holder.cc index 35773ab10f..d3bcad532d 100644 --- a/src/vt/vrt/collection/balance/lb_data_holder.cc +++ b/src/vt/vrt/collection/balance/lb_data_holder.cc @@ -700,10 +700,6 @@ void LBDataHolder::readMetadata(nlohmann::json const& j) { min = std::min(min, *identical_phases_.begin()); max = std::max(max, *identical_phases_.rbegin()); } - if (skipped_phases_.size() > 0) { - min = std::min(min, *skipped_phases_.begin()); - max = std::max(max, *skipped_phases_.rbegin()); - } auto phases = j["phases"]; if (phases.is_array()) { diff --git a/src/vt/vrt/collection/balance/lb_data_restart_reader.cc b/src/vt/vrt/collection/balance/lb_data_restart_reader.cc index 6d175881c8..8af49b55d4 100644 --- a/src/vt/vrt/collection/balance/lb_data_restart_reader.cc +++ b/src/vt/vrt/collection/balance/lb_data_restart_reader.cc @@ -90,7 +90,7 @@ void LBDataRestartReader::readHistory(LBDataHolder const& lbdh) { PhaseType last_found_phase = 0; for (PhaseType phase = 0; phase < num_phases_; phase++) { - if (lbdh.node_data_.contains(phase) && lbdh.node_data_.at(phase).size() > 0) { + if (lbdh.node_data_.contains(phase)) { last_found_phase = phase; for (auto const& obj : lbdh.node_data_.at(phase)) { if (obj.first.isMigratable()) { diff --git a/tests/unit/lb/test_offlinelb.cc b/tests/unit/lb/test_offlinelb.cc index beb946465d..a5c72349c3 100644 --- a/tests/unit/lb/test_offlinelb.cc +++ b/tests/unit/lb/test_offlinelb.cc @@ -206,10 +206,6 @@ TEST_F(TestOfflineLB, test_offlinelb_2) { dh.node_data_[i][elms[j]] = LoadSummary{ static_cast(i + j) + 3}; } } - else { - // add empty element - circular buffer expects continuous phases - dh.node_data_[i]; - } } using JSONAppender = util::json::Appender; From 9a056c0b11b48e0f4a54dcb506e9a844b32e11fb Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Thu, 19 Sep 2024 17:33:53 +0200 Subject: [PATCH 72/82] #1934: Update CircularPhasesBuffer documentation --- .../utils/container/circular_phases_buffer.h | 41 +++++++++++++------ 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/src/vt/utils/container/circular_phases_buffer.h b/src/vt/utils/container/circular_phases_buffer.h index fd3d901d67..91872a0c66 100644 --- a/src/vt/utils/container/circular_phases_buffer.h +++ b/src/vt/utils/container/circular_phases_buffer.h @@ -63,9 +63,9 @@ class CircularPhasesBuffer { constexpr static auto no_index = std::numeric_limits::max(); /** - * \brief Creates a new pair to be stored in the buffer + * \brief Creates an empty pair to be stored in the buffer * - * \param phase - the phase to be assigned, \c no_phase otherwise + * \param[in] phase - the phase to be assigned, \c no_phase otherwise * \return the new pair */ static StoredPair makeEmptyPair(const PhaseType& phase = no_phase) { @@ -98,7 +98,9 @@ class CircularPhasesBuffer { } /** - * \brief Get or set data for the phase. + * \brief Get data for the phase. Inserts a new element when phase is not present in the buffer. + * Can call \c vtAbort() when phase is outside of the valid range. + * Check \c canBeStored() for more details. * * \param[in] phase the phase to look for * @@ -106,7 +108,7 @@ class CircularPhasesBuffer { */ StoredType& operator[](const PhaseType phase) { auto& pair = buffer_[phaseToIndex(phase)]; - // Create empty data for new phase + // Inserts empty data for new phase if (pair.first != phase) { store(phase, StoredType{}); } @@ -115,6 +117,8 @@ class CircularPhasesBuffer { /** * \brief Store data in the buffer. + * Can call \c vtAbort() when phase is outside of the valid range. + * Check \c canBeStored() for more details. * * \param[in] phase the phase for which data will be stored * \param[in] obj the data to store @@ -151,7 +155,7 @@ class CircularPhasesBuffer { } /** - * \brief Resize buffer to the requested size. + * \brief Resize the buffer to the requested size. * The minimal size of the buffer is 1. * * \param[in] new_size_in the requested new size of the buffer @@ -167,7 +171,7 @@ class CircularPhasesBuffer { // number of elements to copy auto num = std::min(new_size, buffer_.size() - numFree()); - // copy num phases + // copy data which should be retained auto to_copy = head_phase_; while(num > 0 && to_copy != no_phase) { if (contains(to_copy)) { @@ -297,7 +301,7 @@ class CircularPhasesBuffer { private: /** - * \brief Converts the phase to the index in the buffer + * \brief Converts phase number to the index in the buffer * * \param phase - the phase to be converted * \return the position of the data container in the buffer @@ -307,20 +311,20 @@ class CircularPhasesBuffer { } /** - * \brief Converts the phase to the index in the temporary buffer + * \brief Converts phase number to the index in the temporary buffer * - * @param phase - the phase to be converted - * @param vector - the buffer to return index for - * @return the position of the data container in the buffer + * \param[in] phase - the phase to be converted + * \param[in] vector - the buffer to return index for + * \return the position of the data container in the buffer */ std::size_t calcIndex(const PhaseType& phase, const std::vector& vector) const { return phase % vector.size(); } /** - * \brief Counts spots in the buffer without a valid phase assigned. + * \brief Counts fields in the buffer without a valid phase assigned. * - * @return the number of empty spots + * \return the number of empty fields */ std::size_t numFree() const { return std::count_if(buffer_.begin(), buffer_.end(), @@ -339,6 +343,13 @@ class CircularPhasesBuffer { } } + /** + * \brief Checks if phase can be stored in the buffer. + * Valid phase needs to be higher than (head_phase_ - buffer_.size()) + * + * \param[in] phase - the phase to validate + * \return true if higher than (head_phase_ - buffer_.size()), false otherwise + */ bool canBeStored(const PhaseType& phase) const { if (!empty() && head_phase_ > buffer_.size()) { return phase > head_phase_ - buffer_.size(); @@ -375,6 +386,10 @@ class CircularPhasesBuffer { bool operator!= (const ForwardIterator& it) const { return index_ != it.index_; }; private: + /** + * \brief Advances the iterator to the next element with valid phase number. + * + */ void advance() { index_++; if (index_ == buffer_->size()) { From b9f229396b0f834b6ef20d27fac27a6d4210089b Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Mon, 23 Sep 2024 15:12:37 +0200 Subject: [PATCH 73/82] #1934: Add resizeHistory method back after resolving conflicts --- src/vt/vrt/collection/balance/lb_data_holder.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/vt/vrt/collection/balance/lb_data_holder.cc b/src/vt/vrt/collection/balance/lb_data_holder.cc index d3bcad532d..7c704ddb2d 100644 --- a/src/vt/vrt/collection/balance/lb_data_holder.cc +++ b/src/vt/vrt/collection/balance/lb_data_holder.cc @@ -428,6 +428,15 @@ std::unordered_map LBDataHolder::getObjInfo( #endif +void LBDataHolder::resizeHistory(std::size_t num_to_retain) { + node_data_.resize(num_to_retain); + node_comm_.resize(num_to_retain); + node_subphase_comm_.resize(num_to_retain); + user_defined_json_.resize(num_to_retain); + user_defined_lb_info_.resize(num_to_retain); + node_user_attributes_.resize(num_to_retain); +} + LBDataHolder::LBDataHolder(nlohmann::json const& j) { this_node_ = theContext()->getNode(); From 57d0457558aca400f4f78f98665af0f68d29cb58 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Mon, 23 Sep 2024 17:10:32 +0200 Subject: [PATCH 74/82] #1934: Modify ElementLBData::resetPhase() to reset the head phase of the containers rather than clearing their contents. --- src/vt/elm/elm_lb_data.cc | 10 +++++----- .../utils/container/circular_phases_buffer.h | 19 ++++++++++++++++++ .../test_circular_phases_buffer.nompi.cc | 20 +++++++++++++++++++ 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/src/vt/elm/elm_lb_data.cc b/src/vt/elm/elm_lb_data.cc index 04af3c93a7..55bb0dc41c 100644 --- a/src/vt/elm/elm_lb_data.cc +++ b/src/vt/elm/elm_lb_data.cc @@ -196,11 +196,11 @@ void ElementLBData::updatePhase(PhaseType const& inc) { void ElementLBData::resetPhase() { cur_phase_ = fst_lb_phase; - // Reset containers after resetting the current phase - phase_timings_.clear(); - subphase_timings_.clear(); - phase_comm_.clear(); - subphase_comm_.clear(); + // Resets the current phase in the containers without removing any phase data. + phase_timings_.restartFrom(fst_lb_phase); + subphase_timings_.restartFrom(fst_lb_phase); + phase_comm_.restartFrom(fst_lb_phase); + subphase_comm_.restartFrom(fst_lb_phase); } PhaseType ElementLBData::getPhase() const { diff --git a/src/vt/utils/container/circular_phases_buffer.h b/src/vt/utils/container/circular_phases_buffer.h index 91872a0c66..8a8d985544 100644 --- a/src/vt/utils/container/circular_phases_buffer.h +++ b/src/vt/utils/container/circular_phases_buffer.h @@ -219,6 +219,25 @@ class CircularPhasesBuffer { buffer_.assign(buffer_.size(), makeEmptyPair()); } + /** + * \brief Shifts the buffer's head to the specified phase without removing any data. + * + * \param start_point the new start point for the buffer + */ + void restartFrom(const PhaseType& start_point) { + if (empty()) { + return; + } + + // copy data from head_phase_ + if (phaseToIndex(head_phase_) != phaseToIndex(start_point)) { + buffer_[phaseToIndex(start_point)].second = buffer_[phaseToIndex(head_phase_)].second; + } + + buffer_[phaseToIndex(start_point)].first = start_point; + head_phase_ = start_point; + } + /** * \brief Get the latest phase * diff --git a/tests/unit/utils/test_circular_phases_buffer.nompi.cc b/tests/unit/utils/test_circular_phases_buffer.nompi.cc index 27d5289dee..892b50ff86 100644 --- a/tests/unit/utils/test_circular_phases_buffer.nompi.cc +++ b/tests/unit/utils/test_circular_phases_buffer.nompi.cc @@ -220,6 +220,26 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_resize) { validateMissingPhases(buffer, {28, 29, 30, 31, 32, 33, 34}); } +TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_restart_from) { + CircularBufferType buffer{1}; + + // do nothing on empty buffer + buffer.restartFrom(5); + EXPECT_EQ(std::numeric_limits::max(), buffer.frontPhase()); + + buffer[3] = {3}; + EXPECT_EQ(3, buffer.frontPhase()); + EXPECT_EQ(3, buffer.frontData().x); + + buffer.restartFrom(10); + EXPECT_EQ(10, buffer.frontPhase()); + EXPECT_EQ(3, buffer.frontData().x); + + buffer.restartFrom(0); + EXPECT_EQ(0, buffer.frontPhase()); + EXPECT_EQ(3, buffer.frontData().x); +} + TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_forward_iter) { CircularBufferType buffer; From 57b70f7d123f025eeb43d425ab17c2cbd4f60f6f Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Mon, 23 Sep 2024 18:48:05 +0200 Subject: [PATCH 75/82] #1934: Adapt newly added functionality in LBDataHolder to support CircularPhasesBuffer --- src/vt/vrt/collection/balance/lb_data_holder.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vt/vrt/collection/balance/lb_data_holder.cc b/src/vt/vrt/collection/balance/lb_data_holder.cc index 7c704ddb2d..71a038627e 100644 --- a/src/vt/vrt/collection/balance/lb_data_holder.cc +++ b/src/vt/vrt/collection/balance/lb_data_holder.cc @@ -339,7 +339,7 @@ std::unique_ptr LBDataHolder::toTV(PhaseType phase) const { std::unordered_map objects; - if (node_data_.find(phase) != node_data_.end()) { + if (node_data_.contains(phase)) { for (auto&& elm : node_data_.at(phase)) { ElementIDStruct id = elm.first; double whole_phase_load = elm.second.whole_phase_load; @@ -347,7 +347,7 @@ std::unique_ptr LBDataHolder::toTV(PhaseType phase) const { ElmUserDataType user_defined; if ( - user_defined_lb_info_.find(phase) != user_defined_lb_info_.end() and + user_defined_lb_info_.contains(phase) and user_defined_lb_info_.at(phase).find(id) != user_defined_lb_info_.at(phase).end() ) { @@ -367,7 +367,7 @@ std::unique_ptr LBDataHolder::toTV(PhaseType phase) const { } } - if (node_comm_.find(phase) != node_comm_.end()) { + if (node_comm_.contains(phase)) { for (auto&& elm : node_comm_.at(phase)) { auto const& key = elm.first; auto const& volume = elm.second; @@ -398,7 +398,7 @@ std::unordered_map LBDataHolder::getObjInfo( PhaseType phase ) const { std::unordered_map map; - if (node_data_.find(phase) != node_data_.end()) { + if (node_data_.contains(phase)) { for (auto&& elm : node_data_.at(phase)) { ElementIDStruct id = elm.first; From ddc3c5720c5f288fe84f590ca196abf1410893de Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Mon, 23 Sep 2024 21:31:14 +0200 Subject: [PATCH 76/82] #1934: Remove comparison of signed and unsigned integers in retention tests. --- .../unit/collection/test_lb_data_retention.cc | 16 ++++----- .../test_circular_phases_buffer.nompi.cc | 36 +++++++++---------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/tests/unit/collection/test_lb_data_retention.cc b/tests/unit/collection/test_lb_data_retention.cc index 7cd091e34c..d794e4692d 100644 --- a/tests/unit/collection/test_lb_data_retention.cc +++ b/tests/unit/collection/test_lb_data_retention.cc @@ -112,10 +112,10 @@ struct TestCol : vt::Collection { EXPECT_EQ(comm_phase_count, buffers_size); EXPECT_EQ(sp_comm_phase_count, buffers_size); } else if (phase == 0) { - EXPECT_EQ(load_phase_count, 1); - EXPECT_EQ(sp_load_phase_count, 1); - EXPECT_EQ(comm_phase_count, 0); - EXPECT_EQ(sp_comm_phase_count, 0); + EXPECT_EQ(load_phase_count, std::size_t{1}); + EXPECT_EQ(sp_load_phase_count, std::size_t{1}); + EXPECT_EQ(comm_phase_count, std::size_t{0}); + EXPECT_EQ(sp_comm_phase_count, std::size_t{0}); } else { // updatePhase will have caused entries to be added for the // next phase already @@ -125,10 +125,10 @@ struct TestCol : vt::Collection { EXPECT_EQ(sp_comm_phase_count, phase + 1); } #else - EXPECT_EQ(load_phase_count, 0); - EXPECT_EQ(sp_load_phase_count, 0); - EXPECT_EQ(comm_phase_count, 0); - EXPECT_EQ(sp_comm_phase_count, 0); + EXPECT_EQ(load_phase_count, std::size_t{0}); + EXPECT_EQ(sp_load_phase_count, std::size_t{0}); + EXPECT_EQ(comm_phase_count, std::size_t{0}); + EXPECT_EQ(sp_comm_phase_count, std::size_t{0}); #endif } }; diff --git a/tests/unit/utils/test_circular_phases_buffer.nompi.cc b/tests/unit/utils/test_circular_phases_buffer.nompi.cc index 892b50ff86..d1b73b344c 100644 --- a/tests/unit/utils/test_circular_phases_buffer.nompi.cc +++ b/tests/unit/utils/test_circular_phases_buffer.nompi.cc @@ -51,7 +51,7 @@ namespace vt { namespace tests { namespace unit { using TestCircularPhasesBuffer = TestHarness; struct Dummy { - int x; + PhaseType x; }; using CircularBufferType = util::container::CircularPhasesBuffer; @@ -103,8 +103,8 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_empty) { EXPECT_TRUE(buffer.contains(0)); EXPECT_EQ(std::size_t{1}, buffer.size()); EXPECT_FALSE(buffer.empty()); - EXPECT_EQ(0, buffer.frontPhase()); - EXPECT_EQ(0, buffer.frontData().x); + EXPECT_EQ(PhaseType{0}, buffer.frontPhase()); + EXPECT_EQ(PhaseType{0}, buffer.frontData().x); EXPECT_NE(nullptr, buffer.find(0)); buffer[1] = {1}; @@ -115,8 +115,8 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_empty) { EXPECT_TRUE(buffer.contains(1)); EXPECT_EQ(std::size_t{4}, buffer.size()); EXPECT_FALSE(buffer.empty()); - EXPECT_EQ(4, buffer.frontPhase()); - EXPECT_EQ(8, buffer.frontData().x); + EXPECT_EQ(PhaseType{4}, buffer.frontPhase()); + EXPECT_EQ(PhaseType{8}, buffer.frontData().x); EXPECT_EQ(nullptr, buffer.find(0)); EXPECT_NE(nullptr, buffer.find(3)); @@ -134,7 +134,7 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_single_element) { EXPECT_EQ(false, buffer.contains(0)); - for (int i = 0; i < 5; i++) { + for (PhaseType i = 0; i < 5; i++) { buffer.store(i, {i}); EXPECT_EQ(i == 0, buffer.contains(0)); EXPECT_EQ(i == 1, buffer.contains(1)); @@ -154,7 +154,7 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_single_element) { TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_multi_elements) { CircularBufferType buffer{5}; - for (int i = 0; i < 15; i++) { + for (PhaseType i = 0; i < 15; i++) { buffer.store(i, {i}); EXPECT_EQ(i, buffer.frontPhase()); @@ -179,7 +179,7 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_store) { validateMissingPhases(buffer, {0, 1, 3, 4, 5, 6, 7, 8, 9}); // store series of elements - for (int i = 3; i < 15; i++) { + for (PhaseType i = 3; i < 15; i++) { buffer.store(i, {i}); } @@ -191,7 +191,7 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_store) { TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_resize) { CircularBufferType buffer{10}; - for (int i = 0; i <= 15; i++) { + for (PhaseType i = 0; i <= 15; i++) { buffer[i] = {i}; } validatePresentPhases(buffer, {6, 7, 8, 9, 10, 11, 12, 13, 14, 15}); @@ -200,7 +200,7 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_resize) { validatePresentPhases(buffer, {11, 12, 13, 14, 15}); validateMissingPhases(buffer, {6, 7, 8, 9, 10}); - for (int i = 15; i <= 32; i++) { + for (PhaseType i = 15; i <= 32; i++) { buffer[i] = {i}; } validatePresentPhases(buffer, {28, 29, 30, 31, 32}); @@ -210,7 +210,7 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_resize) { validatePresentPhases(buffer, {28, 29, 30, 31, 32}); - for (int i = 33; i <= 35; i++) { + for (PhaseType i = 33; i <= 35; i++) { buffer[i] = {i}; } validatePresentPhases(buffer, {28, 29, 30, 31, 32, 33, 34, 35}); @@ -228,16 +228,16 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_restart_from) { EXPECT_EQ(std::numeric_limits::max(), buffer.frontPhase()); buffer[3] = {3}; - EXPECT_EQ(3, buffer.frontPhase()); - EXPECT_EQ(3, buffer.frontData().x); + EXPECT_EQ(PhaseType{3}, buffer.frontPhase()); + EXPECT_EQ(PhaseType{3}, buffer.frontData().x); buffer.restartFrom(10); - EXPECT_EQ(10, buffer.frontPhase()); - EXPECT_EQ(3, buffer.frontData().x); + EXPECT_EQ(PhaseType{10}, buffer.frontPhase()); + EXPECT_EQ(PhaseType{3}, buffer.frontData().x); buffer.restartFrom(0); - EXPECT_EQ(0, buffer.frontPhase()); - EXPECT_EQ(3, buffer.frontData().x); + EXPECT_EQ(PhaseType{0}, buffer.frontPhase()); + EXPECT_EQ(PhaseType{3}, buffer.frontData().x); } TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_forward_iter) { @@ -273,7 +273,7 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_forward_iter) { EXPECT_EQ(visited.size(), buffer.size()); } - for (int i = 0; i <= 15; i++) { + for (PhaseType i = 0; i <= 15; i++) { buffer[i] = {i}; } From c6db9571df1afd0378f7553c75b0c1580e683dde Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 24 Sep 2024 15:28:41 +0200 Subject: [PATCH 77/82] #1934: Add LB data retention tests for chckpointing case --- src/vt/elm/elm_lb_data.cc | 12 +-- .../unit/collection/test_lb_data_retention.cc | 77 +++++++++++++++++++ 2 files changed, 83 insertions(+), 6 deletions(-) diff --git a/src/vt/elm/elm_lb_data.cc b/src/vt/elm/elm_lb_data.cc index 55bb0dc41c..2672e2e898 100644 --- a/src/vt/elm/elm_lb_data.cc +++ b/src/vt/elm/elm_lb_data.cc @@ -195,12 +195,12 @@ void ElementLBData::updatePhase(PhaseType const& inc) { } void ElementLBData::resetPhase() { - cur_phase_ = fst_lb_phase; - // Resets the current phase in the containers without removing any phase data. - phase_timings_.restartFrom(fst_lb_phase); - subphase_timings_.restartFrom(fst_lb_phase); - phase_comm_.restartFrom(fst_lb_phase); - subphase_comm_.restartFrom(fst_lb_phase); + // cur_phase_ = fst_lb_phase; + // // Resets the current phase in the containers without removing any phase data. + // phase_timings_.restartFrom(fst_lb_phase); + // subphase_timings_.restartFrom(fst_lb_phase); + // phase_comm_.restartFrom(fst_lb_phase); + // subphase_comm_.restartFrom(fst_lb_phase); } PhaseType ElementLBData::getPhase() const { diff --git a/tests/unit/collection/test_lb_data_retention.cc b/tests/unit/collection/test_lb_data_retention.cc index d794e4692d..468fafdbea 100644 --- a/tests/unit/collection/test_lb_data_retention.cc +++ b/tests/unit/collection/test_lb_data_retention.cc @@ -433,4 +433,81 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_model_switch_2) { validatePersistedPhases({16}); } +TEST_F(TestLBDataRetention, test_lbdata_retention_checkpoint) { + static constexpr int const num_phases = 8; + theConfig()->vt_lb_data_retention = 4; + + auto this_node = theContext()->getNode(); + std::string const checkpoint_name(getUniqueFilenameWithRanks()); + auto range = vt::Index1D(num_elms); + vt::vrt::collection::CollectionProxy proxy; + + runInEpochCollective([&]{ + proxy = vt::theCollection()->constructCollective( + range, "test_lbdata_retention_checkpoint" + ); + proxy.broadcastCollective(); + }); + + // Get the base model, assert it's valid + auto base = theLBManager()->getBaseLoadModel(); + EXPECT_NE(base, nullptr); + + // Create a new model + auto persist = std::make_shared(base, 4U); + + // Set the new model + theLBManager()->setLoadModel(persist); + + for (int i=0; i(); + }); + // Go to the next phase. + vt::thePhase()->nextPhaseCollective(); + } + + // Check the phases persisted in the node + validatePersistedPhases({4,5,6,7}); + + vt::runInEpochCollective([&]{ + vt_print(gen, "checkpointToFile\n"); + vt::theCollection()->checkpointToFile(proxy, checkpoint_name); + }); + + vt::runInEpochCollective([&]{ + if (this_node == 0) { + proxy.destroy(); + } + }); + + auto proxy_new = vt::theCollection()->constructCollective( + range, "test_lbdata_retention_checkpoint" + ); + + vt::runInEpochCollective([&]{ + // Now, restore from the previous distribution + vt_print(gen, "restoreFromFileInPlace\n"); + vt::theCollection()->restoreFromFileInPlace( + proxy_new, range, checkpoint_name + ); + }); + + // Check the phases persisted in the node + validatePersistedPhases({4,5,6,7}); + + for (int i=0; i(); + }); + // Go to the next phase. + vt::thePhase()->nextPhaseCollective(); + } + + // Check the phases persisted in the node + validatePersistedPhases({12, 13, 14, 15}); +} + }}}} // end namespace vt::tests::unit::TestLBDataRetention From a4ff0c653076c2b496f6592024309426aeb5514f Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Tue, 24 Sep 2024 16:50:09 +0200 Subject: [PATCH 78/82] #1934: Improve documentation for CircularPhasesBuffer --- .../utils/container/circular_phases_buffer.h | 180 +++++++++--------- 1 file changed, 87 insertions(+), 93 deletions(-) diff --git a/src/vt/utils/container/circular_phases_buffer.h b/src/vt/utils/container/circular_phases_buffer.h index 8a8d985544..097b98cde4 100644 --- a/src/vt/utils/container/circular_phases_buffer.h +++ b/src/vt/utils/container/circular_phases_buffer.h @@ -53,7 +53,13 @@ namespace vt { namespace util { namespace container { /** * \struct CircularPhasesBuffer * - * \brief The circular buffer which holds data related to a set of phases. + * \brief A circular buffer for storing and accessing data with phase-based indexing. + * + * The buffer supports a valid range of phases that spans from `frontPhase() - capacity()` + * to `frontPhase()`, allowing both random access and insertion of new phases within this window. + * Phases outside this range, i.e., those before the window, are not guaranteed to remain accessible. + * Inserting a phase greater than the current `frontPhase()` will automatically advance the + * `frontPhase()`, shifting the valid window forward to accommodate the new phase. */ template class CircularPhasesBuffer { @@ -63,10 +69,10 @@ class CircularPhasesBuffer { constexpr static auto no_index = std::numeric_limits::max(); /** - * \brief Creates an empty pair to be stored in the buffer + * \brief Create an empty phase-data pair for initializing the buffer. * - * \param[in] phase - the phase to be assigned, \c no_phase otherwise - * \return the new pair + * \param[in] phase The phase to assign to the pair (defaults to \c no_phase if not provided) + * \return A new pair containing the phase and an empty \c StoredType object. */ static StoredPair makeEmptyPair(const PhaseType& phase = no_phase) { return std::make_pair(phase, StoredType{}); @@ -75,9 +81,9 @@ class CircularPhasesBuffer { public: /** - * \brief Construct a CircularPhasesBuffer + * \brief Constructor to initialize the circular buffer with a specified size. * - * \param[in] size_in the requested size of the buffer + * \param[in] size_in The size of the buffer (must be greater than zero). */ CircularPhasesBuffer(std::size_t size_in = 1) : buffer_(size_in, makeEmptyPair()) @@ -85,26 +91,22 @@ class CircularPhasesBuffer { vtAssert(size_in > 0, "Size of CircularPhasesBuffer needs to be greather than zero."); } - /** - * \brief Check if phase is present in the buffer. + * \brief Check if a given phase exists in the buffer. * - * \param[in] phase the phase to look for - * - * \return whenever the buffer contains the phase or not + * \param[in] phase The phase to check for existence. + * \return \c true if the phase is present, otherwise \c false. */ bool contains(const PhaseType& phase) const { return buffer_[phaseToIndex(phase)].first == phase; } /** - * \brief Get data for the phase. Inserts a new element when phase is not present in the buffer. - * Can call \c vtAbort() when phase is outside of the valid range. - * Check \c canBeStored() for more details. - * - * \param[in] phase the phase to look for + * \brief Access data for a given phase. If the phase is not present, it inserts a new element. + * This method can abort the process if the phase is out of range (check \c canBeStored()). * - * \return reference to the stored data + * \param[in] phase The phase to retrieve data for. + * \return A reference to the stored data for the phase. */ StoredType& operator[](const PhaseType phase) { auto& pair = buffer_[phaseToIndex(phase)]; @@ -116,12 +118,11 @@ class CircularPhasesBuffer { } /** - * \brief Store data in the buffer. - * Can call \c vtAbort() when phase is outside of the valid range. - * Check \c canBeStored() for more details. + * \brief Store data for a given phase in the buffer. + * Can abort the process if the phase is out of the valid range (check \c canBeStored()). * - * \param[in] phase the phase for which data will be stored - * \param[in] obj the data to store + * \param[in] phase The phase for which data will be stored. + * \param[in] data The data to store. */ void store(const PhaseType& phase, StoredType data) { vtAssert(canBeStored(phase), "Phase is out of valid range"); @@ -131,11 +132,11 @@ class CircularPhasesBuffer { } /** - * \brief Get data related to the phase. + * \brief Retrieve data for a specific phase. * - * \param[in] phase the phase to look for - * - * \return reference to the stored data + * \param[in] phase The phase to retrieve. + * \return A reference to the stored data. + * \throw Asserts if the phase is not present in the buffer. */ StoredType& at(const PhaseType phase) { vtAssert(contains(phase), "Phase is not stored in the buffer."); @@ -143,11 +144,11 @@ class CircularPhasesBuffer { } /** - * \brief Get data related to the phase. - * - * \param[in] phase the phase to look for + * \brief Retrieve data for a specific phase. * - * \return reference to the stored data + * \param[in] phase The phase to retrieve. + * \return A const reference to the stored data. + * \throw Asserts if the phase is not present in the buffer. */ const StoredType& at(const PhaseType phase) const { vtAssert(contains(phase), "Phase is not stored in the buffer."); @@ -155,10 +156,10 @@ class CircularPhasesBuffer { } /** - * \brief Resize the buffer to the requested size. - * The minimal size of the buffer is 1. + * \brief Resize the buffer to a new size. + * The buffer's minimal size is 1. * - * \param[in] new_size_in the requested new size of the buffer + * \param[in] new_size_in The requested new size of the buffer. */ void resize(const std::size_t new_size_in) { auto new_size = std::max(std::size_t{1}, new_size_in); @@ -175,7 +176,7 @@ class CircularPhasesBuffer { auto to_copy = head_phase_; while(num > 0 && to_copy != no_phase) { if (contains(to_copy)) { - tmp[calcIndex(to_copy, tmp)] = buffer_[phaseToIndex(to_copy)]; + tmp[to_copy % tmp.size()] = buffer_[phaseToIndex(to_copy)]; num--; } to_copy--; @@ -185,34 +186,34 @@ class CircularPhasesBuffer { } /** - * \brief Check if the buffer is empty. + * \brief Check if the buffer is empty (i.e., contains no valid phases). * - * \return whether the buffer is empty or not + * \return \c true if the buffer is empty, otherwise \c false. */ bool empty() const { return head_phase_ == no_phase; } /** - * \brief Get the number of valid elements in the buffer + * \brief Get the number of valid elements currently stored in the buffer. * - * \return the number of valid elements + * \return The number of valid elements in the buffer. */ std::size_t size() const { return buffer_.size() - numFree(); } /** - * \brief Returns the current capacity of the buffer + * \brief Get the total capacity of the buffer. * - * \return the buffer capacity + * \return The capacity of the buffer. */ std::size_t capacity() const { return buffer_.size(); } /** - * \brief Clears content of the buffer. + * \brief Clear all elements in the buffer, resetting it to an empty state. */ void clear() { head_phase_ = no_phase; @@ -220,9 +221,10 @@ class CircularPhasesBuffer { } /** - * \brief Shifts the buffer's head to the specified phase without removing any data. + * \brief Restart the buffer from a specific phase, shifting the head. + * This does not remove any existing data. * - * \param start_point the new start point for the buffer + * \param start_point The phase to start from. */ void restartFrom(const PhaseType& start_point) { if (empty()) { @@ -239,29 +241,29 @@ class CircularPhasesBuffer { } /** - * \brief Get the latest phase + * \brief Retrieve the most recent phase in the buffer. * - * \return the latest phase + * \return The phase at the front of the buffer. */ PhaseType frontPhase() const { return head_phase_; } /** - * \brief Get the data for the latest phase + * \brief Retrieve the data associated with the most recent phase. * - * \return the reference to the latest data + * \return A reference to the data for the latest phase. + * \throw Asserts if the buffer is empty. */ StoredType& frontData() { return at(head_phase_); } /** - * \brief Find data for a phase. + * \brief Find data associated with a phase. * - * \param[in] phase the phase to look for - * - * \return pointer to phase data, nullptr otherwise. + * \param[in] phase The phase to search for. + * \return A pointer to the data if the phase is present, otherwise \c nullptr. */ StoredType* find(const PhaseType& phase) { if (contains(phase)) { @@ -271,11 +273,10 @@ class CircularPhasesBuffer { } /** - * \brief Find data for a phase. - * - * \param[in] phase the phase to look for + * \brief Find data associated with a phase. * - * \return pointer to phase data, nullptr otherwise. + * \param[in] phase The phase to search for. + * \return A const pointer to the data if the phase is present, otherwise \c nullptr. */ const StoredType* find(const PhaseType& phase) const { if (contains(phase)) { @@ -285,30 +286,30 @@ class CircularPhasesBuffer { } /** - * \brief Get const iterator to the first valid element in the buffer + * \brief Get a const iterator to the first valid element in the buffer. * - * \return the const iterator + * \return A const iterator to the first valid element. */ auto begin() const { return ++ForwardIterator(&buffer_, no_index); } /** - * \brief Get iterator to the first valid element in the buffer + * \brief Get an iterator to the first valid element in the buffer. * - * \return the iterator + * \return An iterator to the first valid element. */ auto begin() { return ++ForwardIterator(&buffer_, no_index); } /** - * \brief Get const iterator to the space after the buffer + * \brief Get a const iterator to the end of the buffer (one past the last element). * - * \return the const end iterator + * \return A const iterator to the end of the buffer. */ auto end() const { return ForwardIterator(&buffer_, buffer_.size()); } /** - * \brief Get iterator to the space after the buffer + * \brief Get an iterator to the end of the buffer (one past the last element). * - * \return the end iterator + * \return An iterator to the end of the buffer. */ auto end() { return ForwardIterator(&buffer_, buffer_.size()); } @@ -320,30 +321,19 @@ class CircularPhasesBuffer { private: /** - * \brief Converts phase number to the index in the buffer + * \brief Convert a phase number to its corresponding index in the buffer. * - * \param phase - the phase to be converted - * \return the position of the data container in the buffer + * \param[in] phase The phase to convert. + * \return The buffer index for the phase. */ std::size_t phaseToIndex(const PhaseType& phase) const { return phase % buffer_.size(); } /** - * \brief Converts phase number to the index in the temporary buffer + * \brief Count the number of empty (without a valid phase) slots in the buffer. * - * \param[in] phase - the phase to be converted - * \param[in] vector - the buffer to return index for - * \return the position of the data container in the buffer - */ - std::size_t calcIndex(const PhaseType& phase, const std::vector& vector) const { - return phase % vector.size(); - } - - /** - * \brief Counts fields in the buffer without a valid phase assigned. - * - * \return the number of empty fields + * \return The number of empty slots. */ std::size_t numFree() const { return std::count_if(buffer_.begin(), buffer_.end(), @@ -352,9 +342,9 @@ class CircularPhasesBuffer { } /** - * \brief Update the head phase stored in the buffer if necessary + * \brief Update the head phase if a newer phase is stored. * - * \param phase - the phase to compare to \c head_phase_ + * \param[in] phase The phase being stored. */ void updateHead(const PhaseType& phase) { if (head_phase_ == no_phase || phase > head_phase_) { @@ -363,23 +353,28 @@ class CircularPhasesBuffer { } /** - * \brief Checks if phase can be stored in the buffer. - * Valid phase needs to be higher than (head_phase_ - buffer_.size()) + * \brief Check whether a given phase can be stored in the buffer. + * A phase is valid if it is greater than \c (head_phase_ - capacity()). * - * \param[in] phase - the phase to validate - * \return true if higher than (head_phase_ - buffer_.size()), false otherwise + * \param[in] phase The phase to validate. + * \return \c true if the phase can be stored, otherwise \c false. */ bool canBeStored(const PhaseType& phase) const { - if (!empty() && head_phase_ > buffer_.size()) { - return phase > head_phase_ - buffer_.size(); + if (!empty() && head_phase_ > capacity()) { + return phase > head_phase_ - capacity(); } return true; } - PhaseType head_phase_ = no_phase; - std::vector buffer_; + PhaseType head_phase_ = no_phase; ///< The most recent phase in the buffer. + std::vector buffer_; ///< The underlying data buffer. public: + /** + * \struct ForwardIterator + * + * \brief An iterator for traversing the buffer in a forward direction, skipping empty slots. + */ struct ForwardIterator { using iterator_category = std::forward_iterator_tag; using difference_type = std::ptrdiff_t; @@ -406,8 +401,7 @@ class CircularPhasesBuffer { private: /** - * \brief Advances the iterator to the next element with valid phase number. - * + * \brief Move the iterator to the next element with a valid phase. */ void advance() { index_++; @@ -419,8 +413,8 @@ class CircularPhasesBuffer { } } - std::size_t index_; - std::vector* buffer_; + std::size_t index_; ///< The current index in the buffer. + std::vector* buffer_; ///< Pointer to the buffer being iterated over. }; }; From c9e91200e208addff809e0955bd71d626ae3886d Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Thu, 26 Sep 2024 12:48:11 +0200 Subject: [PATCH 79/82] #1934: Modify test harness to allow for vt restarts --- tests/unit/test_parallel_harness.h | 34 ++++++++++++++++++------------ 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/tests/unit/test_parallel_harness.h b/tests/unit/test_parallel_harness.h index d5c8e1c7fc..a96260f72e 100644 --- a/tests/unit/test_parallel_harness.h +++ b/tests/unit/test_parallel_harness.h @@ -61,8 +61,6 @@ extern char** test_argv; template struct TestParallelHarnessAny : TestHarnessAny { virtual void SetUp() override { - using namespace vt; - TestHarnessAny::SetUp(); #if vt_feature_cmake_test_trace_on @@ -84,15 +82,24 @@ struct TestParallelHarnessAny : TestHarnessAny { if (!init) { MPI_Init(&test_argc, &test_argv); } - MPI_Comm comm = MPI_COMM_WORLD; - auto const new_args = injectAdditionalArgs(test_argc, test_argv); - auto custom_argc = new_args.first; - auto custom_argv = new_args.second; + + // inject args only once + injectAdditionalArgs(test_argc, test_argv); + + initVt(); + } + + void initVt() { + using namespace vt; + + int custom_argc = additional_args_.size() - 1; + char** custom_argv = additional_args_.data(); vtAssert( custom_argv[custom_argc] == nullptr, "The value of argv[argc] should always be 0" ); // communicator is duplicated. + MPI_Comm comm = MPI_COMM_WORLD; CollectiveOps::initialize(custom_argc, custom_argv, true, &comm); #if DEBUG_TEST_HARNESS_PRINT @@ -103,6 +110,12 @@ struct TestParallelHarnessAny : TestHarnessAny { } virtual void TearDown() override { + destroyVt(); + + TestHarnessAny::TearDown(); + } + + void destroyVt() { using namespace vt; try { @@ -117,8 +130,6 @@ struct TestParallelHarnessAny : TestHarnessAny { #endif CollectiveOps::finalize(); - - TestHarnessAny::TearDown(); } protected: @@ -134,8 +145,7 @@ struct TestParallelHarnessAny : TestHarnessAny { } private: - std::pair - injectAdditionalArgs(int old_argc, char** old_argv) { + void injectAdditionalArgs(int old_argc, char** old_argv) { additional_args_.insert( additional_args_.begin(), old_argv, old_argv + old_argc ); @@ -143,10 +153,6 @@ struct TestParallelHarnessAny : TestHarnessAny { addAdditionalArgs(); additional_args_.emplace_back(nullptr); - int custom_argc = additional_args_.size() - 1; - char** custom_argv = additional_args_.data(); - - return std::make_pair(custom_argc, custom_argv); } /** From 0623fc4b7bd22d5eb5de369090a4405ad23d5e29 Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Thu, 26 Sep 2024 15:34:23 +0200 Subject: [PATCH 80/82] #1934: Prepare content of the containers for work after restore from checkpoint --- src/vt/elm/elm_lb_data.cc | 15 +++++++------ .../utils/container/circular_phases_buffer.h | 21 +++++++++++++------ .../test_circular_phases_buffer.nompi.cc | 13 ++++++------ 3 files changed, 30 insertions(+), 19 deletions(-) diff --git a/src/vt/elm/elm_lb_data.cc b/src/vt/elm/elm_lb_data.cc index 2672e2e898..37ecfb9da4 100644 --- a/src/vt/elm/elm_lb_data.cc +++ b/src/vt/elm/elm_lb_data.cc @@ -195,12 +195,15 @@ void ElementLBData::updatePhase(PhaseType const& inc) { } void ElementLBData::resetPhase() { - // cur_phase_ = fst_lb_phase; - // // Resets the current phase in the containers without removing any phase data. - // phase_timings_.restartFrom(fst_lb_phase); - // subphase_timings_.restartFrom(fst_lb_phase); - // phase_comm_.restartFrom(fst_lb_phase); - // subphase_comm_.restartFrom(fst_lb_phase); + // This method will become obsolete once VT gains full restart capability, + // allowing it to load all necessary data (like PhaseManager state, NodeLBData, etc.) from a checkpoint. + + cur_phase_ = fst_lb_phase; + // Resets the current phase in the containers. + phase_timings_.restartFrom(fst_lb_phase); + subphase_timings_.restartFrom(fst_lb_phase); + phase_comm_.restartFrom(fst_lb_phase); + subphase_comm_.restartFrom(fst_lb_phase); } PhaseType ElementLBData::getPhase() const { diff --git a/src/vt/utils/container/circular_phases_buffer.h b/src/vt/utils/container/circular_phases_buffer.h index 097b98cde4..52aa64b9f3 100644 --- a/src/vt/utils/container/circular_phases_buffer.h +++ b/src/vt/utils/container/circular_phases_buffer.h @@ -221,22 +221,31 @@ class CircularPhasesBuffer { } /** - * \brief Restart the buffer from a specific phase, shifting the head. - * This does not remove any existing data. + * \brief Resets the buffer to a specified phase, discarding all earlier phases + * and retaining only the most recent phase data that will be mapped to the new starting point. * * \param start_point The phase to start from. */ void restartFrom(const PhaseType& start_point) { if (empty()) { + head_phase_ = start_point; return; } - // copy data from head_phase_ - if (phaseToIndex(head_phase_) != phaseToIndex(start_point)) { - buffer_[phaseToIndex(start_point)].second = buffer_[phaseToIndex(head_phase_)].second; + std::size_t index = phaseToIndex(start_point); + if (std::size_t head_index = phaseToIndex(head_phase_); head_index != index) { + // copy data from head_phase_ + buffer_[index].second = buffer_[head_index].second; } - buffer_[phaseToIndex(start_point)].first = start_point; + // clear rest of the data + for (std::size_t i = 0; i < buffer_.size(); i++) { + if (i != index) { + buffer_[i] = makeEmptyPair(); + } + } + + buffer_[index].first = start_point; head_phase_ = start_point; } diff --git a/tests/unit/utils/test_circular_phases_buffer.nompi.cc b/tests/unit/utils/test_circular_phases_buffer.nompi.cc index d1b73b344c..386ffa5a1f 100644 --- a/tests/unit/utils/test_circular_phases_buffer.nompi.cc +++ b/tests/unit/utils/test_circular_phases_buffer.nompi.cc @@ -223,21 +223,20 @@ TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_resize) { TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_restart_from) { CircularBufferType buffer{1}; - // do nothing on empty buffer buffer.restartFrom(5); - EXPECT_EQ(std::numeric_limits::max(), buffer.frontPhase()); + EXPECT_EQ(PhaseType{5}, buffer.frontPhase()); - buffer[3] = {3}; - EXPECT_EQ(PhaseType{3}, buffer.frontPhase()); - EXPECT_EQ(PhaseType{3}, buffer.frontData().x); + buffer[5] = {5}; + EXPECT_EQ(PhaseType{5}, buffer.frontPhase()); + EXPECT_EQ(PhaseType{5}, buffer.frontData().x); buffer.restartFrom(10); EXPECT_EQ(PhaseType{10}, buffer.frontPhase()); - EXPECT_EQ(PhaseType{3}, buffer.frontData().x); + EXPECT_EQ(PhaseType{5}, buffer.frontData().x); buffer.restartFrom(0); EXPECT_EQ(PhaseType{0}, buffer.frontPhase()); - EXPECT_EQ(PhaseType{3}, buffer.frontData().x); + EXPECT_EQ(PhaseType{5}, buffer.frontData().x); } TEST_F(TestCircularPhasesBuffer, test_circular_phases_buffer_forward_iter) { From 37b719f1799f5f7277efab313d138f26a8d7fe4d Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Thu, 26 Sep 2024 15:35:02 +0200 Subject: [PATCH 81/82] #1934: Update retention test to do a full recreation of the vt objects --- .../unit/collection/test_lb_data_retention.cc | 128 ++++++++++++------ 1 file changed, 88 insertions(+), 40 deletions(-) diff --git a/tests/unit/collection/test_lb_data_retention.cc b/tests/unit/collection/test_lb_data_retention.cc index 468fafdbea..61488b0d86 100644 --- a/tests/unit/collection/test_lb_data_retention.cc +++ b/tests/unit/collection/test_lb_data_retention.cc @@ -131,6 +131,19 @@ struct TestCol : vt::Collection { EXPECT_EQ(sp_comm_phase_count, std::size_t{0}); #endif } + + static void emptyDataHandler(TestCol* col) { + auto& lb_data = col->lb_data_; + auto load_phase_count = lb_data.getLoadPhaseCount(); + auto comm_phase_count = lb_data.getCommPhaseCount(); + auto sp_load_phase_count = lb_data.getSubphaseLoadPhaseCount(); + auto sp_comm_phase_count = lb_data.getSubphaseCommPhaseCount(); + + EXPECT_EQ(load_phase_count, std::size_t{1}); + EXPECT_EQ(sp_load_phase_count, std::size_t{1}); + EXPECT_EQ(comm_phase_count, std::size_t{1}); + EXPECT_EQ(sp_comm_phase_count, std::size_t{1}); + } }; static constexpr int32_t const num_elms = 16; @@ -433,59 +446,87 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_model_switch_2) { validatePersistedPhases({16}); } -TEST_F(TestLBDataRetention, test_lbdata_retention_checkpoint) { - static constexpr int const num_phases = 8; - theConfig()->vt_lb_data_retention = 4; +struct TestLBDataRetentionOnCheckpoint : TestParallelHarness { + virtual void SetUp() override { + TestParallelHarness::SetUp(); - auto this_node = theContext()->getNode(); + // We must have more or equal number of elements than nodes for this test to + // work properly + SET_MAX_NUM_NODES_CONSTRAINT(num_elms); + } +}; + +TEST_F(TestLBDataRetentionOnCheckpoint, test_lbdata_retention_checkpoint) { + static constexpr int const num_phases = 8; std::string const checkpoint_name(getUniqueFilenameWithRanks()); auto range = vt::Index1D(num_elms); - vt::vrt::collection::CollectionProxy proxy; - - runInEpochCollective([&]{ - proxy = vt::theCollection()->constructCollective( - range, "test_lbdata_retention_checkpoint" - ); - proxy.broadcastCollective(); - }); - - // Get the base model, assert it's valid - auto base = theLBManager()->getBaseLoadModel(); - EXPECT_NE(base, nullptr); - // Create a new model - auto persist = std::make_shared(base, 4U); + { + theConfig()->vt_lb_data_retention = 4; - // Set the new model - theLBManager()->setLoadModel(persist); + auto this_node = theContext()->getNode(); + vt::vrt::collection::CollectionProxy proxy; - for (int i=0; i(); + proxy = vt::theCollection()->constructCollective( + range, "test_lbdata_retention_checkpoint" + ); + proxy.broadcastCollective(); }); - // Go to the next phase. - vt::thePhase()->nextPhaseCollective(); - } - // Check the phases persisted in the node - validatePersistedPhases({4,5,6,7}); + // Get the base model, assert it's valid + auto base = theLBManager()->getBaseLoadModel(); + EXPECT_NE(base, nullptr); - vt::runInEpochCollective([&]{ - vt_print(gen, "checkpointToFile\n"); - vt::theCollection()->checkpointToFile(proxy, checkpoint_name); - }); + // Create a new model + auto persist = std::make_shared(base, 4U); - vt::runInEpochCollective([&]{ - if (this_node == 0) { - proxy.destroy(); + // Set the new model + theLBManager()->setLoadModel(persist); + + for (int i=0; i(); + }); + // Go to the next phase. + vt::thePhase()->nextPhaseCollective(); } - }); + + // Check the phases persisted in the node + validatePersistedPhases({4,5,6,7}); + + vt::runInEpochCollective([&]{ + vt_print(gen, "checkpointToFile\n"); + vt::theCollection()->checkpointToFile(proxy, checkpoint_name); + }); + + vt::runInEpochCollective([&]{ + if (this_node == 0) { + proxy.destroy(); + } + }); + } + + // Destroy and init fresh instance + TestLBDataRetentionOnCheckpoint::destroyVt(); + vt_print(gen, "newVtInstance\n"); + TestLBDataRetentionOnCheckpoint::initVt(); auto proxy_new = vt::theCollection()->constructCollective( range, "test_lbdata_retention_checkpoint" ); + // Get the base model, assert it's valid + auto base = theLBManager()->getBaseLoadModel(); + EXPECT_NE(base, nullptr); + + // Create a new model + auto persist = std::make_shared(base, 4U); + + // Set the new model + theLBManager()->setLoadModel(persist); + vt::runInEpochCollective([&]{ // Now, restore from the previous distribution vt_print(gen, "restoreFromFileInPlace\n"); @@ -494,12 +535,19 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_checkpoint) { ); }); - // Check the phases persisted in the node - validatePersistedPhases({4,5,6,7}); + // After restore node LB data is empty + validatePersistedPhases({}); + runInEpochCollective([&]{ + proxy_new.broadcastCollective(); + }); + vt::thePhase()->nextPhaseCollective(); + + validatePersistedPhases({0}); + + // Do more work. for (int i=0; i(); }); // Go to the next phase. @@ -507,7 +555,7 @@ TEST_F(TestLBDataRetention, test_lbdata_retention_checkpoint) { } // Check the phases persisted in the node - validatePersistedPhases({12, 13, 14, 15}); + validatePersistedPhases({5, 6, 7, 8}); } }}}} // end namespace vt::tests::unit::TestLBDataRetention From 0b2489f731f4bb250d62e4ea96e167f683f88dbf Mon Sep 17 00:00:00 2001 From: Arkadiusz Szczepkowicz Date: Thu, 26 Sep 2024 18:27:09 +0200 Subject: [PATCH 82/82] #1934: Fix retention test checks when LB is disabled --- tests/unit/collection/test_lb_data_retention.cc | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/tests/unit/collection/test_lb_data_retention.cc b/tests/unit/collection/test_lb_data_retention.cc index 61488b0d86..c4c1af908b 100644 --- a/tests/unit/collection/test_lb_data_retention.cc +++ b/tests/unit/collection/test_lb_data_retention.cc @@ -139,10 +139,17 @@ struct TestCol : vt::Collection { auto sp_load_phase_count = lb_data.getSubphaseLoadPhaseCount(); auto sp_comm_phase_count = lb_data.getSubphaseCommPhaseCount(); - EXPECT_EQ(load_phase_count, std::size_t{1}); - EXPECT_EQ(sp_load_phase_count, std::size_t{1}); - EXPECT_EQ(comm_phase_count, std::size_t{1}); - EXPECT_EQ(sp_comm_phase_count, std::size_t{1}); + #if vt_check_enabled(lblite) + EXPECT_EQ(load_phase_count, std::size_t{1}); + EXPECT_EQ(sp_load_phase_count, std::size_t{1}); + EXPECT_EQ(comm_phase_count, std::size_t{1}); + EXPECT_EQ(sp_comm_phase_count, std::size_t{1}); + #else + EXPECT_EQ(load_phase_count, std::size_t{0}); + EXPECT_EQ(sp_load_phase_count, std::size_t{0}); + EXPECT_EQ(comm_phase_count, std::size_t{0}); + EXPECT_EQ(sp_comm_phase_count, std::size_t{0}); + #endif } };