From 36751cb4c308aac27e1368738b42b9dc8f32cfff Mon Sep 17 00:00:00 2001 From: Caleb Schilly Date: Tue, 16 Apr 2024 10:47:43 -0400 Subject: [PATCH] #16: use QOIVariantTypes as qoi getters; convert to double before rendering --- src/vt-tv/api/info.h | 155 ++++++++++++------ src/vt-tv/api/types.h | 3 +- src/vt-tv/utility/qoi_serializer.h | 6 +- tests/unit/lb_test_data/reader_test_data.json | 6 +- tests/unit/test_json_reader.cc | 6 + 5 files changed, 122 insertions(+), 54 deletions(-) diff --git a/src/vt-tv/api/info.h b/src/vt-tv/api/info.h index fc996fedd5..c18e10b438 100644 --- a/src/vt-tv/api/info.h +++ b/src/vt-tv/api/info.h @@ -149,45 +149,66 @@ struct Info { /* ----------------------------------- Getters ----------------------------------- */ + /** + * \brief Converts a QOI from QOIVariantTypes to double + */ + double convertQOIVariantTypeToDouble_(QOIVariantTypes variant) const { + if (std::holds_alternative(variant)) { + return static_cast(std::get(variant)); + } else if (std::holds_alternative(variant)) { + return static_cast(std::get(variant)); + } else if (std::holds_alternative(variant)) { + return std::get(variant); + } else if (std::holds_alternative(variant)) { + throw std::runtime_error("QOI type must be numerical (received std::string)."); + } else { + throw std::runtime_error("Invalid QOI type received (must be numerical)."); + } + } + + /** * \brief Returns a getter to a specified rank QOI */ - std::function getRankQOIGetter(std::string rank_qoi) const { - std::function qoi_getter; + std::function getRankQOIGetter(std::string rank_qoi) const { + std::function qoi_getter; if (rank_qoi == "load") { qoi_getter = [&](Rank rank, PhaseType phase) { - return getRankLoad(rank, phase); + return convertQOIVariantTypeToDouble_(getRankLoad(rank, phase)); }; } else if (rank_qoi == "received_volume") { qoi_getter = [&](Rank rank, PhaseType phase) { - return getRankReceivedVolume(rank, phase); + return convertQOIVariantTypeToDouble_(getRankReceivedVolume(rank, phase)); }; } else if (rank_qoi == "sent_volume") { qoi_getter = [&](Rank rank, PhaseType phase) { - return getRankSentVolume(rank, phase); + return convertQOIVariantTypeToDouble_(getRankSentVolume(rank, phase)); }; } else if (rank_qoi == "number_of_objects") { qoi_getter = [&](Rank rank, PhaseType phase) { - return getRankNumObjects(rank, phase); + return convertQOIVariantTypeToDouble_(getRankNumObjects(rank, phase)); }; } else if (rank_qoi == "number_of_migratable_objects") { qoi_getter = [&](Rank rank, PhaseType phase) { - return getRankNumMigratableObjects(rank, phase); + return convertQOIVariantTypeToDouble_(getRankNumMigratableObjects(rank, phase)); }; } else if (rank_qoi == "migratable_load") { qoi_getter = [&](Rank rank, PhaseType phase) { - return getRankMigratableLoad(rank, phase); + return convertQOIVariantTypeToDouble_(getRankMigratableLoad(rank, phase)); }; } else if (rank_qoi == "sentinel_load") { qoi_getter = [&](Rank rank, PhaseType phase) { - return getRankSentinelLoad(rank, phase); + return convertQOIVariantTypeToDouble_(getRankSentinelLoad(rank, phase)); }; } else if (rank_qoi == "id") { qoi_getter = [&](Rank rank, PhaseType phase) { - return getRankID(rank, phase); + return convertQOIVariantTypeToDouble_(getRankID(rank, phase)); }; } else { - throw std::runtime_error("Invalid Rank QOI: " + rank_qoi); + // Look in attributes (will throw an error if QOI doesn't exist) + qoi_getter = [&](Rank rank, PhaseType phase) { + return convertQOIVariantTypeToDouble_(getRankAttribute(rank, rank_qoi, phase)); + }; } return qoi_getter; } @@ -195,30 +216,33 @@ struct Info { /** * \brief Returns a getter to a specified object QOI */ - std::function getObjectQoiGetter(std::string object_qoi) const { - std::function qoi_getter; + std::function getObjectQoiGetter(std::string object_qoi) const { + std::function qoi_getter; if (object_qoi == "load") { qoi_getter = [&](ObjectWork obj) { - return getObjectLoad(obj); + return convertQOIVariantTypeToDouble_(getObjectLoad(obj)); }; } else if (object_qoi == "received_volume") { qoi_getter = [&](ObjectWork obj) { - return getObjectReceivedVolume(obj); + return convertQOIVariantTypeToDouble_(getObjectReceivedVolume(obj)); }; } else if (object_qoi == "sent_volume") { qoi_getter = [&](ObjectWork obj) { - return getObjectSentVolume(obj); + return convertQOIVariantTypeToDouble_(getObjectSentVolume(obj)); }; } else if (object_qoi == "max_volume") { qoi_getter = [&](ObjectWork obj) { - return getObjectMaxVolume(obj); + return convertQOIVariantTypeToDouble_(getObjectMaxVolume(obj)); }; } else if (object_qoi == "id") { qoi_getter = [&](ObjectWork obj) { - return getObjectID(obj); + return convertQOIVariantTypeToDouble_(getObjectID(obj)); }; } else { - throw std::runtime_error("Invalid Object QOI: " + object_qoi); + // Look in attributes (will throw an error if QOI doesn't exist) + qoi_getter = [&](ObjectWork obj) { + return convertQOIVariantTypeToDouble_(getObjectAttribute(obj, object_qoi)); + }; } return qoi_getter; } @@ -230,7 +254,7 @@ struct Info { * * \return a map of QOI per rank */ - QoiType getRankQOIAtPhase(ElementIDType rank_id, PhaseType phase, std::string rank_qoi) const { + double getRankQOIAtPhase(ElementIDType rank_id, PhaseType phase, std::string rank_qoi) const { auto qoi_getter = getRankQOIGetter(rank_qoi); auto const& rank = this->ranks_.at(rank_id); return qoi_getter(rank, phase); @@ -241,8 +265,8 @@ struct Info { * * \return a map of QOI per rank */ - std::unordered_map getAllQOIAtRank(ElementIDType rank_id, std::string rank_qoi) const { - std::unordered_map rank_qois; + std::unordered_map getAllQOIAtRank(ElementIDType rank_id, std::string rank_qoi) const { + std::unordered_map rank_qois; auto qoi_getter = getRankQOIGetter(rank_qoi); auto const& rank = this->ranks_.at(rank_id); auto const& phase_work = rank.getPhaseWork(); @@ -258,8 +282,8 @@ struct Info { * * \return a map of QOI per rank */ - std::unordered_map getAllRankQOIAtPhase(PhaseType phase, std::string rank_qoi) const { - std::unordered_map rank_qois; + std::unordered_map getAllRankQOIAtPhase(PhaseType phase, std::string rank_qoi) const { + std::unordered_map rank_qois; auto qoi_getter = getRankQOIGetter(rank_qoi); for (auto const& [rank_id, rank] : this->ranks_) { rank_qois.insert(std::make_pair(rank_id, qoi_getter(rank, phase))); @@ -275,7 +299,7 @@ struct Info { * * \return the object QOI */ - QoiType getObjectQoi(ElementIDType obj_id, PhaseType phase, std::string obj_qoi) const { + double getObjectQoi(ElementIDType obj_id, PhaseType phase, std::string obj_qoi) const { auto qoi_getter = getObjectQoiGetter(obj_qoi); auto const& objects = this->getPhaseObjects(phase); auto const& obj = objects.at(obj_id); @@ -601,7 +625,7 @@ struct Info { * * \return the id */ - QoiType getObjectID(ObjectWork object) const { + QOIVariantTypes getObjectID(ObjectWork object) const { return object.getID(); } @@ -612,7 +636,7 @@ struct Info { * * \return the load */ - QoiType getObjectLoad(ObjectWork object) const { + QOIVariantTypes getObjectLoad(ObjectWork object) const { return object.getLoad(); } @@ -623,9 +647,9 @@ struct Info { * * \return the received volume */ - QoiType getObjectReceivedVolume(ObjectWork object) const { - return object.getReceivedVolume(); - } + QOIVariantTypes getObjectReceivedVolume(ObjectWork object) const { + return object.getReceivedVolume(); + } /** * \brief Get the sent volume of an object at a given phase @@ -634,9 +658,9 @@ struct Info { * * \return the sent volume */ - QoiType getObjectSentVolume(ObjectWork object) const { - return object.getSentVolume(); - } + QOIVariantTypes getObjectSentVolume(ObjectWork object) const { + return object.getSentVolume(); + } /** * \brief Get the max volume of an object at a given phase @@ -645,9 +669,25 @@ struct Info { * * \return the max volume */ - QoiType getObjectMaxVolume(ObjectWork object) const { - return object.getMaxVolume(); + QOIVariantTypes getObjectMaxVolume(ObjectWork object) const { + return object.getMaxVolume(); + } + + /** + * \brief Get the specified attribute of an object at a given phase + * + * \param[in] object the current object + * + * \return the requested attribute + */ + QOIVariantTypes getObjectAttribute(ObjectWork object, std::string object_qoi) const { + auto obj_attributes = object.getAttributes(); + if (obj_attributes.count(object_qoi) > 0) { + return obj_attributes.at(object_qoi); + } else { + throw std::runtime_error("Invalid Object QOI: " + object_qoi); } + } /* ---------------------------------------------------------- */ @@ -661,7 +701,7 @@ struct Info { * * \return the rank id */ - QoiType getRankID(Rank rank, PhaseType phase) const { return rank.getRankID(); } + QOIVariantTypes getRankID(Rank rank, PhaseType phase) const { return rank.getRankID(); } /** * \brief Get load of a given rank @@ -671,7 +711,7 @@ struct Info { * * \return the rank load */ - QoiType getRankLoad(Rank rank, PhaseType phase) const { return rank.getLoad(phase); } + QOIVariantTypes getRankLoad(Rank rank, PhaseType phase) const { return rank.getLoad(phase); } /** * \brief Get the received volume of a rank at a given phase @@ -681,9 +721,9 @@ struct Info { * * \return the received volume */ - QoiType getRankReceivedVolume(Rank rank, PhaseType phase) const { + QOIVariantTypes getRankReceivedVolume(Rank rank, PhaseType phase) const { - QoiType received_volume = 0.; + auto received_volume = 0.; auto const& phase_objects = rank.getPhaseWork().at(phase).getObjectWork(); for (auto const& [obj_id, obj_work] : phase_objects) { received_volume += obj_work.getReceivedVolume(); @@ -699,8 +739,8 @@ struct Info { * * \return the sent volume */ - QoiType getRankSentVolume(Rank rank, PhaseType phase) const { - QoiType sent_volume = 0.; + QOIVariantTypes getRankSentVolume(Rank rank, PhaseType phase) const { + auto sent_volume = 0.; auto const& phase_objects = rank.getPhaseWork().at(phase).getObjectWork(); for (auto const& [obj_id, obj_work] : phase_objects) { sent_volume += obj_work.getSentVolume(); @@ -716,8 +756,8 @@ struct Info { * * \return the number of objects */ - QoiType getRankNumObjects(Rank rank, PhaseType phase) const { - QoiType num_objects = rank.getNumObjects(phase); + QOIVariantTypes getRankNumObjects(Rank rank, PhaseType phase) const { + auto num_objects = rank.getNumObjects(phase); return num_objects; } @@ -729,8 +769,8 @@ struct Info { * * \return the number of migratable objects */ - QoiType getRankNumMigratableObjects(Rank rank, PhaseType phase) const { - QoiType num_migratable_objects = 0; + QOIVariantTypes getRankNumMigratableObjects(Rank rank, PhaseType phase) const { + auto num_migratable_objects = 0; auto const& phase_objects = rank.getPhaseWork().at(phase).getObjectWork(); for (auto const& [obj_id, _] : phase_objects) { if (object_info_.at(obj_id).isMigratable()) { @@ -748,8 +788,8 @@ struct Info { * * \return the total load of migratable objects */ - QoiType getRankMigratableLoad(Rank rank, PhaseType phase) const { - QoiType migratable_load = 0.; + QOIVariantTypes getRankMigratableLoad(Rank rank, PhaseType phase) const { + auto migratable_load = 0.; auto const& phase_objects = rank.getPhaseWork().at(phase).getObjectWork(); for (auto const& [obj_id, obj_work] : phase_objects) { if (object_info_.at(obj_id).isMigratable()) { @@ -767,8 +807,8 @@ struct Info { * * \return the total load of sentinel objects */ - QoiType getRankSentinelLoad(Rank rank, PhaseType phase) const { - QoiType sentinel_load = 0.; + QOIVariantTypes getRankSentinelLoad(Rank rank, PhaseType phase) const { + auto sentinel_load = 0.; auto const& phase_objects = rank.getPhaseWork().at(phase).getObjectWork(); for (auto const& [obj_id, obj_work] : phase_objects) { if (object_info_.at(obj_id).isSentinel()) { @@ -778,6 +818,23 @@ struct Info { return sentinel_load; } + /** + * \brief Get the specified attribute of a rank at a given phase + * + * \param[in] rank the current rank + * \param[in] rank_qoi the attribute + * + * \return the requested attribute + */ + QOIVariantTypes getRankAttribute(Rank rank, std::string rank_qoi, PhaseType phase) const { + auto rank_attributes = rank.getAttributes(); + if (rank_attributes.count(rank_qoi) > 0) { + return rank_attributes.at(rank_qoi); + } else { + throw std::runtime_error("Invalid Rank QOI: " + rank_qoi); + } + } + /* ---------------------------------------------------------- */ /** diff --git a/src/vt-tv/api/types.h b/src/vt-tv/api/types.h index ee234c2108..3116cf0a30 100644 --- a/src/vt-tv/api/types.h +++ b/src/vt-tv/api/types.h @@ -57,10 +57,9 @@ using SubphaseType = uint16_t; using UniqueIndexBitType = uint64_t; using TimeType = double; using CollectionObjGroupIDType = uint64_t; -using QoiType = double; // temporary /// Possible QOIs types -using QOIVariantTypes = std::variant; +using QOIVariantTypes = std::variant; } /* end namespace vt::tv */ diff --git a/src/vt-tv/utility/qoi_serializer.h b/src/vt-tv/utility/qoi_serializer.h index c0167e318e..53de4f84ae 100644 --- a/src/vt-tv/utility/qoi_serializer.h +++ b/src/vt-tv/utility/qoi_serializer.h @@ -54,11 +54,13 @@ namespace nlohmann template <> struct adl_serializer<::vt::tv::QOIVariantTypes> { using VariantTypes = ::vt::tv::QOIVariantTypes; + using ElementIDType = ::vt::tv::ElementIDType; // Produce compilation error if variant types were modified static_assert(std::is_same_v>); static_assert(std::is_same_v>); static_assert(std::is_same_v>); + static_assert(std::is_same_v>); static void to_json(json &j, const VariantTypes &value) { std::visit([&](auto const &arg) @@ -67,7 +69,9 @@ namespace nlohmann } static void from_json(const json &j, VariantTypes &value) { - if (j.is_number_integer()) { + if (j.is_number_unsigned()) { + value = j.get(); + } else if (j.is_number_integer()) { value = j.get(); } else if (j.is_number_float()) { value = j.get(); diff --git a/tests/unit/lb_test_data/reader_test_data.json b/tests/unit/lb_test_data/reader_test_data.json index 0772e444cb..f7c887c61b 100644 --- a/tests/unit/lb_test_data/reader_test_data.json +++ b/tests/unit/lb_test_data/reader_test_data.json @@ -11,7 +11,8 @@ "attributes": { "intSample": 1, "doubleSample": 2.213, - "stringSample": "abc" + "stringSample": "abc", + "elementIDSample": 30000000000 } }, "phases": [ @@ -71,7 +72,8 @@ "attributes": { "intSample": -100, "doubleSample": 0.0, - "stringSample": "" + "stringSample": "", + "elementIDSample": 50000000000 } } ], diff --git a/tests/unit/test_json_reader.cc b/tests/unit/test_json_reader.cc index 78c3d6b39e..aa62d38ed0 100644 --- a/tests/unit/test_json_reader.cc +++ b/tests/unit/test_json_reader.cc @@ -138,6 +138,9 @@ TEST_F(TestJSONReader, test_json_reader_metadata_attributes) { EXPECT_TRUE(rank_attributes.find("stringSample") != rank_attributes.end()); EXPECT_EQ("abc", std::get(rank_attributes.at("stringSample"))); + + EXPECT_TRUE(rank_attributes.find("elementIDSample") != rank_attributes.end()); + EXPECT_EQ(30000000000, std::get(rank_attributes.at("elementIDSample"))); } TEST_F(TestJSONReader, test_json_reader_object_info_attributes) { @@ -164,6 +167,9 @@ TEST_F(TestJSONReader, test_json_reader_object_info_attributes) { EXPECT_TRUE(object_attributes.find("stringSample") != object_attributes.end()); EXPECT_EQ("", std::get(object_attributes.at("stringSample"))); + + EXPECT_TRUE(object_attributes.find("elementIDSample") != object_attributes.end()); + EXPECT_EQ(50000000000, std::get(object_attributes.at("elementIDSample"))); } TEST_F(TestJSONReader, test_json_reader_qoi_serializer) {