blob: 786ef2e6c2e6a7665546648db6297dbeda751083 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// Copyright 2013 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/base/platform/time.h"
6
7#if V8_OS_POSIX
8#include <fcntl.h> // for O_RDONLY
9#include <sys/time.h>
10#include <unistd.h>
11#endif
12#if V8_OS_MACOSX
Ben Murdochc5610432016-08-08 18:44:38 +010013#include <mach/mach.h>
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014#include <mach/mach_time.h>
Ben Murdochc5610432016-08-08 18:44:38 +010015#include <pthread.h>
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016#endif
17
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018#include <cstring>
19#include <ostream>
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020
21#if V8_OS_WIN
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000022#include "src/base/atomicops.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000023#include "src/base/lazy-instance.h"
24#include "src/base/win32-headers.h"
25#endif
26#include "src/base/cpu.h"
27#include "src/base/logging.h"
28#include "src/base/platform/platform.h"
29
Ben Murdochc5610432016-08-08 18:44:38 +010030namespace {
31
32#if V8_OS_MACOSX
33int64_t ComputeThreadTicks() {
34 mach_msg_type_number_t thread_info_count = THREAD_BASIC_INFO_COUNT;
35 thread_basic_info_data_t thread_info_data;
36 kern_return_t kr = thread_info(
37 pthread_mach_thread_np(pthread_self()),
38 THREAD_BASIC_INFO,
39 reinterpret_cast<thread_info_t>(&thread_info_data),
40 &thread_info_count);
41 CHECK(kr == KERN_SUCCESS);
42
43 v8::base::CheckedNumeric<int64_t> absolute_micros(
Ben Murdoch61f157c2016-09-16 13:49:30 +010044 thread_info_data.user_time.seconds +
45 thread_info_data.system_time.seconds);
Ben Murdochc5610432016-08-08 18:44:38 +010046 absolute_micros *= v8::base::Time::kMicrosecondsPerSecond;
Ben Murdoch61f157c2016-09-16 13:49:30 +010047 absolute_micros += (thread_info_data.user_time.microseconds +
48 thread_info_data.system_time.microseconds);
Ben Murdochc5610432016-08-08 18:44:38 +010049 return absolute_micros.ValueOrDie();
50}
51#elif V8_OS_POSIX
52// Helper function to get results from clock_gettime() and convert to a
53// microsecond timebase. Minimum requirement is MONOTONIC_CLOCK to be supported
54// on the system. FreeBSD 6 has CLOCK_MONOTONIC but defines
55// _POSIX_MONOTONIC_CLOCK to -1.
Ben Murdoch61f157c2016-09-16 13:49:30 +010056V8_INLINE int64_t ClockNow(clockid_t clk_id) {
Ben Murdochc5610432016-08-08 18:44:38 +010057#if (defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0) || \
58 defined(V8_OS_BSD) || defined(V8_OS_ANDROID)
Ben Murdoch61f157c2016-09-16 13:49:30 +010059// On AIX clock_gettime for CLOCK_THREAD_CPUTIME_ID outputs time with
60// resolution of 10ms. thread_cputime API provides the time in ns
61#if defined(V8_OS_AIX)
62 thread_cputime_t tc;
63 if (clk_id == CLOCK_THREAD_CPUTIME_ID) {
64 if (thread_cputime(-1, &tc) != 0) {
65 UNREACHABLE();
66 return 0;
67 }
68 }
69#endif
Ben Murdochc5610432016-08-08 18:44:38 +010070 struct timespec ts;
71 if (clock_gettime(clk_id, &ts) != 0) {
72 UNREACHABLE();
73 return 0;
74 }
75 v8::base::internal::CheckedNumeric<int64_t> result(ts.tv_sec);
76 result *= v8::base::Time::kMicrosecondsPerSecond;
Ben Murdoch61f157c2016-09-16 13:49:30 +010077#if defined(V8_OS_AIX)
78 if (clk_id == CLOCK_THREAD_CPUTIME_ID) {
79 result += (tc.stime / v8::base::Time::kNanosecondsPerMicrosecond);
80 } else {
81 result += (ts.tv_nsec / v8::base::Time::kNanosecondsPerMicrosecond);
82 }
83#else
Ben Murdochc5610432016-08-08 18:44:38 +010084 result += (ts.tv_nsec / v8::base::Time::kNanosecondsPerMicrosecond);
Ben Murdoch61f157c2016-09-16 13:49:30 +010085#endif
Ben Murdochc5610432016-08-08 18:44:38 +010086 return result.ValueOrDie();
87#else // Monotonic clock not supported.
88 return 0;
89#endif
90}
Ben Murdoch61f157c2016-09-16 13:49:30 +010091#elif V8_OS_WIN
92V8_INLINE bool IsQPCReliable() {
93 v8::base::CPU cpu;
94 // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is unreliable.
95 return strcmp(cpu.vendor(), "AuthenticAMD") == 0 && cpu.family() == 15;
96}
97
98// Returns the current value of the performance counter.
99V8_INLINE uint64_t QPCNowRaw() {
100 LARGE_INTEGER perf_counter_now = {};
101 // According to the MSDN documentation for QueryPerformanceCounter(), this
102 // will never fail on systems that run XP or later.
103 // https://msdn.microsoft.com/library/windows/desktop/ms644904.aspx
104 BOOL result = ::QueryPerformanceCounter(&perf_counter_now);
105 DCHECK(result);
106 USE(result);
107 return perf_counter_now.QuadPart;
108}
Ben Murdochc5610432016-08-08 18:44:38 +0100109#endif // V8_OS_MACOSX
110
111
112} // namespace
113
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000114namespace v8 {
115namespace base {
116
117TimeDelta TimeDelta::FromDays(int days) {
118 return TimeDelta(days * Time::kMicrosecondsPerDay);
119}
120
121
122TimeDelta TimeDelta::FromHours(int hours) {
123 return TimeDelta(hours * Time::kMicrosecondsPerHour);
124}
125
126
127TimeDelta TimeDelta::FromMinutes(int minutes) {
128 return TimeDelta(minutes * Time::kMicrosecondsPerMinute);
129}
130
131
132TimeDelta TimeDelta::FromSeconds(int64_t seconds) {
133 return TimeDelta(seconds * Time::kMicrosecondsPerSecond);
134}
135
136
137TimeDelta TimeDelta::FromMilliseconds(int64_t milliseconds) {
138 return TimeDelta(milliseconds * Time::kMicrosecondsPerMillisecond);
139}
140
141
142TimeDelta TimeDelta::FromNanoseconds(int64_t nanoseconds) {
143 return TimeDelta(nanoseconds / Time::kNanosecondsPerMicrosecond);
144}
145
146
147int TimeDelta::InDays() const {
148 return static_cast<int>(delta_ / Time::kMicrosecondsPerDay);
149}
150
151
152int TimeDelta::InHours() const {
153 return static_cast<int>(delta_ / Time::kMicrosecondsPerHour);
154}
155
156
157int TimeDelta::InMinutes() const {
158 return static_cast<int>(delta_ / Time::kMicrosecondsPerMinute);
159}
160
161
162double TimeDelta::InSecondsF() const {
163 return static_cast<double>(delta_) / Time::kMicrosecondsPerSecond;
164}
165
166
167int64_t TimeDelta::InSeconds() const {
168 return delta_ / Time::kMicrosecondsPerSecond;
169}
170
171
172double TimeDelta::InMillisecondsF() const {
173 return static_cast<double>(delta_) / Time::kMicrosecondsPerMillisecond;
174}
175
176
177int64_t TimeDelta::InMilliseconds() const {
178 return delta_ / Time::kMicrosecondsPerMillisecond;
179}
180
181
182int64_t TimeDelta::InNanoseconds() const {
183 return delta_ * Time::kNanosecondsPerMicrosecond;
184}
185
186
187#if V8_OS_MACOSX
188
189TimeDelta TimeDelta::FromMachTimespec(struct mach_timespec ts) {
190 DCHECK_GE(ts.tv_nsec, 0);
191 DCHECK_LT(ts.tv_nsec,
192 static_cast<long>(Time::kNanosecondsPerSecond)); // NOLINT
193 return TimeDelta(ts.tv_sec * Time::kMicrosecondsPerSecond +
194 ts.tv_nsec / Time::kNanosecondsPerMicrosecond);
195}
196
197
198struct mach_timespec TimeDelta::ToMachTimespec() const {
199 struct mach_timespec ts;
200 DCHECK(delta_ >= 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000201 ts.tv_sec = static_cast<unsigned>(delta_ / Time::kMicrosecondsPerSecond);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000202 ts.tv_nsec = (delta_ % Time::kMicrosecondsPerSecond) *
203 Time::kNanosecondsPerMicrosecond;
204 return ts;
205}
206
207#endif // V8_OS_MACOSX
208
209
210#if V8_OS_POSIX
211
212TimeDelta TimeDelta::FromTimespec(struct timespec ts) {
213 DCHECK_GE(ts.tv_nsec, 0);
214 DCHECK_LT(ts.tv_nsec,
215 static_cast<long>(Time::kNanosecondsPerSecond)); // NOLINT
216 return TimeDelta(ts.tv_sec * Time::kMicrosecondsPerSecond +
217 ts.tv_nsec / Time::kNanosecondsPerMicrosecond);
218}
219
220
221struct timespec TimeDelta::ToTimespec() const {
222 struct timespec ts;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000223 ts.tv_sec = static_cast<time_t>(delta_ / Time::kMicrosecondsPerSecond);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000224 ts.tv_nsec = (delta_ % Time::kMicrosecondsPerSecond) *
225 Time::kNanosecondsPerMicrosecond;
226 return ts;
227}
228
229#endif // V8_OS_POSIX
230
231
232#if V8_OS_WIN
233
234// We implement time using the high-resolution timers so that we can get
235// timeouts which are smaller than 10-15ms. To avoid any drift, we
236// periodically resync the internal clock to the system clock.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000237class Clock final {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000238 public:
239 Clock() : initial_ticks_(GetSystemTicks()), initial_time_(GetSystemTime()) {}
240
241 Time Now() {
242 // Time between resampling the un-granular clock for this API (1 minute).
243 const TimeDelta kMaxElapsedTime = TimeDelta::FromMinutes(1);
244
245 LockGuard<Mutex> lock_guard(&mutex_);
246
247 // Determine current time and ticks.
248 TimeTicks ticks = GetSystemTicks();
249 Time time = GetSystemTime();
250
251 // Check if we need to synchronize with the system clock due to a backwards
252 // time change or the amount of time elapsed.
253 TimeDelta elapsed = ticks - initial_ticks_;
254 if (time < initial_time_ || elapsed > kMaxElapsedTime) {
255 initial_ticks_ = ticks;
256 initial_time_ = time;
257 return time;
258 }
259
260 return initial_time_ + elapsed;
261 }
262
263 Time NowFromSystemTime() {
264 LockGuard<Mutex> lock_guard(&mutex_);
265 initial_ticks_ = GetSystemTicks();
266 initial_time_ = GetSystemTime();
267 return initial_time_;
268 }
269
270 private:
271 static TimeTicks GetSystemTicks() {
272 return TimeTicks::Now();
273 }
274
275 static Time GetSystemTime() {
276 FILETIME ft;
277 ::GetSystemTimeAsFileTime(&ft);
278 return Time::FromFiletime(ft);
279 }
280
281 TimeTicks initial_ticks_;
282 Time initial_time_;
283 Mutex mutex_;
284};
285
286
287static LazyStaticInstance<Clock, DefaultConstructTrait<Clock>,
288 ThreadSafeInitOnceTrait>::type clock =
289 LAZY_STATIC_INSTANCE_INITIALIZER;
290
291
292Time Time::Now() {
293 return clock.Pointer()->Now();
294}
295
296
297Time Time::NowFromSystemTime() {
298 return clock.Pointer()->NowFromSystemTime();
299}
300
301
302// Time between windows epoch and standard epoch.
303static const int64_t kTimeToEpochInMicroseconds = V8_INT64_C(11644473600000000);
304
305
306Time Time::FromFiletime(FILETIME ft) {
307 if (ft.dwLowDateTime == 0 && ft.dwHighDateTime == 0) {
308 return Time();
309 }
310 if (ft.dwLowDateTime == std::numeric_limits<DWORD>::max() &&
311 ft.dwHighDateTime == std::numeric_limits<DWORD>::max()) {
312 return Max();
313 }
314 int64_t us = (static_cast<uint64_t>(ft.dwLowDateTime) +
315 (static_cast<uint64_t>(ft.dwHighDateTime) << 32)) / 10;
316 return Time(us - kTimeToEpochInMicroseconds);
317}
318
319
320FILETIME Time::ToFiletime() const {
321 DCHECK(us_ >= 0);
322 FILETIME ft;
323 if (IsNull()) {
324 ft.dwLowDateTime = 0;
325 ft.dwHighDateTime = 0;
326 return ft;
327 }
328 if (IsMax()) {
329 ft.dwLowDateTime = std::numeric_limits<DWORD>::max();
330 ft.dwHighDateTime = std::numeric_limits<DWORD>::max();
331 return ft;
332 }
333 uint64_t us = static_cast<uint64_t>(us_ + kTimeToEpochInMicroseconds) * 10;
334 ft.dwLowDateTime = static_cast<DWORD>(us);
335 ft.dwHighDateTime = static_cast<DWORD>(us >> 32);
336 return ft;
337}
338
339#elif V8_OS_POSIX
340
341Time Time::Now() {
342 struct timeval tv;
343 int result = gettimeofday(&tv, NULL);
344 DCHECK_EQ(0, result);
345 USE(result);
346 return FromTimeval(tv);
347}
348
349
350Time Time::NowFromSystemTime() {
351 return Now();
352}
353
354
355Time Time::FromTimespec(struct timespec ts) {
356 DCHECK(ts.tv_nsec >= 0);
357 DCHECK(ts.tv_nsec < static_cast<long>(kNanosecondsPerSecond)); // NOLINT
358 if (ts.tv_nsec == 0 && ts.tv_sec == 0) {
359 return Time();
360 }
361 if (ts.tv_nsec == static_cast<long>(kNanosecondsPerSecond - 1) && // NOLINT
362 ts.tv_sec == std::numeric_limits<time_t>::max()) {
363 return Max();
364 }
365 return Time(ts.tv_sec * kMicrosecondsPerSecond +
366 ts.tv_nsec / kNanosecondsPerMicrosecond);
367}
368
369
370struct timespec Time::ToTimespec() const {
371 struct timespec ts;
372 if (IsNull()) {
373 ts.tv_sec = 0;
374 ts.tv_nsec = 0;
375 return ts;
376 }
377 if (IsMax()) {
378 ts.tv_sec = std::numeric_limits<time_t>::max();
379 ts.tv_nsec = static_cast<long>(kNanosecondsPerSecond - 1); // NOLINT
380 return ts;
381 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000382 ts.tv_sec = static_cast<time_t>(us_ / kMicrosecondsPerSecond);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000383 ts.tv_nsec = (us_ % kMicrosecondsPerSecond) * kNanosecondsPerMicrosecond;
384 return ts;
385}
386
387
388Time Time::FromTimeval(struct timeval tv) {
389 DCHECK(tv.tv_usec >= 0);
390 DCHECK(tv.tv_usec < static_cast<suseconds_t>(kMicrosecondsPerSecond));
391 if (tv.tv_usec == 0 && tv.tv_sec == 0) {
392 return Time();
393 }
394 if (tv.tv_usec == static_cast<suseconds_t>(kMicrosecondsPerSecond - 1) &&
395 tv.tv_sec == std::numeric_limits<time_t>::max()) {
396 return Max();
397 }
398 return Time(tv.tv_sec * kMicrosecondsPerSecond + tv.tv_usec);
399}
400
401
402struct timeval Time::ToTimeval() const {
403 struct timeval tv;
404 if (IsNull()) {
405 tv.tv_sec = 0;
406 tv.tv_usec = 0;
407 return tv;
408 }
409 if (IsMax()) {
410 tv.tv_sec = std::numeric_limits<time_t>::max();
411 tv.tv_usec = static_cast<suseconds_t>(kMicrosecondsPerSecond - 1);
412 return tv;
413 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000414 tv.tv_sec = static_cast<time_t>(us_ / kMicrosecondsPerSecond);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000415 tv.tv_usec = us_ % kMicrosecondsPerSecond;
416 return tv;
417}
418
419#endif // V8_OS_WIN
420
421
422Time Time::FromJsTime(double ms_since_epoch) {
423 // The epoch is a valid time, so this constructor doesn't interpret
424 // 0 as the null time.
425 if (ms_since_epoch == std::numeric_limits<double>::max()) {
426 return Max();
427 }
428 return Time(
429 static_cast<int64_t>(ms_since_epoch * kMicrosecondsPerMillisecond));
430}
431
432
433double Time::ToJsTime() const {
434 if (IsNull()) {
435 // Preserve 0 so the invalid result doesn't depend on the platform.
436 return 0;
437 }
438 if (IsMax()) {
439 // Preserve max without offset to prevent overflow.
440 return std::numeric_limits<double>::max();
441 }
442 return static_cast<double>(us_) / kMicrosecondsPerMillisecond;
443}
444
445
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000446std::ostream& operator<<(std::ostream& os, const Time& time) {
447 return os << time.ToJsTime();
448}
449
450
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000451#if V8_OS_WIN
452
453class TickClock {
454 public:
455 virtual ~TickClock() {}
456 virtual int64_t Now() = 0;
457 virtual bool IsHighResolution() = 0;
458};
459
460
461// Overview of time counters:
462// (1) CPU cycle counter. (Retrieved via RDTSC)
463// The CPU counter provides the highest resolution time stamp and is the least
464// expensive to retrieve. However, the CPU counter is unreliable and should not
465// be used in production. Its biggest issue is that it is per processor and it
466// is not synchronized between processors. Also, on some computers, the counters
467// will change frequency due to thermal and power changes, and stop in some
468// states.
469//
470// (2) QueryPerformanceCounter (QPC). The QPC counter provides a high-
471// resolution (100 nanoseconds) time stamp but is comparatively more expensive
472// to retrieve. What QueryPerformanceCounter actually does is up to the HAL.
473// (with some help from ACPI).
474// According to http://blogs.msdn.com/oldnewthing/archive/2005/09/02/459952.aspx
475// in the worst case, it gets the counter from the rollover interrupt on the
476// programmable interrupt timer. In best cases, the HAL may conclude that the
477// RDTSC counter runs at a constant frequency, then it uses that instead. On
478// multiprocessor machines, it will try to verify the values returned from
479// RDTSC on each processor are consistent with each other, and apply a handful
480// of workarounds for known buggy hardware. In other words, QPC is supposed to
481// give consistent result on a multiprocessor computer, but it is unreliable in
482// reality due to bugs in BIOS or HAL on some, especially old computers.
483// With recent updates on HAL and newer BIOS, QPC is getting more reliable but
484// it should be used with caution.
485//
486// (3) System time. The system time provides a low-resolution (typically 10ms
487// to 55 milliseconds) time stamp but is comparatively less expensive to
488// retrieve and more reliable.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000489class HighResolutionTickClock final : public TickClock {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000490 public:
491 explicit HighResolutionTickClock(int64_t ticks_per_second)
492 : ticks_per_second_(ticks_per_second) {
493 DCHECK_LT(0, ticks_per_second);
494 }
495 virtual ~HighResolutionTickClock() {}
496
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000497 int64_t Now() override {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100498 uint64_t now = QPCNowRaw();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000499
500 // Intentionally calculate microseconds in a round about manner to avoid
501 // overflow and precision issues. Think twice before simplifying!
Ben Murdoch61f157c2016-09-16 13:49:30 +0100502 int64_t whole_seconds = now / ticks_per_second_;
503 int64_t leftover_ticks = now % ticks_per_second_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000504 int64_t ticks = (whole_seconds * Time::kMicrosecondsPerSecond) +
505 ((leftover_ticks * Time::kMicrosecondsPerSecond) / ticks_per_second_);
506
507 // Make sure we never return 0 here, so that TimeTicks::HighResolutionNow()
508 // will never return 0.
509 return ticks + 1;
510 }
511
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000512 bool IsHighResolution() override { return true; }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000513
514 private:
515 int64_t ticks_per_second_;
516};
517
518
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000519class RolloverProtectedTickClock final : public TickClock {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000520 public:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000521 RolloverProtectedTickClock() : rollover_(0) {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000522 virtual ~RolloverProtectedTickClock() {}
523
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000524 int64_t Now() override {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000525 // We use timeGetTime() to implement TimeTicks::Now(), which rolls over
526 // every ~49.7 days. We try to track rollover ourselves, which works if
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000527 // TimeTicks::Now() is called at least every 24 days.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000528 // Note that we do not use GetTickCount() here, since timeGetTime() gives
529 // more predictable delta values, as described here:
530 // http://blogs.msdn.com/b/larryosterman/archive/2009/09/02/what-s-the-difference-between-gettickcount-and-timegettime.aspx
531 // timeGetTime() provides 1ms granularity when combined with
532 // timeBeginPeriod(). If the host application for V8 wants fast timers, it
533 // can use timeBeginPeriod() to increase the resolution.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000534 // We use a lock-free version because the sampler thread calls it
535 // while having the rest of the world stopped, that could cause a deadlock.
536 base::Atomic32 rollover = base::Acquire_Load(&rollover_);
537 uint32_t now = static_cast<uint32_t>(timeGetTime());
538 if ((now >> 31) != static_cast<uint32_t>(rollover & 1)) {
539 base::Release_CompareAndSwap(&rollover_, rollover, rollover + 1);
540 ++rollover;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000541 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000542 uint64_t ms = (static_cast<uint64_t>(rollover) << 31) | now;
543 return static_cast<int64_t>(ms * Time::kMicrosecondsPerMillisecond);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000544 }
545
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000546 bool IsHighResolution() override { return false; }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000547
548 private:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000549 base::Atomic32 rollover_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000550};
551
552
553static LazyStaticInstance<RolloverProtectedTickClock,
554 DefaultConstructTrait<RolloverProtectedTickClock>,
555 ThreadSafeInitOnceTrait>::type tick_clock =
556 LAZY_STATIC_INSTANCE_INITIALIZER;
557
558
559struct CreateHighResTickClockTrait {
560 static TickClock* Create() {
561 // Check if the installed hardware supports a high-resolution performance
562 // counter, and if not fallback to the low-resolution tick clock.
563 LARGE_INTEGER ticks_per_second;
564 if (!QueryPerformanceFrequency(&ticks_per_second)) {
565 return tick_clock.Pointer();
566 }
567
Ben Murdoch61f157c2016-09-16 13:49:30 +0100568 // If QPC not reliable, fallback to low-resolution tick clock.
569 if (IsQPCReliable()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000570 return tick_clock.Pointer();
571 }
572
573 return new HighResolutionTickClock(ticks_per_second.QuadPart);
574 }
575};
576
577
578static LazyDynamicInstance<TickClock, CreateHighResTickClockTrait,
579 ThreadSafeInitOnceTrait>::type high_res_tick_clock =
580 LAZY_DYNAMIC_INSTANCE_INITIALIZER;
581
582
583TimeTicks TimeTicks::Now() {
584 // Make sure we never return 0 here.
585 TimeTicks ticks(tick_clock.Pointer()->Now());
586 DCHECK(!ticks.IsNull());
587 return ticks;
588}
589
590
591TimeTicks TimeTicks::HighResolutionNow() {
592 // Make sure we never return 0 here.
593 TimeTicks ticks(high_res_tick_clock.Pointer()->Now());
594 DCHECK(!ticks.IsNull());
595 return ticks;
596}
597
598
599// static
600bool TimeTicks::IsHighResolutionClockWorking() {
601 return high_res_tick_clock.Pointer()->IsHighResolution();
602}
603
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000604#else // V8_OS_WIN
605
606TimeTicks TimeTicks::Now() {
607 return HighResolutionNow();
608}
609
610
611TimeTicks TimeTicks::HighResolutionNow() {
612 int64_t ticks;
613#if V8_OS_MACOSX
614 static struct mach_timebase_info info;
615 if (info.denom == 0) {
616 kern_return_t result = mach_timebase_info(&info);
617 DCHECK_EQ(KERN_SUCCESS, result);
618 USE(result);
619 }
620 ticks = (mach_absolute_time() / Time::kNanosecondsPerMicrosecond *
621 info.numer / info.denom);
622#elif V8_OS_SOLARIS
623 ticks = (gethrtime() / Time::kNanosecondsPerMicrosecond);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000624#elif V8_OS_POSIX
Ben Murdochc5610432016-08-08 18:44:38 +0100625 ticks = ClockNow(CLOCK_MONOTONIC);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000626#endif // V8_OS_MACOSX
627 // Make sure we never return 0 here.
628 return TimeTicks(ticks + 1);
629}
630
631
632// static
633bool TimeTicks::IsHighResolutionClockWorking() {
634 return true;
635}
636
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000637#endif // V8_OS_WIN
638
Ben Murdochc5610432016-08-08 18:44:38 +0100639
640// TODO(lpy): For windows ThreadTicks implementation,
641// see http://crbug.com/v8/5000
642bool ThreadTicks::IsSupported() {
643#if (defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \
644 defined(V8_OS_MACOSX) || defined(V8_OS_ANDROID)
645 return true;
646#else
647 return false;
648#endif
649}
650
651
652ThreadTicks ThreadTicks::Now() {
653#if V8_OS_MACOSX
654 return ThreadTicks(ComputeThreadTicks());
655#elif(defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \
656 defined(V8_OS_ANDROID)
657 return ThreadTicks(ClockNow(CLOCK_THREAD_CPUTIME_ID));
Ben Murdoch61f157c2016-09-16 13:49:30 +0100658#elif V8_OS_WIN
659 return ThreadTicks::GetForThread(::GetCurrentThread());
Ben Murdochc5610432016-08-08 18:44:38 +0100660#else
661 UNREACHABLE();
662 return ThreadTicks();
663#endif
664}
665
Ben Murdoch61f157c2016-09-16 13:49:30 +0100666
667#if V8_OS_WIN
668ThreadTicks ThreadTicks::GetForThread(const HANDLE& thread_handle) {
669 DCHECK(IsSupported());
670
671 // Get the number of TSC ticks used by the current thread.
672 ULONG64 thread_cycle_time = 0;
673 ::QueryThreadCycleTime(thread_handle, &thread_cycle_time);
674
675 // Get the frequency of the TSC.
676 double tsc_ticks_per_second = TSCTicksPerSecond();
677 if (tsc_ticks_per_second == 0)
678 return ThreadTicks();
679
680 // Return the CPU time of the current thread.
681 double thread_time_seconds = thread_cycle_time / tsc_ticks_per_second;
682 return ThreadTicks(
683 static_cast<int64_t>(thread_time_seconds * Time::kMicrosecondsPerSecond));
684}
685
686// static
687bool ThreadTicks::IsSupportedWin() {
688 static bool is_supported = base::CPU().has_non_stop_time_stamp_counter() &&
689 !IsQPCReliable();
690 return is_supported;
691}
692
693// static
694void ThreadTicks::WaitUntilInitializedWin() {
695 while (TSCTicksPerSecond() == 0)
696 ::Sleep(10);
697}
698
699double ThreadTicks::TSCTicksPerSecond() {
700 DCHECK(IsSupported());
701
702 // The value returned by QueryPerformanceFrequency() cannot be used as the TSC
703 // frequency, because there is no guarantee that the TSC frequency is equal to
704 // the performance counter frequency.
705
706 // The TSC frequency is cached in a static variable because it takes some time
707 // to compute it.
708 static double tsc_ticks_per_second = 0;
709 if (tsc_ticks_per_second != 0)
710 return tsc_ticks_per_second;
711
712 // Increase the thread priority to reduces the chances of having a context
713 // switch during a reading of the TSC and the performance counter.
714 int previous_priority = ::GetThreadPriority(::GetCurrentThread());
715 ::SetThreadPriority(::GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
716
717 // The first time that this function is called, make an initial reading of the
718 // TSC and the performance counter.
719 static const uint64_t tsc_initial = __rdtsc();
720 static const uint64_t perf_counter_initial = QPCNowRaw();
721
722 // Make a another reading of the TSC and the performance counter every time
723 // that this function is called.
724 uint64_t tsc_now = __rdtsc();
725 uint64_t perf_counter_now = QPCNowRaw();
726
727 // Reset the thread priority.
728 ::SetThreadPriority(::GetCurrentThread(), previous_priority);
729
730 // Make sure that at least 50 ms elapsed between the 2 readings. The first
731 // time that this function is called, we don't expect this to be the case.
732 // Note: The longer the elapsed time between the 2 readings is, the more
733 // accurate the computed TSC frequency will be. The 50 ms value was
734 // chosen because local benchmarks show that it allows us to get a
735 // stddev of less than 1 tick/us between multiple runs.
736 // Note: According to the MSDN documentation for QueryPerformanceFrequency(),
737 // this will never fail on systems that run XP or later.
738 // https://msdn.microsoft.com/library/windows/desktop/ms644905.aspx
739 LARGE_INTEGER perf_counter_frequency = {};
740 ::QueryPerformanceFrequency(&perf_counter_frequency);
741 DCHECK_GE(perf_counter_now, perf_counter_initial);
742 uint64_t perf_counter_ticks = perf_counter_now - perf_counter_initial;
743 double elapsed_time_seconds =
744 perf_counter_ticks / static_cast<double>(perf_counter_frequency.QuadPart);
745
746 const double kMinimumEvaluationPeriodSeconds = 0.05;
747 if (elapsed_time_seconds < kMinimumEvaluationPeriodSeconds)
748 return 0;
749
750 // Compute the frequency of the TSC.
751 DCHECK_GE(tsc_now, tsc_initial);
752 uint64_t tsc_ticks = tsc_now - tsc_initial;
753 tsc_ticks_per_second = tsc_ticks / elapsed_time_seconds;
754
755 return tsc_ticks_per_second;
756}
757#endif // V8_OS_WIN
758
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000759} // namespace base
760} // namespace v8