OLD | NEW |
| (Empty) |
1 // Copyright 2013 the V8 project authors. All rights reserved. | |
2 // Redistribution and use in source and binary forms, with or without | |
3 // modification, are permitted provided that the following conditions are | |
4 // met: | |
5 // | |
6 // * Redistributions of source code must retain the above copyright | |
7 // notice, this list of conditions and the following disclaimer. | |
8 // * Redistributions in binary form must reproduce the above | |
9 // copyright notice, this list of conditions and the following | |
10 // disclaimer in the documentation and/or other materials provided | |
11 // with the distribution. | |
12 // * Neither the name of Google Inc. nor the names of its | |
13 // contributors may be used to endorse or promote products derived | |
14 // from this software without specific prior written permission. | |
15 // | |
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
27 | |
28 #include "platform/time.h" | |
29 | |
30 #if V8_OS_POSIX | |
31 #include <sys/time.h> | |
32 #endif | |
33 #if V8_OS_MACOSX | |
34 #include <mach/mach_time.h> | |
35 #endif | |
36 | |
37 #include <cstring> | |
38 | |
39 #include "checks.h" | |
40 #include "cpu.h" | |
41 #include "platform.h" | |
42 #if V8_OS_WIN | |
43 #include "win32-headers.h" | |
44 #endif | |
45 | |
46 namespace v8 { | |
47 namespace internal { | |
48 | |
49 TimeDelta TimeDelta::FromDays(int days) { | |
50 return TimeDelta(days * Time::kMicrosecondsPerDay); | |
51 } | |
52 | |
53 | |
54 TimeDelta TimeDelta::FromHours(int hours) { | |
55 return TimeDelta(hours * Time::kMicrosecondsPerHour); | |
56 } | |
57 | |
58 | |
59 TimeDelta TimeDelta::FromMinutes(int minutes) { | |
60 return TimeDelta(minutes * Time::kMicrosecondsPerMinute); | |
61 } | |
62 | |
63 | |
64 TimeDelta TimeDelta::FromSeconds(int64_t seconds) { | |
65 return TimeDelta(seconds * Time::kMicrosecondsPerSecond); | |
66 } | |
67 | |
68 | |
69 TimeDelta TimeDelta::FromMilliseconds(int64_t milliseconds) { | |
70 return TimeDelta(milliseconds * Time::kMicrosecondsPerMillisecond); | |
71 } | |
72 | |
73 | |
74 TimeDelta TimeDelta::FromNanoseconds(int64_t nanoseconds) { | |
75 return TimeDelta(nanoseconds / Time::kNanosecondsPerMicrosecond); | |
76 } | |
77 | |
78 | |
79 int TimeDelta::InDays() const { | |
80 return static_cast<int>(delta_ / Time::kMicrosecondsPerDay); | |
81 } | |
82 | |
83 | |
84 int TimeDelta::InHours() const { | |
85 return static_cast<int>(delta_ / Time::kMicrosecondsPerHour); | |
86 } | |
87 | |
88 | |
89 int TimeDelta::InMinutes() const { | |
90 return static_cast<int>(delta_ / Time::kMicrosecondsPerMinute); | |
91 } | |
92 | |
93 | |
94 double TimeDelta::InSecondsF() const { | |
95 return static_cast<double>(delta_) / Time::kMicrosecondsPerSecond; | |
96 } | |
97 | |
98 | |
99 int64_t TimeDelta::InSeconds() const { | |
100 return delta_ / Time::kMicrosecondsPerSecond; | |
101 } | |
102 | |
103 | |
104 double TimeDelta::InMillisecondsF() const { | |
105 return static_cast<double>(delta_) / Time::kMicrosecondsPerMillisecond; | |
106 } | |
107 | |
108 | |
109 int64_t TimeDelta::InMilliseconds() const { | |
110 return delta_ / Time::kMicrosecondsPerMillisecond; | |
111 } | |
112 | |
113 | |
114 int64_t TimeDelta::InNanoseconds() const { | |
115 return delta_ * Time::kNanosecondsPerMicrosecond; | |
116 } | |
117 | |
118 | |
119 #if V8_OS_WIN | |
120 | |
121 // We implement time using the high-resolution timers so that we can get | |
122 // timeouts which are smaller than 10-15ms. To avoid any drift, we | |
123 // periodically resync the internal clock to the system clock. | |
124 class Clock V8_FINAL { | |
125 public: | |
126 Clock() : initial_time_(CurrentWallclockTime()), | |
127 initial_ticks_(TimeTicks::Now()), | |
128 mutex_(OS::CreateMutex()) {} | |
129 | |
130 ~Clock() { delete mutex_; } | |
131 | |
132 Time Now() { | |
133 // This must be executed under lock. | |
134 ScopedLock sl(mutex_); | |
135 | |
136 // Calculate the time elapsed since we started our timer. | |
137 TimeDelta elapsed = TimeTicks::Now() - initial_ticks_; | |
138 | |
139 // Check if we don't need to synchronize with the wallclock yet. | |
140 if (elapsed.InMicroseconds() <= kMaxMicrosecondsToAvoidDrift) { | |
141 return initial_time_ + elapsed; | |
142 } | |
143 | |
144 // Resynchronize with the wallclock. | |
145 initial_ticks_ = TimeTicks::Now(); | |
146 initial_time_ = CurrentWallclockTime(); | |
147 return initial_time_; | |
148 } | |
149 | |
150 Time NowFromSystemTime() { | |
151 ScopedLock sl(mutex_); | |
152 initial_ticks_ = TimeTicks::Now(); | |
153 initial_time_ = CurrentWallclockTime(); | |
154 return initial_time_; | |
155 } | |
156 | |
157 private: | |
158 // Time between resampling the un-granular clock for this API (1 minute). | |
159 static const int64_t kMaxMicrosecondsToAvoidDrift = | |
160 Time::kMicrosecondsPerMinute; | |
161 | |
162 static Time CurrentWallclockTime() { | |
163 FILETIME ft; | |
164 ::GetSystemTimeAsFileTime(&ft); | |
165 return Time::FromFiletime(ft); | |
166 } | |
167 | |
168 TimeTicks initial_ticks_; | |
169 Time initial_time_; | |
170 Mutex* mutex_; | |
171 }; | |
172 | |
173 | |
174 static LazyDynamicInstance<Clock, | |
175 DefaultCreateTrait<Clock>, | |
176 ThreadSafeInitOnceTrait>::type clock = LAZY_DYNAMIC_INSTANCE_INITIALIZER; | |
177 | |
178 | |
179 Time Time::Now() { | |
180 return clock.Pointer()->Now(); | |
181 } | |
182 | |
183 | |
184 Time Time::NowFromSystemTime() { | |
185 return clock.Pointer()->NowFromSystemTime(); | |
186 } | |
187 | |
188 | |
189 // Time between windows epoch and standard epoch. | |
190 static const int64_t kTimeToEpochInMicroseconds = V8_INT64_C(11644473600000000); | |
191 | |
192 | |
193 Time Time::FromFiletime(FILETIME ft) { | |
194 if (ft.dwLowDateTime == 0 && ft.dwHighDateTime == 0) { | |
195 return Time(); | |
196 } | |
197 if (ft.dwLowDateTime == std::numeric_limits<DWORD>::max() && | |
198 ft.dwHighDateTime == std::numeric_limits<DWORD>::max()) { | |
199 return Max(); | |
200 } | |
201 int64_t us = (static_cast<uint64_t>(ft.dwLowDateTime) + | |
202 (static_cast<uint64_t>(ft.dwHighDateTime) << 32)) / 10; | |
203 return Time(us - kTimeToEpochInMicroseconds); | |
204 } | |
205 | |
206 | |
207 FILETIME Time::ToFiletime() const { | |
208 ASSERT(us_ >= 0); | |
209 FILETIME ft; | |
210 if (IsNull()) { | |
211 ft.dwLowDateTime = 0; | |
212 ft.dwHighDateTime = 0; | |
213 return ft; | |
214 } | |
215 if (IsMax()) { | |
216 ft.dwLowDateTime = std::numeric_limits<DWORD>::max(); | |
217 ft.dwHighDateTime = std::numeric_limits<DWORD>::max(); | |
218 return ft; | |
219 } | |
220 uint64_t us = static_cast<uint64_t>(us_ + kTimeToEpochInMicroseconds) * 10; | |
221 ft.dwLowDateTime = static_cast<DWORD>(us); | |
222 ft.dwHighDateTime = static_cast<DWORD>(us >> 32); | |
223 return ft; | |
224 } | |
225 | |
226 #elif V8_OS_POSIX | |
227 | |
228 Time Time::Now() { | |
229 struct timeval tv; | |
230 int result = gettimeofday(&tv, NULL); | |
231 ASSERT_EQ(0, result); | |
232 USE(result); | |
233 return FromTimeval(tv); | |
234 } | |
235 | |
236 | |
237 Time Time::NowFromSystemTime() { | |
238 return Now(); | |
239 } | |
240 | |
241 | |
242 Time Time::FromTimeval(struct timeval tv) { | |
243 ASSERT(tv.tv_usec >= 0); | |
244 ASSERT(tv.tv_usec < static_cast<suseconds_t>(kMicrosecondsPerSecond)); | |
245 if (tv.tv_usec == 0 && tv.tv_sec == 0) { | |
246 return Time(); | |
247 } | |
248 if (tv.tv_usec == static_cast<suseconds_t>(kMicrosecondsPerSecond - 1) && | |
249 tv.tv_sec == std::numeric_limits<time_t>::max()) { | |
250 return Max(); | |
251 } | |
252 return Time(tv.tv_sec * kMicrosecondsPerSecond + tv.tv_usec); | |
253 } | |
254 | |
255 | |
256 struct timeval Time::ToTimeval() const { | |
257 struct timeval tv; | |
258 if (IsNull()) { | |
259 tv.tv_sec = 0; | |
260 tv.tv_usec = 0; | |
261 return tv; | |
262 } | |
263 if (IsMax()) { | |
264 tv.tv_sec = std::numeric_limits<time_t>::max(); | |
265 tv.tv_usec = static_cast<suseconds_t>(kMicrosecondsPerSecond - 1); | |
266 return tv; | |
267 } | |
268 tv.tv_sec = us_ / kMicrosecondsPerSecond; | |
269 tv.tv_usec = us_ % kMicrosecondsPerSecond; | |
270 return tv; | |
271 } | |
272 | |
273 #endif // V8_OS_WIN | |
274 | |
275 | |
276 Time Time::FromJsTime(double ms_since_epoch) { | |
277 // The epoch is a valid time, so this constructor doesn't interpret | |
278 // 0 as the null time. | |
279 if (ms_since_epoch == std::numeric_limits<double>::max()) { | |
280 return Max(); | |
281 } | |
282 return Time( | |
283 static_cast<int64_t>(ms_since_epoch * kMicrosecondsPerMillisecond)); | |
284 } | |
285 | |
286 | |
287 double Time::ToJsTime() const { | |
288 if (IsNull()) { | |
289 // Preserve 0 so the invalid result doesn't depend on the platform. | |
290 return 0; | |
291 } | |
292 if (IsMax()) { | |
293 // Preserve max without offset to prevent overflow. | |
294 return std::numeric_limits<double>::max(); | |
295 } | |
296 return static_cast<double>(us_) / kMicrosecondsPerMillisecond; | |
297 } | |
298 | |
299 | |
300 #if V8_OS_WIN | |
301 | |
302 class TickClock { | |
303 public: | |
304 virtual ~TickClock() {} | |
305 virtual int64_t Now() = 0; | |
306 }; | |
307 | |
308 | |
309 // Overview of time counters: | |
310 // (1) CPU cycle counter. (Retrieved via RDTSC) | |
311 // The CPU counter provides the highest resolution time stamp and is the least | |
312 // expensive to retrieve. However, the CPU counter is unreliable and should not | |
313 // be used in production. Its biggest issue is that it is per processor and it | |
314 // is not synchronized between processors. Also, on some computers, the counters | |
315 // will change frequency due to thermal and power changes, and stop in some | |
316 // states. | |
317 // | |
318 // (2) QueryPerformanceCounter (QPC). The QPC counter provides a high- | |
319 // resolution (100 nanoseconds) time stamp but is comparatively more expensive | |
320 // to retrieve. What QueryPerformanceCounter actually does is up to the HAL. | |
321 // (with some help from ACPI). | |
322 // According to http://blogs.msdn.com/oldnewthing/archive/2005/09/02/459952.aspx | |
323 // in the worst case, it gets the counter from the rollover interrupt on the | |
324 // programmable interrupt timer. In best cases, the HAL may conclude that the | |
325 // RDTSC counter runs at a constant frequency, then it uses that instead. On | |
326 // multiprocessor machines, it will try to verify the values returned from | |
327 // RDTSC on each processor are consistent with each other, and apply a handful | |
328 // of workarounds for known buggy hardware. In other words, QPC is supposed to | |
329 // give consistent result on a multiprocessor computer, but it is unreliable in | |
330 // reality due to bugs in BIOS or HAL on some, especially old computers. | |
331 // With recent updates on HAL and newer BIOS, QPC is getting more reliable but | |
332 // it should be used with caution. | |
333 // | |
334 // (3) System time. The system time provides a low-resolution (typically 10ms | |
335 // to 55 milliseconds) time stamp but is comparatively less expensive to | |
336 // retrieve and more reliable. | |
337 class HighResolutionTickClock V8_FINAL : public TickClock { | |
338 public: | |
339 explicit HighResolutionTickClock(int64_t ticks_per_second) | |
340 : ticks_per_second_(ticks_per_second) { | |
341 ASSERT_LT(0, ticks_per_second); | |
342 } | |
343 virtual ~HighResolutionTickClock() {} | |
344 | |
345 virtual int64_t Now() V8_OVERRIDE { | |
346 LARGE_INTEGER now; | |
347 BOOL result = QueryPerformanceCounter(&now); | |
348 ASSERT(result); | |
349 USE(result); | |
350 | |
351 // Intentionally calculate microseconds in a round about manner to avoid | |
352 // overflow and precision issues. Think twice before simplifying! | |
353 int64_t whole_seconds = now.QuadPart / ticks_per_second_; | |
354 int64_t leftover_ticks = now.QuadPart % ticks_per_second_; | |
355 int64_t ticks = (whole_seconds * Time::kMicrosecondsPerSecond) + | |
356 ((leftover_ticks * Time::kMicrosecondsPerSecond) / ticks_per_second_); | |
357 | |
358 // Make sure we never return 0 here, so that TimeTicks::HighResNow() | |
359 // will never return 0. | |
360 return ticks + 1; | |
361 } | |
362 | |
363 private: | |
364 int64_t ticks_per_second_; | |
365 }; | |
366 | |
367 | |
368 class RolloverProtectedTickClock V8_FINAL : public TickClock { | |
369 public: | |
370 RolloverProtectedTickClock() | |
371 : mutex_(OS::CreateMutex()), last_seen_now_(0), rollover_ms_(1) { | |
372 // We initialize rollover_ms_ to 1 to ensure that we will never | |
373 // return 0 from TimeTicks::HighResNow() and TimeTicks::Now() below. | |
374 } | |
375 virtual ~RolloverProtectedTickClock() { delete mutex_; } | |
376 | |
377 virtual int64_t Now() V8_OVERRIDE { | |
378 ScopedLock sl(mutex_); | |
379 // We use timeGetTime() to implement TimeTicks::Now(), which rolls over | |
380 // every ~49.7 days. We try to track rollover ourselves, which works if | |
381 // TimeTicks::Now() is called at least every 49 days. | |
382 // Note that we do not use GetTickCount() here, since timeGetTime() gives | |
383 // more predictable delta values, as described here: | |
384 // http://blogs.msdn.com/b/larryosterman/archive/2009/09/02/what-s-the-diffe
rence-between-gettickcount-and-timegettime.aspx | |
385 DWORD now = timeGetTime(); | |
386 if (now < last_seen_now_) { | |
387 rollover_ms_ += V8_INT64_C(0x100000000); // ~49.7 days. | |
388 } | |
389 last_seen_now_ = now; | |
390 return now + rollover_ms_; | |
391 } | |
392 | |
393 private: | |
394 Mutex* mutex_; | |
395 DWORD last_seen_now_; | |
396 int64_t rollover_ms_; | |
397 }; | |
398 | |
399 | |
400 static LazyDynamicInstance<RolloverProtectedTickClock, | |
401 DefaultCreateTrait<RolloverProtectedTickClock>, | |
402 ThreadSafeInitOnceTrait>::type tick_clock = | |
403 LAZY_DYNAMIC_INSTANCE_INITIALIZER; | |
404 | |
405 | |
406 struct CreateHighResTickClockTrait { | |
407 static TickClock* Create() { | |
408 // Check if the installed hardware supports a high-resolution performance | |
409 // counter, and if not fallback to the low-resolution tick clock. | |
410 LARGE_INTEGER ticks_per_second; | |
411 if (!QueryPerformanceFrequency(&ticks_per_second)) { | |
412 return tick_clock.Pointer(); | |
413 } | |
414 | |
415 // On Athlon X2 CPUs (e.g. model 15) the QueryPerformanceCounter | |
416 // is unreliable, fallback to the low-resolution tick clock. | |
417 CPU cpu; | |
418 if (strcmp(cpu.vendor(), "AuthenticAMD") == 0 && cpu.family() == 15) { | |
419 return tick_clock.Pointer(); | |
420 } | |
421 | |
422 return new HighResolutionTickClock(ticks_per_second.QuadPart); | |
423 } | |
424 }; | |
425 | |
426 | |
427 static LazyDynamicInstance<TickClock, | |
428 CreateHighResTickClockTrait, | |
429 ThreadSafeInitOnceTrait>::type high_res_tick_clock = | |
430 LAZY_DYNAMIC_INSTANCE_INITIALIZER; | |
431 | |
432 | |
433 TimeTicks TimeTicks::Now() { | |
434 // Make sure we never return 0 here. | |
435 TimeTicks ticks(tick_clock.Pointer()->Now()); | |
436 ASSERT(!ticks.IsNull()); | |
437 return ticks; | |
438 } | |
439 | |
440 | |
441 TimeTicks TimeTicks::HighResNow() { | |
442 // Make sure we never return 0 here. | |
443 TimeTicks ticks(high_res_tick_clock.Pointer()->Now()); | |
444 ASSERT(!ticks.IsNull()); | |
445 return ticks; | |
446 } | |
447 | |
448 #else // V8_OS_WIN | |
449 | |
450 TimeTicks TimeTicks::Now() { | |
451 return HighResNow(); | |
452 } | |
453 | |
454 | |
455 TimeTicks TimeTicks::HighResNow() { | |
456 int64_t ticks; | |
457 #if V8_OS_MACOSX | |
458 static struct mach_timebase_info info; | |
459 if (info.denom == 0) { | |
460 kern_return_t result = mach_timebase_info(&info); | |
461 ASSERT_EQ(KERN_SUCCESS, result); | |
462 USE(result); | |
463 } | |
464 ticks = (mach_absolute_time() / Time::kNanosecondsPerMicrosecond * | |
465 info.numer / info.denom); | |
466 #elif V8_OS_SOLARIS | |
467 ticks = (gethrtime() / Time::kNanosecondsPerMicrosecond); | |
468 #elif V8_OS_POSIX | |
469 struct timespec ts; | |
470 int result = clock_gettime(CLOCK_MONOTONIC, &ts); | |
471 ASSERT_EQ(0, result); | |
472 USE(result); | |
473 ticks = (ts.tv_sec * Time::kMicrosecondsPerSecond + | |
474 ts.tv_nsec / Time::kNanosecondsPerMicrosecond); | |
475 #endif // V8_OS_MACOSX | |
476 // Make sure we never return 0 here. | |
477 return TimeTicks(ticks + 1); | |
478 } | |
479 | |
480 #endif // V8_OS_WIN | |
481 | |
482 } } // namespace v8::internal | |
OLD | NEW |