The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2005 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | // |
| 18 | // Timer functions. |
| 19 | // |
| 20 | #include <utils/Timers.h> |
| 21 | #include <utils/ported.h> // may need usleep |
| 22 | #include <utils/Log.h> |
| 23 | |
| 24 | #include <stdlib.h> |
| 25 | #include <stdio.h> |
| 26 | #include <unistd.h> |
| 27 | #include <sys/time.h> |
| 28 | #include <time.h> |
| 29 | #include <errno.h> |
| 30 | |
| 31 | #ifdef HAVE_WIN32_THREADS |
| 32 | #include <windows.h> |
| 33 | #endif |
| 34 | |
| 35 | nsecs_t systemTime(int clock) |
| 36 | { |
| 37 | #if defined(HAVE_POSIX_CLOCKS) |
| 38 | static const clockid_t clocks[] = { |
| 39 | CLOCK_REALTIME, |
| 40 | CLOCK_MONOTONIC, |
| 41 | CLOCK_PROCESS_CPUTIME_ID, |
| 42 | CLOCK_THREAD_CPUTIME_ID |
| 43 | }; |
| 44 | struct timespec t; |
| 45 | t.tv_sec = t.tv_nsec = 0; |
| 46 | clock_gettime(clocks[clock], &t); |
| 47 | return nsecs_t(t.tv_sec)*1000000000LL + t.tv_nsec; |
| 48 | #else |
| 49 | // we don't support the clocks here. |
| 50 | struct timeval t; |
| 51 | t.tv_sec = t.tv_usec = 0; |
| 52 | gettimeofday(&t, NULL); |
| 53 | return nsecs_t(t.tv_sec)*1000000000LL + nsecs_t(t.tv_usec)*1000LL; |
| 54 | #endif |
| 55 | } |
| 56 | |
| 57 | //#define MONITOR_USLEEP |
| 58 | |
| 59 | /* |
| 60 | * Sleep long enough that we'll wake up "interval" milliseconds after |
| 61 | * the previous snooze. |
| 62 | * |
| 63 | * The "nextTick" argument is updated on each call, and should be passed |
| 64 | * in every time. Set its fields to zero on the first call. |
| 65 | * |
| 66 | * Returns the #of intervals we have overslept, which will be zero if we're |
| 67 | * on time. [Currently just returns 0 or 1.] |
| 68 | */ |
| 69 | int sleepForInterval(long interval, struct timeval* pNextTick) |
| 70 | { |
| 71 | struct timeval now; |
| 72 | long long timeBeforeNext; |
| 73 | long sleepTime = 0; |
| 74 | bool overSlept = false; |
| 75 | //int usleepBias = 0; |
| 76 | |
| 77 | #ifdef USLEEP_BIAS |
| 78 | /* |
| 79 | * Linux likes to add 9000ms or so. |
| 80 | * [not using this for now] |
| 81 | */ |
| 82 | //usleepBias = USLEEP_BIAS; |
| 83 | #endif |
| 84 | |
| 85 | gettimeofday(&now, NULL); |
| 86 | |
| 87 | if (pNextTick->tv_sec == 0) { |
| 88 | /* special-case for first time through */ |
| 89 | *pNextTick = now; |
| 90 | sleepTime = interval; |
| 91 | android::DurationTimer::addToTimeval(pNextTick, interval); |
| 92 | } else { |
| 93 | /* |
| 94 | * Compute how much time there is before the next tick. If this |
| 95 | * value is negative, we've run over. If we've run over a little |
| 96 | * bit we can shorten the next frame to keep the pace steady, but |
| 97 | * if we've dramatically overshot we need to re-sync. |
| 98 | */ |
| 99 | timeBeforeNext = android::DurationTimer::subtractTimevals(pNextTick, &now); |
| 100 | //printf("TOP: now=%ld.%ld next=%ld.%ld diff=%ld\n", |
| 101 | // now.tv_sec, now.tv_usec, pNextTick->tv_sec, pNextTick->tv_usec, |
| 102 | // (long) timeBeforeNext); |
| 103 | if (timeBeforeNext < -interval) { |
| 104 | /* way over */ |
| 105 | overSlept = true; |
| 106 | sleepTime = 0; |
| 107 | *pNextTick = now; |
| 108 | } else if (timeBeforeNext <= 0) { |
| 109 | /* slightly over, keep the pace steady */ |
| 110 | overSlept = true; |
| 111 | sleepTime = 0; |
| 112 | } else if (timeBeforeNext <= interval) { |
| 113 | /* right on schedule */ |
| 114 | sleepTime = timeBeforeNext; |
| 115 | } else if (timeBeforeNext > interval && timeBeforeNext <= 2*interval) { |
| 116 | /* sleep call returned early; do a longer sleep this time */ |
| 117 | sleepTime = timeBeforeNext; |
| 118 | } else if (timeBeforeNext > interval) { |
| 119 | /* we went back in time -- somebody updated system clock? */ |
| 120 | /* (could also be a *seriously* broken usleep()) */ |
| 121 | LOG(LOG_DEBUG, "", |
| 122 | " Impossible: timeBeforeNext = %ld\n", (long)timeBeforeNext); |
| 123 | sleepTime = 0; |
| 124 | *pNextTick = now; |
| 125 | } |
| 126 | android::DurationTimer::addToTimeval(pNextTick, interval); |
| 127 | } |
| 128 | //printf(" Before sleep: now=%ld.%ld next=%ld.%ld sleepTime=%ld\n", |
| 129 | // now.tv_sec, now.tv_usec, pNextTick->tv_sec, pNextTick->tv_usec, |
| 130 | // sleepTime); |
| 131 | |
| 132 | /* |
| 133 | * Sleep for the designated period of time. |
| 134 | * |
| 135 | * Linux tends to sleep for longer than requested, often by 17-18ms. |
| 136 | * MinGW tends to sleep for less than requested, by as much as 14ms, |
| 137 | * but occasionally oversleeps for 40+ms (looks like some external |
| 138 | * factors plus round-off on a 64Hz clock). Cygwin is pretty steady. |
| 139 | * |
| 140 | * If you start the MinGW version, and then launch the Cygwin version, |
| 141 | * the MinGW clock becomes more erratic. Not entirely sure why. |
| 142 | * |
| 143 | * (There's a lot of stuff here; it's really just a usleep() call with |
| 144 | * a bunch of instrumentation.) |
| 145 | */ |
| 146 | if (sleepTime > 0) { |
| 147 | #if defined(MONITOR_USLEEP) |
| 148 | struct timeval before, after; |
| 149 | long long actual; |
| 150 | |
| 151 | gettimeofday(&before, NULL); |
| 152 | usleep((long) sleepTime); |
| 153 | gettimeofday(&after, NULL); |
| 154 | |
| 155 | /* check usleep() accuracy; default Linux threads are pretty sloppy */ |
| 156 | actual = android::DurationTimer::subtractTimevals(&after, &before); |
| 157 | if ((long) actual < sleepTime - 14000 /*(sleepTime/10)*/ || |
| 158 | (long) actual > sleepTime + 20000 /*(sleepTime/10)*/) |
| 159 | { |
| 160 | LOG(LOG_DEBUG, "", " Odd usleep: req=%ld, actual=%ld\n", sleepTime, |
| 161 | (long) actual); |
| 162 | } |
| 163 | #else |
| 164 | #ifdef HAVE_WIN32_THREADS |
| 165 | Sleep( sleepTime/1000 ); |
| 166 | #else |
| 167 | usleep((long) sleepTime); |
| 168 | #endif |
| 169 | #endif |
| 170 | } |
| 171 | |
| 172 | //printf("slept %d\n", sleepTime); |
| 173 | |
| 174 | if (overSlept) |
| 175 | return 1; // close enough |
| 176 | else |
| 177 | return 0; |
| 178 | } |
| 179 | |
| 180 | |
| 181 | /* |
| 182 | * =========================================================================== |
| 183 | * DurationTimer |
| 184 | * =========================================================================== |
| 185 | */ |
| 186 | |
| 187 | using namespace android; |
| 188 | |
| 189 | // Start the timer. |
| 190 | void DurationTimer::start(void) |
| 191 | { |
| 192 | gettimeofday(&mStartWhen, NULL); |
| 193 | } |
| 194 | |
| 195 | // Stop the timer. |
| 196 | void DurationTimer::stop(void) |
| 197 | { |
| 198 | gettimeofday(&mStopWhen, NULL); |
| 199 | } |
| 200 | |
| 201 | // Get the duration in microseconds. |
| 202 | long long DurationTimer::durationUsecs(void) const |
| 203 | { |
| 204 | return (long) subtractTimevals(&mStopWhen, &mStartWhen); |
| 205 | } |
| 206 | |
| 207 | // Subtract two timevals. Returns the difference (ptv1-ptv2) in |
| 208 | // microseconds. |
| 209 | /*static*/ long long DurationTimer::subtractTimevals(const struct timeval* ptv1, |
| 210 | const struct timeval* ptv2) |
| 211 | { |
| 212 | long long stop = ((long long) ptv1->tv_sec) * 1000000LL + |
| 213 | ((long long) ptv1->tv_usec); |
| 214 | long long start = ((long long) ptv2->tv_sec) * 1000000LL + |
| 215 | ((long long) ptv2->tv_usec); |
| 216 | return stop - start; |
| 217 | } |
| 218 | |
| 219 | // Add the specified amount of time to the timeval. |
| 220 | /*static*/ void DurationTimer::addToTimeval(struct timeval* ptv, long usec) |
| 221 | { |
| 222 | if (usec < 0) { |
| 223 | LOG(LOG_WARN, "", "Negative values not supported in addToTimeval\n"); |
| 224 | return; |
| 225 | } |
| 226 | |
| 227 | // normalize tv_usec if necessary |
| 228 | if (ptv->tv_usec >= 1000000) { |
| 229 | ptv->tv_sec += ptv->tv_usec / 1000000; |
| 230 | ptv->tv_usec %= 1000000; |
| 231 | } |
| 232 | |
| 233 | ptv->tv_usec += usec % 1000000; |
| 234 | if (ptv->tv_usec >= 1000000) { |
| 235 | ptv->tv_usec -= 1000000; |
| 236 | ptv->tv_sec++; |
| 237 | } |
| 238 | ptv->tv_sec += usec / 1000000; |
| 239 | } |
| 240 | |