You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
396 lines
7.9 KiB
396 lines
7.9 KiB
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** |
|
* Qwt Widget Library |
|
* Copyright (C) 1997 Josef Wilgen |
|
* Copyright (C) 2002 Uwe Rathmann |
|
* |
|
* This library is free software; you can redistribute it and/or |
|
* modify it under the terms of the Qwt License, Version 1.0 |
|
*****************************************************************************/ |
|
|
|
#include "qwt_system_clock.h" |
|
|
|
#if QT_VERSION >= 0x040800 |
|
#define USE_ELAPSED_TIMER 1 |
|
#endif |
|
|
|
#if USE_ELAPSED_TIMER |
|
|
|
#include <qelapsedtimer.h> |
|
|
|
class QwtSystemClock::PrivateData |
|
{ |
|
public: |
|
QElapsedTimer timer; |
|
}; |
|
|
|
QwtSystemClock::QwtSystemClock() |
|
{ |
|
d_data = new PrivateData(); |
|
} |
|
|
|
QwtSystemClock::~QwtSystemClock() |
|
{ |
|
delete d_data; |
|
} |
|
|
|
bool QwtSystemClock::isNull() const |
|
{ |
|
return d_data->timer.isValid(); |
|
} |
|
|
|
void QwtSystemClock::start() |
|
{ |
|
d_data->timer.start(); |
|
} |
|
|
|
double QwtSystemClock::restart() |
|
{ |
|
const qint64 nsecs = d_data->timer.restart(); |
|
return nsecs / 1e6; |
|
} |
|
|
|
double QwtSystemClock::elapsed() const |
|
{ |
|
const qint64 nsecs = d_data->timer.nsecsElapsed(); |
|
return nsecs / 1e6; |
|
} |
|
|
|
#else // !USE_ELAPSED_TIMER |
|
|
|
#include <qdatetime.h> |
|
|
|
#if !defined(Q_OS_WIN) |
|
#include <unistd.h> |
|
#endif |
|
|
|
#if defined(Q_OS_MAC) |
|
#include <stdint.h> |
|
#include <mach/mach_time.h> |
|
#define QWT_HIGH_RESOLUTION_CLOCK |
|
#elif defined(_POSIX_TIMERS) |
|
#include <time.h> |
|
#define QWT_HIGH_RESOLUTION_CLOCK |
|
#elif defined(Q_OS_WIN) |
|
#define QWT_HIGH_RESOLUTION_CLOCK |
|
#include <qt_windows.h> |
|
#endif |
|
|
|
#if defined(QWT_HIGH_RESOLUTION_CLOCK) |
|
|
|
class QwtHighResolutionClock |
|
{ |
|
public: |
|
QwtHighResolutionClock(); |
|
|
|
void start(); |
|
double restart(); |
|
double elapsed() const; |
|
|
|
bool isNull() const; |
|
|
|
static double precision(); |
|
|
|
private: |
|
|
|
#if defined(Q_OS_MAC) |
|
static double msecsTo( uint64_t, uint64_t ); |
|
|
|
uint64_t d_timeStamp; |
|
#elif defined(_POSIX_TIMERS) |
|
|
|
static double msecsTo( const struct timespec &, |
|
const struct timespec & ); |
|
|
|
static bool isMonotonic(); |
|
|
|
struct timespec d_timeStamp; |
|
clockid_t d_clockId; |
|
|
|
#elif defined(Q_OS_WIN) |
|
|
|
LARGE_INTEGER d_startTicks; |
|
LARGE_INTEGER d_ticksPerSecond; |
|
#endif |
|
}; |
|
|
|
#if defined(Q_OS_MAC) |
|
QwtHighResolutionClock::QwtHighResolutionClock(): |
|
d_timeStamp( 0 ) |
|
{ |
|
} |
|
|
|
double QwtHighResolutionClock::precision() |
|
{ |
|
return 1e-6; |
|
} |
|
|
|
void QwtHighResolutionClock::start() |
|
{ |
|
d_timeStamp = mach_absolute_time(); |
|
} |
|
|
|
double QwtHighResolutionClock::restart() |
|
{ |
|
const uint64_t timeStamp = mach_absolute_time(); |
|
const double elapsed = msecsTo( d_timeStamp, timeStamp ); |
|
d_timeStamp = timeStamp; |
|
|
|
return elapsed; |
|
} |
|
|
|
double QwtHighResolutionClock::elapsed() const |
|
{ |
|
return msecsTo( d_timeStamp, mach_absolute_time() ); |
|
} |
|
|
|
bool QwtHighResolutionClock::isNull() const |
|
{ |
|
return d_timeStamp == 0; |
|
} |
|
|
|
double QwtHighResolutionClock::msecsTo( |
|
uint64_t from, uint64_t to ) |
|
{ |
|
const uint64_t difference = to - from; |
|
|
|
static double conversion = 0.0; |
|
if ( conversion == 0.0 ) |
|
{ |
|
mach_timebase_info_data_t info; |
|
kern_return_t err = mach_timebase_info( &info ); |
|
|
|
// convert the timebase into ms |
|
if ( err == 0 ) |
|
conversion = 1e-6 * ( double ) info.numer / ( double ) info.denom; |
|
} |
|
|
|
return conversion * ( double ) difference; |
|
} |
|
|
|
#elif defined(_POSIX_TIMERS) |
|
|
|
QwtHighResolutionClock::QwtHighResolutionClock() |
|
{ |
|
d_clockId = isMonotonic() ? CLOCK_MONOTONIC : CLOCK_REALTIME; |
|
d_timeStamp.tv_sec = d_timeStamp.tv_nsec = 0; |
|
} |
|
|
|
double QwtHighResolutionClock::precision() |
|
{ |
|
struct timespec resolution; |
|
|
|
int clockId = isMonotonic() ? CLOCK_MONOTONIC : CLOCK_REALTIME; |
|
::clock_getres( clockId, &resolution ); |
|
|
|
return resolution.tv_nsec / 1e3; |
|
} |
|
|
|
inline bool QwtHighResolutionClock::isNull() const |
|
{ |
|
return d_timeStamp.tv_sec <= 0 && d_timeStamp.tv_nsec <= 0; |
|
} |
|
|
|
inline void QwtHighResolutionClock::start() |
|
{ |
|
::clock_gettime( d_clockId, &d_timeStamp ); |
|
} |
|
|
|
double QwtHighResolutionClock::restart() |
|
{ |
|
struct timespec timeStamp; |
|
::clock_gettime( d_clockId, &timeStamp ); |
|
|
|
const double elapsed = msecsTo( d_timeStamp, timeStamp ); |
|
|
|
d_timeStamp = timeStamp; |
|
return elapsed; |
|
} |
|
|
|
inline double QwtHighResolutionClock::elapsed() const |
|
{ |
|
struct timespec timeStamp; |
|
::clock_gettime( d_clockId, &timeStamp ); |
|
|
|
return msecsTo( d_timeStamp, timeStamp ); |
|
} |
|
|
|
inline double QwtHighResolutionClock::msecsTo( |
|
const struct timespec &t1, const struct timespec &t2 ) |
|
{ |
|
return ( t2.tv_sec - t1.tv_sec ) * 1e3 |
|
+ ( t2.tv_nsec - t1.tv_nsec ) * 1e-6; |
|
} |
|
|
|
bool QwtHighResolutionClock::isMonotonic() |
|
{ |
|
// code copied from qcore_unix.cpp |
|
|
|
#if (_POSIX_MONOTONIC_CLOCK-0 > 0) |
|
return true; |
|
#else |
|
static int returnValue = 0; |
|
|
|
if ( returnValue == 0 ) |
|
{ |
|
#if (_POSIX_MONOTONIC_CLOCK-0 < 0) || !defined(_SC_MONOTONIC_CLOCK) |
|
returnValue = -1; |
|
#elif (_POSIX_MONOTONIC_CLOCK == 0) |
|
// detect if the system support monotonic timers |
|
const long x = sysconf( _SC_MONOTONIC_CLOCK ); |
|
returnValue = ( x >= 200112L ) ? 1 : -1; |
|
#endif |
|
} |
|
|
|
return returnValue != -1; |
|
#endif |
|
} |
|
|
|
#elif defined(Q_OS_WIN) |
|
|
|
QwtHighResolutionClock::QwtHighResolutionClock() |
|
{ |
|
d_startTicks.QuadPart = 0; |
|
QueryPerformanceFrequency( &d_ticksPerSecond ); |
|
} |
|
|
|
double QwtHighResolutionClock::precision() |
|
{ |
|
LARGE_INTEGER ticks; |
|
if ( QueryPerformanceFrequency( &ticks ) && ticks.QuadPart > 0 ) |
|
return 1e3 / ticks.QuadPart; |
|
|
|
return 0.0; |
|
} |
|
|
|
inline bool QwtHighResolutionClock::isNull() const |
|
{ |
|
return d_startTicks.QuadPart <= 0; |
|
} |
|
|
|
inline void QwtHighResolutionClock::start() |
|
{ |
|
QueryPerformanceCounter( &d_startTicks ); |
|
} |
|
|
|
inline double QwtHighResolutionClock::restart() |
|
{ |
|
LARGE_INTEGER ticks; |
|
QueryPerformanceCounter( &ticks ); |
|
|
|
const double dt = ticks.QuadPart - d_startTicks.QuadPart; |
|
d_startTicks = ticks; |
|
|
|
return dt / d_ticksPerSecond.QuadPart * 1e3; |
|
} |
|
|
|
inline double QwtHighResolutionClock::elapsed() const |
|
{ |
|
LARGE_INTEGER ticks; |
|
QueryPerformanceCounter( &ticks ); |
|
|
|
const double dt = ticks.QuadPart - d_startTicks.QuadPart; |
|
return dt / d_ticksPerSecond.QuadPart * 1e3; |
|
} |
|
|
|
#endif |
|
|
|
#endif // QWT_HIGH_RESOLUTION_CLOCK |
|
|
|
class QwtSystemClock::PrivateData |
|
{ |
|
public: |
|
#if defined(QWT_HIGH_RESOLUTION_CLOCK) |
|
QwtHighResolutionClock *clock; |
|
#endif |
|
QTime time; |
|
}; |
|
|
|
//! Constructs a null clock object. |
|
QwtSystemClock::QwtSystemClock() |
|
{ |
|
d_data = new PrivateData; |
|
|
|
#if defined(QWT_HIGH_RESOLUTION_CLOCK) |
|
d_data->clock = NULL; |
|
if ( QwtHighResolutionClock::precision() > 0.0 ) |
|
d_data->clock = new QwtHighResolutionClock; |
|
#endif |
|
} |
|
|
|
//! Destructor |
|
QwtSystemClock::~QwtSystemClock() |
|
{ |
|
#if defined(QWT_HIGH_RESOLUTION_CLOCK) |
|
delete d_data->clock; |
|
#endif |
|
delete d_data; |
|
} |
|
|
|
/*! |
|
\return true if the clock has never been started. |
|
*/ |
|
bool QwtSystemClock::isNull() const |
|
{ |
|
#if defined(QWT_HIGH_RESOLUTION_CLOCK) |
|
if ( d_data->clock ) |
|
return d_data->clock->isNull(); |
|
#endif |
|
|
|
return d_data->time.isNull(); |
|
} |
|
|
|
/*! |
|
Sets the start time to the current time. |
|
*/ |
|
void QwtSystemClock::start() |
|
{ |
|
#if defined(QWT_HIGH_RESOLUTION_CLOCK) |
|
if ( d_data->clock ) |
|
{ |
|
d_data->clock->start(); |
|
return; |
|
} |
|
#endif |
|
|
|
d_data->time.start(); |
|
} |
|
|
|
/*! |
|
Set the start time to the current time |
|
\return Time, that is elapsed since the previous start time. |
|
*/ |
|
double QwtSystemClock::restart() |
|
{ |
|
#if defined(QWT_HIGH_RESOLUTION_CLOCK) |
|
if ( d_data->clock ) |
|
return d_data->clock->restart(); |
|
#endif |
|
|
|
return d_data->time.restart(); |
|
} |
|
|
|
/*! |
|
\return Number of milliseconds that have elapsed since the last time |
|
start() or restart() was called or 0.0 for null clocks. |
|
*/ |
|
double QwtSystemClock::elapsed() const |
|
{ |
|
double elapsed = 0.0; |
|
|
|
#if defined(QWT_HIGH_RESOLUTION_CLOCK) |
|
if ( d_data->clock ) |
|
{ |
|
if ( !d_data->clock->isNull() ) |
|
elapsed = d_data->clock->elapsed(); |
|
|
|
return elapsed; |
|
} |
|
#endif |
|
|
|
if ( !d_data->time.isNull() ) |
|
elapsed = d_data->time.elapsed(); |
|
|
|
return elapsed; |
|
} |
|
|
|
#endif
|
|
|