• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
IsSupported()640 bool ThreadTicks::IsSupported() {
641 #if (defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \
642     defined(V8_OS_MACOSX) || defined(V8_OS_ANDROID) || defined(V8_OS_SOLARIS)
643   return true;
644 #elif defined(V8_OS_WIN)
645   return IsSupportedWin();
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_SOLARIS
659   return ThreadTicks(gethrvtime() / Time::kNanosecondsPerMicrosecond);
660 #elif V8_OS_WIN
661   return ThreadTicks::GetForThread(::GetCurrentThread());
662 #else
663   UNREACHABLE();
664   return ThreadTicks();
665 #endif
666 }
667 
668 
669 #if V8_OS_WIN
GetForThread(const HANDLE & thread_handle)670 ThreadTicks ThreadTicks::GetForThread(const HANDLE& thread_handle) {
671   DCHECK(IsSupported());
672 
673   // Get the number of TSC ticks used by the current thread.
674   ULONG64 thread_cycle_time = 0;
675   ::QueryThreadCycleTime(thread_handle, &thread_cycle_time);
676 
677   // Get the frequency of the TSC.
678   double tsc_ticks_per_second = TSCTicksPerSecond();
679   if (tsc_ticks_per_second == 0)
680     return ThreadTicks();
681 
682   // Return the CPU time of the current thread.
683   double thread_time_seconds = thread_cycle_time / tsc_ticks_per_second;
684   return ThreadTicks(
685       static_cast<int64_t>(thread_time_seconds * Time::kMicrosecondsPerSecond));
686 }
687 
688 // static
IsSupportedWin()689 bool ThreadTicks::IsSupportedWin() {
690   static bool is_supported = base::CPU().has_non_stop_time_stamp_counter() &&
691                              !IsQPCReliable();
692   return is_supported;
693 }
694 
695 // static
WaitUntilInitializedWin()696 void ThreadTicks::WaitUntilInitializedWin() {
697   while (TSCTicksPerSecond() == 0)
698     ::Sleep(10);
699 }
700 
TSCTicksPerSecond()701 double ThreadTicks::TSCTicksPerSecond() {
702   DCHECK(IsSupported());
703 
704   // The value returned by QueryPerformanceFrequency() cannot be used as the TSC
705   // frequency, because there is no guarantee that the TSC frequency is equal to
706   // the performance counter frequency.
707 
708   // The TSC frequency is cached in a static variable because it takes some time
709   // to compute it.
710   static double tsc_ticks_per_second = 0;
711   if (tsc_ticks_per_second != 0)
712     return tsc_ticks_per_second;
713 
714   // Increase the thread priority to reduces the chances of having a context
715   // switch during a reading of the TSC and the performance counter.
716   int previous_priority = ::GetThreadPriority(::GetCurrentThread());
717   ::SetThreadPriority(::GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
718 
719   // The first time that this function is called, make an initial reading of the
720   // TSC and the performance counter.
721   static const uint64_t tsc_initial = __rdtsc();
722   static const uint64_t perf_counter_initial = QPCNowRaw();
723 
724   // Make a another reading of the TSC and the performance counter every time
725   // that this function is called.
726   uint64_t tsc_now = __rdtsc();
727   uint64_t perf_counter_now = QPCNowRaw();
728 
729   // Reset the thread priority.
730   ::SetThreadPriority(::GetCurrentThread(), previous_priority);
731 
732   // Make sure that at least 50 ms elapsed between the 2 readings. The first
733   // time that this function is called, we don't expect this to be the case.
734   // Note: The longer the elapsed time between the 2 readings is, the more
735   //   accurate the computed TSC frequency will be. The 50 ms value was
736   //   chosen because local benchmarks show that it allows us to get a
737   //   stddev of less than 1 tick/us between multiple runs.
738   // Note: According to the MSDN documentation for QueryPerformanceFrequency(),
739   //   this will never fail on systems that run XP or later.
740   //   https://msdn.microsoft.com/library/windows/desktop/ms644905.aspx
741   LARGE_INTEGER perf_counter_frequency = {};
742   ::QueryPerformanceFrequency(&perf_counter_frequency);
743   DCHECK_GE(perf_counter_now, perf_counter_initial);
744   uint64_t perf_counter_ticks = perf_counter_now - perf_counter_initial;
745   double elapsed_time_seconds =
746       perf_counter_ticks / static_cast<double>(perf_counter_frequency.QuadPart);
747 
748   const double kMinimumEvaluationPeriodSeconds = 0.05;
749   if (elapsed_time_seconds < kMinimumEvaluationPeriodSeconds)
750     return 0;
751 
752   // Compute the frequency of the TSC.
753   DCHECK_GE(tsc_now, tsc_initial);
754   uint64_t tsc_ticks = tsc_now - tsc_initial;
755   tsc_ticks_per_second = tsc_ticks / elapsed_time_seconds;
756 
757   return tsc_ticks_per_second;
758 }
759 #endif  // V8_OS_WIN
760 
761 }  // namespace base
762 }  // namespace v8
763