// ************************************************************************** // * This file is part of the zenXML project. It is distributed under the * // * Boost Software License: http://www.boost.org/LICENSE_1_0.txt * // * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #ifndef ZEN_TICK_COUNT_HEADER_3807326 #define ZEN_TICK_COUNT_HEADER_3807326 #include #include #include "type_traits.h" #include "assert_static.h" #include #ifdef FFS_WIN #include "win.h" //includes "windows.h" #elif defined FFS_LINUX #include //Posix ::clock_gettime() #endif namespace zen { //a portable "GetTickCount()" using "wall time equivalent" - e.g. no jumps due to ntp time corrections class TickVal; std::int64_t dist(const TickVal& lhs, const TickVal& rhs); //use absolute difference for paranoid security: even QueryPerformanceCounter "wraps-around" at *some* time std::int64_t ticksPerSec(); //return 0 on error TickVal getTicks(); //return invalid value on error: !TickVal::isValid() //############################ implementation ############################## class TickVal { public: #ifdef FFS_WIN typedef LARGE_INTEGER NativeVal; #elif defined FFS_LINUX typedef timespec NativeVal; #endif TickVal() : val_() {} explicit TickVal(const NativeVal& val) : val_(val) {} inline friend std::int64_t dist(const TickVal& lhs, const TickVal& rhs) { #ifdef FFS_WIN assert_static(IsSignedInt::value); return std::abs(lhs.val_.QuadPart - rhs.val_.QuadPart); #elif defined FFS_LINUX assert_static(IsSignedInt::value); assert_static(IsSignedInt::value); return std::abs(static_cast(lhs.val_.tv_sec - rhs.val_.tv_sec) * 1000000000.0 + (lhs.val_.tv_nsec - rhs.val_.tv_nsec)); #endif } inline friend bool operator<(const TickVal& lhs, const TickVal& rhs) //evaluate directly rather than reuse operator- { #ifdef FFS_WIN return lhs.val_.QuadPart < rhs.val_.QuadPart; #elif defined FFS_LINUX if (lhs.val_.tv_sec != rhs.val_.tv_sec) return lhs.val_.tv_sec < rhs.val_.tv_sec; return lhs.val_.tv_nsec < rhs.val_.tv_nsec; #endif } bool isValid() const { return dist(*this, TickVal()) != 0; } private: NativeVal val_; }; inline std::int64_t ticksPerSec() //return 0 on error { #ifdef FFS_WIN LARGE_INTEGER frequency = {}; if (!::QueryPerformanceFrequency(&frequency)) //MSDN promises: "The frequency cannot change while the system is running." return 0; assert_static(sizeof(std::int64_t) >= sizeof(frequency.QuadPart)); return frequency.QuadPart; #elif defined FFS_LINUX return 1000000000; //precision: nanoseconds #endif } inline TickVal getTicks() //return 0 on error { #ifdef FFS_WIN LARGE_INTEGER now = {}; if (!::QueryPerformanceCounter(&now)) //msdn: SetThreadAffinityMask() may be required if there are bugs in BIOS or HAL" return TickVal(); #elif defined FFS_LINUX //gettimeofday() seems fine but is deprecated timespec now = {}; if (::clock_gettime(CLOCK_MONOTONIC_RAW, &now) != 0) //CLOCK_MONOTONIC measures time reliably across processors! return TickVal(); #endif return TickVal(now); } } #endif //ZEN_TICK_COUNT_HEADER_3807326