From ab9d16714d31e853d000a0757f3487bcb9804023 Mon Sep 17 00:00:00 2001 From: Patrick Mullen <33095288+pdmullen@users.noreply.github.com> Date: Fri, 11 Aug 2023 10:15:38 -0600 Subject: [PATCH 01/36] Update Iterative Tasking Infrastructure (#917) * Add lroberts36/merge-sparse-with-jdolence-sparse's changes to iterative tasking * Update copyrights * Add undordered map include * Update changelog * Fix function name typos in task_list.hpp --------- Co-authored-by: Patrick Mullen Co-authored-by: Patrick Mullen --- CHANGELOG.md | 1 + src/basic_types.hpp | 4 +- src/tasks/task_list.hpp | 191 +++++++++++++++++++++++++++------------- 3 files changed, 134 insertions(+), 62 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d841a9231061..29feeb213f33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ - [[PR 885]](https://github.com/parthenon-hpc-lab/parthenon/pull/885) Expose PackDescriptor and use uids in SparsePacks ### Fixed (not changing behavior/API/variables/...) +- [[PR 917]](https://github.com/parthenon-hpc-lab/parthenon/pull/917) Update Iterative Tasking Infrastructure - [[PR 890]](https://github.com/parthenon-hpc-lab/parthenon/pull/890) Fix bugs in sparse communication and prolongation ### Infrastructure (changes irrelevant to downstream codes) diff --git a/src/basic_types.hpp b/src/basic_types.hpp index ad599373e465..4a5fa41a6f24 100644 --- a/src/basic_types.hpp +++ b/src/basic_types.hpp @@ -1,5 +1,5 @@ //======================================================================================== -// (C) (or copyright) 2021-2022. Triad National Security, LLC. All rights reserved. +// (C) (or copyright) 2021-2023. Triad National Security, LLC. All rights reserved. // // This program was produced under U.S. Government contract 89233218CNA000001 for Los // Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC @@ -36,7 +36,7 @@ using Real = double; #endif #endif -enum class TaskStatus { fail, complete, incomplete, iterate, skip }; +enum class TaskStatus { fail, complete, incomplete, iterate, skip, waiting }; enum class AmrTag : int { derefine = -1, same = 0, refine = 1 }; enum class RefinementOp_t { Prolongation, Restriction, None }; diff --git a/src/tasks/task_list.hpp b/src/tasks/task_list.hpp index 961e2e123f16..322d1a788d70 100644 --- a/src/tasks/task_list.hpp +++ b/src/tasks/task_list.hpp @@ -1,5 +1,5 @@ //======================================================================================== -// (C) (or copyright) 2021. Triad National Security, LLC. All rights reserved. +// (C) (or copyright) 2023. Triad National Security, LLC. All rights reserved. // // This program was produced under U.S. Government contract 89233218CNA000001 for Los // Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -44,17 +45,18 @@ TaskID AddTaskHelper(TaskList *, Task); class IterativeTasks { public: + IterativeTasks() = default; IterativeTasks(TaskList *tl, int key) : tl_(tl), key_(key) { max_iterations_ = std::numeric_limits::max(); } // overload to add member functions of class T to task list // NOTE: we must capture the object pointer - template - TaskID AddTask(TaskID const &dep, TaskStatus (T::*func)(Args...), U *obj, - Args &&...args) { + template + TaskID AddTask(TaskID const &dep, TaskStatus (T::*func)(Args1...), U *obj, + Args2 &&...args) { return this->AddTask_(TaskType::iterative, 1, dep, [=]() mutable -> TaskStatus { - return (obj->*func)(std::forward(args)...); + return (obj->*func)(std::forward(args)...); }); } @@ -94,6 +96,8 @@ class IterativeTasks { int GetMaxIterations() const { return max_iterations_; } int GetIterationCount() const { return count_; } void IncrementCount() { count_++; } + void ResetCount() { count_ = 0; } + void PrintList() { std::cout << "tl_ = " << tl_ << std::endl; } private: template @@ -139,7 +143,8 @@ class TaskList { for (auto &task : task_list_) { if (task.GetID() == id) { return (task.GetStatus() != TaskStatus::incomplete && - task.GetStatus() != TaskStatus::skip); + task.GetStatus() != TaskStatus::skip && + task.GetStatus() != TaskStatus::waiting); } } return false; @@ -184,6 +189,7 @@ class TaskList { ++task; } } + iter_tasks[key].ResetCount(); } void ResetIteration(const int key) { PARTHENON_REQUIRE_THROWS(key < iter_tasks.size(), "Invalid iteration key"); @@ -197,6 +203,11 @@ class TaskList { PARTHENON_WARN("Iteration " + iter_labels[key] + " reached maximum allowed cycles without convergence."); } + for (auto &task : task_list_) { + if (task.GetKey() == key && task.GetType() == TaskType::completion_criteria) { + MarkTaskComplete(task.GetID()); + } + } ClearIteration(key); return; } @@ -219,36 +230,47 @@ class TaskList { } } } - void CompleteIfNeeded(const TaskID &id) { + bool CompleteIfNeeded(const TaskID &id) { MarkTaskComplete(id); auto task = task_list_.begin(); while (task != task_list_.end()) { if (task->GetID() == id) { if (task->GetType() == TaskType::completion_criteria) { ClearIteration(task->GetKey()); + return true; } else if (task->GetType() == TaskType::single) { - task_list_.erase(task); + task = task_list_.erase(task); + } else { + task->SetStatus(TaskStatus::waiting); } break; } else { ++task; } } + return false; } void DoAvailable() { - for (auto &task : task_list_) { + auto task = task_list_.begin(); + while (task != task_list_.end()) { // first skip task if it's complete. Possible for iterative tasks - if (task.GetStatus() != TaskStatus::incomplete) continue; - auto dep = task.GetDependency(); + if (task->GetStatus() != TaskStatus::incomplete) { + ++task; + continue; + } + auto dep = task->GetDependency(); if (CheckDependencies(dep)) { - task(); - if (task.GetStatus() == TaskStatus::complete && !task.IsRegional()) { - MarkTaskComplete(task.GetID()); - } else if (task.GetStatus() == TaskStatus::skip && - task.GetType() == TaskType::completion_criteria) { - ResetIteration(task.GetKey()); + (*task)(); + if (task->GetStatus() == TaskStatus::complete && !task->IsRegional()) { + MarkTaskComplete(task->GetID()); + } else if (task->GetStatus() == TaskStatus::skip && + task->GetType() == TaskType::completion_criteria) { + ResetIteration(task->GetKey()); + } else if (task->GetStatus() == TaskStatus::iterate && !task->IsRegional()) { + ResetIteration(task->GetKey()); } } + ++task; } ClearComplete(); } @@ -274,21 +296,21 @@ class TaskList { return valid; } - TaskID AddTask(Task tsk) { + TaskID AddTask(Task &tsk) { TaskID id(tasks_added_ + 1); tsk.SetID(id); - task_list_.push_back(tsk); + task_list_.push_back(std::move(tsk)); tasks_added_++; return id; } // overload to add member functions of class T to task list // NOTE: we must capture the object pointer - template - TaskID AddTask(TaskID const &dep, TaskStatus (T::*func)(Args...), U *obj, - Args &&...args) { + template + TaskID AddTask(TaskID const &dep, TaskStatus (T::*func)(Args1...), U *obj, + Args2 &&...args) { return this->AddTask(dep, [=]() mutable -> TaskStatus { - return (obj->*func)(std::forward(args)...); + return (obj->*func)(std::forward(args)...); }); } @@ -305,9 +327,9 @@ class TaskList { IterativeTasks &AddIteration(const std::string &label) { int key = iter_tasks.size(); - iter_tasks.push_back(IterativeTasks(this, key)); - iter_labels.push_back(label); - return iter_tasks.back(); + iter_tasks[key] = IterativeTasks(this, key); + iter_labels[key] = label; + return iter_tasks[key]; } void Print() { @@ -315,8 +337,8 @@ class TaskList { std::cout << "TaskList::Print():" << std::endl; for (auto &t : task_list_) { std::cout << " " << i << " " << t.GetID().to_string() << " " - << t.GetDependency().to_string() << " " - << (t.GetStatus() == TaskStatus::incomplete) + << t.GetDependency().to_string() << " " << tasks_completed_.to_string() + << " " << (t.GetStatus() == TaskStatus::incomplete) << (t.GetStatus() == TaskStatus::complete) << (t.GetStatus() == TaskStatus::skip) << (t.GetStatus() == TaskStatus::iterate) @@ -327,8 +349,8 @@ class TaskList { } protected: - std::vector iter_tasks; - std::vector iter_labels; + std::map iter_tasks; + std::map iter_labels; std::list task_list_; int tasks_added_ = 0; TaskID tasks_completed_; @@ -340,41 +362,92 @@ namespace task_list_impl { inline TaskID AddTaskHelper(TaskList *tl, Task tsk) { return tl->AddTask(tsk); } } // namespace task_list_impl +class RegionCounter { + public: + explicit RegionCounter(const std::string &base) : base_(base), cnt_(0) {} + std::string ID() { return base_ + std::to_string(cnt_++); } + + private: + const std::string base_; + int cnt_; +}; + class TaskRegion { public: explicit TaskRegion(const int size) : lists(size) {} - void AddRegionalDependencies(const int reg_dep_id, const int list_index, TaskID id) { - auto task_pair = std::make_pair(list_index, id); - id_for_reg[reg_dep_id].push_back(task_pair); - lists[list_index].MarkRegional(id); - all_done[reg_dep_id].val = 0; + void AddRegionalDependencies(const int reg_dep_id, const int list_index, + const TaskID &id) { + AddRegionalDependencies(std::to_string(reg_dep_id), list_index, id); + } + void AddRegionalDependencies(const std::string ®_dep_id, const int list_index, + const TaskID &id) { + AddDependencies(reg_dep_id, list_index, id); + global[reg_dep_id] = false; + } + void AddGlobalDependencies(const int reg_dep_id, const int list_index, + const TaskID &id) { + AddGlobalDependencies(std::to_string(reg_dep_id), list_index, id); + } + void AddGlobalDependencies(const std::string ®_dep_id, const int list_index, + const TaskID &id) { + AddDependencies(reg_dep_id, list_index, id); + global[reg_dep_id] = true; } TaskList &operator[](int i) { return lists[i]; } int size() const { return lists.size(); } + bool Execute() { + for (auto i = 0; i < lists.size(); ++i) { + if (!lists[i].IsComplete()) { + lists[i].DoAvailable(); + } + } + return CheckAndUpdate(); + } + bool CheckAndUpdate() { - for (auto ®_dep : id_for_reg) { - auto reg_id = reg_dep.first; + auto it = id_for_reg.begin(); + while (it != id_for_reg.end()) { + auto ®_id = it->first; + bool check = false; if (HasRun(reg_id) && !all_done[reg_id].active) { all_done[reg_id].val = IsComplete(reg_id); - all_done[reg_id].StartReduce(MPI_MIN); + if (global[reg_id]) { + all_done[reg_id].StartReduce(MPI_MIN); + } else { + check = true; + } } - if (all_done[reg_id].active) { + if (global[reg_id] && all_done[reg_id].active) { auto status = all_done[reg_id].CheckReduce(); if (status == TaskStatus::complete) { - if (all_done[reg_id].val) { - for (auto &lst : reg_dep.second) { - lists[lst.first].CompleteIfNeeded(lst.second); - } + check = true; + } + } + if (check) { + if (all_done[reg_id].val) { + bool clear = false; + for (auto &lst : it->second) { + clear = lists[lst.first].CompleteIfNeeded(lst.second); + } + if (clear) { + all_done.erase(reg_id); + global.erase(reg_id); + it = id_for_reg.erase(it); } else { - for (auto &lst : reg_dep.second) { - lists[lst.first].ResetIfNeeded(lst.second); - } - all_done[reg_id].val = 0; + ++it; + } + } else { + for (auto &lst : it->second) { + lists[lst.first].ResetIfNeeded(lst.second); } + all_done[reg_id].val = 0; + ++it; } + } else { + ++it; } } int complete_cnt = 0; @@ -393,7 +466,12 @@ class TaskRegion { } private: - bool HasRun(const int reg_id) { + void AddDependencies(const std::string &label, const int list_id, const TaskID &tid) { + id_for_reg[label][list_id] = tid; + lists[list_id].MarkRegional(tid); + all_done[label].val = 0; + } + bool HasRun(const std::string ®_id) { auto &lvec = id_for_reg[reg_id]; int n_to_run = lvec.size(); int n_ran = 0; @@ -406,7 +484,7 @@ class TaskRegion { } return n_ran == n_to_run; } - bool IsComplete(const int reg_id) { + bool IsComplete(const std::string ®_id) { auto &lvec = id_for_reg[reg_id]; int n_to_finish = lvec.size(); int n_finished = 0; @@ -420,10 +498,10 @@ class TaskRegion { return n_finished == n_to_finish; } - // id_for_reg[region_id] = std::pair<>(task_list_index, task_id_of_regional_task) - std::map>> id_for_reg; + std::unordered_map> id_for_reg; std::vector lists; - std::map> all_done; + std::unordered_map> all_done; + std::unordered_map global; }; class TaskCollection { @@ -437,15 +515,8 @@ class TaskCollection { assert(Validate()); for (auto ®ion : regions) { bool complete = false; - auto num_lists = region.size(); while (!complete) { - // TODO(pgrete): need to let Kokkos::PartitionManager handle this - for (auto i = 0; i < num_lists; ++i) { - if (!region[i].IsComplete()) { - region[i].DoAvailable(); - } - } - complete = region.CheckAndUpdate(); + complete = region.Execute(); } } return TaskListStatus::complete; From fd6d56549ddf7d4322c5fc0b258c01f9e4916c63 Mon Sep 17 00:00:00 2001 From: jdolence Date: Fri, 11 Aug 2023 10:25:57 -0600 Subject: [PATCH 02/36] add the ability to get a list of vars given constraints --- src/interface/data_collection.cpp | 8 +-- src/interface/metadata.cpp | 15 ++++++ src/interface/metadata.hpp | 12 +++++ src/interface/state_descriptor.cpp | 80 ++++++++++++++++++++++++++++++ src/interface/state_descriptor.hpp | 27 +++++++++- tst/unit/test_metadata.cpp | 5 +- tst/unit/test_state_descriptor.cpp | 74 +++++++++++++++++++++++++++ 7 files changed, 213 insertions(+), 8 deletions(-) diff --git a/src/interface/data_collection.cpp b/src/interface/data_collection.cpp index 6a1d72c9ce0b..7d8cb08258ee 100644 --- a/src/interface/data_collection.cpp +++ b/src/interface/data_collection.cpp @@ -24,17 +24,17 @@ namespace parthenon { template std::shared_ptr DataCollection::Add(const std::string &name, const std::shared_ptr &src, - const std::vector &flags) { + const std::vector &field_names) { auto it = containers_.find(name); if (it != containers_.end()) { - if (!(it->second)->Contains(flags)) { - PARTHENON_THROW(name + "already exists in collection but does not contain flags"); + if (!(it->second)->Contains(field_names)) { + PARTHENON_THROW(name + "already exists in collection but does not contain field names"); } return it->second; } auto c = std::make_shared(); - c->Copy(src, flags); + c->Copy(src, field_names); containers_[name] = c; return containers_[name]; diff --git a/src/interface/metadata.cpp b/src/interface/metadata.cpp index ee355c1773ed..38466b2f4ed1 100644 --- a/src/interface/metadata.cpp +++ b/src/interface/metadata.cpp @@ -37,6 +37,8 @@ namespace parthenon { PARTHENON_INTERNAL_FOREACH_BUILTIN_FLAG #undef PARTHENON_INTERNAL_FOR_FLAG +int Metadata::num_flags = static_cast(internal::MetadataInternal::Max); + namespace internal { class UserMetadataState { @@ -85,6 +87,7 @@ class UserMetadataState { parthenon::internal::UserMetadataState metadata_state; MetadataFlag Metadata::AddUserFlag(const std::string &name) { + num_flags++; return metadata_state.AllocateNewFlag(name); } @@ -256,4 +259,16 @@ Metadata::GetArrayDims(std::weak_ptr wpmb, bool coarse) const { return arrDims; } +namespace MetadataUtils { +bool MatchFlags(const Metadata::FlagCollection &flags, Metadata m) { + const auto &intersections = flags.GetIntersections(); + const auto &unions = flags.GetUnions(); + const auto &exclusions = flags.GetExclusions(); + + return m.AllFlagsSet(intersections) && + (unions.empty() || m.AnyFlagsSet(unions)) && + m.NoFlagsSet(exclusions); +} +} // namespace MetadataUtils + } // namespace parthenon diff --git a/src/interface/metadata.hpp b/src/interface/metadata.hpp index fabfc083cbe8..755a0778d237 100644 --- a/src/interface/metadata.hpp +++ b/src/interface/metadata.hpp @@ -331,6 +331,7 @@ class Metadata { static MetadataFlag AddUserFlag(const std::string &name); static bool FlagNameExists(const std::string &flagname); static MetadataFlag GetUserFlag(const std::string &flagname); + static int num_flags; // Sparse threshold routines void SetSparseThresholds(parthenon::Real alloc, parthenon::Real dealloc, @@ -510,6 +511,16 @@ class Metadata { return AllFlagsSet(FlagVec{flag, std::forward(args)...}); } + template