aboutsummaryrefslogtreecommitdiff
path: root/Source/Utils/MsgLogger/MsgLogger.H
blob: ca55289b2c6f1cf74399ff1376b0c99ccf2c059c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
/* Copyright 2021 Luca Fedeli
 *
 * This file is part of WarpX.
 *
 * License: BSD-3-Clause-LBNL
 */

#ifndef WARPX_MSG_LOGGER_H_
#define WARPX_MSG_LOGGER_H_

#include <AMReX.H>

#include <cstdint>
#include <map>
#include <string>
#include <utility>
#include <vector>

namespace Utils{
namespace MsgLogger{

    /** Priority is recorded together with messages. It influences
    * the display order and the appearance of a message.
    */
    enum class Priority
    {
        /** Low priority message */
        low,
        /** Medium priority message */
        medium,
        /** High priority message */
        high
    };

    /**
    * \brief This function converts a Priority into the corresponding
    * string (e.g, Priority::low --> "low")
    *
    * @param[in] priority the priority
    * @return the corresponding string
    */
    std::string PriorityToString(const Priority& priority);

    /**
    * \brief This function converts a string into the corresponding
    * priority (e.g, "low" --> Priority::low)
    *
    * @param[in] priority_string the priority string
    * @return the corresponding priority
    */
    Priority StringToPriority(const std::string& priority_string);

    /**
    * This struct represents a message, which is composed by
    * a topic, a text and a priority. It also provides methods for
    * serialization and deserialization.
    */
    struct Msg
    {
        std::string topic  /*! The message topic*/;
        std::string text   /*! The message text*/;
        Priority priority  /*! The priority of the message*/;

        /**
        * \brief This function returns a byte representation of the struct
        *
        * @return a byte vector
        */
        std::vector<char> serialize() const;

        /**
        * \brief This function generates a Msg struct from a byte vector
        *
        * @param[in] it iterator of a byte array
        * @return a Msg struct
        */
        static Msg deserialize(std::vector<char>::const_iterator& it);

        /**
        * \brief Same as static Msg deserialize(std::vector<char>::const_iterator& it)
        * but accepting an rvalue as an argument
        *
        * @param[in] it iterator of a byte array
        * @return a Msg struct
        */
        static Msg deserialize(std::vector<char>::const_iterator&& it);
    };

    /**
    * This struct represents a message with counter, which is composed
    * by a message and a counter. The latter is intended to store the
    * number of times a message is recorded. The struct also provides
    * methods for serialization and deserialization.
    */
    struct MsgWithCounter
    {
        Msg msg      /*! A message*/;
        std::int64_t counter  /*! The counter*/;

        /**
        * \brief This function returns a byte representation of the struct
        *
        * @return a byte vector
        */
        std::vector<char> serialize() const;

        /**
        * \brief This function generates a MsgWithCounter struct from a byte vector
        *
        * @param[in] it iterator of a byte array
        * @return a MsgWithCounter struct
        */
        static MsgWithCounter deserialize(std::vector<char>::const_iterator& it);

        /**
        * \brief Same as static Msg MsgWithCounter(std::vector<char>::const_iterator& it)
        * but accepting an rvalue as an argument
        *
        * @param[in] it iterator of a byte array
        * @return a MsgWithCounter struct
        */
        static MsgWithCounter deserialize(std::vector<char>::const_iterator&& it);
    };

    /**
    * This struct represents a message with counter and ranks, which is
    * composed by a message with counter, a bool flag and a std::vector<int>.
    * The bool flag is used to store if a message is emitted by all the ranks.
    * The std::vector<int> is used to store the affected ranks
    * (note: when we switch to C++17, should we consider variants?).
    * The struct also provides methods for serialization and deserialization.
    */
    struct MsgWithCounterAndRanks
    {
        MsgWithCounter msg_with_counter /*! A message with counter*/;
        bool all_ranks                  /*! Flag to store if message is emitted by all ranks*/;
        std::vector<int> ranks          /*! Affected ranks*/;

        /**
        * \brief This function returns a byte representation of the struct
        *
        * @return a byte vector
        */
        std::vector<char> serialize() const;

        /**
        * \brief This function generates a MsgWithCounterAndRanks struct from a byte vector
        *
        * @param[in] it iterator of a byte array
        * @return a MsgWithCounterAndRanks struct
        */
        static MsgWithCounterAndRanks deserialize(std::vector<char>::const_iterator& it);

