DPsim
Timer.h
1 /* Copyright 2017-2021 Institute for Automation of Complex Power Systems,
2  * EONERC, RWTH Aachen University
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, You can obtain one at https://mozilla.org/MPL/2.0/.
7  *********************************************************************************/
8 
9 #pragma once
10 
11 #include <chrono>
12 
13 #include <dpsim/Config.h>
14 
15 namespace DPsim {
16 
17 class Timer {
18 public:
20  uint64_t overruns;
21  };
22 
23  using Ticks = std::chrono::nanoseconds;
24 
25  using StartClock = std::chrono::system_clock;
26  using IntervalClock = std::chrono::steady_clock;
27 
28  using StartTimePoint = std::chrono::time_point<StartClock, Ticks>;
29  using IntervalTimePoint = std::chrono::time_point<IntervalClock, Ticks>;
30 
31 protected:
32  enum State { running, stopped } mState;
33 
34  StartTimePoint mStartAt;
35  IntervalTimePoint mNextTick;
36  Ticks mTickInterval;
37 
38 #ifdef HAVE_TIMERFD
39  int mTimerFd;
40 #endif
41  long long mOverruns;
42  long long mTicks;
43  int mFlags;
44 
45 public:
46  enum Flags : int { fail_on_overrun = 1 };
47 
48  Timer(int flags = 0);
49 
50  ~Timer();
51 
52  void start(const StartTimePoint &startAt);
53 
55  void start();
56 
58  void stop();
59 
61  void sleep();
62 
63  // Getter
64  const long long &overruns() { return mOverruns; }
65 
66  long long ticks() { return mTicks; }
67 
68  Ticks interval() { return mTickInterval; }
69 
70  // Setter
71  void setStartTime(const StartTimePoint &start) { mStartAt = start; }
72 
73  void setInterval(const Ticks &intv) { mTickInterval = intv; }
74 
75  void setInterval(double dt) {
76  mTickInterval = Timer::Ticks((uintmax_t)(dt * 1e9));
77  }
78 };
79 
80 #ifdef HAVE_TIMERFD
81 template <class Rep, class Period>
82 struct timespec to_timespec(std::chrono::duration<Rep, Period> dur) {
83  auto nsDur = std::chrono::duration_cast<std::chrono::nanoseconds>(dur);
84 
85  struct timespec ts;
86 
87  ts.tv_sec = nsDur.count() / 1000000000;
88  ts.tv_nsec = nsDur.count() % 1000000000;
89 
90  return ts;
91 }
92 #endif
93 
94 } // namespace DPsim
95 
96 #include <ctime>
97 #include <iomanip>
98 #include <iostream>
99 
100 template <typename Clock, typename Duration>
101 std::ostream &
102 operator<<(std::ostream &stream,
103  const std::chrono::time_point<Clock, Duration> &time_point) {
104  const auto sys_time_point =
105  std::chrono::time_point_cast<typename Clock::duration, Clock>(time_point);
106  const std::time_t time = Clock::to_time_t(sys_time_point);
107 
108 #if __GNUC__ > 4 || \
109  ((__GNUC__ == 4) && __GNUC_MINOR__ > 8 && __GNUC_REVISION__ > 1)
110  // Maybe the put_time will be implemented later?
111  struct tm tm;
112  localtime_r(&time, &tm);
113  return stream << std::put_time(&tm, "%c"); // Print standard date&time
114 #elif defined(_MSC_VER)
115  char buffer[26];
116  ctime_s(buffer, 26, &time);
117  buffer[24] = '\0'; // Removes the newline that is added
118  return stream << buffer;
119 #else
120  char buffer[26];
121  ctime_r(&time, buffer);
122  buffer[24] = '\0'; // Removes the newline that is added
123  return stream << buffer;
124 #endif
125 }
126 
127 template <typename Rep, typename Period>
128 std::ostream &operator<<(std::ostream &stream,
129  const std::chrono::duration<Rep, Period> &dur) {
130 
131  using namespace std::chrono;
132 
133  auto d = dur;
134 
135  if (dur == dur.zero())
136  stream << "0";
137  else {
138  auto h = duration_cast<hours>(d);
139  d -= h;
140  auto m = duration_cast<minutes>(d);
141  d -= m;
142  auto s = duration_cast<seconds>(d);
143  d -= s;
144  auto ms = duration_cast<milliseconds>(d);
145  d -= ms;
146  auto us = duration_cast<microseconds>(d);
147  d -= us;
148  auto ns = duration_cast<nanoseconds>(d);
149 
150  long long vals[] = {h.count(), m.count(), s.count(),
151  ms.count(), us.count(), ns.count()};
152  const char *units[] = {"hrs", "mins", "secs", "msecs", "usecs", "nsecs"};
153 
154  for (int i = 0; i < 6; i++) {
155  if (i)
156  stream << " ";
157 
158  if (vals[i] == 0)
159  continue;
160 
161  stream << vals[i] << " " << units[i];
162  }
163  }
164 
165  return stream;
166 }
void start()
Start real-time timer.
Definition: Timer.cpp:78
void stop()
Stop real-time timer.
Definition: Timer.cpp:111
void sleep()
Suspend thread execution until next tick.
Definition: Timer.cpp:45