Commit d30346d5 authored by Jussi Lindgren's avatar Jussi Lindgren
Browse files

Modules: Refactored often-used time conversion to a function

- Code cleanup
parent 474be03f
......@@ -11,7 +11,7 @@
#if defined(TARGET_HAS_Boost_Chrono)
#define OV_BOOST_CHRONO_TIME // Use timing routines based on boost::chrono.
#else
#define OV_CLASSIC_TIME // Use the 'classic' openvibe timing routines.
#define OV_CLASSIC_TIME // Use the 'classic' openvibe timing routines. deprecated, should be removed after a transition period.
#endif
#if defined(OV_BOOST_CHRONO_TIME)
......@@ -36,6 +36,12 @@
#define uint32 System::uint32
#define uint64 System::uint64
// From ITimeArithmetics
static uint64 subsecondsToTime(const uint64 ui64Seconds, const uint64 ui64Subseconds, const uint64 ui64SubsInSecond)
{
return (ui64Seconds << 32) + (ui64Subseconds << 32) / ui64SubsInSecond;
}
#if defined(OV_CLASSIC_TIME)
boolean System::Time::sleep(const uint32 ui32MilliSeconds)
......@@ -78,7 +84,7 @@ namespace
QueryPerformanceCounter(&l_oPerformanceCounter);
l_ui64Counter=l_oPerformanceCounter.QuadPart-l_ui64CounterStart;
l_ui64Result=((l_ui64Counter/l_ui64Frequency)<<32)+(((l_ui64Counter%l_ui64Frequency)<<32)/l_ui64Frequency);
l_ui64Result=subsecondsToTime(l_ui64Counter/l_ui64Frequency, l_ui64Counter%l_ui64Frequency, l_ui64Frequency);
return l_ui64Result;
}
......@@ -97,7 +103,7 @@ namespace
uint64 l_ui64Counter;
l_ui64Counter=uint64(timeGetTime());
l_ui64Counter=((l_ui64Counter/1000)<<32)+(((l_ui64Counter%1000)<<32)/1000);
l_ui64Counter=subsecondsToTime(l_ui64Counter/1000, l_ui64Counter%1000, 1000);
if(!l_bInitialized)
{
......@@ -206,7 +212,9 @@ uint64 System::Time::zgetTime(void)
l_i64TimeMicroSecond+=l_i64SecDiff*1000000;
l_i64TimeMicroSecond+=l_i64USecDiff;
l_ui64Result=((l_i64TimeMicroSecond/1000000)<<32)+(((l_i64TimeMicroSecond%1000000)<<32)/1000000);
const uint64 l_ui64MicrosInSecond = 1000*1000;
l_ui64Result=subsecondsToTime(l_i64TimeMicroSecond/l_ui64MicrosInSecond, l_i64TimeMicroSecond % l_ui64MicrosInSecond, l_ui64MicrosInSecond);
return l_ui64Result;
}
......@@ -278,7 +286,7 @@ uint64 System::Time::zgetTime(void)
const uint64_t l_ui64Fraction = l_oElapsedMs.count() % l_ui64MicrosPerSecond;
// below in fraction part, scale [0,l_ui64MicrosPerSecond-1] to 32bit integer range
const uint64_t l_ui64ReturnValue = (l_ui64Seconds<<32) + l_ui64Fraction*(0xFFFFFFFFLL / (l_ui64MicrosPerSecond-1) );
const uint64_t l_ui64ReturnValue = subsecondsToTime(l_ui64Seconds, l_ui64Fraction, l_ui64MicrosPerSecond);
return l_ui64ReturnValue;
}
......
......@@ -53,6 +53,12 @@ using namespace std;
namespace OpenViBE {
class ITimeArithmetics {
public:
// From ITimeArithmetics
static uint64_t subsecondsToTime(const uint64_t ui64Seconds, const uint64_t ui64Subseconds, const uint64_t ui64SubsInSecond)
{
return (ui64Seconds << 32) + (ui64Subseconds << 32) / ui64SubsInSecond;
}
static double timeToSeconds(const uint64_t ui64Time)
{
return (ui64Time>>m_ui32Shift)/double(m_ui32Multiplier);
......@@ -106,8 +112,8 @@ static uint64_t zgetTime1(void)
LARGE_INTEGER l_oPerformanceCounter;
QueryPerformanceCounter(&l_oPerformanceCounter);
l_ui64Counter=l_oPerformanceCounter.QuadPart-l_ui64CounterStart;
l_ui64Result=((l_ui64Counter/l_ui64Frequency)<<32)+(((l_ui64Counter%l_ui64Frequency)<<32)/l_ui64Frequency);
l_ui64Result=OpenViBE::ITimeArithmetics::subsecondsToTime(l_ui64Counter/l_ui64Frequency, l_ui64Counter%l_ui64Frequency, l_ui64Frequency);
return l_ui64Result;
}
......@@ -126,7 +132,7 @@ static uint64_t zgetTime2(void)
uint64_t l_ui64Counter;
l_ui64Counter=uint64_t(timeGetTime());
l_ui64Counter=((l_ui64Counter/1000)<<32)+(((l_ui64Counter%1000)<<32)/1000);
l_ui64Counter=OpenViBE::ITimeArithmetics::subsecondsToTime(l_ui64Counter/1000, l_ui64Counter%1000, 1000);
if(!l_bInitialized)
{
......@@ -214,10 +220,12 @@ uint64_t zgetTime(void)
uint64_t l_ui64SecDiff=(uint64_t)(l_oTimeValue.tv_sec-l_oTimeValueStart.tv_sec);
uint64_t l_ui64USecDiff=(uint64_t)(l_oTimeValue.tv_usec-l_oTimeValueStart.tv_usec);
l_ui64TimeMicroSecond+=l_ui64SecDiff*1000000;
const uint64_t l_ui64MicrosInSecond = 1000*1000;
l_ui64TimeMicroSecond+=l_ui64SecDiff*l_ui64MicrosInSecond;
l_ui64TimeMicroSecond+=l_ui64USecDiff;
uint64_t l_ui64Result=((l_ui64TimeMicroSecond/1000000)<<32)+(((l_ui64TimeMicroSecond%1000000)<<32)/1000000);
uint64_t l_ui64Result=OpenViBE::ITimeArithmetics::subsecondsToTime(l_ui64TimeMicroSecond/l_ui64MicrosInSecond, l_ui64TimeMicroSecond % l_ui64MicrosInSecond, l_ui64MicrosInSecond);
return l_ui64Result;
#endif
......@@ -237,11 +245,11 @@ uint64_t getSystemTime(void)
static const uint64_t l_ui64IntervalsPerSecond = 10*1000*1000; // 100ns -> ms -> s
uint64_t seconds = ll_now / l_ui64IntervalsPerSecond;
uint64_t fraction = ll_now % l_ui64IntervalsPerSecond;
const uint64_t seconds = ll_now / l_ui64IntervalsPerSecond;
const uint64_t fraction = ll_now % l_ui64IntervalsPerSecond;
// below in fraction part, scale [0,l_uiIntervalsPerSecond-1] to 32bit integer range
return (seconds<<32) + fraction*(0xFFFFFFFF/l_ui64IntervalsPerSecond);
return OpenViBE::ITimeArithmetics::subsecondsToTime(seconds, fraction, l_ui64IntervalsPerSecond);
}
#endif // TARGET_OS_Windows
......@@ -264,7 +272,7 @@ uint64_t getBoostTime(void)
const uint64_t fraction = micros % l_ui64MicrosPerSecond;
// below in fraction part, scale [0,l_ui64MicrosPerSecond-1] to 32bit integer range
const uint64_t retVal = (seconds<<32) + fraction*(0xFFFFFFFF / (l_ui64MicrosPerSecond-1) );
const uint64_t retVal = OpenViBE::ITimeArithmetics::subsecondsToTime(seconds, fraction, l_ui64MicrosPerSecond);
return retVal;
}
......@@ -296,7 +304,7 @@ uint64_t getBoostChronoTime(void)
const uint64_t fraction = l_oElapsedMs.count() % l_ui64MicrosPerSecond;
// below in fraction part, scale [0,l_ui64MicrosPerSecond-1] to 32bit integer range
const uint64_t retVal = (seconds<<32) + fraction*(0xFFFFFFFFLL / (l_ui64MicrosPerSecond-1) );
const uint64_t retVal = OpenViBE::ITimeArithmetics::subsecondsToTime(seconds, fraction, l_ui64MicrosPerSecond);
return retVal;
}
......@@ -352,7 +360,7 @@ uint64_t getFTime(void)
const uint64_t fraction = l_ui64ElapsedMs % l_ui64MillisPerSecond;
// below in fraction part, scale [0,l_ui64MicrosPerSecond-1] to 32bit integer range
const uint64_t retVal = (seconds<<32) + fraction*(0xFFFFFFFF/l_ui64MillisPerSecond);
const uint64_t retVal = OpenViBE::ITimeArithmetics::subsecondsToTime(seconds, fraction, l_ui64MillisPerSecond);
return retVal;
......@@ -506,9 +514,8 @@ int main(int argc, char** argv)
spinTest("ovCTime", ovGetTime);
#if defined(TARGET_HAS_Boost_Chrono)
spinTest("boost::chrono", getBoostChronoTime);
#else
spinTest("zgetTime", zgetTime);
#endif
spinTest("zgetTime", zgetTime);
#if defined(TARGET_OS_Windows)
spinTest("ftime", getFTime);
#endif
......@@ -528,7 +535,7 @@ int main(int argc, char** argv)
std::vector<Clock> l_vClocks;
l_vClocks.push_back(Clock("ovCTime", System::Time::zgetTime)); // the first clock controls the duration of the test
l_vClocks.push_back(Clock("ovCTime", ovGetTime)); // the first clock controls the duration of the test
#if defined(TARGET_HAS_Boost_Chrono)
l_vClocks.push_back(Clock("BoostChronoTime", getBoostChronoTime));
#endif
......@@ -540,8 +547,8 @@ int main(int argc, char** argv)
l_vClocks.push_back(Clock("zgetTime2", zgetTime2));
l_vClocks.push_back(Clock("ftime", getFTime));
#endif
#define USE_NTP
#if defined(USE_NTP)
// #define OV_TEST_USE_NTP
#if defined(OV_TEST_USE_NTP)
l_vClocks.push_back(Clock("NTP", getNTPTime));
// NTP clock needs a moment to complete the poll, call once to start
getNTPTime();
......
......@@ -65,6 +65,16 @@ namespace OpenViBE
return ((uint64)(f64Time*double(m_ui32Multiplier)))<<m_ui32Shift;
}
// \brief Convert seconds and subseconds pair to fixed point
// \param ui64Seconds : Number of seconds
// \param ui64Subseconds : Number of subseconds
// \param ui64SubsInSecond : Maximum subseconds in a second (e.g. 1000*1000 if subseconds are microseconds, 1000 for millis)
// \return Time in fixed point format
static uint64 subsecondsToTime(const uint64 ui64Seconds, const uint64 ui64Subseconds, const uint64 ui64SubsInSecond)
{
return (ui64Seconds << 32) + (ui64Subseconds << 32) / ui64SubsInSecond;
}
// Increase m_ui32DecimalPrecision to get more precision in decimals for timeToSeconds() and secondsToTime().
// The default value of 10 bits suffices for (1/2^10)s=(1/1024)s precision in time, i.e. a bit under 1ms.
// Using higher sampling rates than 1024hz would require a correspondingly higher decimal precision.
......
......@@ -7,6 +7,7 @@
#include <iomanip>
#include <cstdlib> // abs() on Linux
#include <bitset>
#include <vector>
#include <openvibe/ovITimeArithmetics.h>
......@@ -408,7 +409,7 @@ int main(int argc, char *argv[])
//
// 1ms obtained by (1LL<<32)/1000LL is 0x418937 -> about 2x difference to method 1
// 1ms obtained by ov secondstoTime is 0x400000
// 1ms obtained by (2^32/1000 is 4294967.296 = 0x418937 + 0.296
// 1ms obtained by (2^32)/1000 is 4294967.296 = 0x418937 + 0.296
// 1ms obtained by (2^32-1)/1000 is 4294967.295 = 0x418937 + 0.295
//
......@@ -456,5 +457,36 @@ int main(int argc, char *argv[])
std::cout << ITimeArithmetics::timeToSeconds(test3) << "->" << ITimeArithmetics::timeToSeconds(test3/10) << "\n";
*/
// Fraction test, converting <secs,ms> pair to 32:32 fixed point
const uint64 microsInSecond = 1000*1000;
std::vector< std::pair<uint64,uint64> > tmp;
tmp.push_back(std::pair<uint64,uint64>(0LL,0LL)); // 0s
tmp.push_back(std::pair<uint64,uint64>(0LL,1LL)); // 1s + 1us
tmp.push_back(std::pair<uint64,uint64>(0LL,2LL));
tmp.push_back(std::pair<uint64,uint64>(0LL,(microsInSecond / 2LL))); // 500ms
tmp.push_back(std::pair<uint64,uint64>(0LL,microsInSecond-2));
tmp.push_back(std::pair<uint64,uint64>(0LL,microsInSecond-1)); // 1 step below 1s
tmp.push_back(std::pair<uint64,uint64>(1LL,0LL)); // 1s
tmp.push_back(std::pair<uint64,uint64>(1LL,1LL)); // 1 step above 1s
tmp.push_back(std::pair<uint64,uint64>(0LL,microsInSecond+1)); // same as (1LL,1LL), but shouldn't happen as micro fraction is meant to be capped under 1s
tmp.push_back(std::pair<uint64,uint64>(1LL,2LL));
tmp.push_back(std::pair<uint64,uint64>(1LL,1000LL)); // 1s + 1ms
tmp.push_back(std::pair<uint64,uint64>(1LL,2000LL)); // 1s + 2ms
for(size_t i=0;i<tmp.size();i++)
{
const uint64 l_ui64FixedPoint = ITimeArithmetics::subsecondsToTime(tmp[i].first, tmp[i].second, microsInSecond);
cout << "m9 pair (" << tmp[i].first << "s, " << tmp[i].second << "us) as float="
<< ITimeArithmetics::timeToSeconds( l_ui64FixedPoint ) << "s, parts secs="
<< (l_ui64FixedPoint>>32) << " fract=" << (l_ui64FixedPoint & 0xFFFFFFFFLL) << "\n";
}
// These should be approx equal
cout << "m9 Diff 1 " << ITimeArithmetics::subsecondsToTime(tmp[1].first,tmp[1].second,microsInSecond)-ITimeArithmetics::subsecondsToTime(tmp[0].first,tmp[0].second,microsInSecond) << "\n";
cout << "m9 Diff 1 " << ITimeArithmetics::subsecondsToTime(tmp[6].first,tmp[6].second,microsInSecond)-ITimeArithmetics::subsecondsToTime(tmp[5].first,tmp[5].second,microsInSecond) << "\n";
cout << "m9 Diff 1 " << ITimeArithmetics::subsecondsToTime(tmp[7].first,tmp[7].second,microsInSecond)-ITimeArithmetics::subsecondsToTime(tmp[6].first,tmp[6].second,microsInSecond) << "\n";
return retVal;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment