/* * 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 #include // may need usleep #include #include #include #include #include #include #include #ifdef HAVE_WIN32_THREADS #include #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; }