OSDN Git Service

auto import from //depot/cupcake/@132589
[android-x86/frameworks-native.git] / libs / utils / Timers.cpp
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