1 // 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
13 #include <mach/mach.h>
14 #include <mach/mach_time.h>
15 #include <pthread.h>
16 #endif
17
18 #include <cstring>
19 #include <ostream>
20
21 #if V8_OS_WIN
22 #include "src/base/atomicops.h"
23 #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
30 namespace {
31
32 #if V8_OS_MACOSX
ComputeThreadTicks()33 int64_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(
44 thread_info_data.user_time.seconds +
45 thread_info_data.system_time.seconds);
46 absolute_micros *= v8::base::Time::kMicrosecondsPerSecond;
47 absolute_micros += (thread_info_data.user_time.microseconds +
48 thread_info_data.system_time.microseconds);
49 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.
56 V8_INLINE int64_t ClockNow(clockid_t clk_id) {
57 #if (defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0) || \
58 defined(V8_OS_BSD) || defined(V8_OS_ANDROID)
59 // 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
70 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;
77 #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
84 result += (ts.tv_nsec / v8::base::Time::kNanosecondsPerMicrosecond);
85 #endif
86 return result.ValueOrDie();
87 #else // Monotonic clock not supported.
88 return 0;
89 #endif
90 }
91 #elif V8_OS_WIN
92 V8_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.
99 V8_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 }
109 #endif // V8_OS_MACOSX
110
111
112 } // namespace
113
114 namespace v8 {
115 namespace base {
116
FromDays(int days)117 TimeDelta TimeDelta::FromDays(int days) {
118 return TimeDelta(days * Time::kMicrosecondsPerDay);
119 }
120
121
FromHours(int hours)122 TimeDelta TimeDelta::FromHours(int hours) {
123 return TimeDelta(hours * Time::kMicrosecondsPerHour);
124 }
125
126
FromMinutes(int minutes)127 TimeDelta TimeDelta::FromMinutes(int minutes) {
128 return TimeDelta(minutes * Time::kMicrosecondsPerMinute);
129 }
130
131
FromSeconds(int64_t seconds)132 TimeDelta TimeDelta::FromSeconds(int64_t seconds) {
133 return TimeDelta(seconds * Time::kMicrosecondsPerSecond);
134 }
135
136
FromMilliseconds(int64_t milliseconds)137 TimeDelta TimeDelta::FromMilliseconds(int64_t milliseconds) {
138 return TimeDelta(milliseconds * Time::kMicrosecondsPerMillisecond);
139 }
140
141
FromNanoseconds(int64_t nanoseconds)142 TimeDelta TimeDelta::FromNanoseconds(int64_t nanoseconds) {
143 return TimeDelta(nanoseconds / Time::kNanosecondsPerMicrosecond);
144 }
145
146
InDays() const147 int TimeDelta::InDays() const {
148 return static_cast<int>(delta_ / Time::kMicrosecondsPerDay);
149 }
150
151
InHours() const152 int TimeDelta::InHours() const {
153 return static_cast<int>(delta_ / Time::kMicrosecondsPerHour);
154 }
155
156
InMinutes() const157 int TimeDelta::InMinutes() const {
158 return static_cast<int>(delta_ / Time::kMicrosecondsPerMinute);
159 }
160
161
InSecondsF() const162 double TimeDelta::InSecondsF() const {
163 return static_cast<double>(delta_) / Time::kMicrosecondsPerSecond;
164 }
165
166
InSeconds() const167 int64_t TimeDelta::InSeconds() const {
168 return delta_ / Time::kMicrosecondsPerSecond;
169 }
170
171
InMillisecondsF() const172 double TimeDelta::InMillisecondsF() const {
173 return static_cast<double>(delta_) / Time::kMicrosecondsPerMillisecond;
174 }
175
176
InMilliseconds() const177 int64_t TimeDelta::InMilliseconds() const {
178 return delta_ / Time::kMicrosecondsPerMillisecond;
179 }
180
181
InNanoseconds() const182 int64_t TimeDelta::InNanoseconds() const {
183 return delta_ * Time::kNanosecondsPerMicrosecond;
184 }
185
186
187 #if V8_OS_MACOSX
188
FromMachTimespec(struct mach_timespec ts)189 TimeDelta 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
ToMachTimespec() const198 struct mach_timespec TimeDelta::ToMachTimespec() const {
199 struct mach_timespec ts;
200 DCHECK(delta_ >= 0);
201 ts.tv_sec = static_cast<unsigned>(delta_ / Time::kMicrosecondsPerSecond);
202 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
FromTimespec(struct timespec ts)212 TimeDelta 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
ToTimespec() const221 struct timespec TimeDelta::ToTimespec() const {
222 struct timespec ts;
223 ts.tv_sec = static_cast<time_t>(delta_ / Time::kMicrosecondsPerSecond);
224 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.
237 class Clock final {
238 public:
Clock()239 Clock() : initial_ticks_(GetSystemTicks()), initial_time_(GetSystemTime()) {}
240
Now()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
NowFromSystemTime()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:
GetSystemTicks()271 static TimeTicks GetSystemTicks() {
272 return TimeTicks::Now();
273 }
274
GetSystemTime()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
287 static LazyStaticInstance<Clock, DefaultConstructTrait<Clock>,
288 ThreadSafeInitOnceTrait>::type clock =
289 LAZY_STATIC_INSTANCE_INITIALIZER;
290
291
Now()292 Time Time::Now() {
293 return clock.Pointer()->Now();
294 }
295
296
NowFromSystemTime()297 Time Time::NowFromSystemTime() {
298 return clock.Pointer()->NowFromSystemTime();
299 }
300
301
302 // Time between windows epoch and standard epoch.
303 static const int64_t kTimeToEpochInMicroseconds = V8_INT64_C(11644473600000000);
304
305
FromFiletime(FILETIME ft)306 Time 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
ToFiletime() const320 FILETIME 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
Now()341 Time 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
NowFromSystemTime()350 Time Time::NowFromSystemTime() {
351 return Now();
352 }
353
354
FromTimespec(struct timespec ts)355 Time 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
ToTimespec() const370 struct 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 }
382 ts.tv_sec = static_cast<time_t>(us_ / kMicrosecondsPerSecond);
383 ts.tv_nsec = (us_ % kMicrosecondsPerSecond) * kNanosecondsPerMicrosecond;
384 return ts;
385 }
386
387
FromTimeval(struct timeval tv)388 Time 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
ToTimeval() const402 struct 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 }
414 tv.tv_sec = static_cast<time_t>(us_ / kMicrosecondsPerSecond);
415 tv.tv_usec = us_ % kMicrosecondsPerSecond;
416 return tv;
417 }
418
419 #endif // V8_OS_WIN
420
421
FromJsTime(double ms_since_epoch)422 Time 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
ToJsTime() const433 double 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
operator <<(std::ostream & os,const Time & time)446 std::ostream& operator<<(std::ostream& os, const Time& time) {
447 return os << time.ToJsTime();
448 }
449
450
451 #if V8_OS_WIN
452
453 class TickClock {
454 public:
~TickClock()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.
489 class HighResolutionTickClock final : public TickClock {
490 public:
HighResolutionTickClock(int64_t ticks_per_second)491 explicit HighResolutionTickClock(int64_t ticks_per_second)
492 : ticks_per_second_(ticks_per_second) {
493 DCHECK_LT(0, ticks_per_second);
494 }
~HighResolutionTickClock()495 virtual ~HighResolutionTickClock() {}
496
Now()497 int64_t Now() override {
498 uint64_t now = QPCNowRaw();
499
500 // Intentionally calculate microseconds in a round about manner to avoid
501 // overflow and precision issues. Think twice before simplifying!
502 int64_t whole_seconds = now / ticks_per_second_;
503 int64_t leftover_ticks = now % ticks_per_second_;
504 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
IsHighResolution()512 bool IsHighResolution() override { return true; }
513
514 private:
515 int64_t ticks_per_second_;
516 };
517
518
519 class RolloverProtectedTickClock final : public TickClock {
520 public:
RolloverProtectedTickClock()521 RolloverProtectedTickClock() : rollover_(0) {}
~RolloverProtectedTickClock()522 virtual ~RolloverProtectedTickClock() {}
523
Now()524 int64_t Now() override {
525 // We use timeGetTime() to implement TimeTicks::Now(), which rolls over
526 // every ~49.7 days. We try to track rollover ourselves, which works if
527 // TimeTicks::Now() is called at least every 24 days.
528 // 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.
534 // 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;
541 }
542 uint64_t ms = (static_cast<uint64_t>(rollover) << 31) | now;
543 return static_cast<int64_t>(ms * Time::kMicrosecondsPerMillisecond);
544 }
545
IsHighResolution()546 bool IsHighResolution() override { return false; }
547
548 private:
549 base::Atomic32 rollover_;
550 };
551
552
553 static LazyStaticInstance<RolloverProtectedTickClock,
554 DefaultConstructTrait<RolloverProtectedTickClock>,
555 ThreadSafeInitOnceTrait>::type tick_clock =
556 LAZY_STATIC_INSTANCE_INITIALIZER;
557
558
559 struct CreateHighResTickClockTrait {
Createv8::base::CreateHighResTickClockTrait560 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
568 // If QPC not reliable, fallback to low-resolution tick clock.
569 if (IsQPCReliable()) {
570 return tick_clock.Pointer();
571 }
572
573 return new HighResolutionTickClock(ticks_per_second.QuadPart);
574 }
575 };
576
577
578 static LazyDynamicInstance<TickClock, CreateHighResTickClockTrait,
579 ThreadSafeInitOnceTrait>::type high_res_tick_clock =
580 LAZY_DYNAMIC_INSTANCE_INITIALIZER;
581
582
Now()583 TimeTicks 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
HighResolutionNow()591 TimeTicks 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
IsHighResolutionClockWorking()600 bool TimeTicks::IsHighResolutionClockWorking() {
601 return high_res_tick_clock.Pointer()->IsHighResolution();
602 }
603
604 #else // V8_OS_WIN
605
Now()606 TimeTicks TimeTicks::Now() {
607 return HighResolutionNow();
608 }
609
610
HighResolutionNow()611 TimeTicks 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);
624 #elif V8_OS_POSIX
625 ticks = ClockNow(CLOCK_MONOTONIC);
626 #endif // V8_OS_MACOSX
627 // Make sure we never return 0 here.
628 return TimeTicks(ticks + 1);
629 }
630
631
632 // static
IsHighResolutionClockWorking()633 bool TimeTicks::IsHighResolutionClockWorking() {
634 return true;
635 }
636
637 #endif // V8_OS_WIN
638
639
640 // TODO(lpy): For windows ThreadTicks implementation,
641 // see http://crbug.com/v8/5000
IsSupported()642 bool 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
Now()652 ThreadTicks 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));
658 #elif V8_OS_WIN
659 return ThreadTicks::GetForThread(::GetCurrentThread());
660 #else
661 UNREACHABLE();
662 return ThreadTicks();
663 #endif
664 }
665
666
667 #if V8_OS_WIN
GetForThread(const HANDLE & thread_handle)668 ThreadTicks 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
IsSupportedWin()687 bool 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
WaitUntilInitializedWin()694 void ThreadTicks::WaitUntilInitializedWin() {
695 while (TSCTicksPerSecond() == 0)
696 ::Sleep(10);
697 }
698
TSCTicksPerSecond()699 double 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
759 } // namespace base
760 } // namespace v8
761