MADARA  3.4.1
SimTime.cpp
Go to the documentation of this file.
1 #include "SimTime.h"
2 
3 #ifdef MADARA_FEATURE_SIMTIME
4 
5 #include <chrono>
6 #include <cmath>
7 
8 namespace madara
9 {
10 namespace utility
11 {
12 const double minrate = 0.0000000001;
13 
14 std::mutex SimTime::mutex_{};
15 
16 sim_time_callback_fn SimTime::callback_ = nullptr;
17 
18 uint64_t SimTime::last_realtime_ = SimTime::realtime();
19 uint64_t SimTime::last_simtime_ = -1;
20 double SimTime::last_rate_ = 1.0;
21 
22 uint64_t SimTime::realtime()
23 {
24  namespace sc = std::chrono;
25  auto now = sc::steady_clock::now();
26  auto dur = now.time_since_epoch();
27  return sc::duration_cast<sc::nanoseconds>(dur).count();
28 }
29 
30 uint64_t SimTime::realtime(uint64_t simtime)
31 {
32  uint64_t prt;
33  uint64_t pst;
34  double pr;
35  sim_time_callback_fn callback;
36 
37  {
38  std::lock_guard<std::mutex> guard{mutex_};
39  callback = callback_;
40  if (callback)
41  {
42  uint64_t st;
43  double r;
44 
45  callback_(&st, &r);
46 
47  prt = last_realtime_ = realtime();
48  pst = last_simtime_ = st;
49  pr = last_rate_ = r;
50  }
51  else
52  {
53  prt = last_realtime_;
54  pst = last_simtime_;
55  pr = last_rate_;
56  }
57  }
58 
59  if (pst == (uint64_t)-1)
60  {
61  return simtime;
62  }
63 
64  if (pr == 0)
65  {
66  pr = 1;
67  }
68 
69  return ((simtime - pst) / pr) + prt;
70 }
71 
72 uint64_t SimTime::time()
73 {
74  uint64_t prt;
75  uint64_t pst;
76  double pr;
77  uint64_t st;
78  double r;
79  sim_time_callback_fn callback;
80 
81  int64_t now = realtime();
82  {
83  std::lock_guard<std::mutex> guard{mutex_};
84  callback = callback_;
85  if (callback)
86  {
87  callback_(&st, &r);
88 
89  last_realtime_ = now;
90  last_simtime_ = st;
91  last_rate_ = r;
92  }
93  else
94  {
95  prt = last_realtime_;
96  pst = last_simtime_;
97  pr = last_rate_;
98  }
99  }
100 
101  if (!callback)
102  {
103  if (pst == (uint64_t)-1)
104  {
105  return now;
106  }
107  if (pr == 0)
108  {
109  return pst;
110  }
111 
112  int64_t offset = now - prt;
113 
114  if (pr < minrate)
115  {
116  pr = minrate;
117  }
118 
119  double delta = offset * pr;
120  st = pst + (int64_t)delta;
121  }
122 
123  return st;
124 }
125 
126 double SimTime::rate()
127 {
128  double r;
129  sim_time_callback_fn callback;
130 
131  {
132  std::lock_guard<std::mutex> guard{mutex_};
133  callback = callback_;
134 
135  if (callback)
136  {
137  callback(nullptr, &r);
138  }
139  else
140  {
141  r = last_rate_;
142  }
143  }
144 
145  return r;
146 }
147 
148 uint64_t SimTime::duration(uint64_t sim_duration)
149 {
150  double r = rate();
151 
152  if (r < minrate)
153  {
154  return -1;
155  }
156 
157  return sim_duration / r;
158 }
159 
160 uint64_t SimTime::future(uint64_t sim_offset)
161 {
162  uint64_t now = realtime();
163  uint64_t offset = duration(sim_offset);
164 
165  if (offset == (uint64_t)-1)
166  {
167  return -1;
168  }
169 
170  return now + offset;
171 }
172 
173 sim_time_callback_fn set_sim_time_callback(sim_time_callback_fn fn)
174 {
175  std::lock_guard<std::mutex> guard{SimTime::mutex_};
176  using std::swap;
177  swap(fn, SimTime::callback_);
178  return fn;
179 }
180 
181 void sim_time_notify(uint64_t time, double rate)
182 {
183  bool update_time = time != (uint64_t)-1;
184  bool update_rate = !std::isnan(rate);
185 
186  if (!update_time && !update_rate)
187  {
188  return;
189  }
190 
191  uint64_t now = SimTime::realtime();
192  std::lock_guard<std::mutex> guard{SimTime::mutex_};
193 
194  if (update_time)
195  {
196  SimTime::last_realtime_ = now;
197  SimTime::last_simtime_ = time;
198  }
199  else if (SimTime::last_simtime_ == (uint64_t)-1)
200  {
201  SimTime::last_realtime_ = now;
202  SimTime::last_simtime_ = now;
203  }
204 
205  if (update_rate)
206  {
207  SimTime::last_rate_ = rate;
208  }
209 }
210 }
211 }
212 
213 #endif
Provides utility functions and classes for common tasks and needs.
Definition: IteratorImpl.h:15
Copyright(c) 2020 Galois.