BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bsls_timeutil.h
Go to the documentation of this file.
1/// @file bsls_timeutil.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bsls_timeutil.h -*-C++-*-
8#ifndef INCLUDED_BSLS_TIMEUTIL
9#define INCLUDED_BSLS_TIMEUTIL
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bsls_timeutil bsls_timeutil
15/// @brief Provide a platform-neutral functional interface to system clocks.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bsls
19/// @{
20/// @addtogroup bsls_timeutil
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bsls_timeutil-purpose"> Purpose</a>
25/// * <a href="#bsls_timeutil-classes"> Classes </a>
26/// * <a href="#bsls_timeutil-description"> Description </a>
27/// * <a href="#bsls_timeutil-thread-timers"> Thread Timers </a>
28/// * <a href="#bsls_timeutil-accuracy-and-precision"> Accuracy and Precision </a>
29/// * <a href="#bsls_timeutil-accuracy-on-windows"> Accuracy on Windows </a>
30/// * <a href="#bsls_timeutil-cpu-scaling"> CPU Scaling </a>
31/// * <a href="#bsls_timeutil-multi-core-issues"> Multi-Core Issues </a>
32/// * <a href="#bsls_timeutil-ensuring-accurate-timers-on-windows"> Ensuring Accurate Timers on Windows </a>
33/// * <a href="#bsls_timeutil-precision-on-windows"> Precision on Windows </a>
34/// * <a href="#bsls_timeutil-usage"> Usage </a>
35/// * <a href="#bsls_timeutil-example-1-implementing-a-very-simple-timer"> Example 1: Implementing a Very Simple Timer </a>
36/// * <a href="#bsls_timeutil-example-2-thread-timers"> Example 2: Thread Timers </a>
37///
38/// # Purpose {#bsls_timeutil-purpose}
39/// Provide a platform-neutral functional interface to system clocks.
40///
41/// # Classes {#bsls_timeutil-classes}
42///
43/// - bsls::TimeUtil: namespace for platform-neutral system-time pure procedures
44///
45/// @see bsls_stopwatch
46///
47/// # Description {#bsls_timeutil-description}
48/// This component provides a set of platform-neutral pure
49/// procedures to access real-time system clock functionality. High-resolution
50/// time functions intended for interval-timing return a time interval in
51/// nanoseconds (1 nsec = 1E-9 sec) as a 64-bit integer. In addition to wall
52/// time, this component provides process and thread CPU timers. On platforms
53/// where per-thread CPU timers are unavailable, thread timer methods return -1.
54///
55/// ## Thread Timers {#bsls_timeutil-thread-timers}
56///
57///
58/// `bsls::TimeUtil::getThreadSystemTimer`,
59/// `bsls::TimeUtil::getThreadUserTimer`, and
60/// `bsls::TimeUtil::getThreadTimers` report CPU time consumed by the calling
61/// thread. On platforms where per-thread CPU timing APIs are unavailable,
62/// these methods return -1 for each unavailable value.
63///
64/// ## Accuracy and Precision {#bsls_timeutil-accuracy-and-precision}
65///
66///
67/// `bsls::TimeUtil` high-resolution functions return time values as absolute
68/// nanoseconds from an arbitrary reference that will *in many cases* remain
69/// fixed within a single process (and among running processes on a single
70/// machine). Absolute monotonic behavior is platform-dependent, however, as
71/// are accuracy and useful precision, despite the nominal nanosecond precision
72/// implied by the return value. The user is advised to determine the actual
73/// performance on each platform of interest.
74///
75/// ### Accuracy on Windows {#bsls_timeutil-accuracy-on-windows}
76///
77///
78/// On certain windows platform configurations, `bsls::TimeUtil::getTimer` and
79/// `bsls::TimeUtil::getRawTimer` can produce unreliable results. On some
80/// machines, these high-resolution functions have been observed to run at
81/// inconsistent speeds, with worst cases as slow as half the speed of actual
82/// wall time. This is known behavior of the underlying high-performance timer
83/// function `QueryPerformanceCounter`, upon which the Windows implementation of
84/// `bsls::TimeUtil` relies.
85///
86/// Reference: https://msdn.microsoft.com/library/windows/desktop/dn553408
87///
88/// #### CPU Scaling {#bsls_timeutil-cpu-scaling}
89///
90///
91/// The behavior of the timer on windows platforms depends on the interaction of
92/// operating system, BIOS, and processor, and certain combinations of the three
93/// (particularly older ones) are vulnerable to timer inaccuracy. For example,
94/// frequently the `QueryPerformanceCounter` function that `TimeUtil` uses on
95/// Windows will utilize the CPU's timestamp counter (TSC), and CPUs with speed
96/// scaling mechanisms such as SpeedStep (frequently used for power management)
97/// will generally see the clock speed vary with the CPU frequency. However,
98/// newer processors often provide an `Invariant TSC` that solves this
99/// problem. Also versions of Windows starting with Vista may internally handle
100/// the inconsistency by automatically using a lower resolution, but accurate,
101/// counter on processors that do not provide an `Invariant TSC`.
102///
103/// #### Multi-Core Issues {#bsls_timeutil-multi-core-issues}
104///
105///
106/// In addition, on multi-core machines, each call to `QueryPerformanceCounter`
107/// may read the TSC from a different CPU. The TSCs of the CPUs may be out of
108/// sync, resulting in slightly inconsistent or even non-monotonic behavior.
109///
110/// Reference: http://support.microsoft.com/kb/895980
111///
112/// ### Ensuring Accurate Timers on Windows {#bsls_timeutil-ensuring-accurate-timers-on-windows}
113///
114///
115/// If a Windows machine appears to have a slow and/or inconsistent
116/// high-resolution timer, it can be reconfigured to avoid using the TSC. On
117/// Windows XP and earlier versions, add the parameter `/usepmtimer` to the
118/// operating system's boot configuration in `boot.ini`. On Windows Vista and
119/// later, run the following command as an administrator:
120/// @code
121/// bcdedit /set useplatformclock true
122/// @endcode
123/// Note that unless the machine has a High Performance Event Timer (HPET) and
124/// it has been enabled in the BIOS, these steps might reduce the resolution of
125/// the `bsls::TimeUtil` high-resolution functions from the nanosecond range to
126/// the microsecond range (or worse).
127///
128/// ### Precision on Windows {#bsls_timeutil-precision-on-windows}
129///
130///
131/// Providing that the underlying timer is capable of supporting the
132/// `QueryPerformanceCounter` interface, `getTimer` and `convertRawTime` will
133/// perform their calculations to nanosecond precision based on the values
134/// reported by `QueryPerformanceCounter`. Because of overflow concerns, these
135/// routines do not simply divide the result of `QueryPerformanceCounter` by the
136/// result of `QueryPerformanceFrequency`. In the course of calculating the
137/// final nanosecond-precision time, there are two places where some precision
138/// might be lost. Therefore, the times reported by `getTimer` and
139/// `convertRawTime` may be as much as two nanoseconds less than the actual time
140/// expressed by the `QueryPerformanceCounter` interface. Note that the times
141/// will still be monotonically non-decreasing.
142///
143/// ## Usage {#bsls_timeutil-usage}
144///
145///
146/// This section illustrates intended use of this component.
147///
148/// ### Example 1: Implementing a Very Simple Timer {#bsls_timeutil-example-1-implementing-a-very-simple-timer}
149///
150///
151/// In this example we illustrate how to use `bsls::TimeUtil` functions to
152/// implement a very simple timer. Only the most primitive functionality is
153/// illustrated. See the `bsls::Stopwatch` component for a better example of a
154/// timer interface.
155/// @code
156/// // my_timer.h
157///
158/// #ifndef INCLUDED_BSLS_TYPES
159/// #include <bsls_types.h> // bsls::Types::Int64
160/// #endif
161///
162/// #ifndef INCLUDED_BSLS_TIMEUTIL
163/// #include <bsls_timeutil.h>
164/// #endif
165///
166/// class my_Timer {
167/// // This class implements a simple interval timer that is created in
168/// // the "running" state, and may be queried for its cumulative
169/// // interval (as a 'double', in seconds) but never stopped or reset.
170///
171/// bsls::Types::Int64 d_startWallTime; // time at creation (nsec)
172/// bsls::Types::Int64 d_startUserTime; // time at creation (nsec)
173/// bsls::Types::Int64 d_startSystemTime; // time at creation (nsec)
174///
175/// public:
176/// // CREATORS
177/// my_Timer() {
178/// d_startWallTime = bsls::TimeUtil::getTimer();
179/// d_startUserTime = bsls::TimeUtil::getProcessUserTimer();
180/// d_startSystemTime = bsls::TimeUtil::getProcessSystemTimer();
181/// }
182/// // Create a timer object initialized with the times at creation.
183/// // All values returned by subsequent calls to 'elapsed<...>Time()'
184/// // are with respect to this creation time.
185///
186/// ~my_Timer() {}
187///
188/// // ACCESSORS
189/// double elapsedWallTime();
190/// // Return the total elapsed time in seconds since the creation of
191/// // this timer object.
192/// double elapsedUserTime();
193/// // Return the elapsed user time in seconds since the creation of
194/// // this timer object.
195/// double elapsedSystemTime();
196/// // Return the elapsed system time in seconds since the creation of
197/// // this timer object.
198/// };
199///
200/// inline
201/// double my_Timer::elapsedWallTime()
202/// {
203/// return (double) (bsls::TimeUtil::getTimer() - d_startWallTime) * 1.0E-9;
204/// }
205///
206/// inline
207/// double my_Timer::elapsedUserTime()
208/// {
209/// return (double) (bsls::TimeUtil::getProcessUserTimer()
210/// - d_startUserTime) * 1.0E-9;
211/// }
212///
213/// inline
214/// double my_Timer::elapsedSystemTime()
215/// {
216/// return (double) (bsls::TimeUtil::getProcessSystemTimer()
217/// - d_startSystemTime) * 1.0E-9;
218/// }
219/// // ...
220/// @endcode
221/// The `my_Timer` object may be used to time some section of code at runtime as
222/// follows:
223/// @code
224/// // ...
225/// {
226/// my_Timer tw;
227/// for (int i = 0; i < 1000000; ++i) {
228/// // ...
229/// }
230/// double dTw = tw.elapsedWallTime();
231/// my_Timer tu;
232/// for (int i = 0; i < 1000000; ++i) {
233/// // ...
234/// }
235/// double dTu = tu.elapsedUserTime();
236/// my_Timer ts;
237/// for (int i = 0; i < 1000000; ++i) {
238/// // ...
239/// }
240/// double dTs = ts.elapsedSystemTime();
241/// printf("elapsed wall time: %g\n"
242/// "elapsed user time: %g\n"
243/// "elapsed system time: %g\n",
244/// dTw, dTu, dTs);
245/// }
246/// @endcode
247///
248/// ### Example 2: Thread Timers {#bsls_timeutil-example-2-thread-timers}
249///
250///
251/// In this example we show how to use the thread CPU timers and how to detect
252/// when they are unsupported on a given platform:
253/// @code
254/// bsls::Types::Int64 threadSystemStart;
255/// bsls::Types::Int64 threadUserStart;
256/// bsls::TimeUtil::getThreadTimers(&threadSystemStart, &threadUserStart);
257///
258/// if (threadSystemStart >= 0 && threadUserStart >= 0) {
259/// // ... run code on the current thread ...
260///
261/// bsls::Types::Int64 threadSystemEnd;
262/// bsls::Types::Int64 threadUserEnd;
263/// bsls::TimeUtil::getThreadTimers(&threadSystemEnd, &threadUserEnd);
264///
265/// double dThreadSystem =
266/// (double)(threadSystemEnd - threadSystemStart) * 1.0E-9;
267/// double dThreadUser =
268/// (double)(threadUserEnd - threadUserStart) * 1.0E-9;
269///
270/// printf("elapsed thread system time: %g\n"
271/// "elapsed thread user time: %g\n",
272/// dThreadSystem,
273/// dThreadUser);
274/// }
275/// else {
276/// printf("thread CPU timers are not supported on this platform\n");
277/// }
278/// @endcode
279/// @}
280/** @} */
281/** @} */
282
283/** @addtogroup bsl
284 * @{
285 */
286/** @addtogroup bsls
287 * @{
288 */
289/** @addtogroup bsls_timeutil
290 * @{
291 */
292
293#include <bsls_platform.h>
294#include <bsls_types.h>
295
296#ifdef BSLS_PLATFORM_OS_UNIX
297 #include <time.h>
298#endif
299
300#if defined(BSLS_PLATFORM_OS_AIX) || defined(BSLS_PLATFORM_OS_FREEBSD) \
301 || defined(BSLS_PLATFORM_OS_DARWIN)
302 #include <sys/time.h>
303#endif
304
305
306
307namespace bsls {
308
309 // ===============
310 // struct TimeUtil
311 // ===============
312
313/// This `struct` provides a namespace for a set of platform-neutral pure
314/// procedures to access real-time system clock functionality.
315/// High-resolution time functions intended for interval-timing return an
316/// interval in nanoseconds (1 nsec = 1E-9 sec) as a platform-independent
317/// 64-bit integer.
318///
319/// For maximum performance on some platforms where fetching the native
320/// clock is significantly faster than converting the fetched value to
321/// nanoseconds, this class also provides a "raw" method returning an opaque
322/// native time value and a conversion method returning a value in
323/// nanoseconds.
324///
325/// See @ref bsls_timeutil
326struct TimeUtil {
327
328 // TYPES
329#if defined BSLS_PLATFORM_OS_SOLARIS
330 typedef struct { Types::Int64 d_opaque; } OpaqueNativeTime;
331#elif defined BSLS_PLATFORM_OS_AIX
332 typedef timebasestruct_t OpaqueNativeTime;
333#elif defined(BSLS_PLATFORM_OS_LINUX) || defined(BSLS_PLATFORM_OS_CYGWIN)
334 typedef timespec OpaqueNativeTime;
335#elif defined BSLS_PLATFORM_OS_DARWIN
336 typedef struct { Types::Uint64 d_opaque; } OpaqueNativeTime;
337#elif defined BSLS_PLATFORM_OS_UNIX
338 typedef timeval OpaqueNativeTime;
339#elif defined BSLS_PLATFORM_OS_WINDOWS
340 typedef struct { Types::Int64 d_opaque; } OpaqueNativeTime;
341#endif
342
343 // CLASS METHODS
344
345 // Initializers
346
347 /// Do a platform-dependent initialization for the utilities.
348 ///
349 /// \note Note that the other methods in this component are guaranteed to be thread-safe
350 /// only after calling this method.
351 static void initialize();
352
353 // Operations
354
355 /// Convert the specified `rawTime` to a value in nanoseconds,
356 /// referenced to an arbitrary but fixed origin, and return the result of the conversion.
357 ///
358 /// \note Note that this method is thread-safe only if
359 /// `initialize` has been called before.
360 static Types::Int64 convertRawTime(OpaqueNativeTime rawTime);
361
362 /// Return the instantaneous values of a platform-dependent timer for the
363 /// current process system time in absolute nanoseconds referenced to an
364 /// arbitrary but fixed origin. If the system call fails return -1.
365 ///
366 /// \note Note that this method is thread-safe only if `initialize` has been called
367 /// before.
369
370 /// Load into the specified `systemTimer` and `userTimer` the
371 /// instantaneous values of platform-dependent system timer and user
372 /// timer in absolute nanoseconds referenced to an arbitrary but fixed
373 /// origin. If the system call fails fill both time arguments with -1.
374 ///
375 /// \note Note that this method is thread-safe only if `initialize` has been
376 /// called before.
377 static void getProcessTimers(Types::Int64 *systemTimer,
378 Types::Int64 *userTimer);
379
380 /// Return the instantaneous values of a platform-dependent timer for the
381 /// current process user time in absolute nanoseconds referenced to an
382 /// arbitrary but fixed origin. If the system call fails return -1.
383 ///
384 /// \note Note that this method is thread-safe only if `initialize` has been called
385 /// before.
387
388 /// Return the instantaneous values of a platform-dependent timer for
389 /// the current thread system time in absolute nanoseconds referenced
390 /// to an arbitrary but fixed origin. Return -1 on platforms where
391 /// per-thread CPU timers are unavailable or in case of a system call failure.
392 ///
393 /// \note Note that this method is thread-safe only if `initialize`
394 /// has been called before.
396
397 /// Load into the specified `systemTimer` and `userTimer` the
398 /// instantaneous values of platform-dependent system timer and user
399 /// timer for the current thread, in absolute nanoseconds referenced
400 /// to an arbitrary but fixed origin. Load -1 into both timers on
401 /// platforms where per-thread CPU timers are unavailable or in case of a system call failure.
402 ///
403 /// \note Note that this method is thread-safe only if
404 /// `initialize` has been called before.
405 static void getThreadTimers(Types::Int64 *systemTimer,
406 Types::Int64 *userTimer);
407
408 /// Return the instantaneous values of a platform-dependent timer for
409 /// the current thread user time in absolute nanoseconds referenced to
410 /// an arbitrary but fixed origin. Return -1 on platforms where per-thread
411 /// CPU timers are unavailable or in case of a system call failure.
412 ///
413 /// \note Note that this method is thread-safe only if `initialize` has been called
414 /// before.
416
417 /// Return the instantaneous value of a platform-dependent system timer
418 /// in absolute nanoseconds referenced to an arbitrary but fixed origin.
419 ///
420 /// \note Note that this method is thread-safe only if `initialize` has been
421 /// called before.
423
424 /// Load into the specified `timeValue` the value of an opaque,
425 /// platform-dependent type representing the current time. `timeValue`
426 /// must be converted by the `convertRawTime` method to conventional
427 /// units (nanoseconds). This method is intended to facilitate accurate
428 /// timing of small segments of code, and care must be used in interpreting the results.
429 ///
430 /// \note Note that this method is thread-safe only
431 /// if `initialize` has been called before.
432 static void getTimerRaw(OpaqueNativeTime *timeValue);
433
434};
435
436} // close package namespace
437
438#ifndef BDE_OPENSOURCE_PUBLICATION // BACKWARD_COMPATIBILITY
439// ============================================================================
440// BACKWARD COMPATIBILITY
441// ============================================================================
442
443/// This alias is defined for backward compatibility.
445#endif // BDE_OPENSOURCE_PUBLICATION -- BACKWARD_COMPATIBILITY
446
447
448
449#endif
450
451// ----------------------------------------------------------------------------
452// Copyright 2013 Bloomberg Finance L.P.
453//
454// Licensed under the Apache License, Version 2.0 (the "License");
455// you may not use this file except in compliance with the License.
456// You may obtain a copy of the License at
457//
458// http://www.apache.org/licenses/LICENSE-2.0
459//
460// Unless required by applicable law or agreed to in writing, software
461// distributed under the License is distributed on an "AS IS" BASIS,
462// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
463// See the License for the specific language governing permissions and
464// limitations under the License.
465// ----------------------------- END-OF-FILE ----------------------------------
466
467/** @} */
468/** @} */
469/** @} */
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
bsls::TimeUtil bsls_TimeUtil
This alias is defined for backward compatibility.
Definition bsls_timeutil.h:444
Definition bdlt_iso8601util.h:707
Definition bsls_timeutil.h:326
static Types::Int64 getThreadUserTimer()
static Types::Int64 getThreadSystemTimer()
static Types::Int64 convertRawTime(OpaqueNativeTime rawTime)
static void initialize()
static Types::Int64 getTimer()
static Types::Int64 getProcessUserTimer()
static void getTimerRaw(OpaqueNativeTime *timeValue)
static void getThreadTimers(Types::Int64 *systemTimer, Types::Int64 *userTimer)
static void getProcessTimers(Types::Int64 *systemTimer, Types::Int64 *userTimer)
static Types::Int64 getProcessSystemTimer()
unsigned long long Uint64
Definition bsls_types.h:139
long long Int64
Definition bsls_types.h:134