Line data Source code
1 0 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : #pragma once
5 :
6 : #include <map>
7 : #include <pup.h>
8 : #include <tuple>
9 : #include <vector>
10 :
11 : #include "DataStructures/DataBox/Access.hpp"
12 : #include "DataStructures/DataBox/DataBox.hpp"
13 : #include "Domain/Structure/ElementId.hpp"
14 : #include "IO/Observer/ObserverComponent.hpp"
15 : #include "IO/Observer/ReductionActions.hpp"
16 : #include "Options/Auto.hpp"
17 : #include "Options/String.hpp"
18 : #include "Parallel/DistributedObject.hpp"
19 : #include "Parallel/GlobalCache.hpp"
20 : #include "Parallel/Invoke.hpp"
21 : #include "Parallel/Reduction.hpp"
22 : #include "ParallelAlgorithms/EventsAndTriggers/Event.hpp"
23 : #include "Utilities/PrettyType.hpp"
24 : #include "Utilities/TMPL.hpp"
25 :
26 : namespace Events {
27 :
28 : namespace detail {
29 :
30 : struct map_add {
31 : std::map<std::string, size_t> operator()(
32 : std::map<std::string, size_t> map_1,
33 : const std::map<std::string, size_t>& map_2) {
34 : for (const auto& [key, value] : map_2) {
35 : map_1.at(key) += value;
36 : }
37 : return map_1;
38 : }
39 : };
40 :
41 : using ReductionType = Parallel::ReductionData<
42 : // Time
43 : Parallel::ReductionDatum<double, funcl::AssertEqual<>>,
44 : // Map of total mem usage in MB per item in DataBoxes
45 : Parallel::ReductionDatum<std::map<std::string, size_t>, map_add>>;
46 :
47 : template <typename ContributingComponent>
48 : struct ReduceDataBoxSize {
49 : template <typename ParallelComponent, typename DbTags, typename Metavariables,
50 : typename ArrayIndex>
51 : static void apply(db::DataBox<DbTags>& /*box*/,
52 : Parallel::GlobalCache<Metavariables>& cache,
53 : const ArrayIndex& /*array_index*/, const double time,
54 : const std::map<std::string, size_t>& item_sizes) {
55 : auto& observer_writer_proxy = Parallel::get_parallel_component<
56 : observers::ObserverWriter<Metavariables>>(cache);
57 : const std::string subfile_name =
58 : "/DataBoxSizeInMb/" + pretty_type::name<ContributingComponent>();
59 : std::vector<std::string> legend;
60 : legend.reserve(item_sizes.size() + 1);
61 : legend.emplace_back("Time");
62 : std::vector<double> columns;
63 : columns.reserve(item_sizes.size() + 1);
64 : columns.emplace_back(time);
65 : const double scaling = 1.0 / 1048576.0; // so size is in MB
66 : for (const auto& [name, size] : item_sizes) {
67 : legend.emplace_back(name);
68 : columns.emplace_back(scaling * static_cast<double>(size));
69 : }
70 : Parallel::threaded_action<
71 : observers::ThreadedActions::WriteReductionDataRow>(
72 : // Node 0 is always the writer
73 : observer_writer_proxy[0], subfile_name, legend,
74 : std::make_tuple(columns));
75 : }
76 : };
77 :
78 : struct ContributeDataBoxSize {
79 : template <typename ParallelComponent, typename DbTags, typename Metavariables,
80 : typename ArrayIndex>
81 : static void apply(db::DataBox<DbTags>& box,
82 : Parallel::GlobalCache<Metavariables>& cache,
83 : const ArrayIndex& array_index, const double time) {
84 : const auto& my_proxy =
85 : Parallel::get_parallel_component<ParallelComponent>(cache)[array_index];
86 : auto& target_proxy = Parallel::get_parallel_component<
87 : observers::ObserverWriter<Metavariables>>(cache);
88 : const auto item_sizes = box.size_of_items();
89 : if constexpr (Parallel::is_singleton_v<ParallelComponent>) {
90 : Parallel::simple_action<ReduceDataBoxSize<ParallelComponent>>(
91 : target_proxy[0], time, item_sizes);
92 : } else {
93 : Parallel::contribute_to_reduction<ReduceDataBoxSize<ParallelComponent>>(
94 : ReductionType{time, item_sizes}, my_proxy, target_proxy[0]);
95 : }
96 : }
97 : };
98 : } // namespace detail
99 :
100 : /// \brief Event that will collect the size in MBs used by each DataBox item on
101 : /// each parallel component.
102 : ///
103 : /// \details The data will be written to disk in the reductions file under the
104 : /// `/DataBoxSizeInMb/` group. The name of each file is the `pretty_type::name`
105 : /// of each parallel component. There will be a column for each item in the
106 : /// DataBox that is not a subitem or reference item.
107 1 : class ObserveDataBox : public Event {
108 0 : struct DoNotWrite {};
109 :
110 : public:
111 : /// \cond
112 : explicit ObserveDataBox(CkMigrateMessage* m);
113 : using PUP::able::register_constructor;
114 : WRAPPED_PUPable_decl_template(ObserveDataBox); // NOLINT
115 : /// \endcond
116 :
117 0 : struct WriteTagNamesToFile {
118 0 : using type = ::Options::Auto<std::string, DoNotWrite>;
119 0 : static constexpr Options::String help = {
120 : "The text file to write the names of the DataBox tags to."};
121 : };
122 :
123 0 : using options = tmpl::list<WriteTagNamesToFile>;
124 0 : static constexpr Options::String help = {
125 : "Observe size (in MB) of each item (except reference items) in each "
126 : "DataBox"};
127 :
128 0 : ObserveDataBox() = default;
129 0 : explicit ObserveDataBox(std::optional<std::string> file_name_for_tag_names);
130 :
131 0 : using compute_tags_for_observation_box = tmpl::list<>;
132 :
133 0 : using return_tags = tmpl::list<>;
134 0 : using argument_tags = tmpl::list<::Tags::ObservationBox>;
135 :
136 : template <typename DataBoxType, size_t VolumeDim, typename ParallelComponent,
137 : typename Metavariables, typename ComputeTagsList>
138 0 : void operator()(const ObservationBox<DataBoxType, ComputeTagsList>& box,
139 : Parallel::GlobalCache<Metavariables>& /*cache*/,
140 : const ElementId<VolumeDim>& array_index,
141 : const ParallelComponent* /*meta*/,
142 : const ObservationValue& observation_value) const;
143 :
144 0 : using is_ready_argument_tags = tmpl::list<>;
145 :
146 : template <typename Metavariables, typename ArrayIndex, typename Component>
147 0 : bool is_ready(Parallel::GlobalCache<Metavariables>& /*cache*/,
148 : const ArrayIndex& /*array_index*/,
149 : const Component* const /*meta*/) const {
150 : return true;
151 : }
152 :
153 1 : bool needs_evolved_variables() const override { return false; }
154 :
155 : // NOLINTNEXTLINE(google-runtime-references)
156 0 : void pup(PUP::er& p) override;
157 :
158 : private:
159 : template <size_t VolumeDim>
160 0 : void impl(const db::Access& box_access,
161 : const ElementId<VolumeDim>& array_index,
162 : const ObservationValue& observation_value) const;
163 :
164 0 : std::optional<std::string> file_name_for_tag_names_;
165 : };
166 :
167 : template <typename DataBoxType, size_t VolumeDim, typename ParallelComponent,
168 : typename Metavariables, typename ComputeTagsList>
169 : void ObserveDataBox::operator()(
170 : const ObservationBox<DataBoxType, ComputeTagsList>& box,
171 : Parallel::GlobalCache<Metavariables>& cache,
172 : const ElementId<VolumeDim>& array_index,
173 : const ParallelComponent* const /*meta*/,
174 : const ObservationValue& observation_value) const {
175 : if (is_zeroth_element(array_index)) {
176 : using component_list =
177 : tmpl::push_back<typename Metavariables::component_list>;
178 : tmpl::for_each<component_list>([&observation_value,
179 : &cache](auto component_v) {
180 : using component = tmpl::type_from<decltype(component_v)>;
181 : auto& target_proxy = Parallel::get_parallel_component<component>(cache);
182 : Parallel::simple_action<detail::ContributeDataBoxSize>(
183 : target_proxy, observation_value.value);
184 : });
185 : }
186 : impl(box.databox(), array_index, observation_value);
187 : }
188 : } // namespace Events
|