The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.
Please select the desired protocol below to get the URL.
This URL has Read-Only access.
main_repo / deps / v8 / src / platform / time.cc @ f230a1cf
History | View | Annotate | Download (17.1 KB)
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_MACOSX
|
120 |
|
121 |
TimeDelta TimeDelta::FromMachTimespec(struct mach_timespec ts) {
|
122 |
ASSERT_GE(ts.tv_nsec, 0);
|
123 |
ASSERT_LT(ts.tv_nsec, |
124 |
static_cast<long>(Time::kNanosecondsPerSecond)); // NOLINT |
125 |
return TimeDelta(ts.tv_sec * Time::kMicrosecondsPerSecond +
|
126 |
ts.tv_nsec / Time::kNanosecondsPerMicrosecond); |
127 |
} |
128 |
|
129 |
|
130 |
struct mach_timespec TimeDelta::ToMachTimespec() const { |
131 |
struct mach_timespec ts;
|
132 |
ASSERT(delta_ >= 0);
|
133 |
ts.tv_sec = delta_ / Time::kMicrosecondsPerSecond; |
134 |
ts.tv_nsec = (delta_ % Time::kMicrosecondsPerSecond) * |
135 |
Time::kNanosecondsPerMicrosecond; |
136 |
return ts;
|
137 |
} |
138 |
|
139 |
#endif // V8_OS_MACOSX |
140 |
|
141 |
|
142 |
#if V8_OS_POSIX
|
143 |
|
144 |
TimeDelta TimeDelta::FromTimespec(struct timespec ts) {
|
145 |
ASSERT_GE(ts.tv_nsec, 0);
|
146 |
ASSERT_LT(ts.tv_nsec, |
147 |
static_cast<long>(Time::kNanosecondsPerSecond)); // NOLINT |
148 |
return TimeDelta(ts.tv_sec * Time::kMicrosecondsPerSecond +
|
149 |
ts.tv_nsec / Time::kNanosecondsPerMicrosecond); |
150 |
} |
151 |
|
152 |
|
153 |
struct timespec TimeDelta::ToTimespec() const { |
154 |
struct timespec ts;
|
155 |
ts.tv_sec = delta_ / Time::kMicrosecondsPerSecond; |
156 |
ts.tv_nsec = (delta_ % Time::kMicrosecondsPerSecond) * |
157 |
Time::kNanosecondsPerMicrosecond; |
158 |
return ts;
|
159 |
} |
160 |
|
161 |
#endif // V8_OS_POSIX |
162 |
|
163 |
|
164 |
#if V8_OS_WIN
|
165 |
|
166 |
// We implement time using the high-resolution timers so that we can get
|
167 |
// timeouts which are smaller than 10-15ms. To avoid any drift, we
|
168 |
// periodically resync the internal clock to the system clock.
|
169 |
class Clock V8_FINAL { |
170 |
public:
|
171 |
Clock() : initial_ticks_(GetSystemTicks()), initial_time_(GetSystemTime()) {} |
172 |
|
173 |
Time Now() { |
174 |
// Time between resampling the un-granular clock for this API (1 minute).
|
175 |
const TimeDelta kMaxElapsedTime = TimeDelta::FromMinutes(1); |
176 |
|
177 |
LockGuard<Mutex> lock_guard(&mutex_); |
178 |
|
179 |
// Determine current time and ticks.
|
180 |
TimeTicks ticks = GetSystemTicks(); |
181 |
Time time = GetSystemTime(); |
182 |
|
183 |
// Check if we need to synchronize with the system clock due to a backwards
|
184 |
// time change or the amount of time elapsed.
|
185 |
TimeDelta elapsed = ticks - initial_ticks_; |
186 |
if (time < initial_time_ || elapsed > kMaxElapsedTime) {
|
187 |
initial_ticks_ = ticks; |
188 |
initial_time_ = time; |
189 |
return time;
|
190 |
} |
191 |
|
192 |
return initial_time_ + elapsed;
|
193 |
} |
194 |
|
195 |
Time NowFromSystemTime() { |
196 |
LockGuard<Mutex> lock_guard(&mutex_); |
197 |
initial_ticks_ = GetSystemTicks(); |
198 |
initial_time_ = GetSystemTime(); |
199 |
return initial_time_;
|
200 |
} |
201 |
|
202 |
private:
|
203 |
static TimeTicks GetSystemTicks() {
|
204 |
return TimeTicks::Now();
|
205 |
} |
206 |
|
207 |
static Time GetSystemTime() {
|
208 |
FILETIME ft; |
209 |
::GetSystemTimeAsFileTime(&ft); |
210 |
return Time::FromFiletime(ft);
|
211 |
} |
212 |
|
213 |
TimeTicks initial_ticks_; |
214 |
Time initial_time_; |
215 |
Mutex mutex_; |
216 |
}; |
217 |
|
218 |
|
219 |
static LazyStaticInstance<Clock,
|
220 |
DefaultConstructTrait<Clock>, |
221 |
ThreadSafeInitOnceTrait>::type clock = LAZY_STATIC_INSTANCE_INITIALIZER; |
222 |
|
223 |
|
224 |
Time Time::Now() { |
225 |
return clock.Pointer()->Now();
|
226 |
} |
227 |
|
228 |
|
229 |
Time Time::NowFromSystemTime() { |
230 |
return clock.Pointer()->NowFromSystemTime();
|
231 |
} |
232 |
|
233 |
|
234 |
// Time between windows epoch and standard epoch.
|
235 |
static const int64_t kTimeToEpochInMicroseconds = V8_INT64_C(11644473600000000); |
236 |
|
237 |
|
238 |
Time Time::FromFiletime(FILETIME ft) { |
239 |
if (ft.dwLowDateTime == 0 && ft.dwHighDateTime == 0) { |
240 |
return Time();
|
241 |
} |
242 |
if (ft.dwLowDateTime == std::numeric_limits<DWORD>::max() &&
|
243 |
ft.dwHighDateTime == std::numeric_limits<DWORD>::max()) { |
244 |
return Max();
|
245 |
} |
246 |
int64_t us = (static_cast<uint64_t>(ft.dwLowDateTime) +
|
247 |
(static_cast<uint64_t>(ft.dwHighDateTime) << 32)) / 10; |
248 |
return Time(us - kTimeToEpochInMicroseconds);
|
249 |
} |
250 |
|
251 |
|
252 |
FILETIME Time::ToFiletime() const {
|
253 |
ASSERT(us_ >= 0);
|
254 |
FILETIME ft; |
255 |
if (IsNull()) {
|
256 |
ft.dwLowDateTime = 0;
|
257 |
ft.dwHighDateTime = 0;
|
258 |
return ft;
|
259 |
} |
260 |
if (IsMax()) {
|
261 |
ft.dwLowDateTime = std::numeric_limits<DWORD>::max(); |
262 |
ft.dwHighDateTime = std::numeric_limits<DWORD>::max(); |
263 |
return ft;
|
264 |
} |
265 |
uint64_t us = static_cast<uint64_t>(us_ + kTimeToEpochInMicroseconds) * 10; |
266 |
ft.dwLowDateTime = static_cast<DWORD>(us);
|
267 |
ft.dwHighDateTime = static_cast<DWORD>(us >> 32); |
268 |
return ft;
|
269 |
} |
270 |
|
271 |
#elif V8_OS_POSIX
|
272 |
|
273 |
Time Time::Now() { |
274 |
struct timeval tv;
|
275 |
int result = gettimeofday(&tv, NULL); |
276 |
ASSERT_EQ(0, result);
|
277 |
USE(result); |
278 |
return FromTimeval(tv);
|
279 |
} |
280 |
|
281 |
|
282 |
Time Time::NowFromSystemTime() { |
283 |
return Now();
|
284 |
} |
285 |
|
286 |
|
287 |
Time Time::FromTimespec(struct timespec ts) {
|
288 |
ASSERT(ts.tv_nsec >= 0);
|
289 |
ASSERT(ts.tv_nsec < static_cast<long>(kNanosecondsPerSecond)); // NOLINT |
290 |
if (ts.tv_nsec == 0 && ts.tv_sec == 0) { |
291 |
return Time();
|
292 |
} |
293 |
if (ts.tv_nsec == static_cast<long>(kNanosecondsPerSecond - 1) && // NOLINT |
294 |
ts.tv_sec == std::numeric_limits<time_t>::max()) { |
295 |
return Max();
|
296 |
} |
297 |
return Time(ts.tv_sec * kMicrosecondsPerSecond +
|
298 |
ts.tv_nsec / kNanosecondsPerMicrosecond); |
299 |
} |
300 |
|
301 |
|
302 |
struct timespec Time::ToTimespec() const { |
303 |
struct timespec ts;
|
304 |
if (IsNull()) {
|
305 |
ts.tv_sec = 0;
|
306 |
ts.tv_nsec = 0;
|
307 |
return ts;
|
308 |
} |
309 |
if (IsMax()) {
|
310 |
ts.tv_sec = std::numeric_limits<time_t>::max(); |
311 |
ts.tv_nsec = static_cast<long>(kNanosecondsPerSecond - 1); // NOLINT |
312 |
return ts;
|
313 |
} |
314 |
ts.tv_sec = us_ / kMicrosecondsPerSecond; |
315 |
ts.tv_nsec = (us_ % kMicrosecondsPerSecond) * kNanosecondsPerMicrosecond; |
316 |
return ts;
|
317 |
} |
318 |
|
319 |
|
320 |
Time Time::FromTimeval(struct timeval tv) {
|
321 |
ASSERT(tv.tv_usec >= 0);
|
322 |
ASSERT(tv.tv_usec < static_cast<suseconds_t>(kMicrosecondsPerSecond));
|
323 |
if (tv.tv_usec == 0 && tv.tv_sec == 0) { |
324 |
return Time();
|
325 |
} |
326 |
if (tv.tv_usec == static_cast<suseconds_t>(kMicrosecondsPerSecond - 1) && |
327 |
tv.tv_sec == std::numeric_limits<time_t>::max()) { |
328 |
return Max();
|
329 |
} |
330 |
return Time(tv.tv_sec * kMicrosecondsPerSecond + tv.tv_usec);
|
331 |
} |
332 |
|
333 |
|
334 |
struct timeval Time::ToTimeval() const { |
335 |
struct timeval tv;
|
336 |
if (IsNull()) {
|
337 |
tv.tv_sec = 0;
|
338 |
tv.tv_usec = 0;
|
339 |
return tv;
|
340 |
} |
341 |
if (IsMax()) {
|
342 |
tv.tv_sec = std::numeric_limits<time_t>::max(); |
343 |
tv.tv_usec = static_cast<suseconds_t>(kMicrosecondsPerSecond - 1); |
344 |
return tv;
|
345 |
} |
346 |
tv.tv_sec = us_ / kMicrosecondsPerSecond; |
347 |
tv.tv_usec = us_ % kMicrosecondsPerSecond; |
348 |
return tv;
|
349 |
} |
350 |
|
351 |
#endif // V8_OS_WIN |
352 |
|
353 |
|
354 |
Time Time::FromJsTime(double ms_since_epoch) {
|
355 |
// The epoch is a valid time, so this constructor doesn't interpret
|
356 |
// 0 as the null time.
|
357 |
if (ms_since_epoch == std::numeric_limits<double>::max()) { |
358 |
return Max();
|
359 |
} |
360 |
return Time(
|
361 |
static_cast<int64_t>(ms_since_epoch * kMicrosecondsPerMillisecond));
|
362 |
} |
363 |
|
364 |
|
365 |
double Time::ToJsTime() const { |
366 |
if (IsNull()) {
|
367 |
// Preserve 0 so the invalid result doesn't depend on the platform.
|
368 |
return 0; |
369 |
} |
370 |
if (IsMax()) {
|
371 |
// Preserve max without offset to prevent overflow.
|
372 |
return std::numeric_limits<double>::max(); |
373 |
} |
374 |
return static_cast<double>(us_) / kMicrosecondsPerMillisecond; |
375 |
} |
376 |
|
377 |
|
378 |
#if V8_OS_WIN
|
379 |
|
380 |
class TickClock { |
381 |
public:
|
382 |
virtual ~TickClock() {}
|
383 |
virtual int64_t Now() = 0; |
384 |
virtual bool IsHighResolution() = 0; |
385 |
}; |
386 |
|
387 |
|
388 |
// Overview of time counters:
|
389 |
// (1) CPU cycle counter. (Retrieved via RDTSC)
|
390 |
// The CPU counter provides the highest resolution time stamp and is the least
|
391 |
// expensive to retrieve. However, the CPU counter is unreliable and should not
|
392 |
// be used in production. Its biggest issue is that it is per processor and it
|
393 |
// is not synchronized between processors. Also, on some computers, the counters
|
394 |
// will change frequency due to thermal and power changes, and stop in some
|
395 |
// states.
|
396 |
//
|
397 |
// (2) QueryPerformanceCounter (QPC). The QPC counter provides a high-
|
398 |
// resolution (100 nanoseconds) time stamp but is comparatively more expensive
|
399 |
// to retrieve. What QueryPerformanceCounter actually does is up to the HAL.
|
400 |
// (with some help from ACPI).
|
401 |
// According to http://blogs.msdn.com/oldnewthing/archive/2005/09/02/459952.aspx
|
402 |
// in the worst case, it gets the counter from the rollover interrupt on the
|
403 |
// programmable interrupt timer. In best cases, the HAL may conclude that the
|
404 |
// RDTSC counter runs at a constant frequency, then it uses that instead. On
|
405 |
// multiprocessor machines, it will try to verify the values returned from
|
406 |
// RDTSC on each processor are consistent with each other, and apply a handful
|
407 |
// of workarounds for known buggy hardware. In other words, QPC is supposed to
|
408 |
// give consistent result on a multiprocessor computer, but it is unreliable in
|
409 |
// reality due to bugs in BIOS or HAL on some, especially old computers.
|
410 |
// With recent updates on HAL and newer BIOS, QPC is getting more reliable but
|
411 |
// it should be used with caution.
|
412 |
//
|
413 |
// (3) System time. The system time provides a low-resolution (typically 10ms
|
414 |
// to 55 milliseconds) time stamp but is comparatively less expensive to
|
415 |
// retrieve and more reliable.
|
416 |
class HighResolutionTickClock V8_FINAL : public TickClock { |
417 |
public:
|
418 |
explicit HighResolutionTickClock(int64_t ticks_per_second)
|
419 |
: ticks_per_second_(ticks_per_second) { |
420 |
ASSERT_LT(0, ticks_per_second);
|
421 |
} |
422 |
virtual ~HighResolutionTickClock() {}
|
423 |
|
424 |
virtual int64_t Now() V8_OVERRIDE {
|
425 |
LARGE_INTEGER now; |
426 |
BOOL result = QueryPerformanceCounter(&now); |
427 |
ASSERT(result); |
428 |
USE(result); |
429 |
|
430 |
// Intentionally calculate microseconds in a round about manner to avoid
|
431 |
// overflow and precision issues. Think twice before simplifying!
|
432 |
int64_t whole_seconds = now.QuadPart / ticks_per_second_; |
433 |
int64_t leftover_ticks = now.QuadPart % ticks_per_second_; |
434 |
int64_t ticks = (whole_seconds * Time::kMicrosecondsPerSecond) + |
435 |
((leftover_ticks * Time::kMicrosecondsPerSecond) / ticks_per_second_); |
436 |
|
437 |
// Make sure we never return 0 here, so that TimeTicks::HighResolutionNow()
|
438 |
// will never return 0.
|
439 |
return ticks + 1; |
440 |
} |
441 |
|
442 |
virtual bool IsHighResolution() V8_OVERRIDE { |
443 |
return true; |
444 |
} |
445 |
|
446 |
private:
|
447 |
int64_t ticks_per_second_; |
448 |
}; |
449 |
|
450 |
|
451 |
class RolloverProtectedTickClock V8_FINAL : public TickClock { |
452 |
public:
|
453 |
// We initialize rollover_ms_ to 1 to ensure that we will never
|
454 |
// return 0 from TimeTicks::HighResolutionNow() and TimeTicks::Now() below.
|
455 |
RolloverProtectedTickClock() : last_seen_now_(0), rollover_ms_(1) {} |
456 |
virtual ~RolloverProtectedTickClock() {}
|
457 |
|
458 |
virtual int64_t Now() V8_OVERRIDE {
|
459 |
LockGuard<Mutex> lock_guard(&mutex_); |
460 |
// We use timeGetTime() to implement TimeTicks::Now(), which rolls over
|
461 |
// every ~49.7 days. We try to track rollover ourselves, which works if
|
462 |
// TimeTicks::Now() is called at least every 49 days.
|
463 |
// Note that we do not use GetTickCount() here, since timeGetTime() gives
|
464 |
// more predictable delta values, as described here:
|
465 |
// http://blogs.msdn.com/b/larryosterman/archive/2009/09/02/what-s-the-difference-between-gettickcount-and-timegettime.aspx
|
466 |
// timeGetTime() provides 1ms granularity when combined with
|
467 |
// timeBeginPeriod(). If the host application for V8 wants fast timers, it
|
468 |
// can use timeBeginPeriod() to increase the resolution.
|
469 |
DWORD now = timeGetTime(); |
470 |
if (now < last_seen_now_) {
|
471 |
rollover_ms_ += V8_INT64_C(0x100000000); // ~49.7 days. |
472 |
} |
473 |
last_seen_now_ = now; |
474 |
return (now + rollover_ms_) * Time::kMicrosecondsPerMillisecond;
|
475 |
} |
476 |
|
477 |
virtual bool IsHighResolution() V8_OVERRIDE { |
478 |
return false; |
479 |
} |
480 |
|
481 |
private:
|
482 |
Mutex mutex_; |
483 |
DWORD last_seen_now_; |
484 |
int64_t rollover_ms_; |
485 |
}; |
486 |
|
487 |
|
488 |
static LazyStaticInstance<RolloverProtectedTickClock,
|
489 |
DefaultConstructTrait<RolloverProtectedTickClock>, |
490 |
ThreadSafeInitOnceTrait>::type tick_clock = |
491 |
LAZY_STATIC_INSTANCE_INITIALIZER; |
492 |
|
493 |
|
494 |
struct CreateHighResTickClockTrait {
|
495 |
static TickClock* Create() {
|
496 |
// Check if the installed hardware supports a high-resolution performance
|
497 |
// counter, and if not fallback to the low-resolution tick clock.
|
498 |
LARGE_INTEGER ticks_per_second; |
499 |
if (!QueryPerformanceFrequency(&ticks_per_second)) {
|
500 |
return tick_clock.Pointer();
|
501 |
} |
502 |
|
503 |
// On Athlon X2 CPUs (e.g. model 15) the QueryPerformanceCounter
|
504 |
// is unreliable, fallback to the low-resolution tick clock.
|
505 |
CPU cpu; |
506 |
if (strcmp(cpu.vendor(), "AuthenticAMD") == 0 && cpu.family() == 15) { |
507 |
return tick_clock.Pointer();
|
508 |
} |
509 |
|
510 |
return new HighResolutionTickClock(ticks_per_second.QuadPart); |
511 |
} |
512 |
}; |
513 |
|
514 |
|
515 |
static LazyDynamicInstance<TickClock,
|
516 |
CreateHighResTickClockTrait, |
517 |
ThreadSafeInitOnceTrait>::type high_res_tick_clock = |
518 |
LAZY_DYNAMIC_INSTANCE_INITIALIZER; |
519 |
|
520 |
|
521 |
TimeTicks TimeTicks::Now() { |
522 |
// Make sure we never return 0 here.
|
523 |
TimeTicks ticks(tick_clock.Pointer()->Now()); |
524 |
ASSERT(!ticks.IsNull()); |
525 |
return ticks;
|
526 |
} |
527 |
|
528 |
|
529 |
TimeTicks TimeTicks::HighResolutionNow() { |
530 |
// Make sure we never return 0 here.
|
531 |
TimeTicks ticks(high_res_tick_clock.Pointer()->Now()); |
532 |
ASSERT(!ticks.IsNull()); |
533 |
return ticks;
|
534 |
} |
535 |
|
536 |
|
537 |
// static
|
538 |
bool TimeTicks::IsHighResolutionClockWorking() {
|
539 |
return high_res_tick_clock.Pointer()->IsHighResolution();
|
540 |
} |
541 |
|
542 |
#else // V8_OS_WIN |
543 |
|
544 |
TimeTicks TimeTicks::Now() { |
545 |
return HighResolutionNow();
|
546 |
} |
547 |
|
548 |
|
549 |
TimeTicks TimeTicks::HighResolutionNow() { |
550 |
int64_t ticks; |
551 |
#if V8_OS_MACOSX
|
552 |
static struct mach_timebase_info info; |
553 |
if (info.denom == 0) { |
554 |
kern_return_t result = mach_timebase_info(&info); |
555 |
ASSERT_EQ(KERN_SUCCESS, result); |
556 |
USE(result); |
557 |
} |
558 |
ticks = (mach_absolute_time() / Time::kNanosecondsPerMicrosecond * |
559 |
info.numer / info.denom); |
560 |
#elif V8_OS_SOLARIS
|
561 |
ticks = (gethrtime() / Time::kNanosecondsPerMicrosecond); |
562 |
#elif V8_LIBRT_NOT_AVAILABLE
|
563 |
// TODO(bmeurer): This is a temporary hack to support cross-compiling
|
564 |
// Chrome for Android in AOSP. Remove this once AOSP is fixed, also
|
565 |
// cleanup the tools/gyp/v8.gyp file.
|
566 |
struct timeval tv;
|
567 |
int result = gettimeofday(&tv, NULL); |
568 |
ASSERT_EQ(0, result);
|
569 |
USE(result); |
570 |
ticks = (tv.tv_sec * Time::kMicrosecondsPerSecond + tv.tv_usec); |
571 |
#elif V8_OS_POSIX
|
572 |
struct timespec ts;
|
573 |
int result = clock_gettime(CLOCK_MONOTONIC, &ts);
|
574 |
ASSERT_EQ(0, result);
|
575 |
USE(result); |
576 |
ticks = (ts.tv_sec * Time::kMicrosecondsPerSecond + |
577 |
ts.tv_nsec / Time::kNanosecondsPerMicrosecond); |
578 |
#endif // V8_OS_MACOSX |
579 |
// Make sure we never return 0 here.
|
580 |
return TimeTicks(ticks + 1); |
581 |
} |
582 |
|
583 |
|
584 |
// static
|
585 |
bool TimeTicks::IsHighResolutionClockWorking() {
|
586 |
return true; |
587 |
} |
588 |
|
589 |
#endif // V8_OS_WIN |
590 |
|
591 |
} } // namespace v8::internal
|