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:
@@ -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)) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -36,12 +36,17 @@
|
||||
# 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__ )
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -32,81 +32,243 @@
|
||||
# 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 {
|
||||
|
||||
private:
|
||||
|
||||
long seconds;
|
||||
long usec;
|
||||
|
||||
public:
|
||||
typedef long sec_type;
|
||||
typedef int nsec_type;
|
||||
|
||||
/** Default constructor */
|
||||
SGTimeStamp();
|
||||
/** Default constructor, initialize time to zero. */
|
||||
SGTimeStamp() :
|
||||
_sec(0),
|
||||
_nsec(0)
|
||||
{ }
|
||||
|
||||
/**
|
||||
* 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
|
||||
/** 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( 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();
|
||||
|
||||
/**
|
||||
* Increment the saved time by the specified number of microseconds
|
||||
* @param t time stamp
|
||||
* @param m microseconds increment
|
||||
* @return new time stamp
|
||||
*/
|
||||
friend SGTimeStamp operator + (const SGTimeStamp& t, const long& m);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
/** 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** @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 */
|
||||
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() :
|
||||
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 SGTimeStamp::SGTimeStamp( const long s, const long u ) {
|
||||
seconds = s;
|
||||
usec = u;
|
||||
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 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
|
||||
|
||||
Reference in New Issue
Block a user