#pragma once #include #include #include #include #include namespace Gaudi { namespace Timers { /** * @brief A std::chrono compatible Clock using rdtsc as its timing source * * This clock is not directly related to wall time but meant as a low-overhead * time interval measurement. The Precision template parameter determines the * internal precision of the clock (e.g. `std::milli`, `std::micro`). On first * invocation of `now()` the timer is calibrated against a wall-time clock, * which will have an overhead of several milliseconds. This can be avoided by * calling `calibrate()` explicitly before the first measurement. * */ template class RdtscClock { public: // to meet requirements of TrivialClock: typedef typename Precision::rep rep; typedef typename Precision::period period; typedef std::chrono::duration duration; typedef std::chrono::time_point time_point; static constexpr bool is_steady{true}; // some sanity checks: static_assert( period::num == 1, "The Precision of RdtscClock must be reducible to 1/N" ); static_assert( std::ratio_less_equal(), "The Precision of RdtscClock must be at least std::chrono::milliseconds" ); /// Calibrate the RDTSC clock against wall time static rep calibrate() noexcept { return ticks_per_unit(); } static time_point now() noexcept { return time_point{duration( __rdtsc() / ticks_per_unit() )}; } private: static rep ticks_per_unit() noexcept { static rep ticks_per_unit = do_calibrate(); // local static guarantees thread-safety return ticks_per_unit; } static rep do_calibrate() noexcept { // Calibration time and conversion factor to unit of Precision static constexpr auto calibTime = std::chrono::milliseconds( 100 ); static constexpr auto toPrec = std::ratio_divide::num; // Calibrate against wall clock auto t1_ref = std::chrono::high_resolution_clock::now(); auto t1 = __rdtsc(); std::this_thread::sleep_for( calibTime ); auto t2 = __rdtsc(); auto t2_ref = std::chrono::high_resolution_clock::now(); // Calculate ticks per unit of Precision auto dt_ref = std::chrono::duration_cast( t2_ref - t1_ref ).count(); rep ticks_per_unit = ( t2 - t1 ) / ( dt_ref * toPrec ); return ticks_per_unit; } }; } // namespace Timers } // namespace Gaudi