diff --git a/data/ccm_example_phase_1/data.0.json b/data/ccm_example_phase_1/data.0.json new file mode 100644 index 000000000..90a88d419 --- /dev/null +++ b/data/ccm_example_phase_1/data.0.json @@ -0,0 +1 @@ +{"metadata":{"type":"LBDatafile","rank":0},"phases":[{"id":1,"tasks":[{"entity":{"home":0,"id":0,"migratable":true,"type":"object"},"node":0,"resource":"cpu","time":2.0,"user_defined":{"shared_id":0,"shared_bytes":10000.0,"home_rank":0}},{"entity":{"home":0,"id":1,"migratable":true,"type":"object"},"node":0,"resource":"cpu","time":3.5,"user_defined":{"shared_id":0,"shared_bytes":10000.0,"home_rank":0}}],"communications":[{"type":"SendRecv","to":{"type":"object","id":2},"messages":1,"from":{"type":"object","id":0},"bytes":10000.0},{"type":"SendRecv","to":{"type":"object","id":2},"messages":1,"from":{"type":"object","id":1},"bytes":15000.0},{"type":"SendRecv","to":{"type":"object","id":1},"messages":1,"from":{"type":"object","id":0},"bytes":25000.0}]}]} diff --git a/data/ccm_example_phase_1/data.1.json b/data/ccm_example_phase_1/data.1.json new file mode 100644 index 000000000..b2a1d1009 --- /dev/null +++ b/data/ccm_example_phase_1/data.1.json @@ -0,0 +1 @@ +{"metadata":{"type":"LBDatafile","rank":1},"phases":[{"id":1,"tasks":[{"entity":{"home":1,"id":2,"migratable":true,"type":"object"},"node":1,"resource":"cpu","time":5.0,"user_defined":{"shared_id":1,"shared_bytes":15000.0,"home_rank":1}}],"communications":[{"type":"SendRecv","to":{"type":"object","id":1},"messages":1,"from":{"type":"object","id":2},"bytes":20000.0}]}]} diff --git a/src/vt-tv/api/info.h b/src/vt-tv/api/info.h index 45bf79f08..65edb511f 100644 --- a/src/vt-tv/api/info.h +++ b/src/vt-tv/api/info.h @@ -68,9 +68,11 @@ namespace vt::tv { struct Info { Info( std::unordered_map in_object_info, - std::unordered_map in_ranks) - : object_info_(std::move(in_object_info)), - ranks_(std::move(in_ranks)) { } + std::unordered_map in_ranks + ) : object_info_(std::move(in_object_info)), + ranks_(std::move(in_ranks)), + min_phase_(getMinPhase()) + { } Info() = default; @@ -88,6 +90,10 @@ struct Info { assert(ranks_.find(r.getRankID()) == ranks_.end() && "Rank must not exist"); ranks_.try_emplace(r.getRankID(), std::move(r)); + + if (min_phase_ == std::numeric_limits::max()) { + min_phase_ = getMinPhase(); + } } void setSelectedPhase(PhaseType selected_phase) { @@ -455,6 +461,31 @@ struct Info { return objects; } + /** + * \brief Get the minimum phase in the data + * + * \return the minimim phase in the data + */ + PhaseType getMinPhase() const { + if (min_phase_ != std::numeric_limits::max()) { + return min_phase_; + } + // Otherwise, we have to calculate it + + // Get the rank info for any rank (all ranks should have the same phases) + auto const& rank_info = ranks_.begin()->second; + + // Get the phase work map + auto const& pw = rank_info.getPhaseWork(); + + std::set keys; + for (auto& [key, _] : pw) { + keys.insert(key); + } + + return keys.size() > 0 ? *keys.begin() : 0; + } + /** * \brief Get all objects in all ranks for a given phase and LB iteration * @@ -526,7 +557,7 @@ struct Info { } } } else { - for (PhaseType phase = 0; phase < n_phases; phase++) { + for (PhaseType phase = getMinPhase(); phase < getMinPhase() + n_phases; phase++) { auto const& objects = getPhaseObjects(phase, no_lb_iter); for (auto const& [obj_id, obj_work] : objects) { auto obj_max_v = obj_work.getMaxVolume(); @@ -576,7 +607,7 @@ struct Info { } } } else { - for (PhaseType phase = 0; phase < n_phases; phase++) { + for (PhaseType phase = getMinPhase(); phase < getMinPhase() + n_phases; phase++) { auto const& objects = getPhaseObjects(phase, no_lb_iter); for (auto const& [obj_id, obj_work] : objects) { auto obj_load = obj_work.getLoad(); @@ -623,14 +654,16 @@ struct Info { auto& phase_history = rank_info.getPhaseWork(); // Get phase work at specified phase - auto phase_work = phase_history.find(phase); + if (auto phase_work = phase_history.find(phase); + phase_work != phase_history.end()) { - // Get all objects at specified phase - auto& object_work_at_phase = phase_work->second.getObjectWork(); + // Get all objects at specified phase + auto& object_work_at_phase = phase_work->second.getObjectWork(); - for (auto const& [elm_id, obj_work] : object_work_at_phase) { - // fmt::print(" Object Id: {}\n", elm_id); - objects_at_phase.insert(std::make_pair(elm_id, obj_work)); + for (auto const& [elm_id, obj_work] : object_work_at_phase) { + // fmt::print(" Object Id: {}\n", elm_id); + objects_at_phase.insert(std::make_pair(elm_id, obj_work)); + } } } return objects_at_phase; @@ -764,32 +797,34 @@ struct Info { for (auto& [rank_id, rank] : ranks_) { // fmt::print(" Checking objects in rank {}.\n", rank_id); auto& phaseWork = rank.getPhaseWork(); - auto& phaseWorkAtPhase = phaseWork.at(phase); - auto& objects = phaseWorkAtPhase.getObjectWork(); - for (auto& [obj_id, obj_work] : objects) { - // fmt::print(" Checking if object {} needs to be updated.\n", obj_id); - // fmt::print(" Communications to update:\n"); - uint64_t i = 0; - for (auto& [object_to_update, sender_id, recipient_id, bytes] : - communications_to_add) { - // fmt::print(" {} needs to be updated in {} -> {} communication of {} bytes.\n", object_to_update, - // sender_id, recipient_id, bytes); - if (object_to_update == "sender" && sender_id == obj_id) { - // fmt::print(" Sender to be updated is object on this rank. Updating.\n"); - rank.addObjectSentCommunicationAtPhase( - phase, obj_id, recipient_id, bytes); - communications_to_add.erase(communications_to_add.begin() + i); - } else if ( - object_to_update == "recipient" && recipient_id == obj_id) { - // fmt::print(" Recipient to be updated is object on this rank. Updating.\n"); - rank.addObjectReceivedCommunicationAtPhase( - phase, obj_id, sender_id, bytes); - communications_to_add.erase(communications_to_add.begin() + i); + if (phaseWork.find(phase) != phaseWork.end()) { + auto& phaseWorkAtPhase = phaseWork.at(phase); + auto& objects = phaseWorkAtPhase.getObjectWork(); + for (auto& [obj_id, obj_work] : objects) { + // fmt::print(" Checking if object {} needs to be updated.\n", obj_id); + // fmt::print(" Communications to update:\n"); + uint64_t i = 0; + for (auto& [object_to_update, sender_id, recipient_id, bytes] : + communications_to_add) { + // fmt::print(" {} needs to be updated in {} -> {} communication of {} bytes.\n", object_to_update, + // sender_id, recipient_id, bytes); + if (object_to_update == "sender" && sender_id == obj_id) { + // fmt::print(" Sender to be updated is object on this rank. Updating.\n"); + rank.addObjectSentCommunicationAtPhase( + phase, obj_id, recipient_id, bytes); + communications_to_add.erase(communications_to_add.begin() + i); + } else if ( + object_to_update == "recipient" && recipient_id == obj_id) { + // fmt::print(" Recipient to be updated is object on this rank. Updating.\n"); + rank.addObjectReceivedCommunicationAtPhase( + phase, obj_id, sender_id, bytes); + communications_to_add.erase(communications_to_add.begin() + i); + } + if (communications_to_add.empty()) { + return; + } + i++; } - if (communications_to_add.empty()) { - return; - } - i++; } } } @@ -960,7 +995,7 @@ struct Info { bool hasRankUserDefined(std::string const& key) const { for (auto const& [id, rank] : ranks_) { auto const num_phases = rank.getNumPhases(); - for (std::size_t i = 0; i < num_phases; i++) { + for (std::size_t i = getMinPhase(); i < getMinPhase()+num_phases; i++) { auto const& ud = rank.getPhaseWork().at(i).getUserDefined(); if (auto iter = ud.find(key); iter != ud.end()) { return true; @@ -987,7 +1022,7 @@ struct Info { QOIVariantTypes getFirstRankUserDefined(std::string const& key) const { for (auto const& [id, rank] : ranks_) { auto const num_phases = rank.getNumPhases(); - for (std::size_t i = 0; i < num_phases; i++) { + for (std::size_t i = getMinPhase(); i < getMinPhase()+num_phases; i++) { auto const& ud = rank.getPhaseWork().at(i).getUserDefined(); if (auto iter = ud.find(key); iter != ud.end()) { return iter->second; @@ -1215,6 +1250,9 @@ struct Info { /// The current phase (or indication to use all phases) PhaseType selected_phase_ = std::numeric_limits::max(); + + /// The min phase found in the data (could start at non-zero) + PhaseType min_phase_ = std::numeric_limits::max(); }; } /* end namespace vt::tv */ diff --git a/src/vt-tv/render/render.cc b/src/vt-tv/render/render.cc index a242801a4..9d26df6b0 100644 --- a/src/vt-tv/render/render.cc +++ b/src/vt-tv/render/render.cc @@ -88,7 +88,7 @@ Render::Render(Info in_info) if (selected_phase_ != std::numeric_limits::max()) { info_.normalizeEdges(selected_phase_); } else { - for (PhaseType phase = 0; phase < n_phases_; phase++) { + for (PhaseType phase = info_.getMinPhase(); phase < info_.getMinPhase() + n_phases_; phase++) { info_.normalizeEdges(phase); } } @@ -240,7 +240,7 @@ Render::computeObjectQOIRange_() { updateQOIRange(objects2, selected_phase_, lb_iter_id); } } else { - for (PhaseType phase = 0; phase < n_phases_; phase++) { + for (PhaseType phase = info_.getMinPhase(); phase < info_.getMinPhase() + n_phases_; phase++) { auto const& objects = info_.getPhaseObjects(phase, no_lb_iter); updateQOIRange(objects, phase, no_lb_iter); auto const& lb_iters = @@ -1287,7 +1287,7 @@ void Render::generate(uint64_t font_size, uint64_t win_size) { createMeshAndRender(selected_phase_, id, cur_frame); } } else { - for (PhaseType phase = 0; phase < n_phases_; phase++) { + for (PhaseType phase = info_.getMinPhase(); phase < info_.getMinPhase() + n_phases_; phase++) { createMeshAndRender(phase, no_lb_iter, cur_frame); auto const& lb_iters = info_.getRank(0).getPhaseWork().at(phase).getLBIterations(); diff --git a/src/vt-tv/utility/json_reader.cc b/src/vt-tv/utility/json_reader.cc index cd084345a..2e3e7f876 100644 --- a/src/vt-tv/utility/json_reader.cc +++ b/src/vt-tv/utility/json_reader.cc @@ -134,7 +134,13 @@ std::unique_ptr JSONReader::parsePhaseIter( assert(node.is_number() && "task node must be a number"); if (etype == "object") { - auto object = task["entity"].value("id", task["entity"]["seq_id"]); + nlohmann::json object; + if (task["entity"].find("id") != task["entity"].end()) { + object = task["entity"]["id"]; + } else { + object = task["entity"]["seq_id"]; + } + auto home = task["entity"]["home"]; bool migratable = task["entity"]["migratable"]; diff --git a/tests/config/ccm-example_phase_1.yaml b/tests/config/ccm-example_phase_1.yaml new file mode 100644 index 000000000..cfb882825 --- /dev/null +++ b/tests/config/ccm-example_phase_1.yaml @@ -0,0 +1,18 @@ +input: + directory: data/ccm_example_phase_1 + n_ranks: 2 + +viz: + x_ranks: 2 + y_ranks: 1 + z_ranks: 1 + object_jitter: 0.0 + rank_qoi: load + object_qoi: shared_id + save_meshes: true + save_pngs: true + force_continuous_object_qoi: true + +output: + directory: output/tests + file_stem: ccm_example diff --git a/tests/unit/render/test_render.cc b/tests/unit/render/test_render.cc index bac69d476..0d3dba72b 100644 --- a/tests/unit/render/test_render.cc +++ b/tests/unit/render/test_render.cc @@ -336,7 +336,7 @@ TEST_P(RenderTest, test_render_from_config_with_png) { INSTANTIATE_TEST_SUITE_P( RenderTests, RenderTest, - ::testing::Values("conf.yaml", "ccm-example.yaml"), + ::testing::Values("conf.yaml", "ccm-example.yaml", "ccm-example_phase_1.yaml"), [](const ::testing::TestParamInfo& in_info) { // test suffix as slug auto suffix = std::regex_replace(in_info.param, std::regex("\\.yaml"), "");