BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bsls_timeutil

Detailed Description

Provide a platform-neutral functional interface to system clocks.

Outline

Purpose

Provide a platform-neutral functional interface to system clocks.

Classes

See also
bsls_stopwatch

Description

This component provides a set of platform-neutral pure procedures to access real-time system clock functionality. High-resolution time functions intended for interval-timing return a time interval in nanoseconds (1 nsec = 1E-9 sec) as a 64-bit integer. In addition to wall time, this component provides process and thread CPU timers. On platforms where per-thread CPU timers are unavailable, thread timer methods return -1.

Thread Timers

bsls::TimeUtil::getThreadSystemTimer, bsls::TimeUtil::getThreadUserTimer, and bsls::TimeUtil::getThreadTimers report CPU time consumed by the calling thread. On platforms where per-thread CPU timing APIs are unavailable, these methods return -1 for each unavailable value.

Accuracy and Precision

bsls::TimeUtil high-resolution functions return time values as absolute nanoseconds from an arbitrary reference that will in many cases remain fixed within a single process (and among running processes on a single machine). Absolute monotonic behavior is platform-dependent, however, as are accuracy and useful precision, despite the nominal nanosecond precision implied by the return value. The user is advised to determine the actual performance on each platform of interest.

Accuracy on Windows

On certain windows platform configurations, bsls::TimeUtil::getTimer and bsls::TimeUtil::getRawTimer can produce unreliable results. On some machines, these high-resolution functions have been observed to run at inconsistent speeds, with worst cases as slow as half the speed of actual wall time. This is known behavior of the underlying high-performance timer function QueryPerformanceCounter, upon which the Windows implementation of bsls::TimeUtil relies.

Reference: https://msdn.microsoft.com/library/windows/desktop/dn553408

CPU Scaling

The behavior of the timer on windows platforms depends on the interaction of operating system, BIOS, and processor, and certain combinations of the three (particularly older ones) are vulnerable to timer inaccuracy. For example, frequently the QueryPerformanceCounter function that TimeUtil uses on Windows will utilize the CPU's timestamp counter (TSC), and CPUs with speed scaling mechanisms such as SpeedStep (frequently used for power management) will generally see the clock speed vary with the CPU frequency. However, newer processors often provide an Invariant TSC that solves this problem. Also versions of Windows starting with Vista may internally handle the inconsistency by automatically using a lower resolution, but accurate, counter on processors that do not provide an Invariant TSC.

Multi-Core Issues

In addition, on multi-core machines, each call to QueryPerformanceCounter may read the TSC from a different CPU. The TSCs of the CPUs may be out of sync, resulting in slightly inconsistent or even non-monotonic behavior.

Reference: http://support.microsoft.com/kb/895980

Ensuring Accurate Timers on Windows

If a Windows machine appears to have a slow and/or inconsistent high-resolution timer, it can be reconfigured to avoid using the TSC. On Windows XP and earlier versions, add the parameter /usepmtimer to the operating system's boot configuration in boot.ini. On Windows Vista and later, run the following command as an administrator:

bcdedit /set useplatformclock true

Note that unless the machine has a High Performance Event Timer (HPET) and it has been enabled in the BIOS, these steps might reduce the resolution of the bsls::TimeUtil high-resolution functions from the nanosecond range to the microsecond range (or worse).

Precision on Windows

Providing that the underlying timer is capable of supporting the QueryPerformanceCounter interface, getTimer and convertRawTime will perform their calculations to nanosecond precision based on the values reported by QueryPerformanceCounter. Because of overflow concerns, these routines do not simply divide the result of QueryPerformanceCounter by the result of QueryPerformanceFrequency. In the course of calculating the final nanosecond-precision time, there are two places where some precision might be lost. Therefore, the times reported by getTimer and convertRawTime may be as much as two nanoseconds less than the actual time expressed by the QueryPerformanceCounter interface. Note that the times will still be monotonically non-decreasing.

Usage

This section illustrates intended use of this component.

