preCICE v3.1.1
Loading...
Searching...
No Matches
EventUtils.cpp
Go to the documentation of this file.
1#include <algorithm>
2#include <array>
3#include <cassert>
4#include <ctime>
5#include <filesystem>
6#include <fstream>
7#include <iomanip>
8#include <iterator>
9#include <memory>
10#include <optional>
11#include <ratio>
12#include <string>
13#include <string_view>
14#include <sys/types.h>
15#include <tuple>
16#include <utility>
17#include <variant>
18
19#include "logging/LogMacros.hpp"
20#include "profiling/Event.hpp"
22#include "utils/assertion.hpp"
23#include "utils/fmt.hpp"
24
25namespace precice::profiling {
26
29
31std::string timepoint_to_string(sys_clk::time_point c)
32{
33 using namespace std::chrono;
35 auto ms = duration_cast<microseconds>(c.time_since_epoch()) % 1000;
36
38 ss << std::put_time(std::localtime(&ts), "%FT%T") << "." << std::setw(3) << std::setfill('0') << ms.count();
39 return ss.str();
40}
41
42// -----------------------------------------------------------------------
43
48
54
55void EventRegistry::initialize(std::string_view applicationName, int rank, int size)
56{
58 auto initTime = std::chrono::system_clock::now();
59
60 this->_applicationName = std::move(applicationName);
61 this->_rank = rank;
62 this->_size = size;
63 this->_initTime = initTime;
64 this->_initClock = initClock;
65
66 _writeQueue.clear();
67 _firstwrite = true;
68 _globalId = std::nullopt;
69
70 _initialized = true;
71 _finalized = false;
74 }
75}
76
81
83{
84 _directory = directory;
85}
86
88{
89 _mode = mode;
90}
91
92namespace {
93std::string toString(Mode m)
94{
95 switch (m) {
96 case (Mode::Off):
97 return "off";
98 case (Mode::Fundamental):
99 return "fundamental";
100 case (Mode::All):
101 return "all";
102 }
103 PRECICE_UNREACHABLE("Unknown mode");
104}
105} // namespace
106
108{
109 if (_mode == Mode::Off) {
110 PRECICE_DEBUG("Profiling is turned off. Backend will not start.");
111 return;
112 }
113
115
116 // Create the directory if necessary
117 bool isLocal = _directory.empty() || _directory == ".";
118 if (!isLocal) {
119 auto exists = std::filesystem::exists(_directory);
122 "The destination folder \"{}\" exists but isn't a directory. Please remove the directory \"precice-run\" and try again.",
123 _directory);
124 if (!exists) {
126 }
127 }
128 auto filename = fmt::format("{}/{}-{}-{}.json", _directory, _applicationName, _rank, _size);
129 PRECICE_DEBUG("Starting backend with events-file: \"{}\"", filename);
130 _output.open(filename);
131 PRECICE_CHECK(_output, "Unable to open the events-file: \"{}\"", filename);
132 _globalId = nameToID("_GLOBAL");
134
135 // write header
136 fmt::print(_output,
137 R"({{
138 "meta":{{
139 "name": "{}",
140 "rank": "{}",
141 "size": "{}",
142 "unix_us": "{}",
143 "tinit": "{}",
144 "mode": "{}"
145 }},
146 "events":[
147 )",
149 _rank,
150 _size,
151 std::chrono::duration_cast<std::chrono::microseconds>(_initTime.time_since_epoch()).count(),
153 toString(_mode));
154 _output.flush();
155 _isBackendRunning = true;
156}
157
159{
160 if (_mode == Mode::Off || !_isBackendRunning) {
161 return;
162 }
163 // create end of global event
164 auto now = Event::Clock::now();
166 // flush the queue
167 flush();
168 _output << "]}";
169 _output.close();
171
172 _isBackendRunning = false;
173}
174
176{
178 return;
179 }
180
181 stopBackend();
183 _initialized = false;
184 _finalized = true;
185}
186
188{
189 _writeQueue.clear();
190}
191
194 PRECICE_ASSERT(_mode != Mode::Off, "The profiling is off.");
195 _writeQueue.emplace_back(std::move(pe));
196 if (_writeQueueMax > 0 && _writeQueue.size() > _writeQueueMax) {
197 flush();
198 }
199}
200
201namespace {
202struct EventWriter {
204 Event::Clock::time_point initClock;
206
207 auto sinceInit(Event::Clock::time_point tp)
208 {
209 return std::chrono::duration_cast<std::chrono::microseconds>(tp - initClock).count();
210 }
211
212 void operator()(const StartEntry &se)
213 {
214 fmt::print(out,
215 R"({}{{"et":"{}","eid":{},"ts":{}}})",
216 prefix, se.type, se.eid, sinceInit(se.clock));
217 }
218
219 void operator()(const StopEntry &se)
220 {
221 fmt::print(out,
222 R"({}{{"et":"{}","eid":{},"ts":{}}})",
223 prefix, se.type, se.eid, sinceInit(se.clock));
224 }
225
226 void operator()(const DataEntry &de)
227 {
228 fmt::print(out,
229 R"({}{{"et":"{}","eid":{},"ts":{},"dn":{},"dv":"{}"}})",
230 prefix, de.type, de.eid, sinceInit(de.clock), de.did, de.dvalue);
231 }
233 void operator()(const NameEntry &ne)
234 {
235 fmt::print(out,
236 R"({}{{"et":"n","en":"{}","eid":{}}})",
237 prefix, ne.name, ne.id);
238 }
239};
240} // namespace
241
243try {
244 if (_mode == Mode::Off || _writeQueue.empty()) {
245 return;
246 }
247 PRECICE_ASSERT(_output, "Filestream doesn't exist.");
248
249 auto first = _writeQueue.begin();
250 // Don't prefix the first write with a comma
251 if (_firstwrite) {
252 PRECICE_ASSERT(!_writeQueue.empty() && !_writeQueue.front().valueless_by_exception());
253 std::visit(EventWriter{_output, _initClock, ""}, _writeQueue.front());
254 ++first;
255 _firstwrite = false;
256 }
258 EventWriter ew{_output, _initClock, ","};
259 std::for_each(first, _writeQueue.end(), [&ew](const auto &pe) { std::visit(ew, pe); });
260
261 _output.flush();
262 _writeQueue.clear();
263} catch (const std::bad_variant_access &e) {
264 PRECICE_UNREACHABLE(e.what());
265}
266
268{
269 if (auto iter = _nameDict.find(name);
270 iter == _nameDict.end()) {
271 int id = _nameDict.size();
272 _nameDict.insert(iter, {std::string(name), id});
273 _writeQueue.emplace_back(NameEntry{std::string(name), id});
274 return id;
275 } else {
276 return iter->second;
277 }
278}
279
280} // namespace precice::profiling
Eigen::Vector2d ts
Event::Clock::time_point initClock
std::string prefix
std::ostream & out
#define PRECICE_DEBUG(...)
Definition LogMacros.hpp:64
#define PRECICE_CHECK(check,...)
Definition LogMacros.hpp:35
std::string name
#define PRECICE_ASSERT(...)
Definition assertion.hpp:87
#define PRECICE_UNREACHABLE(...)
Definition assertion.hpp:95
static EventRegistry & instance()
Returns the only instance (singleton) of the EventRegistry class.
void startBackend()
Create the file and starts the filestream if profiling is turned on.
void initialize(std::string_view applicationName, int rank=0, int size=1)
Sets the global start time.
void clear()
Clears the registry.
void setWriteQueueMax(std::size_t size)
Sets the maximum size of the writequeue before calling flush(). Use 0 to flush on destruction.
void setDirectory(std::string_view directory)
Sets the directory where to write the event files to.
int nameToID(std::string_view name)
int _size
The amount of parallel instances of the current program.
void finalize()
Sets the global end time and flushes buffers.
void setMode(Mode mode)
Sets the operational mode of the registry.
void stopBackend()
Stops the global event, flushes the buffers and closes the filestream.
Mode _mode
The operational mode of the registry.
std::vector< PendingEntry > _writeQueue
bool _firstwrite
Indicator for the first record to be written.
void put(PendingEntry pe)
Records an event.
std::map< std::string, int, std::less<> > _nameDict
Event::Clock::time_point _initClock
The initial time clock, used to take runtime measurements.
std::optional< int > _globalId
The id of the global event.
std::string _applicationName
The name of the current participant.
void flush()
Writes all recorded events to file and flushes the buffer.
std::chrono::system_clock::time_point _initTime
The initial time, used to describe when the run started.
T clear(T... args)
T close(T... args)
T create_directories(T... args)
T empty(T... args)
T end(T... args)
T exists(T... args)
T find(T... args)
T flush(T... args)
T for_each(T... args)
T insert(T... args)
T is_directory(T... args)
T localtime(T... args)
contains profiling utilities.
Mode
The Mode of the Event utility.
std::variant< StartEntry, StopEntry, DataEntry, NameEntry > PendingEntry
std::string timepoint_to_string(sys_clk::time_point c)
Converts the time_point into a string like "2019-01-10T18:30:46.834".
T open(T... args)
T put_time(T... args)
T setfill(T... args)
T setw(T... args)
T size(T... args)
T str(T... args)
T value(T... args)
T visit(T... args)