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 <ArmarXCore/interface/core/TimeServerInterface.h>
30 
31 #include <IceUtil/Time.h>
32 
33 #include <chrono>
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).count();\
78  }\
79  template<class Rep, class Period>\
80  inline bool operator op(std::chrono::duration<Rep, Period> a, IceUtil::Time b)\
81  {\
82  return std::chrono::duration_cast<std::chrono::microseconds>(a).count() op b.toMicroSeconds();\
83  }
90 #undef GENERATE_TIME_OPERATOR_COMP
91 #define GENERATE_TIME_OPERATORS_ARITH(op)\
92  template<class Rep, class Period>\
93  inline IceUtil::Time operator op(IceUtil::Time a, std::chrono::duration<Rep, Period> b)\
94  {\
95  return a op IceUtil::Time::microSeconds(std::chrono::duration_cast<std::chrono::microseconds>(b).count());\
96  }\
97  template<class Rep, class Period>\
98  inline IceUtil::Time operator op(std::chrono::duration<Rep, Period> a, IceUtil::Time b)\
99  {\
100  return IceUtil::Time::microSeconds(std::chrono::duration_cast<std::chrono::microseconds>(a).count()) op b;\
101  }
106 #undef GENERATE_TIME_OPERATORS_ARITH
107 #endif
108 
109  // forward declarations to reduce dependency tree
110  class LocalTimeServer;
112 
113  /**
114  * @brief Time mode to be used.
115  * @ingroup VirtualTime
116  *
117  * `SystemTime` enforces the local system time, while `VirtualTime` uses the virtual time provided by the time server.
118  */
119  enum class TimeMode
120  {
121  SystemTime,
123  };
124 
125  /**
126  * @class TimeUtil
127  * @brief provides utility functions for getting the current time
128  * @ingroup VirtualTime
129  */
130  class TimeUtil
131  {
132  public:
133  /**
134  * @brief Get the current time.
135  * @param timeMode Time mode to be used.
136  * @return The current time considering timeMode
137  */
139 
140  /**
141  * @deprecated Use `TimeUtil::GetTime(TimeMode)` instead.
142  * @brief get the current time
143  * @param forceSystemTime If true, this function will always return the time of the system and never the virtual time.
144  * @return the current time
145  *
146  * Depending on if a TimeServer is used, the system time or the
147  * TimeServer time is returned
148  */
149  static IceUtil::Time GetTime(bool forceSystemTime);
150 
151  /**
152  * @brief Get the difference between the current time and a reference time.
153  * @param referenceTime Reference point in time.
154  * @param timeMode Time mode to be used.
155  * @return Current timestamp minus the given reference time to get the delta.
156  */
157  static IceUtil::Time GetTimeSince(IceUtil::Time referenceTime,
158  TimeMode timeMode = TimeMode::VirtualTime);
159 
160  /**
161  * @deprecated Use `TimeUtil::GetTimeSince(IceUtil::Time, TimeMode)` instead.
162  * @brief Get the difference between the current time and a reference time.
163  * @param referenceTime Reference point in time.
164  * @param forceSystemTime If true, this function will always return the time of the system
165  * and never the virtual time.
166  * @return Current timestamp minus the given reference time to get the delta.
167  */
168  static IceUtil::Time GetTimeSince(IceUtil::Time referenceTime,
169  bool forceSystemTime);
170 
171  /**
172  * @brief lock the calling thread for a given duration (like usleep(...) but using Timeserver time)
173  * @param duration how long to sleep
174  *
175  * Sleep for the given duration using timeserver time. Granularity is limited to 1 ms when a Timeserver is running (else 1 us).
176  */
177  static void Sleep(IceUtil::Time duration);
178 
179  /**
180  * @brief lock the calling thread for a given duration (like usleep(...) but using Timeserver time)
181  * @param duration how long to sleep
182  *
183  * Sleep for the given duration using timeserver time. Granularity is limited to 1 ms when a Timeserver is running (else 1 us).
184  */
185  template<class Rep, class Period>
186  static void Sleep(std::chrono::duration<Rep, Period> d)
187  {
188  Sleep(IceUtil::Time::microSeconds(std::chrono::duration_cast<std::chrono::microseconds>(d).count()));
189  }
190 
191  static void Sleep(float seconds)
192  {
193  Sleep(IceUtil::Time::microSeconds(int(1000000 * seconds)));
194  }
195  static void SleepMS(float milliseconds)
196  {
197  Sleep(IceUtil::Time::microSeconds(int(1000 * milliseconds)));
198  }
199  static void SleepUS(float microseconds)
200  {
201  Sleep(IceUtil::Time::microSeconds(int(microseconds)));
202  }
203 
204  /**
205  * @brief lock the calling thread for a given duration (like usleep(...) but using Timeserver time)
206  * @param durationMS how long to sleep in milliseconds
207  */
208  static void MSSleep(int durationMS);
209  /**
210  * @brief block until the next tick of the timeserver. Noop if no timeserver in use.
211  *
212  * Can be used to pause execution if the timeserver is paused.
213  * If the timeserver is runing, this may block for up to one tick interval (typically 1ms).
214  */
215  static void WaitForNextTick();
216 
217  static void SetTimeServer(LocalTimeServerPtr ts);
219  /**
220  * @brief check if we have been initialized with a Timeserver
221  **/
222  static bool HasTimeServer();
223 
224  /**
225  * @brief like timed_wait on boost condition_variables, but with timeserver support
226  *
227  * The implementation only checks for timeout periodically (see granularity parameter), so precision is limited
228  * @param cond the boost::condition_variable to wait on (as shared_ptr)
229  * @param lock an already locked unique_lock
230  * @param duration timeout
231  * @param granularity how often timeout is checked, default is to use a tenth of duration
232  * @return false, if the thread was unlocked due to a timeout, else true
233  **/
234  // static bool TimedWait(boost::condition_variable& cond, boost::unique_lock<boost::mutex>& lock, IceUtil::Time duration, IceUtil::Time granularity = IceUtil::Time());
235 
236 
237  /**
238  * Usleep convenience function that uses internally nanosleep.
239  * @note This function does not use virtual time!
240  */
241  static int USleep(long usec);
242  /**
243  * Nanosleep convenience function.
244  * @note This function does not use virtual time!
245  */
246  static int NanoSleep(long usec);
247 
248 
249  /// Return a date string like "2020-01-31" (Y-M-D).
250  static std::string toStringDate(const IceUtil::Time& time);
251 
252  /// Return a time string like "15-30-05" (H-M-S).
253  static std::string toStringTime(const IceUtil::Time& time);
254 
255  /// Return a date & time string like "2020-01-31_15-30-05" (Y-M-D_H-M-S).
256  static std::string toStringDateTime(const IceUtil::Time& time);
257 
258 
259  protected:
260 
261  TimeUtil();
262 
263  /**
264  * @brief pointer to the applications LocalTimeServer
265  * if NULL, system time is used
266  */
268  };
269 
270  /** \ingroup VirtualTime
271  * Helper macro to do timing tests.
272  * Usage:
273  * \verbatim
274  TIMING_START(descriptiveName) // create variables with name descriptiveName for later reference
275  // do your stuff
276  TIMING_END(descriptiveName) // prints duration with descriptiveName as prefix
277  TIMING_CEND(descriptiveName, 10) // only printed if takes longer than 10ms
278  \endverbatim
279  */
280 #define TIMING_START(name) auto name = IceUtil::Time::now();
281 
282  //! \ingroup VirtualTime
283  //! Prints duration with comment in front of it, yet only once per second.
284 #define TIMING_END_COMMENT_STREAM(name, comment, os) \
285  { \
286  name = (IceUtil::Time::now() - name); \
287  os << deactivateSpam(1, comment) << comment << " - duration: " << name.toMilliSecondsDouble() << " ms"; \
288  }
289 
290  //! \ingroup VirtualTime
291  //! Prints duration with comment in front of it, yet only once per second.
292 #define TIMING_END_COMMENT(name, comment) TIMING_END_COMMENT_STREAM(name, comment, ARMARX_INFO)
293 
294  //! \ingroup VirtualTime
295  //! Prints duration
296 #define TIMING_END(name) TIMING_END_COMMENT(name, #name)
297 
298  //! \ingroup VirtualTime
299  //! Prints duration
300 #define TIMING_END_STREAM(name, os) TIMING_END_COMMENT_STREAM(name, #name, os)
301 
302 
303  //! \ingroup VirtualTime
304  //! Prints duration with comment in front of it if it took longer than threshold
305 #define TIMING_CEND_COMMENT(name, comment, thresholdMs) if((IceUtil::Time::now()-name).toMilliSecondsDouble() >= thresholdMs) TIMING_END_COMMENT(name, comment)
306 
307  //! \ingroup VirtualTime
308  //! Prints duration if it took longer than thresholdMs
309 #define TIMING_CEND(name, thresholdMs) TIMING_CEND_COMMENT(name, #name, thresholdMs)
310 
311 
312 }
313 
armarx::TimeUtil::SleepUS
static void SleepUS(float microseconds)
Definition: TimeUtil.h:199
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:167
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:162
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:172
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:94
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:186
armarx::TimeUtil::NanoSleep
static int NanoSleep(long usec)
Nanosleep convenience function.
Definition: TimeUtil.cpp:153
armarx::TimeMode::SystemTime
@ SystemTime
armarx::TimeUtil::GetTimeServer
static LocalTimeServerPtr GetTimeServer()
Definition: TimeUtil.cpp:109
armarx::LocalTimeServerPtr
IceInternal::Handle< LocalTimeServer > LocalTimeServerPtr
Definition: LocalTimeServer.h:58
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:267
armarx::TimeUtil::USleep
static int USleep(long usec)
like timed_wait on boost condition_variables, but with timeserver support
Definition: TimeUtil.cpp:148
armarx::TimeUtil::Sleep
static void Sleep(float seconds)
Definition: TimeUtil.h:191
armarx::TimeUtil
provides utility functions for getting the current time
Definition: TimeUtil.h:130
armarx::TimeUtil::HasTimeServer
static bool HasTimeServer()
check if we have been initialized with a Timeserver
Definition: TimeUtil.cpp:114
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:76
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:104
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:119
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:66
armarx::TimeUtil::SetTimeServer
static void SetTimeServer(LocalTimeServerPtr ts)
Definition: TimeUtil.cpp:99
armarx::TimeUtil::SleepMS
static void SleepMS(float milliseconds)
Definition: TimeUtil.h:195
GENERATE_TIME_OPERATORS_ARITH
#define GENERATE_TIME_OPERATORS_ARITH(op)
Definition: TimeUtil.h:91
armarx::TimeMode::VirtualTime
@ VirtualTime
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:28