| /* |
| * 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; |
| } |
| |