// bsls_timeutil.h                                                    -*-C++-*-
#ifndef INCLUDED_BSLS_TIMEUTIL
#define INCLUDED_BSLS_TIMEUTIL

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide a platform-neutral functional interface to system clocks.
//
//@CLASSES:
//  bsls::TimeUtil: namespace for platform-neutral system-time pure procedures
//
//@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.
//
///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
///-----
// The following snippets of code 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();
//         d_startUserTime = bsls::TimeUtil::getProcessUserTimer();
//         d_startSystemTime = bsls::TimeUtil::getProcessSystemTimer();
//     }
//         // 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()
// {
//     return (double) (bsls::TimeUtil::getProcessUserTimer()
//                                                 - d_startUserTime) * 1.0E-9;
// }
//
// inline
// double my_Timer::elapsedSystemTime()
// {
//     return (double) (bsls::TimeUtil::getProcessSystemTimer()
//                                               - d_startSystemTime) * 1.0E-9;
// }
//  // ...
//..
// 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();
//      std::cout << "elapsed wall time:   " << dTw << std::endl
//                << "elapsed user time:   " << dTu << std::endl
//                << "elapsed system time: " << dTs << std::endl;
//  }
//..

#include <bsls_platform.h>
#include <bsls_types.h>

#ifdef BSLS_PLATFORM_OS_UNIX
    #include <time.h>
#endif

#if defined(BSLS_PLATFORM_OS_AIX) || defined(BSLS_PLATFORM_OS_FREEBSD) || defined(BSLS_PLATFORM_OS_DARWIN)
    #include <sys/time.h>
#endif

namespace BloombergLP {

namespace bsls {

                            // ===============
                            // struct TimeUtil
                            // ===============

struct TimeUtil {
    // This 'struct' provides a namespace for a set of platform-neutral pure
    // procedures to access real-time system clock functionality.
    // High-resolution time functions intended for interval-timing return an
    // interval in nanoseconds (1 nsec = 1E-9 sec) as a platform-independent
    // 64-bit integer.
    //
    // For maximum performance on some platforms where fetching the native
    // clock is significantly faster than converting the fetched value to
    // nanoseconds, this class also provides a "raw" method returning an opaque
    // native time value and a conversion method returning a value in
    // nanoseconds.

    // TYPES
#if   defined BSLS_PLATFORM_OS_SOLARIS
    typedef struct { Types::Int64 d_opaque; }  OpaqueNativeTime;
#elif defined BSLS_PLATFORM_OS_AIX
    typedef timebasestruct_t                   OpaqueNativeTime;
#elif defined(BSLS_PLATFORM_OS_LINUX) || defined(BSLS_PLATFORM_OS_CYGWIN)
    typedef timespec                           OpaqueNativeTime;
#elif defined BSLS_PLATFORM_OS_DARWIN
    typedef struct { Types::Uint64 d_opaque; } OpaqueNativeTime;
#elif defined BSLS_PLATFORM_OS_UNIX
    typedef timeval                            OpaqueNativeTime;
#elif defined BSLS_PLATFORM_OS_WINDOWS
    typedef struct { Types::Int64 d_opaque; }  OpaqueNativeTime;
#endif

    // CLASS METHODS

                                  // Initializers

    static void initialize();
        // Do a platform-dependent initialization for the utilities.  Note that
        // the other methods in this component are guaranteed to be thread-safe
        // only after calling this method.

                                  // Operations

    static Types::Int64 convertRawTime(OpaqueNativeTime rawTime);
        // Convert the specified 'rawTime' to a value in nanoseconds,
        // referenced to an arbitrary but fixed origin, and return the result
        // of the conversion.  Note that this method is thread-safe only if
        // 'initialize' has been called before.

    static Types::Int64 getProcessSystemTimer();
        // Return the instantaneous values of a platform-dependent timer for
        // the current process system time in absolute nanoseconds referenced
        // to an arbitrary but fixed origin.  Note that this method is thread-
        // safe only if 'initialize' has been called before.

    static void getProcessTimers(Types::Int64 *systemTimer,
                                 Types::Int64 *userTimer);
        // Load into the specified 'systemTimer' and 'userTimer' the
        // instantaneous values of platform-dependent system timer and user
        // timer in absolute nanoseconds referenced to an arbitrary but fixed
        // origin.  Note that this method is thread-safe only if 'initialize'
        // has been called before.

    static Types::Int64 getProcessUserTimer();
        // Return the instantaneous values of a platform-dependent timer for
        // the current process user time in absolute nanoseconds referenced to
        // an arbitrary but fixed origin.  Note that this method is thread-safe
        // only if 'initialize' has been called before.

    static Types::Int64 getTimer();
        // Return the instantaneous value of a platform-dependent system timer
        // in absolute nanoseconds referenced to an arbitrary but fixed origin.
        // Note that this method is thread-safe only if 'initialize' has been
        // called before.

    static void getTimerRaw(OpaqueNativeTime *timeValue);
        // Load into the specified 'timeValue' the value of an opaque,
        // platform-dependent type representing the current time.  'timeValue'
        // must be converted by the 'convertRawTime' method to conventional
        // units (nanoseconds).  This method is intended to facilitate accurate
        // timing of small segments of code, and care must be used in
        // interpreting the results.  Note that this method is thread-safe only
        // if 'initialize' has been called before.

};

}  // close package namespace

#ifndef BDE_OPENSOURCE_PUBLICATION  // BACKWARD_COMPATIBILITY
// ============================================================================
//                           BACKWARD COMPATIBILITY
// ============================================================================

typedef bsls::TimeUtil bsls_TimeUtil;
    // This alias is defined for backward compatibility.
#endif  // BDE_OPENSOURCE_PUBLICATION -- BACKWARD_COMPATIBILITY

}  // close enterprise namespace

#endif

// ----------------------------------------------------------------------------
// Copyright 2013 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------