]> git.mxchange.org Git - simgear.git/commitdiff
Make use of posix clocks if available.
authorfrohlich <frohlich>
Thu, 12 Mar 2009 18:34:07 +0000 (18:34 +0000)
committerTim Moore <timoore@redhat.com>
Wed, 18 Mar 2009 06:53:49 +0000 (07:53 +0100)
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

simgear/structure/subsystem_mgr.cxx
simgear/structure/subsystem_mgr.hxx
simgear/timing/testtimestamp.cxx
simgear/timing/timestamp.cxx
simgear/timing/timestamp.hxx

index 8109f41132b6397802308b60ac1b2c6ed54aa985..1385d8eab493a5181e2b94f837be431bfeb22eb4 100644 (file)
@@ -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()));
 }
 
 \f
@@ -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)) {
index 63cad43e769121515d3b0c6321365a2cd57bff77..a751d30699426c14561447c1acbd741e78421384 100644 (file)
@@ -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<TimingInfo> 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);
   
 
 
index 88abc50486a02b11cca8692cc83218ff48a15176..1c49d1018a15ee5876292b4e3266f0d9dcc88bae 100755 (executable)
@@ -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();
index f2eefcf583e5ab7db544921e8baadb72d0b7ce1f..4d14a42acc16ed733b54b80d3fe76c26bd222383 100644 (file)
 #  include <sys/timeb.h> // for ftime() and struct timeb
 #endif
 #ifdef HAVE_UNISTD_H
-#  include <unistd.h>    // for gettimeofday()
+#  include <unistd.h>    // for gettimeofday() and the _POSIX_TIMERS define
 #endif
 #ifdef HAVE_SYS_TIME_H
 #  include <sys/time.h>  // for get/setitimer, gettimeofday, struct timeval
 #endif
 
+#if defined(_POSIX_TIMERS) && (0 < _POSIX_TIMERS)
+#  include <time.h>
+#  include <errno.h>
+#endif
+
 #ifdef WIN32
 #  include <windows.h>
 #  if defined( __CYGWIN__ ) || defined( __CYGWIN32__ )
 
 #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(&current, &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(&current);
-    seconds = current.wSecond;
-    usec = current.wMilliseconds * 1000;
+    _sec = current.wSecond;
+    _nsec = current.wMilliseconds * 1000 * 1000;
 #elif defined( HAVE_FTIME )
     struct timeb current;
     ftime(&current);
-    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);
-}
index c14ab6f9f11ed7c6b07965180ee26d81c27b8231..7b417a84de27a7b389141f8c93a6c5c9296210bc 100644 (file)
 # error This library requires C++
 #endif
 
-
+#include <iosfwd>
+#include <iomanip>
+#include <sstream>
 #include <simgear/compiler.h>
-
-
-// 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 <simgear/math/SGCMath.hxx>
 
 /**
  * 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<typename char_type, typename traits_type> 
+inline
+std::basic_ostream<char_type, traits_type>&
+operator<<(std::basic_ostream<char_type, traits_type>& os, const SGTimeStamp& c)
+{
+  std::basic_stringstream<char_type, traits_type> 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