diff --git a/src/vt/vrt/collection/balance/model/composed_model.cc b/src/vt/vrt/collection/balance/model/composed_model.cc index 166c50c646..1fb3ad3f39 100644 --- a/src/vt/vrt/collection/balance/model/composed_model.cc +++ b/src/vt/vrt/collection/balance/model/composed_model.cc @@ -73,7 +73,7 @@ int ComposedModel::getNumObjects() { } int ComposedModel::getNumCompletedPhases() { - return base_->getNumSubphases(); + return base_->getNumCompletedPhases(); } int ComposedModel::getNumSubphases() { diff --git a/src/vt/vrt/collection/balance/model/persistence_median_last_n.cc b/src/vt/vrt/collection/balance/model/persistence_median_last_n.cc index 7bda8026fc..9b8307c743 100644 --- a/src/vt/vrt/collection/balance/model/persistence_median_last_n.cc +++ b/src/vt/vrt/collection/balance/model/persistence_median_last_n.cc @@ -72,9 +72,9 @@ TimeType PersistenceMedianLastN::getWork(ElementIDType object, PhaseOffset when) std::sort(times.begin(), times.end()); if (phases % 2 == 1) - return times[phases / 2 + 1]; + return times[phases / 2]; else - return (times[phases / 2] + times[phases / 2 + 1]) / 2; + return (times[phases / 2 - 1] + times[phases / 2]) / 2; } }}}} diff --git a/tests/unit/collection/test_model_linear_model.nompi.cc b/tests/unit/collection/test_model_linear_model.nompi.cc new file mode 100644 index 0000000000..0afda59c1f --- /dev/null +++ b/tests/unit/collection/test_model_linear_model.nompi.cc @@ -0,0 +1,155 @@ +/* +//@HEADER +// ***************************************************************************** +// +// test_model_linear_model.nompi +// DARMA Toolkit v. 1.0.0 +// DARMA/vt => Virtual Transport +// +// Copyright 2019 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 + +#include + +#include "test_harness.h" + +#include + +namespace vt { namespace tests { namespace unit { + +using TestLinearModel = TestHarness; + +static int32_t num_phases = 1; + +using vt::vrt::collection::balance::CommMapType; +using vt::vrt::collection::balance::ElementIDType; +using vt::vrt::collection::balance::LinearModel; +using vt::vrt::collection::balance::LoadMapType; +using vt::vrt::collection::balance::LoadModel; +using vt::vrt::collection::balance::ObjectIterator; +using vt::vrt::collection::balance::PhaseOffset; +using vt::vrt::collection::balance::SubphaseLoadMapType; + +struct StubModel : LoadModel { + + StubModel() = default; + virtual ~StubModel() = default; + + void setLoads( + std::vector const* proc_load, + std::vector const*, + std::vector const*) override { + proc_load_ = proc_load; + } + + void updateLoads(PhaseType) override {} + + TimeType getWork(ElementIDType id, PhaseOffset phase) override { + // Most recent phase will be at the end of vector + return proc_load_->at(num_phases + phase.phases).at(id); + } + + virtual ObjectIterator begin() override { + return ObjectIterator(proc_load_->back().begin()); + } + virtual ObjectIterator end() override { + return ObjectIterator(proc_load_->back().end()); + } + + virtual int getNumObjects() override { return 2; } + virtual int getNumCompletedPhases() override { return num_phases; } + virtual int getNumSubphases() override { return 1; } + +private: + std::vector const* proc_load_ = nullptr; +}; + +TEST_F(TestLinearModel, test_model_linear_model_1) { + constexpr int32_t num_test_interations = 6; + + auto test_model = + std::make_shared(std::make_shared(), 4); + + // For linear regression there needs to be at least 2 phases completed + // so we begin with 1 phase already done + std::vector proc_loads{LoadMapType{ + {ElementIDType{1}, TimeType{10}}, {ElementIDType{2}, TimeType{40}}}}; + test_model->setLoads(&proc_loads, nullptr, nullptr); + + // Work loads to be added in each test iteration + std::vector load_holder{ + LoadMapType{ + {ElementIDType{1}, TimeType{5}}, {ElementIDType{2}, TimeType{10}}}, + LoadMapType{ + {ElementIDType{1}, TimeType{30}}, {ElementIDType{2}, TimeType{100}}}, + LoadMapType{ + {ElementIDType{1}, TimeType{50}}, {ElementIDType{2}, TimeType{40}}}, + LoadMapType{ + {ElementIDType{1}, TimeType{2}}, {ElementIDType{2}, TimeType{50}}}, + LoadMapType{ + {ElementIDType{1}, TimeType{60}}, {ElementIDType{2}, TimeType{20}}}, + LoadMapType{ + {ElementIDType{1}, TimeType{100}}, {ElementIDType{2}, TimeType{10}}}, + }; + + std::array, num_test_interations> expected_data{ + std::make_pair(TimeType{0}, TimeType{-20}), // iter 0 results + std::make_pair(TimeType{35}, TimeType{110}), // iter 1 results + std::make_pair(TimeType{60}, TimeType{70}), // iter 2 results + std::make_pair(TimeType{24.5}, TimeType{65}), // iter 3 results + std::make_pair(TimeType{46}, TimeType{-5}), // iter 4 results + std::make_pair(TimeType{105}, TimeType{0}) // iter 5 results + }; + + for (auto iter = 0; iter < num_test_interations; ++iter) { + proc_loads.push_back(load_holder[iter]); + ++num_phases; + + for (auto&& obj : *test_model) { + auto work_val = test_model->getWork(obj, PhaseOffset{}); + EXPECT_EQ( + work_val, + obj == 1 ? expected_data[iter].first : expected_data[iter].second) + << fmt::format("Test failed on iteration {}", iter); + } + } +} + +}}} // end namespace vt::tests::unit diff --git a/tests/unit/collection/test_model_multiple_phases.nompi.cc b/tests/unit/collection/test_model_multiple_phases.nompi.cc new file mode 100644 index 0000000000..a2824d7fc1 --- /dev/null +++ b/tests/unit/collection/test_model_multiple_phases.nompi.cc @@ -0,0 +1,126 @@ +/* +//@HEADER +// ***************************************************************************** +// +// test_model_multiple_phases.nompi +// DARMA Toolkit v. 1.0.0 +// DARMA/vt => Virtual Transport +// +// Copyright 2019 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 + +#include + +#include "test_harness.h" + +#include + +namespace vt { namespace tests { namespace unit { + +using TestModelMultiplePhases = TestHarness; + +using vt::vrt::collection::balance::ElementIDType; +using vt::vrt::collection::balance::LoadModel; +using vt::vrt::collection::balance::MultiplePhases; +using vt::vrt::collection::balance::PhaseOffset; +using vt::vrt::collection::balance::LoadMapType; +using vt::vrt::collection::balance::SubphaseLoadMapType; +using vt::vrt::collection::balance::CommMapType; +using vt::vrt::collection::balance::ObjectIterator; + +struct StubModel : LoadModel { + + StubModel() = default; + virtual ~StubModel() = default; + + void setLoads( + std::vector const* proc_load, + std::vector const*, + std::vector const*) override { + proc_load_ = proc_load; + } + + void updateLoads(PhaseType) override {} + + TimeType getWork(ElementIDType id, PhaseOffset phase) 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); + } + + virtual ObjectIterator begin() override { + return ObjectIterator(proc_load_->back().begin()); + } + virtual ObjectIterator end() override { + return ObjectIterator(proc_load_->back().end()); + } + + // Not used by this test + virtual int getNumObjects() override { return 0; } + virtual int getNumCompletedPhases() override { return 0; } + virtual int getNumSubphases() override { return 0; } + +private: + std::vector const* proc_load_ = nullptr; +}; + +TEST_F(TestModelMultiplePhases, test_model_multiple_phases_1) { + std::vector proc_loads = { + LoadMapType{ + {ElementIDType{1}, TimeType{10}}, {ElementIDType{2}, TimeType{40}}}, + LoadMapType{ + {ElementIDType{1}, TimeType{20}}, {ElementIDType{2}, TimeType{30}}}, + LoadMapType{ + {ElementIDType{1}, TimeType{30}}, {ElementIDType{2}, TimeType{10}}}, + LoadMapType{ + {ElementIDType{1}, TimeType{40}}, {ElementIDType{2}, TimeType{5}}}}; + + auto test_model = + std::make_shared(std::make_shared(), 4); + + test_model->setLoads(&proc_loads, nullptr, nullptr); + + for (auto&& obj : *test_model) { + auto work_val = test_model->getWork(obj, PhaseOffset{}); + EXPECT_EQ(work_val, obj == 1 ? TimeType{100} : TimeType{85}); + } +} + +}}} // end namespace vt::tests::unit diff --git a/tests/unit/collection/test_model_naive_persistence.nompi.cc b/tests/unit/collection/test_model_naive_persistence.nompi.cc new file mode 100644 index 0000000000..13d41976dd --- /dev/null +++ b/tests/unit/collection/test_model_naive_persistence.nompi.cc @@ -0,0 +1,131 @@ +/* +//@HEADER +// ***************************************************************************** +// +// test_model_naive_persistence.nompi.cc +// DARMA Toolkit v. 1.0.0 +// DARMA/vt => Virtual Transport +// +// Copyright 2019 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 + +#include + +#include "test_harness.h" + +#include + +namespace vt { namespace tests { namespace unit { + +using TestModelNaivePersistence = TestHarness; + +using vt::vrt::collection::balance::ElementIDType; +using vt::vrt::collection::balance::LoadModel; +using vt::vrt::collection::balance::NaivePersistence; +using vt::vrt::collection::balance::PhaseOffset; +using vt::vrt::collection::balance::LoadMapType; +using vt::vrt::collection::balance::SubphaseLoadMapType; +using vt::vrt::collection::balance::CommMapType; +using vt::vrt::collection::balance::ObjectIterator; + +static int32_t getIndexFromPhase(int32_t phase) { + return std::max(0, -1 * phase - 1); +} + +struct StubModel : LoadModel { + + StubModel() = default; + virtual ~StubModel() = default; + + void setLoads( + std::vector const* proc_load, + std::vector const*, + std::vector const*) override { + proc_load_ = proc_load; + } + + void updateLoads(PhaseType) override {} + + TimeType getWork(ElementIDType id, PhaseOffset phase) override { + EXPECT_LE(phase.phases, -1); + return proc_load_->at(getIndexFromPhase(phase.phases)).at(id); + } + + virtual ObjectIterator begin() override { + return ObjectIterator(proc_load_->back().begin()); + } + virtual ObjectIterator end() override { + return ObjectIterator(proc_load_->back().end()); + } + + // Not used in this test + virtual int getNumObjects() override { return 1; } + virtual int getNumCompletedPhases() override { return 1; } + virtual int getNumSubphases() override { return 1; } + +private: + std::vector const* proc_load_ = nullptr; +}; + +TEST_F(TestModelNaivePersistence, test_model_naive_persistence_1) { + std::vector proc_loads = { + LoadMapType{ + {ElementIDType{1}, TimeType{10}}, {ElementIDType{2}, TimeType{40}}}, + LoadMapType{ + {ElementIDType{1}, TimeType{4}}, {ElementIDType{2}, TimeType{10}}}, + LoadMapType{ + {ElementIDType{1}, TimeType{20}}, {ElementIDType{2}, TimeType{50}}}, + LoadMapType{ + {ElementIDType{1}, TimeType{40}}, {ElementIDType{2}, TimeType{100}}}}; + + auto test_model = + std::make_shared(std::make_shared()); + + test_model->setLoads(&proc_loads, nullptr, nullptr); + + for (auto&& obj : *test_model) { + for (auto phase : {0, -1, -2, -3, -4}) { + auto work_val = test_model->getWork(obj, PhaseOffset{phase, 1}); + EXPECT_EQ(work_val, proc_loads.at(getIndexFromPhase(phase)).at(obj)); + } + } +} + +}}} // end namespace vt::tests::unit 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 new file mode 100644 index 0000000000..32479f93e4 --- /dev/null +++ b/tests/unit/collection/test_model_persistence_median_last_n.nompi.cc @@ -0,0 +1,156 @@ +/* +//@HEADER +// ***************************************************************************** +// +// test_model_persistence_median_last_n.nompi +// DARMA Toolkit v. 1.0.0 +// DARMA/vt => Virtual Transport +// +// Copyright 2019 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 + +#include + +#include "test_harness.h" + +#include + +namespace vt { namespace tests { namespace unit { + +using TestModelPersistenceMedianLastN = TestHarness; + +static int32_t num_phases = 0; + +using vt::vrt::collection::balance::ElementIDType; +using vt::vrt::collection::balance::LoadModel; +using vt::vrt::collection::balance::PersistenceMedianLastN; +using vt::vrt::collection::balance::PhaseOffset; +using vt::vrt::collection::balance::LoadMapType; +using vt::vrt::collection::balance::SubphaseLoadMapType; +using vt::vrt::collection::balance::CommMapType; +using vt::vrt::collection::balance::ObjectIterator; + +struct StubModel : LoadModel { + + StubModel() = default; + virtual ~StubModel() = default; + + void setLoads( + std::vector const* proc_load, + std::vector const*, + std::vector const*) override { + proc_load_ = proc_load; + } + + void updateLoads(PhaseType) override {} + + TimeType getWork(ElementIDType id, PhaseOffset phase) override { + // Most recent phase will be at the end of vector + return proc_load_->at(num_phases + phase.phases).at(id); + } + + virtual ObjectIterator begin() override { + return ObjectIterator(proc_load_->back().cbegin()); + } + virtual ObjectIterator end() override { + return ObjectIterator(proc_load_->back().cend()); + } + + virtual int getNumObjects() override { return 2; } + virtual int getNumCompletedPhases() override { return num_phases; } + virtual int getNumSubphases() override { return 1; } + +private: + std::vector const* proc_load_ = nullptr; +}; + +TEST_F(TestModelPersistenceMedianLastN, test_model_persistence_median_last_n_1) { + constexpr int32_t num_total_phases = 7; + + auto test_model = + std::make_shared(std::make_shared(), 4); + + std::vector proc_loads; + + test_model->setLoads(&proc_loads, nullptr, nullptr); + + // Work loads to be added in each test iteration + std::vector load_holder{ + LoadMapType{ + {ElementIDType{1}, TimeType{10}}, {ElementIDType{2}, TimeType{40}}}, + LoadMapType{ + {ElementIDType{1}, TimeType{4}}, {ElementIDType{2}, TimeType{10}}}, + LoadMapType{ + {ElementIDType{1}, TimeType{20}}, {ElementIDType{2}, TimeType{100}}}, + LoadMapType{ + {ElementIDType{1}, TimeType{50}}, {ElementIDType{2}, TimeType{40}}}, + LoadMapType{ + {ElementIDType{1}, TimeType{2}}, {ElementIDType{2}, TimeType{50}}}, + LoadMapType{ + {ElementIDType{1}, TimeType{60}}, {ElementIDType{2}, TimeType{20}}}, + LoadMapType{ + {ElementIDType{1}, TimeType{100}}, {ElementIDType{2}, TimeType{10}}}, + }; + + std::array, num_total_phases> expected_medians{ + std::make_pair(TimeType{10}, TimeType{40}), // iter 0 results + std::make_pair(TimeType{7}, TimeType{25}), // iter 1 results + std::make_pair(TimeType{10}, TimeType{40}), // iter 2 results + std::make_pair(TimeType{15}, TimeType{40}), // iter 3 results + std::make_pair(TimeType{12}, TimeType{45}), // iter 4 results + std::make_pair(TimeType{35}, TimeType{45}), // iter 5 results + std::make_pair(TimeType{55}, TimeType{30}) // iter 6 results + }; + + for (auto iter = 0; iter < num_total_phases; ++iter) { + proc_loads.push_back(load_holder[iter]); + ++num_phases; + + for (auto&& obj : *test_model) { + auto work_val = test_model->getWork(obj, PhaseOffset{}); + EXPECT_EQ( + work_val, + obj == 1 ? expected_medians[iter].first : expected_medians[iter].second) + << fmt::format("Test failed on iteration {}", iter); + } + } +} + +}}} // end namespace vt::tests::unit