KaMPIng 0.1.1
Flexible and (near) zero-overhead C++ bindings for MPI
Loading...
Searching...
No Matches
measurement_utils.hpp
Go to the documentation of this file.
1// This file is part of KaMPIng.
2//
3// Copyright 2023 The KaMPIng Authors
4//
5// KaMPIng is free software : you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
7// version. KaMPIng is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
8// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
9// for more details.
10//
11// You should have received a copy of the GNU Lesser General Public License along with KaMPIng. If not, see
12// <https://www.gnu.org/licenses/>.
13
14/// @file
15/// This file contains (distributed) utility classes and functions that are needed for a distributed timer class.
16
17#pragma once
18
19#include <memory>
20#include <optional>
21
22#include <kassert/kassert.hpp>
23#include <mpi.h>
24
25#include "kamping/collectives/bcast.hpp"
26#include "kamping/collectives/gather.hpp"
27#include "kamping/communicator.hpp"
29
30namespace kamping::measurements::internal {
31/// @brief Object encapsulating a maximum operation on a given range of objects.
32struct Max {
33 /// @brief Apply a maximum computation of the given range of objects.
34 /// @tparam Container Type of container storing the objects.
35 /// @param container Container storing objects on which the aggregation operation is applied.
36 /// @return std::optional which either contains maximum of elements in the container or is empty if container is
37 /// empty.
38 template <typename Container>
39 static auto compute(Container const& container) {
40 using T = typename Container::value_type;
41 if (container.size() == 0) {
42 return std::optional<T>{};
43 }
44 auto it = std::max_element(container.begin(), container.end());
45 return std::make_optional(*it);
46 }
47};
48
49/// @brief Object encapsulating a minimum operation on a given range of objects.
50struct Min {
51 /// @brief Apply a minimum computation of the given range of objects.
52 /// @tparam Container Type of container storing the objects.
53 /// @param container Container storing objects on which the aggregation operation is applied.
54 /// @return std::optional which either contains minimum of elements in the container or is empty if container is
55 /// empty.
56 template <typename Container>
57 static auto compute(Container const& container) {
58 using T = typename Container::value_type;
59 if (container.size() == 0) {
60 return std::optional<T>{};
61 }
62 auto it = std::min_element(container.begin(), container.end());
63 return std::make_optional(*it);
64 }
65};
66
67/// @brief Object encapsulating a summation operation on a given range of objects.
68struct Sum {
69 /// @brief Apply a summation computation of the given range of objects.
70 /// @tparam Container Type of container storing the objects.
71 /// @param container Container storing objects on which the aggregation operation is applied.
72 /// @return std::optional which either contains sum of elements in the container or is empty if container is
73 /// empty.
74 template <typename Container>
75 static auto compute(Container const& container) {
76 using T = typename Container::value_type;
77 if (container.size() == 0) {
78 return std::optional<T>{};
79 }
80 auto const sum = std::accumulate(container.begin(), container.end(), T{});
81 return std::make_optional(sum);
82 }
83};
84
85/// @brief Object encapsulating a gather operation on a given range of objects.
86struct Gather {
87 /// @brief Forwards input container.
88 /// @tparam Container Type of container storing the objects.
89 /// @param container Container storing objects which is forward.
90 /// @return Forwarded container.
91 template <typename Container>
92 static decltype(auto) compute(Container&& container) {
93 return std::forward<Container>(container);
94 }
95
96 /// @brief Returns operation's name.
97 /// @return Operations name.
98 static std::string operation_name() {
99 return "gather";
100 }
101};
102
103/// @brief Object representing a node in a tree. The class is not meant to be used on its own but to encapsulate the
104/// basic "tree-node behaviour" (e.g. management of children nodes etc.) for other specialised node classes like
105/// TimerTreeNode via CRTP paradigm.
106/// @tparam DerivedNode Specialised node type for which the basisc "tree node behaviour" is encapsulated.
107template <typename DerivedNode>
108class TreeNode {
109public:
110 /// @brief Constructs node without pointer to parent and empty name.
111 TreeNode() : TreeNode(std::string{}) {}
112
113 /// @brief Constructs node without pointer to parent.
114 /// @param name Name associated with this node.
115 TreeNode(std::string const& name) : TreeNode(name, nullptr) {}
116
117 /// @brief Constructs node pointer to parent.
118 /// @param name Name associated with this node.
119 /// @param parent Pointer to this node's parent pointer.
120 TreeNode(std::string const& name, DerivedNode* parent) : _name{name}, _parent_ptr{parent} {}
121
122 /// @brief Searches the node's children for a node with the given name. If there is no such child a new node is
123 /// inserted.
124 /// @param name Name of the child which is searched.
125 /// @return Reference to the node with the given name.
126 auto& find_or_insert(std::string const& name) {
127 auto it = _children_map.find(name);
128 if (it != _children_map.end()) {
129 return *it->second;
130 } else {
131 auto new_child = std::make_unique<DerivedNode>(name, static_cast<DerivedNode*>(this));
132 auto ptr_to_new_child = new_child.get();
133 _children_map[name] = ptr_to_new_child;
134 _children_storage.push_back(std::move(new_child));
135 return *ptr_to_new_child;
136 }
137 }
138
139 /// @brief Access to the parent pointer.
140 /// @return Reference to the parent pointer.
141 auto& parent_ptr() {
142 return _parent_ptr;
143 }
144
145 /// @brief Access to the node's children.
146 /// @return Return a reference to the node's children.
147 auto const& children() const {
148 return _children_storage;
149 }
150
151 /// @brief Access to the node's children.
152 /// @return Return a reference to the node's children.
153 auto const& name() const {
154 return _name;
155 }
156
157private:
158 std::string _name; ///< Name of the node.
159 DerivedNode* _parent_ptr; ///< Pointer to the node's parent.
160 std::unordered_map<std::string, DerivedNode*>
161 _children_map; ///< Map (used for faster lookup) to the node's children.
162 std::vector<std::unique_ptr<DerivedNode>> _children_storage; ///< Owns the node's children.
163};
164
165/// @brief Class to store measurement data points associated with a node in a measurement tree, e.g., a timer-tree.
166///
167/// @tparam T Type of the data point.
168/// @tparam default_global_aggregation_mode Default mode to use for global aggregation when not further specified.
169template <typename T, GlobalAggregationMode default_global_aggregation_mode>
171public:
172 /// @brief Add the result of a time measurement (i.e. a duration) to the node.
173 ///
174 /// @param datapoint Data point which is added to the node.
175 /// @param mode The kamping::measurements::KeyAggregationMode parameter determines how multiple time measurements
176 /// shall be handled. They can either be accumulated (the durations are added together) or appended (the durations
177 /// are stored in a list).
179 switch (mode) {
180 case LocalAggregationMode::accumulate:
181 if (_datapoints.empty()) {
182 _datapoints.push_back(datapoint);
183 } else {
184 _datapoints.back() += datapoint;
185 }
186 break;
187 case LocalAggregationMode::append:
188 _datapoints.push_back(datapoint);
189 }
190 }
191
192 /// @brief Access to stored duration(s).
193 /// @return Return a reference to duration(s).
194 auto const& measurements() const {
195 return _datapoints;
196 }
197
198 /// @brief Access to the data aggregation operations (used during the evaluation).
199 /// @return Return a reference to data aggregation operations.
201 return _datapoint_aggregation_operations;
202 }
203
204 /// @brief Access to the data aggregation operations (used during the evaluation).
205 /// @return Return a reference to data aggregation operations.
207 return _datapoint_aggregation_operations;
208 }
209
210private:
211 std::vector<T> _datapoints; ///< Datapoints stored at the node
212 std::vector<GlobalAggregationMode> _datapoint_aggregation_operations{
213 default_global_aggregation_mode}; ///< Communicator-wide aggregation operation which will be performed on the
214 ///< measurements. @TODO replace this with a more space efficient variant
215};
216
217/// @brief Class representing a node in the timer tree. Each node represents a time measurement (or multiple with
218/// the same key). A node can have multiple children which represent nested time measurements. The measurements
219/// associated with a node's children are executed while the node's measurement is still active.
220///
221/// @tparam TimePoint Type of a point in time.
222/// @tparam Duration Type of a duration.
223template <typename TimePoint, typename Duration>
224class TimerTreeNode : public TreeNode<TimerTreeNode<TimePoint, Duration>>,
225 public NodeMeasurements<Duration, GlobalAggregationMode::max> {
226public:
228
229 /// @brief Returns the point in time at which the currently active measurement has been started.
230 /// @return Point in time at which the currently active measurement has been started.
232 return _start;
233 }
234
235 /// @brief Sets the point in time at which the currently active measurement has been started.
236 /// @param start New start point for currently active measurement.
237 void startpoint(TimePoint start) {
238 _start = start;
239 }
240
241 /// @brief Sets the activity status of this node (i.e. is there a currently active measurement).
242 /// @param is_active Activity status to set.
243 void is_active(bool is_active) {
244 _is_active = is_active;
245 }
246
247 /// @brief Getter for activity status.
248 /// @return Returns whether this node is associated with a currently active measurement.
249 bool is_active() const {
250 return _is_active;
251 }
252
253private:
254 TimePoint _start; ///< Point in time at which the current measurement has been started.
255 bool _is_active{false}; ///< Indicates whether a time measurement is currently active.
256};
257
258/// @brief Class representing a node in the counter tree. Each node represents a measurement (or multiple with
259/// the same key). A node can have multiple children which represent nested measurements. The measurements
260/// associated with a node's children are executed while the node's measurement is still active.
261///
262/// @tparam TimePoint Type of a point in time.
263/// @tparam Duration Type of a duration.
264template <typename DataType>
265class CounterTreeNode : public TreeNode<CounterTreeNode<DataType>>,
266 public NodeMeasurements<DataType, GlobalAggregationMode::sum> {
267public:
269};
270
271/// @brief Tree consisting of objects of type \c NodeType. The tree constitutes a hierarchy of measurements
272/// such that each node correspond to one (or multiple) measurement(s) with the same name.
273/// For timer tree, the measurements corresponding to the node's children are all started and stopped while the node's
274/// current time measurement is running.
275///
276/// @tparam NodeType Underlying node type.
277template <typename NodeType>
278struct Tree {
279 /// @brief Construct a TimerTree consisting only of a root node.
280 Tree() : root{"root"}, current_node(&root) {
281 root.parent_ptr() = &root;
282 }
283 /// @brief Resets the root node (i.e. deletes and assigns a new empty node).
284 void reset() {
285 root = NodeType{"root"};
287 }
288 NodeType root; ///< Root node of the tree.
289 NodeType* current_node; ///< Pointer to the currently active node of the tree.
290};
291
292/// @brief Checks that the given string is equal on all ranks in the given communicator.
293///
294/// @todo this function should be once superseded by a more general Communicator::is_same_on_all_ranks().
295/// @tparam Communicator Type of communicator.
296/// @param str String which is tested for equality on all ranks.
297/// @param comm Communicator on which the equality test is executed.
298/// @return Returns whether string is equal on all ranks.
299template <typename Communicator>
300inline bool is_string_same_on_all_ranks(std::string const& str, Communicator const& comm) {
301 auto has_same_size = comm.is_same_on_all_ranks(str.size());
302 if (!has_same_size) {
303 return false;
304 }
305
306 // std::vector<char> name_as_char_vector;
307 auto recv_buf = comm.gatherv(send_buf(str));
308 auto result = true;
309 if (comm.is_root()) {
310 for (std::size_t cur_rank = 0; cur_rank < comm.size(); ++cur_rank) {
311 auto begin = recv_buf.begin() + static_cast<int>(cur_rank * str.size());
312 auto end = begin + static_cast<int>(str.size());
313 std::string const cur_string(begin, end);
314 if (cur_string != str) {
315 result = false;
316 break;
317 }
318 }
319 }
320 comm.bcast_single(send_recv_buf(result));
321 return result;
322}
323} // namespace kamping::measurements::internal
Wrapper for MPI communicator providing access to rank() and size() of the communicator....
Definition communicator.hpp:49
STL-compatible allocator for requesting memory using the builtin MPI allocator.
Definition allocator.hpp:32
Class representing a node in the counter tree. Each node represents a measurement (or multiple with t...
Definition measurement_utils.hpp:266
Class to store measurement data points associated with a node in a measurement tree,...
Definition measurement_utils.hpp:170
void aggregate_measurements_locally(T const &datapoint, LocalAggregationMode const &mode)
Add the result of a time measurement (i.e. a duration) to the node.
Definition measurement_utils.hpp:178
auto const & measurements_aggregation_operations() const
Access to the data aggregation operations (used during the evaluation).
Definition measurement_utils.hpp:206
auto const & measurements() const
Access to stored duration(s).
Definition measurement_utils.hpp:194
auto & measurements_aggregation_operations()
Access to the data aggregation operations (used during the evaluation).
Definition measurement_utils.hpp:200
Class representing a node in the timer tree. Each node represents a time measurement (or multiple wit...
Definition measurement_utils.hpp:225
void is_active(bool is_active)
Sets the activity status of this node (i.e. is there a currently active measurement).
Definition measurement_utils.hpp:243
void startpoint(TimePoint start)
Sets the point in time at which the currently active measurement has been started.
Definition measurement_utils.hpp:237
TimePoint startpoint() const
Returns the point in time at which the currently active measurement has been started.
Definition measurement_utils.hpp:231
bool is_active() const
Getter for activity status.
Definition measurement_utils.hpp:249
Object representing a node in a tree. The class is not meant to be used on its own but to encapsulate...
Definition measurement_utils.hpp:108
auto const & children() const
Access to the node's children.
Definition measurement_utils.hpp:147
auto const & name() const
Access to the node's children.
Definition measurement_utils.hpp:153
TreeNode(std::string const &name, DerivedNode *parent)
Constructs node pointer to parent.
Definition measurement_utils.hpp:120
TreeNode()
Constructs node without pointer to parent and empty name.
Definition measurement_utils.hpp:111
auto & find_or_insert(std::string const &name)
Searches the node's children for a node with the given name. If there is no such child a new node is ...
Definition measurement_utils.hpp:126
auto & parent_ptr()
Access to the parent pointer.
Definition measurement_utils.hpp:141
TreeNode(std::string const &name)
Constructs node without pointer to parent.
Definition measurement_utils.hpp:115
auto recv_buf(Container &&container)
Passes a container, into which the received elements will be written, to the underlying call....
Definition named_parameters.hpp:859
auto send_buf(internal::ignore_t< Data > ignore)
Generates a dummy send buf that wraps a nullptr.
Definition named_parameters.hpp:51
auto send_recv_buf(Data &&data)
Passes a container/single value as a send or receive buffer to the underlying MPI call.
Definition named_parameters.hpp:137
@ sum
The sum of the measurement data on the participating ranks will be computed.
LocalAggregationMode
Enum to specify how time measurements with same key shall be aggregated locally.
Definition measurement_aggregation_definitions.hpp:31
bool is_string_same_on_all_ranks(std::string const &str, Communicator const &comm)
Checks that the given string is equal on all ranks in the given communicator.
Definition measurement_utils.hpp:300
STL namespace.
Object encapsulating a gather operation on a given range of objects.
Definition measurement_utils.hpp:86
static std::string operation_name()
Returns operation's name.
Definition measurement_utils.hpp:98
static decltype(auto) compute(Container &&container)
Forwards input container.
Definition measurement_utils.hpp:92
Object encapsulating a maximum operation on a given range of objects.
Definition measurement_utils.hpp:32
static auto compute(Container const &container)
Apply a maximum computation of the given range of objects.
Definition measurement_utils.hpp:39
Object encapsulating a minimum operation on a given range of objects.
Definition measurement_utils.hpp:50
static auto compute(Container const &container)
Apply a minimum computation of the given range of objects.
Definition measurement_utils.hpp:57
Object encapsulating a summation operation on a given range of objects.
Definition measurement_utils.hpp:68
static auto compute(Container const &container)
Apply a summation computation of the given range of objects.
Definition measurement_utils.hpp:75
Tree consisting of objects of type NodeType. The tree constitutes a hierarchy of measurements such th...
Definition measurement_utils.hpp:278
NodeType root
Root node of the tree.
Definition measurement_utils.hpp:288
Tree()
Construct a TimerTree consisting only of a root node.
Definition measurement_utils.hpp:280
NodeType * current_node
Pointer to the currently active node of the tree.
Definition measurement_utils.hpp:289
void reset()
Resets the root node (i.e. deletes and assigns a new empty node).
Definition measurement_utils.hpp:284