SPH
Timer.cpp
Go to the documentation of this file.
1 #include "system/Timer.h"
2 #include <atomic>
3 #include <iomanip>
4 #include <mutex>
5 #include <thread>
6 
8 
9 class TimerThread : public Noncopyable {
10 private:
11  static AutoPtr<TimerThread> instance;
12  std::thread thread;
13  std::atomic<bool> closingDown;
14 
15  struct TimerEntry {
16  WeakPtr<Timer> timer;
17  std::function<void()> callback;
18  };
19 
20  std::mutex entryMutex;
21  Array<TimerEntry> entries;
22 
23 public:
24  TimerThread();
25 
26  ~TimerThread();
27 
28  static TimerThread& getInstance();
29 
30  void registerTimer(const SharedPtr<Timer>& timer, const std::function<void(void)>& callback);
31 
32 private:
33  void runLoop();
34 
35  void removeEntry(TimerEntry& entry);
36 };
37 
38 AutoPtr<TimerThread> TimerThread::instance = nullptr;
39 
40 Timer::Timer(const int64_t interval, const Flags<TimerFlags> flags)
41  : interval(interval)
42  , flags(flags) {
44  std::chrono::milliseconds ms(interval);
45  started = Clock::now() - ms;
46  } else {
47  started = Clock::now();
48  }
49 }
50 
52  started = Clock::now();
53 }
54 
55 int64_t Timer::elapsed(const TimerUnit unit) const {
56  switch (unit) {
57  case TimerUnit::SECOND:
58  return std::chrono::duration_cast<std::chrono::seconds>(Clock::now() - started).count();
60  return std::chrono::duration_cast<std::chrono::milliseconds>(Clock::now() - started).count();
62  return std::chrono::duration_cast<std::chrono::microseconds>(Clock::now() - started).count();
64  return std::chrono::duration_cast<std::chrono::nanoseconds>(Clock::now() - started).count();
65  default:
67  }
68 }
69 
71  if (!isStopped) {
72  isStopped = true;
73  stopped = Clock::now();
74  }
75 }
76 
78  if (isStopped) {
79  isStopped = false;
80  // advance started by stopped duration to report correct elapsed time of the timer
81  started += Clock::now() - stopped;
82  }
83 }
84 
85 int64_t StoppableTimer::elapsed(const TimerUnit unit) const {
86  switch (unit) {
88  return std::chrono::duration_cast<std::chrono::milliseconds>(elapsedImpl()).count();
90  return std::chrono::duration_cast<std::chrono::microseconds>(elapsedImpl()).count();
91  default:
93  }
94 }
95 
96 
97 SharedPtr<Timer> makeTimer(const int64_t interval,
98  const std::function<void(void)>& callback,
99  const Flags<TimerFlags> flags) {
100  SharedPtr<Timer> timer = makeShared<Timer>(interval, flags);
102  instance.registerTimer(timer, callback);
103  return timer;
104 }
105 
107  closingDown = false;
108  thread = std::thread([this]() { this->runLoop(); });
109 }
110 
112  closingDown = true;
113  SPH_ASSERT(thread.joinable());
114  thread.join();
115 }
116 
118  if (!instance) {
119  instance = makeAuto<TimerThread>();
120  }
121  return *instance;
122 }
123 
124 void TimerThread::registerTimer(const SharedPtr<Timer>& timer, const std::function<void(void)>& callback) {
125  std::unique_lock<std::mutex> lock(entryMutex);
126  entries.push(TimerEntry{ timer, callback });
127 }
128 
129 void TimerThread::runLoop() {
130  Array<TimerEntry> copies;
131  while (!closingDown) {
132  {
133  std::unique_lock<std::mutex> lock(entryMutex);
134  copies = copyable(entries);
135  }
136  for (TimerEntry& entry : copies) {
137  // if the timer is expired (and still exists)
138  if (auto timerPtr = entry.timer.lock()) {
139  if (timerPtr->isExpired()) {
140  // run callback
141  entry.callback();
142  if (timerPtr->isPeriodic()) {
143  timerPtr->restart();
144  } else {
145  // one time callback, remove timer from the list
146  this->removeEntry(entry);
147  }
148  }
149  } else {
150  this->removeEntry(entry);
151  }
152  }
153  std::this_thread::sleep_for(std::chrono::milliseconds(50));
154  }
155 }
156 
157 void TimerThread::removeEntry(TimerEntry& entry) {
159  entry.timer.reset();
160 }
161 
163 
164 const int64_t SECOND = 1000;
165 const int64_t MINUTE = 60 * SECOND;
166 const int64_t HOUR = 60 * MINUTE;
167 const int64_t DAY = 24 * HOUR;
168 
169 std::string getFormattedTime(int64_t time) {
170  std::stringstream ss;
171  if (time >= DAY) {
172  ss << time / DAY << "d ";
173  time = time % DAY;
174  }
175  if (time >= HOUR) {
176  ss << std::setw(2) << std::setfill('0') << time / HOUR << "h ";
177  time = time % HOUR;
178  }
179  if (time >= MINUTE) {
180  ss << std::setw(2) << std::setfill('0') << time / MINUTE << "min ";
181  time = time % MINUTE;
182  }
183  ss << std::setw(2) << std::setfill('0') << time / SECOND;
184  ss << "." << std::setw(3) << std::setfill('0') << time % SECOND << "s";
185  return ss.str();
186 }
187 
INLINE CopyableArray< T, TAllocator, TCounter > copyable(const Array< T, TAllocator, TCounter > &array)
Definition: Array.h:558
#define SPH_ASSERT(x,...)
Definition: Assert.h:94
#define NOT_IMPLEMENTED
Helper macro marking missing implementation.
Definition: Assert.h:100
NAMESPACE_SPH_BEGIN
Definition: BarnesHut.cpp:13
#define NAMESPACE_SPH_END
Definition: Object.h:12
const int64_t MINUTE
Definition: Timer.cpp:165
const int64_t SECOND
Definition: Timer.cpp:164
SharedPtr< Timer > makeTimer(const int64_t interval, const std::function< void(void)> &callback, const Flags< TimerFlags > flags)
Creates timer with given interval and callback when time interval is finished.
Definition: Timer.cpp:97
const int64_t HOUR
Definition: Timer.cpp:166
const int64_t DAY
Definition: Timer.cpp:167
std::string getFormattedTime(int64_t time)
Returns the human-readable formatted time in suitable units.
Definition: Timer.cpp:169
Measuring time intervals and executing periodic events.
@ START_EXPIRED
Creates expired timer, calling elapsed immediately after creating will return the timer interval.
TimerUnit
Definition: Timer.h:24
INLINE void push(U &&u)
Adds new element to the end of the array, resizing the array if necessary.
Definition: Array.h:306
constexpr INLINE bool has(const TEnum flag) const
Checks if the object has a given flag.
Definition: Flags.h:77
int64_t elapsed(const TimerUnit unit) const
Returns elapsed time in timer units. Does not reset the timer.
Definition: Timer.cpp:85
auto elapsedImpl() const
Definition: Timer.h:77
TimePoint stopped
Definition: Timer.h:74
void stop()
Stops the timer. Function getElapsed() will report the same value from now on.
Definition: Timer.cpp:70
bool isStopped
Definition: Timer.h:75
void resume()
Resumes stopped timer.
Definition: Timer.cpp:77
void registerTimer(const SharedPtr< Timer > &timer, const std::function< void(void)> &callback)
Definition: Timer.cpp:124
~TimerThread()
Definition: Timer.cpp:111
static TimerThread & getInstance()
Definition: Timer.cpp:117
TimerThread()
Definition: Timer.cpp:106
int64_t interval
Definition: Timer.h:33
int64_t elapsed(const TimerUnit unit) const
Returns elapsed time in timer units. Does not reset the timer.
Definition: Timer.cpp:55
void restart()
Reset elapsed duration to zero.
Definition: Timer.cpp:51
Timer(const int64_t interval=0, const Flags< TimerFlags > flags=EMPTY_FLAGS)
Creates timer with given expiration duration.
Definition: Timer.cpp:40
Flags< TimerFlags > flags
Definition: Timer.h:34
TimePoint started
Definition: Timer.h:32
Object with deleted copy constructor and copy operator.
Definition: Object.h:54