1919#include " kamping/measurements/measurement_aggregation_definitions.hpp"
2020
2121namespace kamping ::measurements {
22- // / @brief Class representing a node in the timer tree. Each node represents a time measurement (or multiple with
23- // / the
24- // / same key). A node can have multiple children which represent nested time measurements. The measurements
25- // / associated with a node's children are executed while the node's measurement is still active.
22+
23+ // / @brief Class representing a node in an (globally) aggregated tree, i.e., a node of a timer (or counter) tree
24+ // / where the global aggregation operations has been performed and which can be printed.
2625// /
27- // / @tparam Duration Type of a duration .
28- template <typename Duration >
29- class AggregatedTreeNode : public internal ::TreeNode<AggregatedTreeNode<Duration >> {
26+ // / @tparam DataType Underlying data type .
27+ template <typename DataType >
28+ class AggregatedTreeNode : public internal ::TreeNode<AggregatedTreeNode<DataType >> {
3029public:
31- using internal::TreeNode<AggregatedTreeNode<Duration >>::TreeNode;
30+ using internal::TreeNode<AggregatedTreeNode<DataType >>::TreeNode;
3231
3332 // /@brief Type into which the aggregated data is stored together with the applied aggregation operation.
34- using StorageType = std::unordered_map<GlobalAggregationMode, std::vector<ScalarOrContainer<Duration >>>;
33+ using StorageType = std::unordered_map<GlobalAggregationMode, std::vector<ScalarOrContainer<DataType >>>;
3534
3635 // / @brief Access to stored aggregated data.
3736 // / @return Reference to aggregated data.
@@ -41,9 +40,9 @@ class AggregatedTreeNode : public internal::TreeNode<AggregatedTreeNode<Duration
4140
4241 // / @brief Add scalar of type T to aggregated data storage together with the name of the applied aggregation
4342 // / operation.
44- // / @param aggregation_mode Aggregation mode that has been applied to the duration data.
43+ // / @param aggregation_mode Aggregation mode that has been applied to the data.
4544 // / @param data Scalar resulted from applying the given aggregation operation.
46- void add (GlobalAggregationMode aggregation_mode, std::optional<Duration > data) {
45+ void add (GlobalAggregationMode aggregation_mode, std::optional<DataType > data) {
4746 if (data) {
4847 _aggregated_data[aggregation_mode].emplace_back (data.value ());
4948 }
@@ -53,11 +52,128 @@ class AggregatedTreeNode : public internal::TreeNode<AggregatedTreeNode<Duration
5352 // / operation.
5453 // / @param aggregation_mode Aggregation mode that has been applied to the duration data.
5554 // / @param data Vector of Scalars resulted from applying the given aggregation operation.
56- void add (GlobalAggregationMode aggregation_mode, std::vector<Duration > const & data) {
55+ void add (GlobalAggregationMode aggregation_mode, std::vector<DataType > const & data) {
5756 _aggregated_data[aggregation_mode].emplace_back (data);
5857 }
5958
6059public:
6160 StorageType _aggregated_data; // /< Storage of the aggregated data.
6261};
62+
63+ // / @brief Class representing an aggregated measurement tree, i.e., a measurement tree for which the global aggregation
64+ // / has been performed.
65+ // /
66+ // / @tparam DataType Type of interanlly stored data.
67+ template <typename DataType>
68+ class AggregatedTree {
69+ public:
70+ // / @brief Globally aggregates the measurement tree provided with \param measurement_root_node across all ranks in
71+ // / \param comm .
72+ // /
73+ // / @tparam MeasurementNode Type of the measurement tree to aggregate.
74+ // / @tparam Communicator Communicator defining the scope for the global aggregation.
75+ template <typename MeasurementNode, typename Communicator>
76+ AggregatedTree (MeasurementNode const & measurement_root_node, Communicator const & comm) : _root{" root" } {
77+ aggregate (_root, measurement_root_node, comm);
78+ }
79+
80+ // / @brief Access to the root of the aggregated tree.
81+ // / @return Reference to root node of aggregated tree.
82+ auto & root () {
83+ return _root;
84+ }
85+
86+ // / @brief Access to the root of the aggregated tree.
87+ // / @return Reference to root node of aggregated tree.
88+ auto const & root () const {
89+ return _root;
90+ }
91+
92+ private:
93+ AggregatedTreeNode<DataType> _root; // /< Root node of aggregated tree.
94+ // / @brief Traverses and evaluates the given (Measurement)TreeNode and stores the result in the corresponding
95+ // / AggregatedTreeNode
96+ // /
97+ // / param aggregation_tree_node Node where the aggregated data points are stored.
98+ // / param measurement_tree_node Node where the raw (not aggregated) data points are stored.
99+ template <typename MeasurementNode, typename Communciator>
100+ void aggregate (
101+ AggregatedTreeNode<DataType>& aggregation_tree_node,
102+ MeasurementNode& measurement_tree_node,
103+ Communciator const & comm
104+ ) {
105+ KASSERT (
106+ internal::is_string_same_on_all_ranks (measurement_tree_node.name (), comm),
107+ " Currently processed MeasurementTreeNode has not the same name on all ranks -> measurement trees have "
108+ " diverged" ,
109+ assert ::heavy_communication
110+ );
111+ KASSERT (
112+ comm.is_same_on_all_ranks (measurement_tree_node.measurements ().size ()),
113+ " Currently processed MeasurementTreeNode has not the same number of measurements on all ranks -> "
114+ " measurement trees have "
115+ " diverged" ,
116+ assert ::light_communication
117+ );
118+
119+ // gather all durations at once as gathering all durations individually may deteriorate
120+ // the performance of the evaluation operation significantly.
121+ auto recv_buf = comm.gatherv (send_buf (measurement_tree_node.measurements ()));
122+ auto const num_durations = measurement_tree_node.measurements ().size ();
123+ for (size_t duration_idx = 0 ; duration_idx < num_durations; ++duration_idx) {
124+ if (!comm.is_root ()) {
125+ continue ;
126+ }
127+ std::vector<DataType> cur_durations;
128+ cur_durations.reserve (comm.size ());
129+ // gather the durations belonging to the same measurement
130+ for (size_t rank = 0 ; rank < comm.size (); ++rank) {
131+ cur_durations.push_back (recv_buf[duration_idx + rank * num_durations]);
132+ }
133+
134+ for (auto const & aggregation_mode: measurement_tree_node.measurements_aggregation_operations ()) {
135+ aggregate_measurements_globally (aggregation_mode, cur_durations, aggregation_tree_node);
136+ }
137+ }
138+ for (auto & measurement_tree_child: measurement_tree_node.children ()) {
139+ auto & aggregation_tree_child = aggregation_tree_node.find_or_insert (measurement_tree_child->name ());
140+ aggregate (aggregation_tree_child, *measurement_tree_child.get (), comm);
141+ }
142+ }
143+
144+ // / @brief Computes the specified aggregation operation on an already gathered range of values.
145+ // /
146+ // / @param mode Aggregation operation to perform.
147+ // / @param gathered_data Durations gathered from all participating ranks.
148+ // / @param evaluation_node Object where the aggregated and evaluated measurements are stored.
149+ void aggregate_measurements_globally (
150+ GlobalAggregationMode mode,
151+ std::vector<DataType> const & gathered_data,
152+ kamping::measurements::AggregatedTreeNode<DataType>& evaluation_node
153+ ) {
154+ switch (mode) {
155+ case GlobalAggregationMode::max: {
156+ using Operation = internal::Max;
157+ evaluation_node.add (mode, Operation::compute (gathered_data));
158+ break ;
159+ }
160+ case GlobalAggregationMode::min: {
161+ using Operation = internal::Min;
162+ evaluation_node.add (mode, Operation::compute (gathered_data));
163+ break ;
164+ }
165+ case GlobalAggregationMode::sum: {
166+ using Operation = internal::Sum;
167+ evaluation_node.add (mode, Operation::compute (gathered_data));
168+ break ;
169+ }
170+ case GlobalAggregationMode::gather: {
171+ using Operation = internal::Gather;
172+ evaluation_node.add (mode, Operation::compute (gathered_data));
173+ break ;
174+ }
175+ }
176+ }
177+ };
178+
63179} // namespace kamping::measurements
0 commit comments