summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2012-08-10 16:13:23 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2012-10-10 08:45:22 +0200
commit66324e304969043b22fb8e5765337e28c562952e (patch)
tree03bc8b13bec1ce3f39e48d70e0c5ceebc80234de /src/corelib
parent4ec79a151f9007d739b0970c062eb452133be4d6 (diff)
QElapsedTimer: Instead of two ints, store only the clock type
We don't need two ints if we can do it with one. We need to store only the clock type to be used, which is either CLOCK_MONOTONIC or CLOCK_REALTIME. In addition, we need an invalid value to indicate that the test hasn't been done yet. This also gets rid of an atomic that wasn't QBasicAtomicInt. Disassembly of the compiled code indicates this is the most optimal solution: - one single variable load - one test-and-branch to verify that a test is needed - straight call to clock_gettime afterwards Change-Id: I49788e45b50b6b7fcb7ba4e9332e5352a4428933 Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/tools/qelapsedtimer_unix.cpp128
1 files changed, 82 insertions, 46 deletions
diff --git a/src/corelib/tools/qelapsedtimer_unix.cpp b/src/corelib/tools/qelapsedtimer_unix.cpp
index 4bbcbcabbf..5dc18ce99f 100644
--- a/src/corelib/tools/qelapsedtimer_unix.cpp
+++ b/src/corelib/tools/qelapsedtimer_unix.cpp
@@ -47,6 +47,7 @@
#include <time.h>
#include <unistd.h>
+#include <qatomic.h>
#include "private/qcore_unix_p.h"
#if defined(QT_NO_CLOCK_MONOTONIC) || defined(QT_BOOTSTRAPPED)
@@ -59,30 +60,87 @@
QT_BEGIN_NAMESPACE
-#if (_POSIX_MONOTONIC_CLOCK-0 != 0)
-static const bool monotonicClockChecked = true;
-static const bool monotonicClockAvailable = _POSIX_MONOTONIC_CLOCK > 0;
+/*
+ * Design:
+ *
+ * POSIX offers a facility to select the system's monotonic clock when getting
+ * the current timestamp. Whereas the functions are mandatory in POSIX.1-2008,
+ * the presence of a monotonic clock is a POSIX Option (see the document
+ * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap02.html#tag_02_01_06 )
+ *
+ * The macro _POSIX_MONOTONIC_CLOCK can therefore assume the following values:
+ * -1 monotonic clock is never supported on this sytem
+ * 0 monotonic clock might be supported, runtime check is needed
+ * >1 (such as 200809L) monotonic clock is always supported
+ *
+ * The unixCheckClockType() function will return the clock to use: either
+ * CLOCK_MONOTONIC or CLOCK_REALTIME. In the case the POSIX option has a value
+ * of zero, then this function stores a static that contains the clock to be
+ * used.
+ *
+ * There's one extra case, which is when CLOCK_REALTIME isn't defined. When
+ * that's the case, we'll emulate the clock_gettime function with gettimeofday.
+ *
+ * Conforming to:
+ * POSIX.1b-1993 section "Clocks and Timers"
+ * included in UNIX98 (Single Unix Specification v2)
+ * included in POSIX.1-2001
+ * see http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html
+ */
+
+#ifndef CLOCK_REALTIME
+# define CLOCK_REALTIME 0
+static inline void qt_clock_gettime(int, struct timespec *ts)
+{
+ // support clock_gettime with gettimeofday
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+ ts->tv_sec = tv.tv_sec;
+ ts->tv_nsec = tv.tv_usec * 1000;
+}
+
+# ifdef _POSIX_MONOTONIC_CLOCK
+# undef _POSIX_MONOTONIC_CLOCK
+# define _POSIX_MONOTONIC_CLOCK -1
+# endif
#else
-static int monotonicClockChecked = false;
-static int monotonicClockAvailable = false;
-#endif
-
-#define load_acquire(x) ((volatile const int&)(x))
-#define store_release(x,v) ((volatile int&)(x) = (v))
-
-static void unixCheckClockType()
+static inline void qt_clock_gettime(clockid_t clock, struct timespec *ts)
{
-#if (_POSIX_MONOTONIC_CLOCK-0 == 0)
- if (Q_LIKELY(load_acquire(monotonicClockChecked)))
- return;
-
-# if defined(_SC_MONOTONIC_CLOCK)
- // detect if the system support monotonic timers
- long x = sysconf(_SC_MONOTONIC_CLOCK);
- store_release(monotonicClockAvailable, x >= 200112L);
-# endif
+ clock_gettime(clock, ts);
+}
+#endif
- store_release(monotonicClockChecked, true);
+static int unixCheckClockType()
+{
+#if (_POSIX_MONOTONIC_CLOCK-0 == 0) && defined(_SC_MONOTONIC_CLOCK)
+ // we need a value we can store in a clockid_t that isn't a valid clock
+ // check if the valid ones are both non-negative or both non-positive
+# if CLOCK_MONOTONIC >= 0 && CLOCK_REALTIME >= 0
+# define IS_VALID_CLOCK(clock) (clock >= 0)
+# define INVALID_CLOCK -1
+# elif CLOCK_MONOTONIC <= 0 && CLOCK_REALTIME <= 0
+# define IS_VALID_CLOCK(clock) (clock <= 0)
+# define INVALID_CLOCK 1
+# else
+# error "Sorry, your system has weird values for CLOCK_MONOTONIC and CLOCK_REALTIME"
+# endif
+
+ static QBasicAtomicInt clockToUse = Q_BASIC_ATOMIC_INITIALIZER(INVALID_CLOCK);
+ int clock = clockToUse.loadAcquire();
+ if (Q_LIKELY(IS_VALID_CLOCK(clock)))
+ return clock;
+
+ // detect if the system supports monotonic timers
+ clock = sysconf(_SC_MONOTONIC_CLOCK) > 0 ? CLOCK_MONOTONIC : CLOCK_REALTIME;
+ clockToUse.storeRelease(clock);
+ return clock;
+
+# undef INVALID_CLOCK
+# undef IS_VALID_CLOCK
+#elif (_POSIX_MONOTONIC_CLOCK-0) > 0
+ return CLOCK_MONOTONIC;
+#else
+ return CLOCK_REALTIME;
#endif
}
@@ -93,42 +151,20 @@ static inline qint64 fractionAdjustment()
bool QElapsedTimer::isMonotonic() Q_DECL_NOTHROW
{
- unixCheckClockType();
- return monotonicClockAvailable;
+ return clockType() == MonotonicClock;
}
QElapsedTimer::ClockType QElapsedTimer::clockType() Q_DECL_NOTHROW
{
- unixCheckClockType();
- return monotonicClockAvailable ? MonotonicClock : SystemTime;
+ return unixCheckClockType() == CLOCK_REALTIME ? SystemTime : MonotonicClock;
}
static inline void do_gettime(qint64 *sec, qint64 *frac)
{
-#if (_POSIX_MONOTONIC_CLOCK-0 >= 0)
- unixCheckClockType();
- if (Q_LIKELY(monotonicClockAvailable)) {
- timespec ts;
- clock_gettime(CLOCK_MONOTONIC, &ts);
- *sec = ts.tv_sec;
- *frac = ts.tv_nsec;
- return;
- }
-#endif
-#ifdef CLOCK_REALTIME
- // even if we don't have a monotonic clock,
- // we can use clock_gettime -> nanosecond resolution
timespec ts;
- clock_gettime(CLOCK_REALTIME, &ts);
+ qt_clock_gettime(unixCheckClockType(), &ts);
*sec = ts.tv_sec;
*frac = ts.tv_nsec;
-#else
- // use gettimeofday
- timeval tv;
- ::gettimeofday(&tv, 0);
- *sec = tv.tv_sec;
- *frac = tv.tv_usec * 1000;
-#endif
}
// used in qcore_unix.cpp and qeventdispatcher_unix.cpp