summaryrefslogtreecommitdiffstats
path: root/libs/utils/Timers.cpp
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:31:44 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:31:44 -0800
commit9066cfe9886ac131c34d59ed0e2d287b0e3c0087 (patch)
treed88beb88001f2482911e3d28e43833b50e4b4e97 /libs/utils/Timers.cpp
parentd83a98f4ce9cfa908f5c54bbd70f03eec07e7553 (diff)
downloadframeworks_base-9066cfe9886ac131c34d59ed0e2d287b0e3c0087.zip
frameworks_base-9066cfe9886ac131c34d59ed0e2d287b0e3c0087.tar.gz
frameworks_base-9066cfe9886ac131c34d59ed0e2d287b0e3c0087.tar.bz2
auto import from //depot/cupcake/@135843
Diffstat (limited to 'libs/utils/Timers.cpp')
-rw-r--r--libs/utils/Timers.cpp240
1 files changed, 240 insertions, 0 deletions
diff --git a/libs/utils/Timers.cpp b/libs/utils/Timers.cpp
new file mode 100644
index 0000000..2abc811
--- /dev/null
+++ b/libs/utils/Timers.cpp
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Timer functions.
+//
+#include <utils/Timers.h>
+#include <utils/ported.h> // may need usleep
+#include <utils/Log.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <time.h>
+#include <errno.h>
+
+#ifdef HAVE_WIN32_THREADS
+#include <windows.h>
+#endif
+
+nsecs_t systemTime(int clock)
+{
+#if defined(HAVE_POSIX_CLOCKS)
+ static const clockid_t clocks[] = {
+ CLOCK_REALTIME,
+ CLOCK_MONOTONIC,
+ CLOCK_PROCESS_CPUTIME_ID,
+ CLOCK_THREAD_CPUTIME_ID
+ };
+ struct timespec t;
+ t.tv_sec = t.tv_nsec = 0;
+ clock_gettime(clocks[clock], &t);
+ return nsecs_t(t.tv_sec)*1000000000LL + t.tv_nsec;
+#else
+ // we don't support the clocks here.
+ struct timeval t;
+ t.tv_sec = t.tv_usec = 0;
+ gettimeofday(&t, NULL);
+ return nsecs_t(t.tv_sec)*1000000000LL + nsecs_t(t.tv_usec)*1000LL;
+#endif
+}
+
+//#define MONITOR_USLEEP
+
+/*
+ * Sleep long enough that we'll wake up "interval" milliseconds after
+ * the previous snooze.
+ *
+ * The "nextTick" argument is updated on each call, and should be passed
+ * in every time. Set its fields to zero on the first call.
+ *
+ * Returns the #of intervals we have overslept, which will be zero if we're
+ * on time. [Currently just returns 0 or 1.]
+ */
+int sleepForInterval(long interval, struct timeval* pNextTick)
+{
+ struct timeval now;
+ long long timeBeforeNext;
+ long sleepTime = 0;
+ bool overSlept = false;
+ //int usleepBias = 0;
+
+#ifdef USLEEP_BIAS
+ /*
+ * Linux likes to add 9000ms or so.
+ * [not using this for now]
+ */
+ //usleepBias = USLEEP_BIAS;
+#endif
+
+ gettimeofday(&now, NULL);
+
+ if (pNextTick->tv_sec == 0) {
+ /* special-case for first time through */
+ *pNextTick = now;
+ sleepTime = interval;
+ android::DurationTimer::addToTimeval(pNextTick, interval);
+ } else {
+ /*
+ * Compute how much time there is before the next tick. If this
+ * value is negative, we've run over. If we've run over a little
+ * bit we can shorten the next frame to keep the pace steady, but
+ * if we've dramatically overshot we need to re-sync.
+ */
+ timeBeforeNext = android::DurationTimer::subtractTimevals(pNextTick, &now);
+ //printf("TOP: now=%ld.%ld next=%ld.%ld diff=%ld\n",
+ // now.tv_sec, now.tv_usec, pNextTick->tv_sec, pNextTick->tv_usec,
+ // (long) timeBeforeNext);
+ if (timeBeforeNext < -interval) {
+ /* way over */
+ overSlept = true;
+ sleepTime = 0;
+ *pNextTick = now;
+ } else if (timeBeforeNext <= 0) {
+ /* slightly over, keep the pace steady */
+ overSlept = true;
+ sleepTime = 0;
+ } else if (timeBeforeNext <= interval) {
+ /* right on schedule */
+ sleepTime = timeBeforeNext;
+ } else if (timeBeforeNext > interval && timeBeforeNext <= 2*interval) {
+ /* sleep call returned early; do a longer sleep this time */
+ sleepTime = timeBeforeNext;
+ } else if (timeBeforeNext > interval) {
+ /* we went back in time -- somebody updated system clock? */
+ /* (could also be a *seriously* broken usleep()) */
+ LOG(LOG_DEBUG, "",
+ " Impossible: timeBeforeNext = %ld\n", (long)timeBeforeNext);
+ sleepTime = 0;
+ *pNextTick = now;
+ }
+ android::DurationTimer::addToTimeval(pNextTick, interval);
+ }
+ //printf(" Before sleep: now=%ld.%ld next=%ld.%ld sleepTime=%ld\n",
+ // now.tv_sec, now.tv_usec, pNextTick->tv_sec, pNextTick->tv_usec,
+ // sleepTime);
+
+ /*
+ * Sleep for the designated period of time.
+ *
+ * Linux tends to sleep for longer than requested, often by 17-18ms.
+ * MinGW tends to sleep for less than requested, by as much as 14ms,
+ * but occasionally oversleeps for 40+ms (looks like some external
+ * factors plus round-off on a 64Hz clock). Cygwin is pretty steady.
+ *
+ * If you start the MinGW version, and then launch the Cygwin version,
+ * the MinGW clock becomes more erratic. Not entirely sure why.
+ *
+ * (There's a lot of stuff here; it's really just a usleep() call with
+ * a bunch of instrumentation.)
+ */
+ if (sleepTime > 0) {
+#if defined(MONITOR_USLEEP)
+ struct timeval before, after;
+ long long actual;
+
+ gettimeofday(&before, NULL);
+ usleep((long) sleepTime);
+ gettimeofday(&after, NULL);
+
+ /* check usleep() accuracy; default Linux threads are pretty sloppy */
+ actual = android::DurationTimer::subtractTimevals(&after, &before);
+ if ((long) actual < sleepTime - 14000 /*(sleepTime/10)*/ ||
+ (long) actual > sleepTime + 20000 /*(sleepTime/10)*/)
+ {
+ LOG(LOG_DEBUG, "", " Odd usleep: req=%ld, actual=%ld\n", sleepTime,
+ (long) actual);
+ }
+#else
+#ifdef HAVE_WIN32_THREADS
+ Sleep( sleepTime/1000 );
+#else
+ usleep((long) sleepTime);
+#endif
+#endif
+ }
+
+ //printf("slept %d\n", sleepTime);
+
+ if (overSlept)
+ return 1; // close enough
+ else
+ return 0;
+}
+
+
+/*
+ * ===========================================================================
+ * DurationTimer
+ * ===========================================================================
+ */
+
+using namespace android;
+
+// Start the timer.
+void DurationTimer::start(void)
+{
+ gettimeofday(&mStartWhen, NULL);
+}
+
+// Stop the timer.
+void DurationTimer::stop(void)
+{
+ gettimeofday(&mStopWhen, NULL);
+}
+
+// Get the duration in microseconds.
+long long DurationTimer::durationUsecs(void) const
+{
+ return (long) subtractTimevals(&mStopWhen, &mStartWhen);
+}
+
+// Subtract two timevals. Returns the difference (ptv1-ptv2) in
+// microseconds.
+/*static*/ long long DurationTimer::subtractTimevals(const struct timeval* ptv1,
+ const struct timeval* ptv2)
+{
+ long long stop = ((long long) ptv1->tv_sec) * 1000000LL +
+ ((long long) ptv1->tv_usec);
+ long long start = ((long long) ptv2->tv_sec) * 1000000LL +
+ ((long long) ptv2->tv_usec);
+ return stop - start;
+}
+
+// Add the specified amount of time to the timeval.
+/*static*/ void DurationTimer::addToTimeval(struct timeval* ptv, long usec)
+{
+ if (usec < 0) {
+ LOG(LOG_WARN, "", "Negative values not supported in addToTimeval\n");
+ return;
+ }
+
+ // normalize tv_usec if necessary
+ if (ptv->tv_usec >= 1000000) {
+ ptv->tv_sec += ptv->tv_usec / 1000000;
+ ptv->tv_usec %= 1000000;
+ }
+
+ ptv->tv_usec += usec % 1000000;
+ if (ptv->tv_usec >= 1000000) {
+ ptv->tv_usec -= 1000000;
+ ptv->tv_sec++;
+ }
+ ptv->tv_sec += usec / 1000000;
+}
+