Utopia  2
Framework for studying models of complex & adaptive systems.
monitor.hh
Go to the documentation of this file.
1 #ifndef UTOPIA_DATAIO_MONITOR_HH
2 #define UTOPIA_DATAIO_MONITOR_HH
3 
4 #include <chrono>
5 #include <iostream>
6 #include <utility>
7 #include <vector>
8 #include <yaml-cpp/yaml.h>
9 
10 #include "../core/string.hh"
11 #include "cfg_utils.hh"
12 
13 
14 namespace Utopia::DataIO
15 {
16 
39 
47 template < class F, class... Args >
49 {
50  template < class U >
51  static auto
52  test(U* p)
53  -> decltype((*p)(std::declval< Args >()...), void(), std::true_type());
54  template < class U >
55  static auto
56  test(...) -> decltype(std::false_type());
57 
58  static constexpr bool value = decltype(test< F >(0))::value;
59 };
60 
63 {
64  public:
65  // -- Data types uses throughout the monitor timer-- //
66 
68  using Clock = std::chrono::high_resolution_clock;
69 
71  using Time = std::chrono::high_resolution_clock::time_point;
72 
74  using DurationType = std::chrono::duration< double >;
75 
76  private:
77  // -- Member declaration -- //
80 
83 
86 
87  public:
89 
97  MonitorTimer(const double emit_interval) :
98  // Store the emit interval
99  _emit_interval(emit_interval),
100  // Set the starting time member
101  _start_time(Clock::now()),
102  // Initialize _last_emit empty, setting it to 1.1.1970, 0:00, meaning
103  // that no emit has occurred yet.
104  _last_emit(){};
105 
107 
112  bool
114  {
115  // Calculate the time difference between now and the last emit
116  const DurationType duration = Clock::now() - _last_emit;
117 
118  // If more time than the _emit_interval has passed, return true
119  return (duration > _emit_interval);
120  }
121 
123  void
125  {
126  _last_emit = Clock::now();
127  }
128 
130  template < class DurationT = DurationType >
131  const DurationT
133  {
134  return Clock::now() - _start_time;
135  }
136 
138  double
140  {
141  return get_time_elapsed< std::chrono::duration< double > >().count();
142  }
143 
145  const DurationType
147  {
148  return _emit_interval;
149  }
150 };
151 
153 
159 {
160  private:
162  using Timer = std::shared_ptr< MonitorTimer >;
163 
164  // -- Members -------------------------------------------------------------
167 
169  YAML::Node _entries;
170 
173 
175  std::size_t _emit_counter;
176 
178  const std::string _emit_prefix;
179 
181  const std::string _emit_suffix;
182 
183  public:
185 
192  MonitorManager(const double emit_interval,
193  const std::string emit_prefix = "!!map ",
194  const std::string emit_suffix = "")
195  :
196  // Create a new MonitorTimer object
197  _timer(std::make_shared< MonitorTimer >(emit_interval)),
198  // Create an empty MonitorEntries object for the data to be emitted
199  _entries(YAML::Node()),
200  // Initialially set the collect data flag to true
201  _emit_enabled(true),
202  _emit_counter(0),
203  _emit_prefix(emit_prefix),
204  _emit_suffix(emit_suffix)
205  {};
206 
208  void
210  {
211  if (not _emit_enabled) return;
212 
213  // Calling recursive_setitem may remove the emitter style, requiring
214  // to reset it here each time. This will only set some flags in the
215  // to-be-created YAML::Emitter and has negligible performance impact.
216  _entries.SetStyle(YAML::EmitterStyle::Flow);
217 
218  std::cout << _emit_prefix
219  << _entries
220  << _emit_suffix
221  << std::endl;
222 
223  _emit_counter++;
224  _timer->reset();
225  _emit_enabled = false;
226  }
227 
229  void
231  {
232  if (_timer->time_has_come())
233  {
234  _emit_enabled = true;
235  }
236  }
237 
239  /* This function can be used as a more performative way to checking whether
240  * it makes sense to collect monitor entries; it makes only sense to
241  * collect entries, if the emission will actually performed in the current
242  * time step.
243  */
244  bool
245  emit_enabled() const
246  {
247  return _emit_enabled;
248  }
249 
251 
264  template < typename Value >
265  void
266  set_entry(const std::string& path,
267  const std::string& key,
268  const Value value)
269  {
271  recursive_setitem(_entries, path + "." + key, value, ".");
272  }
273 
275 
282  template < typename Time >
283  void
284  set_time_entries(const Time time, const Time time_max)
285  {
286  _entries["time"] = time;
287 
288  // Add the progress indicator and the elapsed time
289  _entries["progress"] = float(time) / float(time_max);
290  }
291 
293  Timer&
295  {
296  return _timer;
297  }
298 
300  auto
302  {
303  return _timer->get_emit_interval();
304  }
305 
307  auto
309  {
310  return _emit_counter;
311  }
312 
314  YAML::Node&
316  {
317  return _entries;
318  }
319 };
320 
322 class Monitor
323 {
324  private:
326 
328  const std::string _name;
329 
331  std::shared_ptr< MonitorManager > _mtr_mgr;
332 
333  public:
335 
340  Monitor(std::shared_ptr< MonitorManager > root_mtr_mgr)
341  :
342  _name(""),
343  _mtr_mgr(root_mtr_mgr){};
344 
346 
354  Monitor(const std::string& name, const Monitor& parent_mtr)
355  :
356  _name(parent_mtr.get_name() + "." + name),
357  _mtr_mgr(parent_mtr.get_monitor_manager()){};
358 
360 
367  template < typename Func >
368  void
369  set_by_func(const std::string key, Func&& f)
370  {
371  _mtr_mgr->set_entry(_name, key, f());
372  }
373 
375 
383  template < typename Value >
384  void
385  set_by_value(const std::string key, Value const& v)
386  {
387  _mtr_mgr->set_entry(_name, key, v);
388  }
389 
391 
406  template < typename Arg >
407  void
408  set_entry(const std::string key, Arg arg)
409  {
410  if constexpr (is_callable< Arg >::value)
411  {
412  set_by_func(key, arg);
413  }
414  else
415  {
416  set_by_value(key, arg);
417  }
418  }
419 
421  std::shared_ptr< MonitorManager >
423  {
424  return _mtr_mgr;
425  }
426 
428  std::string
429  get_name() const
430  {
431  return _name;
432  }
433 };
434  // end of group Monitor // end of group DataIO
437 
438 } // namespace Utopia::DataIO
439 
440 #endif // UTOPIA_DATAIO_MONITOR_HH
The Monitor monitors entries that are emitted if a given time has passed.
Definition: monitor.hh:323
const std::string _name
The name of the monitor.
Definition: monitor.hh:328
void set_by_value(const std::string key, Value const &v)
Provide a new entry to the monitor manager.
Definition: monitor.hh:385
Monitor(const std::string &name, const Monitor &parent_mtr)
Construct a monitor object within a hierarchy.
Definition: monitor.hh:354
std::shared_ptr< MonitorManager > _mtr_mgr
The monitor manager.
Definition: monitor.hh:331
Monitor(std::shared_ptr< MonitorManager > root_mtr_mgr)
Constructs a root monitor object.
Definition: monitor.hh:340
std::shared_ptr< MonitorManager > get_monitor_manager() const
Get a shared pointer to the MonitorManager.
Definition: monitor.hh:422
void set_by_func(const std::string key, Func &&f)
Provide a new entry to the monitor manager.
Definition: monitor.hh:369
void set_entry(const std::string key, Arg arg)
Provide a new entry to the monitor manager.
Definition: monitor.hh:408
std::string get_name() const
Get the name of the monitor.
Definition: monitor.hh:429
The MonitorManager manages the monitor entries and MonitorTimer.
Definition: monitor.hh:159
void set_time_entries(const Time time, const Time time_max)
Set time- and progress-related top level entries.
Definition: monitor.hh:284
void check_timer()
Checks with the timer whether the time to emit has come.
Definition: monitor.hh:230
MonitorManager(const double emit_interval, const std::string emit_prefix="!!map ", const std::string emit_suffix="")
Constructor.
Definition: monitor.hh:192
Timer _timer
The monitor timer.
Definition: monitor.hh:166
std::shared_ptr< MonitorTimer > Timer
Type of the timer.
Definition: monitor.hh:162
Timer & get_timer()
Get a shared pointer to the MonitorTimer object.
Definition: monitor.hh:294
std::size_t _emit_counter
Counts the number of emit operations.
Definition: monitor.hh:175
YAML::Node & get_entries()
Get the reference to the monitor entries object.
Definition: monitor.hh:315
const std::string _emit_suffix
A suffix to the emitted string.
Definition: monitor.hh:181
void set_entry(const std::string &path, const std::string &key, const Value value)
Set an entry in the tree of monitor entries.
Definition: monitor.hh:266
auto get_emit_interval()
Return the emit interval.
Definition: monitor.hh:301
bool emit_enabled() const
Returns true if the emission is enabled.
Definition: monitor.hh:245
void emit_if_enabled()
Perform an emission of the data to the terminal, if the flag was set.
Definition: monitor.hh:209
auto get_emit_counter()
Return the emit interval.
Definition: monitor.hh:308
const std::string _emit_prefix
A prefix to the emitted string.
Definition: monitor.hh:178
YAML::Node _entries
The monitor entries.
Definition: monitor.hh:169
bool _emit_enabled
The flag that determines whether to collect data.
Definition: monitor.hh:172
The MonitorTimer keeps track of the time when to emit monitor data.
Definition: monitor.hh:63
const DurationType _emit_interval
The emit interval.
Definition: monitor.hh:79
Time _last_emit
The time of the last emit.
Definition: monitor.hh:85
const DurationT get_time_elapsed() const
Get the time elapsed since the start of this timer.
Definition: monitor.hh:132
const DurationType get_emit_interval() const
Return the emit interval.
Definition: monitor.hh:146
double get_time_elapsed_seconds() const
Get the time elapsed since start of this timer, converted to seconds.
Definition: monitor.hh:139
bool time_has_come() const
Check for whether the time to emit has come or not.
Definition: monitor.hh:113
std::chrono::high_resolution_clock::time_point Time
Data type for a time point.
Definition: monitor.hh:71
const Time _start_time
The starting time of the timer.
Definition: monitor.hh:82
void reset()
Reset the timer to the current time.
Definition: monitor.hh:124
MonitorTimer(const double emit_interval)
Constructor.
Definition: monitor.hh:97
std::chrono::duration< double > DurationType
Data type for the time unit.
Definition: monitor.hh:74
std::chrono::high_resolution_clock Clock
Data type for the clock.
Definition: monitor.hh:68
Check if a type T is callable, i.e., if it has.
Definition: type_traits.hh:685
static constexpr bool value
Definition: type_traits.hh:687
void recursive_setitem(Config &d, std::list< std::string > key_sequence, const T val)
Recursively sets an element in a configuration tree.
Definition: cfg_utils.hh:413
Definition: types.hh:64
Definition: parallel.hh:235
static auto test(...) -> decltype(std::false_type())
static auto test(U *p) -> decltype((*p)(std::declval< Args >()...), void(), std::true_type())