]> git.saurik.com Git - wxWidgets.git/commitdiff
Use ::QueryPerformanceCounter() for wxStopWatch implementation in wxMSW.
authorVadim Zeitlin <vadim@wxwidgets.org>
Sun, 27 Nov 2011 19:50:08 +0000 (19:50 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Sun, 27 Nov 2011 19:50:08 +0000 (19:50 +0000)
QueryPerformanceCounter() provides higher resolution and precision for
measuring time under MSW, even though it suffers from some problems in older
Windows versions.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@69834 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

interface/wx/stopwatch.h
src/common/stopwatch.cpp

index 3f2f98edbecb4d577815d11fc29fe6142883e6f6..632c876e0c71aba96d67ab3fb49faf70680f64b7 100644 (file)
         wxLogMessage("And calling it twice took $ldms in all", sw.Time());
     @endcode
 
+    Since wxWidgets 2.9.3 this class uses @c ::QueryPerformanceCounter()
+    function under MSW to measure the elapsed time. It provides higher
+    precision than the usual timer functions but can suffer from bugs in its
+    implementation in some Windows XP versions. If you encounter such problems,
+    installing a Microsoft hot fix from http://support.microsoft.com/?id=896256
+    could be necessary.
+
     @library{wxbase}
     @category{misc}
 
index 5ed9058504625ba60442705f5a047ce3598bff62..922a5f0ed8b937848f10c00df4bdfe599ccd2beb 100644 (file)
 
 #if wxUSE_STOPWATCH
 
+#ifdef __WXMSW__
+
+namespace
+{
+
+struct PerfCounter
+{
+    PerfCounter()
+    {
+        init = false;
+    }
+
+    bool CanBeUsed() const
+    {
+        return freq.QuadPart != 0;
+    }
+
+    wxCriticalSection cs;
+    LARGE_INTEGER freq;
+    bool init;
+} gs_perfCounter;
+
+} // anonymous namespace
+
+#endif // __WXMSW__
+
 void wxStopWatch::Start(long t)
 {
-#if 0
-// __WXMSW__
-    LARGE_INTEGER frequency_li;
-    ::QueryPerformanceFrequency( &frequency_li );
-    m_frequency = frequency_li.QuadPart;
-    if (m_frequency == 0)
+#ifdef __WXMSW__
+    if ( !gs_perfCounter.init )
     {
-        m_t0 = wxGetLocalTimeMillis() - t;
+        wxCriticalSectionLocker lock(gs_perfCounter.cs);
+        ::QueryPerformanceFrequency(&gs_perfCounter.freq);
+        gs_perfCounter.init = true;
     }
-    else
+
+    LARGE_INTEGER counter;
+    if ( gs_perfCounter.CanBeUsed() && ::QueryPerformanceCounter(&counter) )
     {
-        LARGE_INTEGER counter_li;
-        ::QueryPerformanceCounter( &counter_li );
-        wxLongLong counter = counter_li.QuadPart;
-        m_t0 = (counter * 10000 / m_frequency) - t*10;
+        m_t0 = counter.QuadPart - t*gs_perfCounter.freq.QuadPart/1000;
     }
-#else
-    m_t0 = wxGetLocalTimeMillis() - t;
-#endif
+    else // Fall back to the generic code below.
+#endif // __WXMSW__
+    {
+        m_t0 = wxGetLocalTimeMillis() - t;
+    }
+
     m_pause = 0;
     m_pauseCount = 0;
 }
 
 long wxStopWatch::GetElapsedTime() const
 {
-#if 0
-//__WXMSW__
-    if (m_frequency == 0)
+#ifdef __WXMSW__
+    LARGE_INTEGER counter;
+    if ( gs_perfCounter.CanBeUsed() && ::QueryPerformanceCounter(&counter) )
     {
-        return (wxGetLocalTimeMillis() - m_t0).GetLo();
-    }
-    else
-    {
-        LARGE_INTEGER counter_li;
-        ::QueryPerformanceCounter( &counter_li );
-        wxLongLong counter = counter_li.QuadPart;
-        wxLongLong res = (counter * 10000 / m_frequency) - m_t0;
-        return res.GetLo() / 10;
+        wxLongLong delta(counter.QuadPart);
+        delta -= m_t0;
+
+        return ((delta*1000)/gs_perfCounter.freq.QuadPart).GetLo();
     }
-#else
-    return (wxGetLocalTimeMillis() - m_t0).GetLo();
 #endif
+    return (wxGetLocalTimeMillis() - m_t0).GetLo();
 }
 
 long wxStopWatch::Time() const