TimeUtil.h
Go to the documentation of this file.
1 /*
2 * This file is part of ArmarX.
3 *
4 * Copyright (C) 2011-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5 *
6 * ArmarX is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of
9 * the License, or (at your option) any later version.
10 *
11 * ArmarX is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * @package ArmarXCore::core
20 * @author Clemens Wallrath (uagzs at student dot kit dot edu)
21 * @date 2015
22 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
23 * GNU General Public License
24 */
25 
26 #pragma once
27 
28 
29 #include <chrono>
30 
31 #include <IceUtil/Time.h>
32 
33 #include <ArmarXCore/interface/core/TimeServerInterface.h>
34 
35 /**
36  * @page VirtualTimeDoc ArmarX VirtualTime
37 
38 ArmarX provides the concept of a virtual time which allows components and statecharts to synchronize to time sources other than wall-time/system time.
39 Time sources are defined via the \ref TimeServerInterface wich is implemented by the ArmarXTimeServer application and the simulator from the ArmarXSimulation package.
40 Time itself is represented as IceUtil::Time instances.
41 The "Clock" gui plugin can be used to start, stop, speed up, or slow down the time offered by a TimeServer.
42 
43 For example, the "Plotter" gui plugin uses virtual time to show all measurements in Simulator time and to pause when the simulation is stopped.
44 
45 In order to use a TimeServer, one simply has to set the property
46 \code
47 ArmarX.UseTimeServer = true
48 \endcode
49 in the $HOME/.armarx.default.cfg or the global.cfg of a scenario.
50 Setting `UseTimeServer=false` will provide each caller of the ArmarX VirtualTime commands with the system time.
51 
52 To make your components and statecharts VirtualTime compatible, you have to use the following functions
53 
54 \li replace `IceUtile::Time::now()` with `armarx::TimeUtil::GetTime()` to get the current time.
55 \li replace `sleep()` and `usleep()` with `armarx::TimeUtil::Sleep()` and `armarx::TimeUtil::MSSleep()`
56 
57 
58 `armarx::PeriodicTask` uses system time by default, but can be changed to use TimeServer time by setting the `forceSystemTime` constructor parameter to `false`.
59 
60 Timeouts in statecharts registered with `StateUtility::setTimeoutEvent(...)` will automatically use TimeServer time when `UseTimeServer=true`.
61  */
62 
63 /**
64  * @defgroup VirtualTime
65  * @ingroup core-utility
66  * @copydoc VirtualTimeDoc
67  */
68 
69 namespace armarx
70 {
71  // operator definitions to enable interoperability between IceUtil::Time and std::chrono time
72 #ifndef BOOST_NO_CXX11_HDR_CHRONO
73 #define GENERATE_TIME_OPERATOR_COMP(op) \
74  template <class Rep, class Period> \
75  inline bool operator op(IceUtil::Time a, std::chrono::duration<Rep, Period> b) \
76  { \
77  return a.toMicroSeconds() op std::chrono::duration_cast<std::chrono::microseconds>(b) \
78  .count(); \
79  } \
80  template <class Rep, class Period> \
81  inline bool operator op(std::chrono::duration<Rep, Period> a, IceUtil::Time b) \
82  { \
83  return std::chrono::duration_cast<std::chrono::microseconds>(a).count() \
84  op b.toMicroSeconds(); \
85  }
92 #undef GENERATE_TIME_OPERATOR_COMP
93 #define GENERATE_TIME_OPERATORS_ARITH(op) \
94  template <class Rep, class Period> \
95  inline IceUtil::Time operator op(IceUtil::Time a, std::chrono::duration<Rep, Period> b) \
96  { \
97  return a op IceUtil::Time::microSeconds( \
98  std::chrono::duration_cast<std::chrono::microseconds>(b).count()); \
99  } \
100  template <class Rep, class Period> \
101  inline IceUtil::Time operator op(std::chrono::duration<Rep, Period> a, IceUtil::Time b) \
102  { \
103  return IceUtil::Time::microSeconds( \
104  std::chrono::duration_cast<std::chrono::microseconds>(a).count()) op b; \
105  }
110 #undef GENERATE_TIME_OPERATORS_ARITH
111 #endif
112 
113  // forward declarations to reduce dependency tree
114  class LocalTimeServer;
116 
117  /**
118  * @brief Time mode to be used.
119  * @ingroup VirtualTime
120  *
121  * `SystemTime` enforces the local system time, while `VirtualTime` uses the virtual time provided by the time server.
122  */
123  enum class TimeMode
124  {
125  SystemTime,
127  };
128 
129  /**
130  * @class TimeUtil
131  * @brief provides utility functions for getting the current time
132  * @ingroup VirtualTime
133  */
134  class TimeUtil
135  {
136  public:
137  /**
138  * @brief Get the current time.
139  * @param timeMode Time mode to be used.
140  * @return The current time considering timeMode
141  */
143 
144  /**
145  * @deprecated Use `TimeUtil::GetTime(TimeMode)` instead.
146  * @brief get the current time
147  * @param forceSystemTime If true, this function will always return the time of the system and never the virtual time.
148  * @return the current time
149  *
150  * Depending on if a TimeServer is used, the system time or the
151  * TimeServer time is returned
152  */
153  static IceUtil::Time GetTime(bool forceSystemTime);
154 
155  /**
156  * @brief Get the difference between the current time and a reference time.
157  * @param referenceTime Reference point in time.
158  * @param timeMode Time mode to be used.
159  * @return Current timestamp minus the given reference time to get the delta.
160  */
161  static IceUtil::Time GetTimeSince(IceUtil::Time referenceTime,
162  TimeMode timeMode = TimeMode::VirtualTime);
163 
164  /**
165  * @deprecated Use `TimeUtil::GetTimeSince(IceUtil::Time, TimeMode)` instead.
166  * @brief Get the difference between the current time and a reference time.
167  * @param referenceTime Reference point in time.
168  * @param forceSystemTime If true, this function will always return the time of the system
169  * and never the virtual time.
170  * @return Current timestamp minus the given reference time to get the delta.
171  */
172  static IceUtil::Time GetTimeSince(IceUtil::Time referenceTime, bool forceSystemTime);
173 
174  /**
175  * @brief lock the calling thread for a given duration (like usleep(...) but using Timeserver time)
176  * @param duration how long to sleep
177  *
178  * Sleep for the given duration using timeserver time. Granularity is limited to 1 ms when a Timeserver is running (else 1 us).
179  */
180  static void Sleep(IceUtil::Time duration);
181 
182  /**
183  * @brief lock the calling thread for a given duration (like usleep(...) but using Timeserver time)
184  * @param duration how long to sleep
185  *
186  * Sleep for the given duration using timeserver time. Granularity is limited to 1 ms when a Timeserver is running (else 1 us).
187  */
188  template <class Rep, class Period>
189  static void
190  Sleep(std::chrono::duration<Rep, Period> d)
191  {
192  Sleep(IceUtil::Time::microSeconds(
193  std::chrono::duration_cast<std::chrono::microseconds>(d).count()));
194  }
195 
196  static void
197  Sleep(float seconds)
198  {
199  Sleep(IceUtil::Time::microSeconds(int(1000000 * seconds)));
200  }
201 
202  static void
203  SleepMS(float milliseconds)
204  {
205  Sleep(IceUtil::Time::microSeconds(int(1000 * milliseconds)));
206  }
207 
208  static void
209  SleepUS(float microseconds)
210  {
211  Sleep(IceUtil::Time::microSeconds(int(microseconds)));
212  }
213 
214  /**
215  * @brief lock the calling thread for a given duration (like usleep(...) but using Timeserver time)
216  * @param durationMS how long to sleep in milliseconds
217  */
218  static void MSSleep(int durationMS);
219  /**
220  * @brief block until the next tick of the timeserver. Noop if no timeserver in use.
221  *
222  * Can be used to pause execution if the timeserver is paused.
223  * If the timeserver is runing, this may block for up to one tick interval (typically 1ms).
224  */
225  static void WaitForNextTick();
226 
227  static void SetTimeServer(LocalTimeServerPtr ts);
229  /**
230  * @brief check if we have been initialized with a Timeserver
231  **/
232  static bool HasTimeServer();
233 
234  /**
235  * @brief like timed_wait on boost condition_variables, but with timeserver support
236  *
237  * The implementation only checks for timeout periodically (see granularity parameter), so precision is limited
238  * @param cond the boost::condition_variable to wait on (as shared_ptr)
239  * @param lock an already locked unique_lock
240  * @param duration timeout
241  * @param granularity how often timeout is checked, default is to use a tenth of duration
242  * @return false, if the thread was unlocked due to a timeout, else true
243  **/
244  // static bool TimedWait(boost::condition_variable& cond, boost::unique_lock<boost::mutex>& lock, IceUtil::Time duration, IceUtil::Time granularity = IceUtil::Time());
245 
246 
247  /**
248  * Usleep convenience function that uses internally nanosleep.
249  * @note This function does not use virtual time!
250  */
251  static int USleep(long usec);
252  /**
253  * Nanosleep convenience function.
254  * @note This function does not use virtual time!
255  */
256  static int NanoSleep(long usec);
257 
258 
259  /// Return a date string like "2020-01-31" (Y-M-D).
260  static std::string toStringDate(const IceUtil::Time& time);
261 
262  /// Return a time string like "15-30-05" (H-M-S).
263  static std::string toStringTime(const IceUtil::Time& time);
264 
265  /// Return a date & time string like "2020-01-31_15-30-05" (Y-M-D_H-M-S).
266  static std::string toStringDateTime(const IceUtil::Time& time);
267 
268 
269  protected:
270  TimeUtil();
271 
272  /**
273  * @brief pointer to the applications LocalTimeServer
274  * if NULL, system time is used
275  */
277  };
278 
279  /** \ingroup VirtualTime
280  * Helper macro to do timing tests.
281  * Usage:
282  * \verbatim
283  TIMING_START(descriptiveName) // create variables with name descriptiveName for later reference
284  // do your stuff
285  TIMING_END(descriptiveName) // prints duration with descriptiveName as prefix
286  TIMING_CEND(descriptiveName, 10) // only printed if takes longer than 10ms
287  \endverbatim
288  */
289 #define TIMING_START(name) auto name = IceUtil::Time::now();
290 
291  //! \ingroup VirtualTime
292  //! Prints duration with comment in front of it, yet only once per second.
293 #define TIMING_END_COMMENT_STREAM(name, comment, os) \
294  { \
295  name = (IceUtil::Time::now() - name); \
296  os << deactivateSpam(1, comment) << comment \
297  << " - duration: " << name.toMilliSecondsDouble() << " ms"; \
298  }
299 
300  //! \ingroup VirtualTime
301  //! Prints duration with comment in front of it, yet only once per second.
302 #define TIMING_END_COMMENT(name, comment) TIMING_END_COMMENT_STREAM(name, comment, ARMARX_INFO)
303 
304  //! \ingroup VirtualTime
305  //! Prints duration
306 #define TIMING_END(name) TIMING_END_COMMENT(name, #name)
307 
308  //! \ingroup VirtualTime
309  //! Prints duration
310 #define TIMING_END_STREAM(name, os) TIMING_END_COMMENT_STREAM(name, #name, os)
311 
312 
313  //! \ingroup VirtualTime
314  //! Prints duration with comment in front of it if it took longer than threshold
315 #define TIMING_CEND_COMMENT(name, comment, thresholdMs) \
316  if ((IceUtil::Time::now() - name).toMilliSecondsDouble() >= thresholdMs) \
317  TIMING_END_COMMENT(name, comment)
318 
319  //! \ingroup VirtualTime
320  //! Prints duration if it took longer than thresholdMs
321 #define TIMING_CEND(name, thresholdMs) TIMING_CEND_COMMENT(name, #name, thresholdMs)
322 
323 
324 } // namespace armarx
armarx::TimeUtil::SleepUS
static void SleepUS(float microseconds)
Definition: TimeUtil.h:209
armarx::TimeUtil::toStringTime
static std::string toStringTime(const IceUtil::Time &time)
Return a time string like "15-30-05" (H-M-S).
Definition: TimeUtil.cpp:180
armarx::TimeUtil::toStringDate
static std::string toStringDate(const IceUtil::Time &time)
Return a date string like "2020-01-31" (Y-M-D).
Definition: TimeUtil.cpp:174
armarx::TimeUtil::toStringDateTime
static std::string toStringDateTime(const IceUtil::Time &time)
Return a date & time string like "2020-01-31_15-30-05" (Y-M-D_H-M-S).
Definition: TimeUtil.cpp:186
armarx::TimeUtil::MSSleep
static void MSSleep(int durationMS)
lock the calling thread for a given duration (like usleep(...) but using Timeserver time)
Definition: TimeUtil.cpp:100
armarx::TimeUtil::Sleep
static void Sleep(std::chrono::duration< Rep, Period > d)
lock the calling thread for a given duration (like usleep(...) but using Timeserver time)
Definition: TimeUtil.h:190
armarx::TimeUtil::NanoSleep
static int NanoSleep(long usec)
Nanosleep convenience function.
Definition: TimeUtil.cpp:165
armarx::TimeMode::SystemTime
@ SystemTime
armarx::TimeUtil::GetTimeServer
static LocalTimeServerPtr GetTimeServer()
Definition: TimeUtil.cpp:118
armarx::LocalTimeServerPtr
IceInternal::Handle< LocalTimeServer > LocalTimeServerPtr
Definition: LocalTimeServer.h:61
IceInternal::Handle
Definition: forward_declarations.h:8
armarx::TimeUtil::timeServerPtr
static LocalTimeServerPtr timeServerPtr
pointer to the applications LocalTimeServer if NULL, system time is used
Definition: TimeUtil.h:276
armarx::TimeUtil::USleep
static int USleep(long usec)
like timed_wait on boost condition_variables, but with timeserver support
Definition: TimeUtil.cpp:159
armarx::TimeUtil::Sleep
static void Sleep(float seconds)
Definition: TimeUtil.h:197
armarx::TimeUtil
provides utility functions for getting the current time
Definition: TimeUtil.h:134
armarx::TimeUtil::HasTimeServer
static bool HasTimeServer()
check if we have been initialized with a Timeserver
Definition: TimeUtil.cpp:124
armarx::TimeUtil::TimeUtil
TimeUtil()
armarx::TimeUtil::Sleep
static void Sleep(IceUtil::Time duration)
lock the calling thread for a given duration (like usleep(...) but using Timeserver time)
Definition: TimeUtil.cpp:80
armarx::armem::Time
armarx::core::time::DateTime Time
Definition: forward_declarations.h:13
armarx::TimeUtil::WaitForNextTick
static void WaitForNextTick()
block until the next tick of the timeserver.
Definition: TimeUtil.cpp:112
armarx::TimeUtil::GetTime
static IceUtil::Time GetTime(TimeMode timeMode=TimeMode::VirtualTime)
Get the current time.
Definition: TimeUtil.cpp:42
GENERATE_TIME_OPERATOR_COMP
#define GENERATE_TIME_OPERATOR_COMP(op)
Definition: TimeUtil.h:73
armarx::TimeMode
TimeMode
Time mode to be used.
Definition: TimeUtil.h:123
armarx::TimeUtil::GetTimeSince
static IceUtil::Time GetTimeSince(IceUtil::Time referenceTime, TimeMode timeMode=TimeMode::VirtualTime)
Get the difference between the current time and a reference time.
Definition: TimeUtil.cpp:68
armarx::TimeUtil::SetTimeServer
static void SetTimeServer(LocalTimeServerPtr ts)
Definition: TimeUtil.cpp:106
armarx::TimeUtil::SleepMS
static void SleepMS(float milliseconds)
Definition: TimeUtil.h:203
GENERATE_TIME_OPERATORS_ARITH
#define GENERATE_TIME_OPERATORS_ARITH(op)
Definition: TimeUtil.h:93
armarx::TimeMode::VirtualTime
@ VirtualTime
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:27