| // |
| // System-specific implementation of the clock functions. |
| // |
| // Copyright (C) 2011 Nick Bruun <nick@bruun.co> |
| // Copyright (C) 2013 Vlad Lazarenko <vlad@lazarenko.me> |
| // Copyright (C) 2014 Nicolas Pauss <nicolas.pauss@gmail.com> |
| // |
| // Implementation notes: |
| // |
| // On Windows, QueryPerformanceCounter() is used. It gets |
| // real-time clock with up to nanosecond precision. |
| // |
| // On Apple (OS X, iOS), mach_absolute_time() is used. It gets |
| // CPU/bus dependent real-time clock with up to nanosecond precision. |
| // |
| // On Unix, gethrtime() is used with HP-UX and Solaris. Otherwise, |
| // clock_gettime() is used to access monotonic real-time clock |
| // with up to nanosecond precision. On kernels 2.6.28 and newer, the ticks |
| // are also raw and are not subject to NTP and/or adjtime(3) adjustments. |
| // |
| // Other POSIX compliant platforms resort to using gettimeofday(). It is |
| // subject to clock adjustments, does not allow for higher than microsecond |
| // resolution and is also declared obsolete by POSIX.1-2008. |
| // |
| // Note on C++11: |
| // |
| // Starting with C++11, we could use std::chrono. However, the details of |
| // what clock is really being used is implementation-specific. For example, |
| // Visual Studio 2012 defines "high_resolution_clock" as system clock with |
| // ~1 millisecond precision that is not acceptable for performance |
| // measurements. Therefore, we are much better off having full control of what |
| // mechanism we use to obtain the system clock. |
| // |
| // Note on durations: it is assumed that end times passed to the clock methods |
| // are all after the start time. Wrap-around of clocks is not tested, as |
| // nanosecond precision of unsigned 64-bit integers would require an uptime of |
| // almost 585 years for this to happen. Let's call ourselves safe on that one. |
| // |
| #ifndef __HAYAI_CLOCK |
| #define __HAYAI_CLOCK |
| |
| #include "hayai_compatibility.hpp" |
| |
| |
| // POSIX |
| #if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) |
| #include <unistd.h> |
| #endif |
| |
| // Win32 |
| #if defined(_WIN32) |
| #ifndef NOMINMAX |
| #define NOMINMAX |
| #endif |
| #include <windows.h> |
| |
| // Apple |
| #elif defined(__APPLE__) && defined(__MACH__) |
| #include <mach/mach_time.h> |
| |
| // Unix |
| #elif defined(__unix__) || defined(__unix) || defined(unix) |
| |
| // gethrtime |
| # if (defined(__hpux) || defined(hpux)) || ((defined(__sun__) || defined(__sun) || defined(sun)) && (defined(__SVR4) || defined(__svr4__))) |
| # include <sys/time.h> |
| |
| // clock_gettime |
| # elif defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) |
| # include <time.h> |
| |
| // gettimeofday |
| # else |
| # include <sys/time.h> |
| |
| # endif |
| #else |
| #error "Unable to define high resolution timer for an unknown OS." |
| #endif |
| |
| #include <stdexcept> |
| #include <stdint.h> |
| |
| |
| namespace hayai |
| { |
| // Win32 |
| #if defined(_WIN32) |
| class Clock |
| { |
| public: |
| /// Time point. |
| |
| /// Opaque representation of a point in time. |
| typedef LARGE_INTEGER TimePoint; |
| |
| |
| /// Get the current time as a time point. |
| |
| /// @returns the current time point. |
| static TimePoint Now() |
| { |
| TimePoint result; |
| QueryPerformanceCounter(&result); |
| return result; |
| } |
| |
| |
| /// Get the duration between two time points. |
| |
| /// @param startTime Start time point. |
| /// @param endTime End time point. |
| /// @returns the number of nanoseconds elapsed between the two time |
| /// points. |
| static uint64_t Duration(const TimePoint& startTime, |
| const TimePoint& endTime) |
| { |
| const static double performanceFrequencyNs = |
| PerformanceFrequencyNs(); |
| |
| return static_cast<uint64_t>( |
| (endTime.QuadPart - startTime.QuadPart) |
| * performanceFrequencyNs |
| ); |
| } |
| |
| |
| /// Clock implementation description. |
| |
| /// @returns a description of the clock implementation used. |
| static const char* Description() |
| { |
| return "QueryPerformanceCounter"; |
| } |
| private: |
| static double PerformanceFrequencyNs() |
| { |
| TimePoint result; |
| QueryPerformanceFrequency(&result); |
| return 1e9 / static_cast<double>(result.QuadPart); |
| } |
| }; |
| |
| // Mach kernel. |
| #elif defined(__APPLE__) && defined(__MACH__) |
| class Clock |
| { |
| public: |
| /// Time point. |
| |
| /// Opaque representation of a point in time. |
| typedef uint64_t TimePoint; |
| |
| |
| /// Get the current time as a time point. |
| |
| /// @returns the current time point. |
| static TimePoint Now() __hayai_noexcept |
| { |
| return mach_absolute_time(); |
| } |
| |
| |
| /// Get the duration between two time points. |
| |
| /// @param startTime Start time point. |
| /// @param endTime End time point. |
| /// @returns the number of nanoseconds elapsed between the two time |
| /// points. |
| static uint64_t Duration(const TimePoint& startTime, |
| const TimePoint& endTime) __hayai_noexcept |
| { |
| mach_timebase_info_data_t time_info; |
| mach_timebase_info(&time_info); |
| |
| return (endTime - startTime) * time_info.numer / time_info.denom; |
| } |
| |
| |
| /// Clock implementation description. |
| |
| /// @returns a description of the clock implementation used. |
| static const char* Description() |
| { |
| return "mach_absolute_time"; |
| } |
| }; |
| |
| // Unix |
| #elif defined(__unix__) || defined(__unix) || defined(unix) |
| |
| // gethrtime |
| # if (defined(__hpux) || defined(hpux)) || ((defined(__sun__) || defined(__sun) || defined(sun)) && (defined(__SVR4) || defined(__svr4__))) |
| class Clock |
| { |
| public: |
| /// Time point. |
| |
| /// Opaque representation of a point in time. |
| typedef hrtime_t TimePoint; |
| |
| |
| /// Get the current time as a time point. |
| |
| /// @returns the current time point. |
| static TimePoint Now() __hayai_noexcept |
| { |
| return gethrtime(); |
| } |
| |
| |
| /// Get the duration between two time points. |
| |
| /// @param startTime Start time point. |
| /// @param endTime End time point. |
| /// @returns the number of nanoseconds elapsed between the two time |
| /// points. |
| static uint64_t Duration(const TimePoint& startTime, |
| const TimePoint& endTime) __hayai_noexcept |
| { |
| return static_cast<uint64_t>(endTime - startTime); |
| } |
| |
| |
| /// Clock implementation description. |
| |
| /// @returns a description of the clock implementation used. |
| static const char* Description() |
| { |
| return "gethrtime"; |
| } |
| }; |
| |
| |
| // clock_gettime |
| # elif defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) |
| class Clock |
| { |
| public: |
| /// Time point. |
| |
| /// Opaque representation of a point in time. |
| typedef struct timespec TimePoint; |
| |
| |
| /// Get the current time as a time point. |
| |
| /// @returns the current time point. |
| static TimePoint Now() __hayai_noexcept |
| { |
| TimePoint result; |
| # if defined(CLOCK_MONOTONIC_RAW) |
| clock_gettime(CLOCK_MONOTONIC_RAW, &result); |
| # elif defined(CLOCK_MONOTONIC) |
| clock_gettime(CLOCK_MONOTONIC, &result); |
| # elif defined(CLOCK_REALTIME) |
| clock_gettime(CLOCK_REALTIME, &result); |
| # else |
| clock_gettime((clocId_t)-1, &result); |
| # endif |
| return result; |
| } |
| |
| |
| /// Get the duration between two time points. |
| |
| /// @param startTime Start time point. |
| /// @param endTime End time point. |
| /// @returns the number of nanoseconds elapsed between the two time |
| /// points. |
| static uint64_t Duration(const TimePoint& startTime, |
| const TimePoint& endTime) __hayai_noexcept |
| { |
| TimePoint timeDiff; |
| |
| timeDiff.tv_sec = endTime.tv_sec - startTime.tv_sec; |
| if (endTime.tv_nsec < startTime.tv_nsec) |
| { |
| timeDiff.tv_nsec = endTime.tv_nsec + 1000000000LL - |
| startTime.tv_nsec; |
| timeDiff.tv_sec--; |
| } |
| else |
| timeDiff.tv_nsec = endTime.tv_nsec - startTime.tv_nsec; |
| |
| return static_cast<uint64_t>(timeDiff.tv_sec * 1000000000LL + |
| timeDiff.tv_nsec); |
| } |
| |
| |
| /// Clock implementation description. |
| |
| /// @returns a description of the clock implementation used. |
| static const char* Description() |
| { |
| # if defined(CLOCK_MONOTONIC_RAW) |
| return "clock_gettime(CLOCK_MONOTONIC_RAW)"; |
| # elif defined(CLOCK_MONOTONIC) |
| return "clock_gettime(CLOCK_MONOTONIC)"; |
| # elif defined(CLOCK_REALTIME) |
| return "clock_gettime(CLOCK_REALTIME)"; |
| # else |
| return "clock_gettime(-1)"; |
| # endif |
| } |
| }; |
| |
| // gettimeofday |
| # else |
| class Clock |
| { |
| public: |
| /// Time point. |
| |
| /// Opaque representation of a point in time. |
| typedef struct timeval TimePoint; |
| |
| |
| /// Get the current time as a time point. |
| |
| /// @returns the current time point. |
| static TimePoint Now() __hayai_noexcept |
| { |
| TimePoint result; |
| gettimeofday(&result, NULL); |
| return result; |
| } |
| |
| |
| /// Get the duration between two time points. |
| |
| /// @param startTime Start time point. |
| /// @param endTime End time point. |
| /// @returns the number of nanoseconds elapsed between the two time |
| /// points. |
| static uint64_t Duration(const TimePoint& startTime, |
| const TimePoint& endTime) __hayai_noexcept |
| { |
| TimePoint timeDiff; |
| |
| timeDiff.tv_sec = endTime.tv_sec - startTime.tv_sec; |
| if (endTime.tv_usec < startTime.tv_usec) |
| { |
| timeDiff.tv_usec = endTime.tv_usec + 1000000L - |
| startTime.tv_usec; |
| timeDiff.tv_sec--; |
| } |
| else |
| timeDiff.tv_usec = endTime.tv_usec - startTime.tv_usec; |
| |
| return static_cast<uint64_t>(timeDiff.tv_sec * 1000000000LL + |
| timeDiff.tv_usec * 1000); |
| } |
| |
| |
| /// Clock implementation description. |
| |
| /// @returns a description of the clock implementation used. |
| static const char* Description() |
| { |
| return "gettimeofday"; |
| } |
| }; |
| # endif |
| #endif |
| } |
| #endif |