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