        /**
        * \brief Same as static Msg MsgWithCounterAndRanks(std::vector<char>::const_iterator& it)
        * but accepting an rvalue as an argument
        *
        * @param[in] it iterator of a byte array
        * @return a MsgWithCounterAndRanks struct
        */
        static MsgWithCounterAndRanks deserialize(std::vector<char>::const_iterator&& it);
    };

    /**
    * \brief This implements the < operator for Msg.
    * Warning messages are first ordered by priority (warning: high < medium < low
    * to give precedence to higher priorities), then by topic (alphabetically),
    * and finally by text (alphabetically).
    *
    * @param[in] l a Msg
    * @param[in] r a Msg
    * @return true if l<r, false otherwise
    */
    constexpr bool operator<(const Msg& l, const Msg& r)
    {
        return
            (l.priority > r.priority) ||
            ((l.priority == r.priority) && (l.topic < r.topic)) ||
            ((l.priority == r.priority) && (l.topic == r.topic) && (l.text < r.text));
    }

    /**
    * This class is responsible for storing messages and merging messages
    * collected by different processes.
    */
    class Logger
    {
        public:

        /**
        * \brief The constructor.
        */
        Logger();

        /**
        * \brief This function records a message
        *
        * @param[in] msg a Msg struct
        */
        void record_msg(Msg msg);

        /**
        * \brief This function returns a vector containing the recorded messages
        *
        * @return a vector of the recorded messages
        */
        std::vector<Msg> get_msgs() const;

        /**
        * \brief This function returns a vector containing the recorded messages
        * with the corresponding counters
        *
        * @return a vector of the recorded messages with counters
        */
        std::vector<MsgWithCounter> get_msgs_with_counter() const;

        /**
        * \brief This collective function generates a vector containing the messages
        * with counters and emitting ranks by gathering data from
        * all the ranks
        *
        * @return a vector of messages with counters and ranks if I/O rank, an empty vector otherwise
        */
        std::vector<MsgWithCounterAndRanks>
        collective_gather_msgs_with_counter_and_ranks() const;

        private:

        /**
        * \brief This function implements the trivial special case of
        * collective_gather_msgs_with_counter_and_ranks when there is only one rank.
        *
        * @return a vector of messages with counters and ranks
        */
        std::vector<MsgWithCounterAndRanks>
        one_rank_gather_msgs_with_counter_and_ranks() const;

#ifdef AMREX_USE_MPI
        /**
        * \brief This collective function finds the rank having the
        * most messages and how many messages this rank has. The
        * rank having the most messages is designated as "gather rank".
        *
        * @param[in] how_many_msgs the number of messages that the current rank has
        * @return a pair containing the ID of the "gather rank" and its number of messages
        */
        std::pair<int, int> find_gather_rank_and_its_msgs(
            int how_many_msgs) const;

        /**
        * \brief This function uses data gathered on the "gather rank" to generate
        * a vector of messages with global counters and emitting rank lists
        *
        * @param[in] my_msg_map messages and counters of the current rank (as a map)
        * @param[in] all_data a byte array containing all the data gathered on the gather rank
        * @param[in] displacements a vector of displacements to access data corresponding to a given rank in all_data
        * @param[in] gather_rank the ID of the "gather rank"
        * @return if gather_rank==m_rank a vector of messages with global counters and emitting rank lists, dummy data otherwise
        */
        std::vector<MsgWithCounterAndRanks>
        compute_msgs_with_counter_and_ranks(
            const std::map<Msg,std::int64_t>& my_msg_map,
            const std::vector<char>& all_data,
            const std::vector<int>& displacements,
            const int gather_rank
        ) const;


        /**
        * \brief If the gather_rank is not the I/O rank, this function sends msgs_with_counter_and_ranks
        * to the I/O rank. This function uses point-to-point communications.
        *
        * @param[in] msgs_with_counter_and_ranks a vector of messages with counters and ranks
        * @param[in] gather_rank the ID of the "gather rank"
        */
        void
        swap_with_io_rank(
        std::vector<MsgWithCounterAndRanks>& msgs_with_counter_and_ranks,
        int gather_rank) const;

#endif

        int m_rank = 0         /*! MPI rank of the current process*/;
        int m_num_procs = 0    /*! Number of MPI ranks*/;
        int m_io_rank = 0      /*! Rank of the I/O process*/;
        bool m_am_i_io = false /*! Flag to store if the process is responsible for I/O*/;

        std::map<Msg, std::int64_t> m_messages /*! This stores a map to associate warning messages with the corresponding counters*/;
    };
}
}

#endif //WARPX_MSG_LOGGER_H_