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 +} | 
