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
This commit is contained in:
frohlich
2009-03-18 07:53:49 +01:00
committed by Tim Moore
parent deef158822
commit f1f0fa0aa9
5 changed files with 259 additions and 87 deletions
+10 -13
View File
@@ -74,29 +74,27 @@ SGSubsystem::is_suspended () const
void void
SGSubsystem::printTimingInformation () SGSubsystem::printTimingInformation ()
{ {
SGTimeStamp startTime, endTime; SGTimeStamp startTime;
long duration;
for ( eventTimeVecIterator i = timingInfo.begin(); for ( eventTimeVecIterator i = timingInfo.begin();
i != timingInfo.end(); i != timingInfo.end();
i++) { i++) {
if (i == timingInfo.begin()) { if (i == timingInfo.begin()) {
startTime = i->getTime(); startTime = i->getTime();
} else { } else {
endTime = i->getTime(); SGTimeStamp endTime = i->getTime();
duration = (endTime - startTime); SG_LOG(SG_GENERAL, SG_ALERT, "- Getting to timestamp : "
<< i->getName() << " takes " << endTime - startTime
<< " sec.");
startTime = endTime; 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; timingInfo.push_back(TimingInfo(name, SGTimeStamp::now()));
now.stamp();
timingInfo.push_back(TimingInfo(name, now));
} }
@@ -157,11 +155,10 @@ SGSubsystemGroup::update (double delta_time_sec)
{ {
for (unsigned int i = 0; i < _members.size(); i++) for (unsigned int i = 0; i < _members.size(); i++)
{ {
SGTimeStamp start, now; SGTimeStamp timeStamp = SGTimeStamp::now();
start.stamp();
_members[i]->update(delta_time_sec); // indirect call _members[i]->update(delta_time_sec); // indirect call
now.stamp(); timeStamp = timeStamp - SGTimeStamp::now();
long b = ( now - start ); double b = timeStamp.toUSecs();
_members[i]->updateExecutionTime(b); _members[i]->updateExecutionTime(b);
double threshold = _members[i]->getTimeWarningThreshold(); double threshold = _members[i]->getTimeWarningThreshold();
if (( b > threshold ) && (b > 10000)) { if (( b > threshold ) && (b > 10000)) {
+6 -4
View File
@@ -45,9 +45,11 @@ private:
SGTimeStamp time; SGTimeStamp time;
public: public:
TimingInfo(string name, SGTimeStamp &t) { eventName = name; time = t;}; TimingInfo(const string& name, const SGTimeStamp &t) :
string getName() { return eventName; }; eventName(name), time(t)
SGTimeStamp getTime() { return time; }; { }
const string& getName() const { return eventName; }
const SGTimeStamp& getTime() const { return time; }
}; };
typedef vector<TimingInfo> eventTimeVec; typedef vector<TimingInfo> eventTimeVec;
@@ -271,7 +273,7 @@ public:
* Place time stamps at strategic points in the execution of subsystems * Place time stamps at strategic points in the execution of subsystems
* update() member functions. Predominantly for debugging purposes. * update() member functions. Predominantly for debugging purposes.
*/ */
void stamp(string name); void stamp(const string& name);
+1 -1
View File
@@ -14,7 +14,7 @@ int main()
do { do {
nb += 1; nb += 1;
now.stamp(); now.stamp();
} while ( ( now - start ) < 5000000 ); } while ( ( now - start ).toMicroSeconds() < 5000000 );
cout << ( nb / 5 ) << " iterations per seconds. Press ENTER to quit." << endl; cout << ( nb / 5 ) << " iterations per seconds. Press ENTER to quit." << endl;
c = cin.get(); c = cin.get();
+32 -21
View File
@@ -36,12 +36,17 @@
# include <sys/timeb.h> // for ftime() and struct timeb # include <sys/timeb.h> // for ftime() and struct timeb
#endif #endif
#ifdef HAVE_UNISTD_H #ifdef HAVE_UNISTD_H
# include <unistd.h> // for gettimeofday() # include <unistd.h> // for gettimeofday() and the _POSIX_TIMERS define
#endif #endif
#ifdef HAVE_SYS_TIME_H #ifdef HAVE_SYS_TIME_H
# include <sys/time.h> // for get/setitimer, gettimeofday, struct timeval # include <sys/time.h> // for get/setitimer, gettimeofday, struct timeval
#endif #endif
#if defined(_POSIX_TIMERS) && (0 < _POSIX_TIMERS)
# include <time.h>
# include <errno.h>
#endif
#ifdef WIN32 #ifdef WIN32
# include <windows.h> # include <windows.h>
# if defined( __CYGWIN__ ) || defined( __CYGWIN32__ ) # if defined( __CYGWIN__ ) || defined( __CYGWIN32__ )
@@ -53,43 +58,49 @@
#include "timestamp.hxx" #include "timestamp.hxx"
void SGTimeStamp::stamp() { void SGTimeStamp::stamp() {
#if defined( WIN32 ) && !defined(__CYGWIN__) #if defined( WIN32 ) && !defined(__CYGWIN__)
unsigned int t; unsigned int t;
t = timeGetTime(); t = timeGetTime();
seconds = t / 1000; _sec = t / 1000;
usec = ( t - ( seconds * 1000 ) ) * 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 ) #elif defined( HAVE_GETTIMEOFDAY )
struct timeval current; struct timeval current;
struct timezone tz; struct timezone tz;
// sg_timestamp currtime; // sg_timestamp currtime;
gettimeofday(&current, &tz); gettimeofday(&current, &tz);
seconds = current.tv_sec; _sec = current.tv_sec;
usec = current.tv_usec; _nsec = current.tv_usec * 1000;
#elif defined( HAVE_GETLOCALTIME ) #elif defined( HAVE_GETLOCALTIME )
SYSTEMTIME current; SYSTEMTIME current;
GetLocalTime(&current); GetLocalTime(&current);
seconds = current.wSecond; _sec = current.wSecond;
usec = current.wMilliseconds * 1000; _nsec = current.wMilliseconds * 1000 * 1000;
#elif defined( HAVE_FTIME ) #elif defined( HAVE_FTIME )
struct timeb current; struct timeb current;
ftime(&current); ftime(&current);
seconds = current.time; _sec = current.time;
usec = current.millitm * 1000; _nsec = current.millitm * 1000 * 1000;
#else #else
# error Port me # error Port me
#endif #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);
}
+209 -47
View File
@@ -32,81 +32,243 @@
# error This library requires C++ # error This library requires C++
#endif #endif
#include <iosfwd>
#include <iomanip>
#include <sstream>
#include <simgear/compiler.h> #include <simgear/compiler.h>
#include <simgear/math/SGCMath.hxx>
// 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);
/** /**
* The SGTimeStamp class allows you to mark and compare time stamps * The SGTimeStamp class allows you to mark and compare time stamps
* with microsecond accuracy (if your system has support for this * with nanosecond accuracy (if your system has support for this
* level of accuracy.) * level of accuracy).
* *
* The SGTimeStamp is useful for tracking the elapsed time of various * The SGTimeStamp is useful for tracking the elapsed time of various
* events in your program. You can also use it to keep constistant * events in your program. You can also use it to keep constistant
* motion across varying frame rates. * 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 { class SGTimeStamp {
private:
long seconds;
long usec;
public: public:
typedef long sec_type;
typedef int nsec_type;
/** Default constructor */ /** Default constructor, initialize time to zero. */
SGTimeStamp(); SGTimeStamp() :
_sec(0),
_nsec(0)
{ }
/** /** Hmm, might reenable them at some time, but since it is not clear
* This creates an instance of the SGTimeStamp object. When what the input unit of the int is, omit them for now.
* calling the constructor you may provide initial seconds an Use the static constructor functions where it is clear from the method
* microseconds values. name how the arguments are meant.
* @param s initial seconds value
* @param m initial microseconds value
*/ */
SGTimeStamp( const long s, const long m ); // SGTimeStamp(sec_type sec)
// { setTime(sec, 0); }
// SGTimeStamp(int sec)
// { setTime(sec, 0); }
// SGTimeStamp(const double& sec)
// { setTime(sec); }
/** Update stored time to current time (seconds and microseconds) */ /** Update stored time to current time (seconds and nanoseconds) */
void stamp(); void stamp();
/** /** Set the time from a double value */
* Increment the saved time by the specified number of microseconds void setTime(const double& seconds)
* @param t time stamp {
* @param m microseconds increment sec_type wholeSecs = sec_type(floor(seconds));
* @return new time stamp nsec_type reminder;
*/ reminder = nsec_type(floor((seconds - wholeSecs)*(1000*1000*1000)));
friend SGTimeStamp operator + (const SGTimeStamp& t, const long& m); 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);
}
}
/**
* Subtract two time stamps returning the difference in microseconds.
* @param a timestamp 1
* @param b timestame 2
* @return difference in microseconds
*/
friend long operator - (const SGTimeStamp& a, const SGTimeStamp& b);
/** @return the saved seconds of this time stamp */ /** @return the saved seconds of this time stamp */
inline long get_seconds() const { return seconds; } long get_seconds() const { return _sec; }
/** @return the saved microseconds of this time stamp */ /** @return the saved microseconds of this time stamp */
inline long get_usec() const { return usec; } 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.
*/
double toNSecs() const
{ return _nsec + double(_sec)*1000*1000*1000; }
/** @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;
}
/**
* Create SGTimeStamps from input with given units
*/
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); }
/**
* Return a timestamp with the current time.
*/
static SGTimeStamp now()
{ SGTimeStamp ts; ts.stamp(); return ts; }
private:
SGTimeStamp(sec_type sec, nsec_type nsec)
{ setTime(sec, nsec); }
nsec_type _nsec;
sec_type _sec;
}; };
inline SGTimeStamp::SGTimeStamp() : inline bool
seconds(0), operator==(const SGTimeStamp& c1, const SGTimeStamp& c2)
usec(0)
{ {
if (c1.getNanoSeconds() != c2.getNanoSeconds())
return false;
return c1.getSeconds() == c2.getSeconds();
} }
inline SGTimeStamp::SGTimeStamp( const long s, const long u ) { inline bool
seconds = s; operator!=(const SGTimeStamp& c1, const SGTimeStamp& c2)
usec = u; { 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 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 #endif // _TIMESTAMP_HXX