Example 1: Implementing a Very Simple Timer

In this example we illustrate how to use bsls::TimeUtil functions to implement a very simple timer. Only the most primitive functionality is illustrated. See the bsls::Stopwatch component for a better example of a timer interface.

// my_timer.h
#ifndef INCLUDED_BSLS_TYPES
#include <bsls_types.h> // bsls::Types::Int64
#endif
#ifndef INCLUDED_BSLS_TIMEUTIL
#include <bsls_timeutil.h>
#endif
class my_Timer {
// This class implements a simple interval timer that is created in
// the "running" state, and may be queried for its cumulative
// interval (as a 'double', in seconds) but never stopped or reset.
bsls::Types::Int64 d_startWallTime; // time at creation (nsec)
bsls::Types::Int64 d_startUserTime; // time at creation (nsec)
bsls::Types::Int64 d_startSystemTime; // time at creation (nsec)
public:
// CREATORS
my_Timer() {
d_startWallTime = bsls::TimeUtil::getTimer();
}
// Create a timer object initialized with the times at creation.
// All values returned by subsequent calls to 'elapsed<...>Time()'
// are with respect to this creation time.
~my_Timer() {}
// ACCESSORS
double elapsedWallTime();
// Return the total elapsed time in seconds since the creation of
// this timer object.
double elapsedUserTime();
// Return the elapsed user time in seconds since the creation of
// this timer object.
double elapsedSystemTime();
// Return the elapsed system time in seconds since the creation of
// this timer object.
};
inline
double my_Timer::elapsedWallTime()
{
return (double) (bsls::TimeUtil::getTimer() - d_startWallTime) * 1.0E-9;
}
inline
double my_Timer::elapsedUserTime()
{
- d_startUserTime) * 1.0E-9;
}
inline
double my_Timer::elapsedSystemTime()
{
- d_startSystemTime) * 1.0E-9;
}
// ...
static Types::Int64 getTimer()
static Types::Int64 getProcessUserTimer()
static Types::Int64 getProcessSystemTimer()
long long Int64
Definition bsls_types.h:134

The my_Timer object may be used to time some section of code at runtime as follows:

// ...
{
my_Timer tw;
for (int i = 0; i < 1000000; ++i) {
// ...
}
double dTw = tw.elapsedWallTime();
my_Timer tu;
for (int i = 0; i < 1000000; ++i) {
// ...
}
double dTu = tu.elapsedUserTime();
my_Timer ts;
for (int i = 0; i < 1000000; ++i) {
// ...
}
double dTs = ts.elapsedSystemTime();
printf("elapsed wall time: %g\n"
"elapsed user time: %g\n"
"elapsed system time: %g\n",
dTw, dTu, dTs);
}

Example 2: Thread Timers

In this example we show how to use the thread CPU timers and how to detect when they are unsupported on a given platform:

bsls::Types::Int64 threadSystemStart;
bsls::Types::Int64 threadUserStart;
bsls::TimeUtil::getThreadTimers(&threadSystemStart, &threadUserStart);
if (threadSystemStart >= 0 && threadUserStart >= 0) {
// ... run code on the current thread ...
bsls::Types::Int64 threadSystemEnd;
bsls::Types::Int64 threadUserEnd;
bsls::TimeUtil::getThreadTimers(&threadSystemEnd, &threadUserEnd);
double dThreadSystem =
(double)(threadSystemEnd - threadSystemStart) * 1.0E-9;
double dThreadUser =
(double)(threadUserEnd - threadUserStart) * 1.0E-9;
printf("elapsed thread system time: %g\n"
"elapsed thread user time: %g\n",
dThreadSystem,
dThreadUser);
}
else {
printf("thread CPU timers are not supported on this platform\n");
}
static void getThreadTimers(Types::Int64 *systemTimer, Types::Int64 *userTimer)

Typedefs

typedef bsls::TimeUtil bsls_TimeUtil
 

Typedef Documentation

◆ bsls_TimeUtil

This alias is defined for backward compatibility.