diff options
-rw-r--r-- | host/include/uhd/types/time_spec.hpp | 7 | ||||
-rw-r--r-- | host/lib/types/CMakeLists.txt | 55 | ||||
-rw-r--r-- | host/lib/types/time_spec.cpp | 73 | ||||
-rw-r--r-- | host/tests/time_spec_test.cpp | 19 |
4 files changed, 154 insertions, 0 deletions
diff --git a/host/include/uhd/types/time_spec.hpp b/host/include/uhd/types/time_spec.hpp index 57d002d48..2046fbd3f 100644 --- a/host/include/uhd/types/time_spec.hpp +++ b/host/include/uhd/types/time_spec.hpp @@ -40,6 +40,13 @@ namespace uhd{ public: /*! + * Get the system time in time_spec_t format. + * Uses the highest precision clock available. + * \return the system time as a time_spec_t + */ + static time_spec_t get_system_time(void); + + /*! * Create a time_spec_t from a real-valued seconds count. * \param secs the real-valued seconds count (default = 0) */ diff --git a/host/lib/types/CMakeLists.txt b/host/lib/types/CMakeLists.txt index dfb7cf903..bcc04e08d 100644 --- a/host/lib/types/CMakeLists.txt +++ b/host/lib/types/CMakeLists.txt @@ -16,6 +16,61 @@ # ######################################################################## +# Setup defines for high resolution timing +######################################################################## +MESSAGE(STATUS "") +MESSAGE(STATUS "Configuring high resolution timing...") +INCLUDE(CheckCXXSourceCompiles) + +SET(CMAKE_REQUIRED_LIBRARIES -lrt) +CHECK_CXX_SOURCE_COMPILES(" + #include <ctime> + int main(){ + timespec ts; + return clock_gettime(CLOCK_MONOTONIC, &ts); + } + " HAVE_CLOCK_GETTIME +) +UNSET(CMAKE_REQUIRED_LIBRARIES) + +INCLUDE(CheckCXXSourceCompiles) +CHECK_CXX_SOURCE_COMPILES(" + #include <mach/mach_time.h> + int main(){ + mach_timebase_info_data_t info; + mach_timebase_info(&info); + mach_absolute_time(); + return 0; + } + " HAVE_MACH_ABSOLUTE_TIME +) + +CHECK_CXX_SOURCE_COMPILES(" + #include <Windows.h> + int main(){ + LARGE_INTEGER value; + QueryPerformanceCounter(&value); + QueryPerformanceFrequency(&value); + return 0; + } + " HAVE_QUERY_PERFORMANCE_COUNTER +) + +IF(HAVE_CLOCK_GETTIME) + MESSAGE(STATUS " High resolution timing supported through clock_gettime.") + ADD_DEFINITIONS(-DTIME_SPEC_USE_GETTIME) +ELSEIF(HAVE_MACH_ABSOLUTE_TIME) + MESSAGE(STATUS " High resolution timing supported through mach_absolute_time.") + ADD_DEFINITIONS(-DTIME_SPEC_USE_MACH_ABSOLUTE_TIME) +ELSEIF(HAVE_QUERY_PERFORMANCE_COUNTER) + MESSAGE(STATUS " High resolution timing supported through QueryPerformanceCounter.") + ADD_DEFINITIONS(-DTIME_SPEC_USE_QUERY_PERFORMANCE_COUNTER) +ELSE() + MESSAGE(STATUS " High resolution timing supported though microsec_clock.") + ADD_DEFINITIONS(-DTIME_SPEC_USE_MICROSEC_CLOCK) +ENDIF() + +######################################################################## # This file included, use CMake directory variables ######################################################################## LIBUHD_APPEND_SOURCES( diff --git a/host/lib/types/time_spec.cpp b/host/lib/types/time_spec.cpp index f39625a11..312c161cb 100644 --- a/host/lib/types/time_spec.cpp +++ b/host/lib/types/time_spec.cpp @@ -19,6 +19,73 @@ #include <boost/math/special_functions/round.hpp> using namespace uhd; + +/*********************************************************************** + * Time spec system time + **********************************************************************/ + +/*! + * Creates a time spec from system counts: + * TODO make part of API as a static factory function + * The counts type is 64 bits and will overflow the ticks type of long. + * Therefore, divmod the counts into seconds + sub-second counts first. + */ +#include <inttypes.h> //imaxdiv, intmax_t +static UHD_INLINE time_spec_t time_spec_t_from_counts(intmax_t counts, intmax_t freq){ + imaxdiv_t divres = imaxdiv(counts, freq); + return time_spec_t(time_t(divres.quot), double(divres.rem)/freq); +} + +#ifdef TIME_SPEC_USE_CLOCK_GETTIME +#include <time.h> +time_spec_t time_spec_t::get_system_time(void){ + timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); + return time_spec_t(ts.tv_sec, ts.tv_nsec, 1e9); +} +#endif /* TIME_SPEC_USE_CLOCK_GETTIME */ + + +#ifdef TIME_SPEC_USE_MACH_ABSOLUTE_TIME +#include <mach/mach_time.h> +static intmax_t get_freq(void){ + mach_timebase_info_data_t info; mach_timebase_info(&info); + return intmax_t(1e9*(double(info.denom)/double(info.numer))); +} +time_spec_t time_spec_t::get_system_time(void){ + static const intmax_t freq = get_freq(); + return time_spec_t_from_counts(mach_absolute_time(), freq); +} +#endif /* TIME_SPEC_USE_MACH_ABSOLUTE_TIME */ + + +#ifdef TIME_SPEC_USE_QUERY_PERFORMANCE_COUNTER +#include <Windows.h> +time_spec_t time_spec_t::get_system_time(void){ + LARGE_INTEGER counts, freq; + QueryPerformanceCounter(&counts); + QueryPerformanceFrequency(&freq); + return time_spec_t_from_counts(counts.QuadPart, freq.QuadPart); +} +#endif /* TIME_SPEC_USE_QUERY_PERFORMANCE_COUNTER */ + + +#ifdef TIME_SPEC_USE_MICROSEC_CLOCK +#include <boost/date_time/posix_time/posix_time.hpp> +namespace pt = boost::posix_time; +time_spec_t time_spec_t::get_system_time(void){ + pt::ptime time_now = pt::microsec_clock::universal_time(); + pt::time_duration time_dur = time_now - pt::from_time_t(0); + return time_spec_t( + time_t(time_dur.total_seconds()), + long(time_dur.fractional_seconds()), + double(pt::time_duration::ticks_per_second()) + ); +} +#endif /* TIME_SPEC_USE_MICROSEC_CLOCK */ + +/*********************************************************************** + * Time spec constructors + **********************************************************************/ time_spec_t::time_spec_t(double secs): _full_secs(0), _frac_secs(secs) @@ -40,6 +107,9 @@ time_spec_t::time_spec_t(time_t full_secs, long tick_count, double tick_rate): /* NOP */ } +/*********************************************************************** + * Time spec accessors + **********************************************************************/ long time_spec_t::get_tick_count(double tick_rate) const{ return boost::math::iround(this->get_frac_secs()*tick_rate); } @@ -58,6 +128,9 @@ double time_spec_t::get_frac_secs(void) const{ return std::fmod(this->_frac_secs, 1.0); } +/*********************************************************************** + * Time spec math overloads + **********************************************************************/ time_spec_t &time_spec_t::operator+=(const time_spec_t &rhs){ this->_full_secs += rhs.get_full_secs(); this->_frac_secs += rhs.get_frac_secs(); diff --git a/host/tests/time_spec_test.cpp b/host/tests/time_spec_test.cpp index 5ad782160..070392f93 100644 --- a/host/tests/time_spec_test.cpp +++ b/host/tests/time_spec_test.cpp @@ -18,6 +18,7 @@ #include <boost/test/unit_test.hpp> #include <uhd/types/time_spec.hpp> #include <boost/foreach.hpp> +#include <boost/thread.hpp> //sleep #include <iostream> BOOST_AUTO_TEST_CASE(test_time_spec_compare){ @@ -59,3 +60,21 @@ BOOST_AUTO_TEST_CASE(test_time_spec_parts){ BOOST_CHECK_CLOSE(uhd::time_spec_t(-1.1).get_frac_secs(), -0.1, 0.001); BOOST_CHECK_EQUAL(uhd::time_spec_t(-1.1).get_tick_count(100), -10); } + +BOOST_AUTO_TEST_CASE(test_time_spec_get_system_time){ + std::cout << "Testing time specification get system time..." << std::endl; + + //Not really checking for high resolution timing here, + //just need to check that system time is minimally working. + + uhd::time_spec_t start = uhd::time_spec_t::get_system_time(); + boost::this_thread::sleep(boost::posix_time::milliseconds(500)); + uhd::time_spec_t stop = uhd::time_spec_t::get_system_time(); + + uhd::time_spec_t diff = stop - start; + std::cout << "start: " << start.get_real_secs() << std::endl; + std::cout << "stop: " << stop.get_real_secs() << std::endl; + std::cout << "diff: " << diff.get_real_secs() << std::endl; + BOOST_CHECK(diff.get_real_secs() > 0); //assert positive + BOOST_CHECK(diff.get_real_secs() < 1.0); //assert under 1s +} |