From: frohlich Date: Thu, 12 Mar 2009 18:34:07 +0000 (+0000) Subject: Make use of posix clocks if available. X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=f1f0fa0aa95c2f1562fa9c09365baf8b2b55bfc7;p=simgear.git Make use of posix clocks if available. Have a more general timestamp implementation. Very useful for higher accuracy timings. Modified Files: simgear/structure/subsystem_mgr.cxx simgear/structure/subsystem_mgr.hxx simgear/timing/testtimestamp.cxx simgear/timing/timestamp.cxx simgear/timing/timestamp.hxx --- diff --git a/simgear/structure/subsystem_mgr.cxx b/simgear/structure/subsystem_mgr.cxx index 8109f411..1385d8ea 100644 --- a/simgear/structure/subsystem_mgr.cxx +++ b/simgear/structure/subsystem_mgr.cxx @@ -74,29 +74,27 @@ SGSubsystem::is_suspended () const void SGSubsystem::printTimingInformation () { - SGTimeStamp startTime, endTime; - long duration; + SGTimeStamp startTime; for ( eventTimeVecIterator i = timingInfo.begin(); i != timingInfo.end(); i++) { if (i == timingInfo.begin()) { startTime = i->getTime(); } else { - endTime = i->getTime(); - duration = (endTime - startTime); + SGTimeStamp endTime = i->getTime(); + SG_LOG(SG_GENERAL, SG_ALERT, "- Getting to timestamp : " + << i->getName() << " takes " << endTime - startTime + << " sec."); startTime = endTime; - SG_LOG(SG_GENERAL, SG_ALERT, "- Getting to timestamp : " << i->getName() << " takes " << duration << " usec."); } } } -void SGSubsystem::stamp(string name) +void SGSubsystem::stamp(const string& name) { - SGTimeStamp now; - now.stamp(); - timingInfo.push_back(TimingInfo(name, now)); + timingInfo.push_back(TimingInfo(name, SGTimeStamp::now())); } @@ -157,11 +155,10 @@ SGSubsystemGroup::update (double delta_time_sec) { for (unsigned int i = 0; i < _members.size(); i++) { - SGTimeStamp start, now; - start.stamp(); + SGTimeStamp timeStamp = SGTimeStamp::now(); _members[i]->update(delta_time_sec); // indirect call - now.stamp(); - long b = ( now - start ); + timeStamp = timeStamp - SGTimeStamp::now(); + double b = timeStamp.toUSecs(); _members[i]->updateExecutionTime(b); double threshold = _members[i]->getTimeWarningThreshold(); if (( b > threshold ) && (b > 10000)) { diff --git a/simgear/structure/subsystem_mgr.hxx b/simgear/structure/subsystem_mgr.hxx index 63cad43e..a751d306 100644 --- a/simgear/structure/subsystem_mgr.hxx +++ b/simgear/structure/subsystem_mgr.hxx @@ -45,9 +45,11 @@ private: SGTimeStamp time; public: - TimingInfo(string name, SGTimeStamp &t) { eventName = name; time = t;}; - string getName() { return eventName; }; - SGTimeStamp getTime() { return time; }; + TimingInfo(const string& name, const SGTimeStamp &t) : + eventName(name), time(t) + { } + const string& getName() const { return eventName; } + const SGTimeStamp& getTime() const { return time; } }; typedef vector eventTimeVec; @@ -271,7 +273,7 @@ public: * Place time stamps at strategic points in the execution of subsystems * update() member functions. Predominantly for debugging purposes. */ - void stamp(string name); + void stamp(const string& name); diff --git a/simgear/timing/testtimestamp.cxx b/simgear/timing/testtimestamp.cxx index 88abc504..1c49d101 100755 --- a/simgear/timing/testtimestamp.cxx +++ b/simgear/timing/testtimestamp.cxx @@ -14,7 +14,7 @@ int main() do { nb += 1; now.stamp(); - } while ( ( now - start ) < 5000000 ); + } while ( ( now - start ).toMicroSeconds() < 5000000 ); cout << ( nb / 5 ) << " iterations per seconds. Press ENTER to quit." << endl; c = cin.get(); diff --git a/simgear/timing/timestamp.cxx b/simgear/timing/timestamp.cxx index f2eefcf5..4d14a42a 100644 --- a/simgear/timing/timestamp.cxx +++ b/simgear/timing/timestamp.cxx @@ -36,12 +36,17 @@ # include // for ftime() and struct timeb #endif #ifdef HAVE_UNISTD_H -# include // for gettimeofday() +# include // for gettimeofday() and the _POSIX_TIMERS define #endif #ifdef HAVE_SYS_TIME_H # include // for get/setitimer, gettimeofday, struct timeval #endif +#if defined(_POSIX_TIMERS) && (0 < _POSIX_TIMERS) +# include +# include +#endif + #ifdef WIN32 # include # if defined( __CYGWIN__ ) || defined( __CYGWIN32__ ) @@ -53,43 +58,49 @@ #include "timestamp.hxx" - void SGTimeStamp::stamp() { #if defined( WIN32 ) && !defined(__CYGWIN__) unsigned int t; t = timeGetTime(); - seconds = t / 1000; - usec = ( t - ( seconds * 1000 ) ) * 1000; + _sec = t / 1000; + _nsec = ( t - ( seconds * 1000 ) ) * 1000 * 1000; +#elif defined(_POSIX_TIMERS) && (0 < _POSIX_TIMERS) + struct timespec ts; +#if defined(_POSIX_MONOTONIC_CLOCK) + static clockid_t clockid = CLOCK_MONOTONIC; + static bool firstTime = true; + if (firstTime) { + firstTime = false; + // For the first time test if the monotonic clock is available. + // If so use this if not use the realtime clock. + if (-1 == clock_gettime(clockid, &ts) && errno == EINVAL) + clockid = CLOCK_REALTIME; + } + clock_gettime(clockid, &ts); +#else + clock_gettime(CLOCK_REALTIME, &ts); +#endif + _sec = ts.tv_sec; + _nsec = ts.tv_nsec; #elif defined( HAVE_GETTIMEOFDAY ) struct timeval current; struct timezone tz; // sg_timestamp currtime; gettimeofday(¤t, &tz); - seconds = current.tv_sec; - usec = current.tv_usec; + _sec = current.tv_sec; + _nsec = current.tv_usec * 1000; #elif defined( HAVE_GETLOCALTIME ) SYSTEMTIME current; GetLocalTime(¤t); - seconds = current.wSecond; - usec = current.wMilliseconds * 1000; + _sec = current.wSecond; + _nsec = current.wMilliseconds * 1000 * 1000; #elif defined( HAVE_FTIME ) struct timeb current; ftime(¤t); - seconds = current.time; - usec = current.millitm * 1000; + _sec = current.time; + _nsec = current.millitm * 1000 * 1000; #else # error Port me #endif } -// increment the time stamp by the number of microseconds (usec) -SGTimeStamp operator + (const SGTimeStamp& t, const long& m) { - return SGTimeStamp( t.seconds + ( t.usec + m ) / 1000000, - ( t.usec + m ) % 1000000 ); -} - -// difference between time stamps in microseconds (usec) -long operator - (const SGTimeStamp& a, const SGTimeStamp& b) -{ - return 1000000 * (a.seconds - b.seconds) + (a.usec - b.usec); -} diff --git a/simgear/timing/timestamp.hxx b/simgear/timing/timestamp.hxx index c14ab6f9..7b417a84 100644 --- a/simgear/timing/timestamp.hxx +++ b/simgear/timing/timestamp.hxx @@ -32,81 +32,243 @@ # error This library requires C++ #endif - +#include +#include +#include #include - - -// MSVC++ 6.0 kuldge - Need forward declaration of friends. -class SGTimeStamp; -SGTimeStamp operator + (const SGTimeStamp& t, const long& m); -long operator - (const SGTimeStamp& a, const SGTimeStamp& b); +#include /** * The SGTimeStamp class allows you to mark and compare time stamps - * with microsecond accuracy (if your system has support for this - * level of accuracy.) + * with nanosecond accuracy (if your system has support for this + * level of accuracy). * * The SGTimeStamp is useful for tracking the elapsed time of various * events in your program. You can also use it to keep constistant * motion across varying frame rates. + * + * Note SGTimestamp does not deliver the time of day. The content of this + * stamps might be, dependent on the implementation, a time to an arbitrary + * base time. */ class SGTimeStamp { +public: + typedef long sec_type; + typedef int nsec_type; -private: + /** Default constructor, initialize time to zero. */ + SGTimeStamp() : + _sec(0), + _nsec(0) + { } - long seconds; - long usec; + /** Hmm, might reenable them at some time, but since it is not clear + what the input unit of the int is, omit them for now. + Use the static constructor functions where it is clear from the method + name how the arguments are meant. + */ +// SGTimeStamp(sec_type sec) +// { setTime(sec, 0); } +// SGTimeStamp(int sec) +// { setTime(sec, 0); } +// SGTimeStamp(const double& sec) +// { setTime(sec); } -public: + /** Update stored time to current time (seconds and nanoseconds) */ + void stamp(); - /** Default constructor */ - SGTimeStamp(); + /** Set the time from a double value */ + void setTime(const double& seconds) + { + sec_type wholeSecs = sec_type(floor(seconds)); + nsec_type reminder; + reminder = nsec_type(floor((seconds - wholeSecs)*(1000*1000*1000))); + setTime(wholeSecs, reminder); + } + /** Set the time from a seconds/nanoseconds pair */ + void setTime(sec_type sec, nsec_type nsec) + { + if (0 <= nsec) { + _sec = sec + nsec / (1000*1000*1000); + _nsec = nsec % (1000*1000*1000); + } else { + _sec = sec - 1 + nsec / (1000*1000*1000); + _nsec = (1000*1000*1000) + nsec % (1000*1000*1000); + } + } - /** - * This creates an instance of the SGTimeStamp object. When - * calling the constructor you may provide initial seconds an - * microseconds values. - * @param s initial seconds value - * @param m initial microseconds value + + /** @return the saved seconds of this time stamp */ + long get_seconds() const { return _sec; } + + /** @return the saved microseconds of this time stamp */ + int get_usec() const { return _nsec/1000; } + + /** @return the saved seconds of this time stamp */ + const sec_type& getSeconds() const + { return _sec; } + /** @return the saved nanoseconds of this time stamp */ + const nsec_type& getNanoSeconds() const + { return _nsec; } + + /** @return the value of the timestamp in nanoseconds, + * use doubles to avoid overflow. + * If you need real nanosecond accuracy for time differences, build up a + * SGTimeStamp reference time and compare SGTimeStamps directly. */ - SGTimeStamp( const long s, const long m ); + double toNSecs() const + { return _nsec + double(_sec)*1000*1000*1000; } - /** Update stored time to current time (seconds and microseconds) */ - void stamp(); + /** @return the value of the timestamp in microseconds, + * use doubles to avoid overflow. + * If you need real nanosecond accuracy for time differences, build up a + * SGTimeStamp reference time and compare SGTimeStamps directly. + */ + double toUSecs() const + { return 1e-3*_nsec + double(_sec)*1000*1000; } + + /** @return the value of the timestamp in milliseconds, + * use doubles to avoid overflow. + * If you need real nanosecond accuracy for time differences, build up a + * SGTimeStamp reference time and compare SGTimeStamps directly. + */ + double toMSecs() const + { return 1e-6*_nsec + double(_sec)*1000; } + + /** @return the value of the timestamp in seconds, + * use doubles to avoid overflow. + * If you need real nanosecond accuracy for time differences, build up a + * SGTimeStamp reference time and compare SGTimeStamps directly. + */ + double toSecs() const + { return 1e-9*_nsec + _sec; } + + /** Inplace addition. + */ + SGTimeStamp& operator+=(const SGTimeStamp& c) + { + _sec += c._sec; + _nsec += c._nsec; + if ((1000*1000*1000) <= _nsec) { + _nsec -= (1000*1000*1000); + _sec += 1; + } + return *this; + } + + /** Inplace subtraction. + */ + SGTimeStamp& operator-=(const SGTimeStamp& c) + { + _sec -= c._sec; + _nsec -= c._nsec; + if (_nsec < 0) { + _nsec += (1000*1000*1000); + _sec -= 1; + } + return *this; + } /** - * Increment the saved time by the specified number of microseconds - * @param t time stamp - * @param m microseconds increment - * @return new time stamp + * Create SGTimeStamps from input with given units */ - friend SGTimeStamp operator + (const SGTimeStamp& t, const long& m); + static SGTimeStamp fromSecMSec(sec_type sec, nsec_type msec) + { return SGTimeStamp(sec, 1000*1000*msec); } + static SGTimeStamp fromSecUSec(sec_type sec, nsec_type usec) + { return SGTimeStamp(sec, 1000*usec); } + static SGTimeStamp fromSecNSec(sec_type sec, nsec_type nsec) + { return SGTimeStamp(sec, nsec); } + + static SGTimeStamp fromSec(int sec) + { SGTimeStamp ts; ts.setTime(sec); return ts; } + static SGTimeStamp fromSec(const double& sec) + { SGTimeStamp ts; ts.setTime(sec); return ts; } + static SGTimeStamp fromUSec(nsec_type usec) + { return SGTimeStamp(0, 1000*usec); } + static SGTimeStamp fromNSec(nsec_type nsec) + { return SGTimeStamp(0, nsec); } /** - * Subtract two time stamps returning the difference in microseconds. - * @param a timestamp 1 - * @param b timestame 2 - * @return difference in microseconds + * Return a timestamp with the current time. */ - friend long operator - (const SGTimeStamp& a, const SGTimeStamp& b); + static SGTimeStamp now() + { SGTimeStamp ts; ts.stamp(); return ts; } - /** @return the saved seconds of this time stamp */ - inline long get_seconds() const { return seconds; } +private: + SGTimeStamp(sec_type sec, nsec_type nsec) + { setTime(sec, nsec); } - /** @return the saved microseconds of this time stamp */ - inline long get_usec() const { return usec; } + nsec_type _nsec; + sec_type _sec; }; -inline SGTimeStamp::SGTimeStamp() : - seconds(0), - usec(0) +inline bool +operator==(const SGTimeStamp& c1, const SGTimeStamp& c2) +{ + if (c1.getNanoSeconds() != c2.getNanoSeconds()) + return false; + return c1.getSeconds() == c2.getSeconds(); +} + +inline bool +operator!=(const SGTimeStamp& c1, const SGTimeStamp& c2) +{ return !operator==(c1, c2); } + +inline bool +operator<(const SGTimeStamp& c1, const SGTimeStamp& c2) { + if (c1.getSeconds() < c2.getSeconds()) + return true; + if (c1.getSeconds() > c2.getSeconds()) + return false; + return c1.getNanoSeconds() < c2.getNanoSeconds(); } -inline SGTimeStamp::SGTimeStamp( const long s, const long u ) { - seconds = s; - usec = u; +inline bool +operator>(const SGTimeStamp& c1, const SGTimeStamp& c2) +{ return c2 < c1; } + +inline bool +operator>=(const SGTimeStamp& c1, const SGTimeStamp& c2) +{ return !(c1 < c2); } + +inline bool +operator<=(const SGTimeStamp& c1, const SGTimeStamp& c2) +{ return !(c1 > c2); } + +inline SGTimeStamp +operator+(const SGTimeStamp& c1) +{ return c1; } + +inline SGTimeStamp +operator-(const SGTimeStamp& c1) +{ return SGTimeStamp::fromSec(0) -= c1; } + +inline SGTimeStamp +operator+(const SGTimeStamp& c1, const SGTimeStamp& c2) +{ return SGTimeStamp(c1) += c2; } + +inline SGTimeStamp +operator-(const SGTimeStamp& c1, const SGTimeStamp& c2) +{ return SGTimeStamp(c1) -= c2; } + +template +inline +std::basic_ostream& +operator<<(std::basic_ostream& os, const SGTimeStamp& c) +{ + std::basic_stringstream stream; + + SGTimeStamp pos = c; + if (c.getSeconds() < 0) { + stream << stream.widen('-'); + pos = - c; + } + stream << pos.getSeconds() << stream.widen('.'); + stream << std::setw(9) << std::setfill('0') << pos.getNanoSeconds(); + + return os << stream.str(); } #endif // _TIMESTAMP_HXX