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
38ArmarX provides the concept of a virtual time which allows components and statecharts to synchronize to time sources other than wall-time/system time.
39Time sources are defined via the \ref TimeServerInterface wich is implemented by the ArmarXTimeServer application and the simulator from the ArmarXSimulation package.
40Time itself is represented as IceUtil::Time instances.
41The "Clock" gui plugin can be used to start, stop, speed up, or slow down the time offered by a TimeServer.
42
43For example, the "Plotter" gui plugin uses virtual time to show all measurements in Simulator time and to pause when the simulation is stopped.
44
45In order to use a TimeServer, one simply has to set the property
46\code
47ArmarX.UseTimeServer = true
48\endcode
49in the $HOME/.armarx.default.cfg or the global.cfg of a scenario.
50Setting `UseTimeServer=false` will provide each caller of the ArmarX VirtualTime commands with the system time.
51
52To 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
60Timeouts 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
69namespace 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 {
127 };
128
129 /**
130 * @class TimeUtil
131 * @brief provides utility functions for getting the current time
132 * @ingroup VirtualTime
133 */
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 */
142 static IceUtil::Time GetTime(TimeMode timeMode = TimeMode::VirtualTime);
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,
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:
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
#define GENERATE_TIME_OPERATORS_ARITH(op)
Definition TimeUtil.h:93
#define GENERATE_TIME_OPERATOR_COMP(op)
Definition TimeUtil.h:73
static LocalTimeServerPtr GetTimeServer()
Definition TimeUtil.cpp:118
static IceUtil::Time GetTime(TimeMode timeMode=TimeMode::VirtualTime)
Get the current time.
Definition TimeUtil.cpp:42
static void SetTimeServer(LocalTimeServerPtr ts)
Definition TimeUtil.cpp:106
static std::string toStringDate(const IceUtil::Time &time)
Return a date string like "2020-01-31" (Y-M-D).
Definition TimeUtil.cpp:174
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
static std::string toStringTime(const IceUtil::Time &time)
Return a time string like "15-30-05" (H-M-S).
Definition TimeUtil.cpp:180
static void Sleep(float seconds)
Definition TimeUtil.h:197
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
static void WaitForNextTick()
block until the next tick of the timeserver.
Definition TimeUtil.cpp:112
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
static void MSSleep(int durationMS)
lock the calling thread for a given duration (like usleep(...) but using Timeserver time)
Definition TimeUtil.cpp:100
static int NanoSleep(long usec)
Nanosleep convenience function.
Definition TimeUtil.cpp:165
static void SleepUS(float microseconds)
Definition TimeUtil.h:209
static LocalTimeServerPtr timeServerPtr
pointer to the applications LocalTimeServer if NULL, system time is used
Definition TimeUtil.h:276
static int USleep(long usec)
like timed_wait on boost condition_variables, but with timeserver support
Definition TimeUtil.cpp:159
static void Sleep(IceUtil::Time duration)
lock the calling thread for a given duration (like usleep(...) but using Timeserver time)
Definition TimeUtil.cpp:80
static bool HasTimeServer()
check if we have been initialized with a Timeserver
Definition TimeUtil.cpp:124
static void SleepMS(float milliseconds)
Definition TimeUtil.h:203
TimeMode
Time mode to be used.
Definition TimeUtil.h:124
This file offers overloads of toIce() and fromIce() functions for STL container types.
IceInternal::Handle< LocalTimeServer > LocalTimeServerPtr