enough with umpteen "i18n.h" files. Consolidate on pbd/i18n.h
[ardour.git] / libs / pbd / windows_timer_utils.cc
index d95a69e0c71b47373a7a55d5225bfa62d0b9381d..0fab935b082e5f0c4709e16040fd360e16b085d7 100644 (file)
 
 #include "pbd/compose.h"
 #include "pbd/debug.h"
+#include "pbd/error.h"
+
+#include "pbd/i18n.h"
 
 #define DEBUG_TIMING(msg) DEBUG_TRACE (PBD::DEBUG::Timing, msg);
 
 namespace {
 
+static
 UINT&
 timer_resolution ()
 {
@@ -35,7 +39,7 @@ timer_resolution ()
        return timer_res_ms;
 }
 
-}
+} // namespace
 
 namespace PBD {
 
@@ -100,6 +104,7 @@ reset_resolution ()
                DEBUG_TIMING("Could not reset the Timer resolution.\n");
                return false;
        }
+       DEBUG_TIMING("Reset the Timer resolution.\n");
        timer_resolution() = 0;
        return true;
 }
@@ -108,32 +113,23 @@ reset_resolution ()
 
 namespace {
 
-bool&
-qpc_frequency_success ()
-{
-       static bool success = false;
-       return success;
-}
+static double timer_rate_us = 0.0;
 
-LARGE_INTEGER
-qpc_frequency ()
+static
+bool
+test_qpc_validity ()
 {
-       LARGE_INTEGER freq;
-       if (QueryPerformanceFrequency(&freq) == 0) {
-               DEBUG_TIMING ("Failed to determine frequency of QPC\n");
-               qpc_frequency_success() = false;
-       } else {
-               qpc_frequency_success() = true;
+       int64_t last_timer_val = PBD::QPC::get_microseconds ();
+       if (last_timer_val < 0) return false;
+
+       for (int i = 0; i < 100000; ++i) {
+               int64_t timer_val = PBD::QPC::get_microseconds ();
+               if (timer_val < 0) return false;
+               // try and test for non-syncronized TSC(AMD K8/etc)
+               if (timer_val < last_timer_val) return false;
+               last_timer_val = timer_val;
        }
-
-       return freq;
-}
-
-LARGE_INTEGER
-qpc_frequency_cached ()
-{
-       static LARGE_INTEGER frequency = qpc_frequency ();
-       return frequency;
+       return true;
 }
 
 } // anon namespace
@@ -141,11 +137,27 @@ qpc_frequency_cached ()
 namespace QPC {
 
 bool
-get_timer_valid ()
+check_timer_valid ()
+{
+       if (!timer_rate_us) {
+               return false;
+       }
+       return test_qpc_validity ();
+}
+
+bool
+initialize ()
 {
-       // setup caching the timer frequency
-       qpc_frequency_cached ();
-       return qpc_frequency_success ();
+       LARGE_INTEGER freq;
+       if (!QueryPerformanceFrequency(&freq) || freq.QuadPart < 1) {
+               info << X_("Failed to determine frequency of QPC\n") << endmsg;
+               timer_rate_us = 0;
+       } else {
+               timer_rate_us = 1000000.0 / freq.QuadPart;
+       }
+       info << string_compose(X_("QPC timer microseconds per tick: %1\n"),
+                              timer_rate_us) << endmsg;
+       return !timer_rate_us;
 }
 
 int64_t
@@ -153,12 +165,11 @@ get_microseconds ()
 {
        LARGE_INTEGER current_val;
 
-       if (qpc_frequency_success()) {
+       if (timer_rate_us) {
                // MS docs say this will always succeed for systems >= XP but it may
                // not return a monotonic value with non-invariant TSC's etc
                if (QueryPerformanceCounter(&current_val) != 0) {
-                       return (int64_t)(((double)current_val.QuadPart) /
-                                        ((double)qpc_frequency_cached().QuadPart) * 1000000.0);
+                       return (int64_t)(current_val.QuadPart * timer_rate_us);
                }
        }
        DEBUG_TIMING ("Could not get QPC timer\n");
@@ -170,7 +181,7 @@ get_microseconds ()
 int64_t
 get_microseconds ()
 {
-       if (qpc_frequency_success()) {
+       if (timer_rate_us) {
                return QPC::get_microseconds ();
        }
        // For XP systems that don't support a high-res performance counter