- Fix crash in wxArray::insert() overload taking iterator range (wsu).
- Added wxEventFilter class and wxEvtHandler::{Add,Remove}Filter().
- Added convenient wxCmdLineParser::AddLong{Option,Switch}() wrappers.
+- Added wxStopWatch::TimeInMicro().
All (GUI):
// ctor starts the stop watch
wxStopWatch() { m_pauseCount = 0; Start(); }
- // start the stop watch at the moment t0
+ // Start the stop watch at the moment t0 expressed in milliseconds (i.e.
+ // calling Time() immediately afterwards returns t0). This can be used to
+ // restart an existing stopwatch.
void Start(long t0 = 0);
// pause the stop watch
void Pause()
{
if ( m_pauseCount++ == 0 )
- m_pause = GetElapsedTime();
+ m_elapsedBeforePause = GetCurrentClockValue() - m_t0;
}
// resume it
wxT("Resuming stop watch which is not paused") );
if ( --m_pauseCount == 0 )
- Start(m_pause);
+ {
+ DoStart();
+ m_t0 -= m_elapsedBeforePause;
+ }
}
- // get elapsed time since the last Start() in milliseconds
- long Time() const;
+ // Get elapsed time since the last Start() in microseconds.
+ wxLongLong TimeInMicro() const;
-protected:
- // returns the elapsed time since t0
- long GetElapsedTime() const;
+ // get elapsed time since the last Start() in milliseconds
+ long Time() const { return (TimeInMicro()/1000).ToLong(); }
private:
- // the time of the last Start()
+ // Really starts the stop watch. The initial time is set to current clock
+ // value.
+ void DoStart();
+
+ // Returns the current clock value in its native units.
+ wxLongLong GetCurrentClockValue() const;
+
+ // Return the frequency of the clock used in its ticks per second.
+ wxLongLong GetClockFreq() const;
+
+
+ // The clock value when the stop watch was last started. Its units vary
+ // depending on the platform.
wxLongLong m_t0;
- // the time of the last Pause() (only valid if m_pauseCount > 0)
- long m_pause;
+ // The elapsed time as of last Pause() call (only valid if m_pauseCount >
+ // 0) in the same units as m_t0.
+ wxLongLong m_elapsedBeforePause;
// if > 0, the stop watch is paused, otherwise it is running
int m_pauseCount;
/**
Returns the time in milliseconds since the start (or restart) or the last
call of Pause().
+
+ @see TimeInMicro()
*/
long Time() const;
+
+ /**
+ Returns elapsed time in microseconds.
+
+ This method is similar to Time() but returns the elapsed time in
+ microseconds and not milliseconds. Notice that not all platforms really
+ can measure times with this precision.
+
+ @since 2.9.3
+ */
+ wxLongLong TimeInMicro() const;
};
#if wxUSE_STOPWATCH
-#ifdef __WXMSW__
-
namespace
{
+#ifdef __WXMSW__
+
struct PerfCounter
{
PerfCounter()
bool init;
} gs_perfCounter;
-} // anonymous namespace
-
#endif // __WXMSW__
-void wxStopWatch::Start(long t)
+const int MILLISECONDS_PER_SECOND = 1000;
+const int MICROSECONDS_PER_SECOND = 1000*1000;
+
+} // anonymous namespace
+
+void wxStopWatch::DoStart()
{
#ifdef __WXMSW__
if ( !gs_perfCounter.init )
{
wxCriticalSectionLocker lock(gs_perfCounter.cs);
::QueryPerformanceFrequency(&gs_perfCounter.freq);
+
+ // Just a sanity check: it's not supposed to happen but verify that
+ // ::QueryPerformanceCounter() succeeds so that we can really use it.
+ LARGE_INTEGER counter;
+ if ( !::QueryPerformanceCounter(&counter) )
+ {
+ wxLogDebug("QueryPerformanceCounter() unexpected failed (%s), "
+ "will not use it.", wxSysErrorMsg());
+
+ gs_perfCounter.freq.QuadPart = 0;
+ }
+
gs_perfCounter.init = true;
}
+#endif // __WXMSW__
- LARGE_INTEGER counter;
- if ( gs_perfCounter.CanBeUsed() && ::QueryPerformanceCounter(&counter) )
- {
- m_t0 = counter.QuadPart - t*gs_perfCounter.freq.QuadPart/1000;
- }
- else // Fall back to the generic code below.
+ m_t0 = GetCurrentClockValue();
+}
+
+wxLongLong wxStopWatch::GetClockFreq() const
+{
+#ifdef __WXMSW__
+ // Under MSW we use the high resolution performance counter timer which has
+ // its own frequency (usually related to the CPU clock speed).
+ if ( gs_perfCounter.CanBeUsed() )
+ return gs_perfCounter.freq.QuadPart;
#endif // __WXMSW__
- {
- m_t0 = wxGetLocalTimeMillis() - t;
- }
- m_pause = 0;
- m_pauseCount = 0;
+ // Currently milliseconds are used everywhere else.
+ return MILLISECONDS_PER_SECOND;
}
-long wxStopWatch::GetElapsedTime() const
+void wxStopWatch::Start(long t0)
+{
+ DoStart();
+
+ m_t0 -= (wxLongLong(t0)*GetClockFreq())/MILLISECONDS_PER_SECOND;
+}
+
+wxLongLong wxStopWatch::GetCurrentClockValue() const
{
#ifdef __WXMSW__
- LARGE_INTEGER counter;
- if ( gs_perfCounter.CanBeUsed() && ::QueryPerformanceCounter(&counter) )
+ if ( gs_perfCounter.CanBeUsed() )
{
- wxLongLong delta(counter.QuadPart);
- delta -= m_t0;
-
- return ((delta*1000)/gs_perfCounter.freq.QuadPart).GetLo();
+ LARGE_INTEGER counter;
+ ::QueryPerformanceCounter(&counter);
+ return counter.QuadPart;
}
-#endif
- return (wxGetLocalTimeMillis() - m_t0).GetLo();
+#endif // __WXMSW__
+
+ return wxGetLocalTimeMillis();
}
-long wxStopWatch::Time() const
+wxLongLong wxStopWatch::TimeInMicro() const
{
- return m_pauseCount ? m_pause : GetElapsedTime();
+ const wxLongLong elapsed(m_pauseCount ? m_elapsedBeforePause
+ : GetCurrentClockValue() - m_t0);
+
+ return (elapsed*MICROSECONDS_PER_SECOND)/GetClockFreq();
}
#endif // wxUSE_STOPWATCH
void StopWatchTestCase::Misc()
{
- static const long tolerance = 100; // in ms
+ static const long tolerance = 10; // in ms
wxStopWatch sw;
long t;
+ wxLongLong usec;
sw.Pause(); // pause it immediately
+ // verify that almost no time elapsed
+ usec = sw.TimeInMicro();
+ WX_ASSERT_MESSAGE
+ (
+ ("Elapsed time was %" wxLongLongFmtSpec "dus", usec),
+ usec < tolerance*1000
+ );
+
wxSleep(1);
t = sw.Time();