Line data Source code
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
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_EQ(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 : }
67 : }
68 : #endif
69 : struct timespec ts;
70 28112038 : if (clock_gettime(clk_id, &ts) != 0) {
71 0 : UNREACHABLE();
72 : }
73 28112652 : v8::base::internal::CheckedNumeric<int64_t> result(ts.tv_sec);
74 28112652 : result *= v8::base::Time::kMicrosecondsPerSecond;
75 : #if defined(V8_OS_AIX)
76 : if (clk_id == CLOCK_THREAD_CPUTIME_ID) {
77 : result += (tc.stime / v8::base::Time::kNanosecondsPerMicrosecond);
78 : } else {
79 : result += (ts.tv_nsec / v8::base::Time::kNanosecondsPerMicrosecond);
80 : }
81 : #else
82 28112997 : result += (ts.tv_nsec / v8::base::Time::kNanosecondsPerMicrosecond);
83 : #endif
84 28113004 : return result.ValueOrDie();
85 : #else // Monotonic clock not supported.
86 : return 0;
87 : #endif
88 : }
89 : #elif V8_OS_WIN
90 : V8_INLINE bool IsQPCReliable() {
91 : v8::base::CPU cpu;
92 : // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is unreliable.
93 : return strcmp(cpu.vendor(), "AuthenticAMD") == 0 && cpu.family() == 15;
94 : }
95 :
96 : // Returns the current value of the performance counter.
97 : V8_INLINE uint64_t QPCNowRaw() {
98 : LARGE_INTEGER perf_counter_now = {};
99 : // According to the MSDN documentation for QueryPerformanceCounter(), this
100 : // will never fail on systems that run XP or later.
101 : // https://msdn.microsoft.com/library/windows/desktop/ms644904.aspx
102 : BOOL result = ::QueryPerformanceCounter(&perf_counter_now);
103 : DCHECK(result);
104 : USE(result);
105 : return perf_counter_now.QuadPart;
106 : }
107 : #endif // V8_OS_MACOSX
108 :
109 :
110 : } // namespace
111 :
112 : namespace v8 {
113 : namespace base {
114 :
115 2 : TimeDelta TimeDelta::FromDays(int days) {
116 2 : return TimeDelta(days * Time::kMicrosecondsPerDay);
117 : }
118 :
119 :
120 3 : TimeDelta TimeDelta::FromHours(int hours) {
121 3 : return TimeDelta(hours * Time::kMicrosecondsPerHour);
122 : }
123 :
124 :
125 3 : TimeDelta TimeDelta::FromMinutes(int minutes) {
126 3 : return TimeDelta(minutes * Time::kMicrosecondsPerMinute);
127 : }
128 :
129 :
130 12 : TimeDelta TimeDelta::FromSeconds(int64_t seconds) {
131 12 : return TimeDelta(seconds * Time::kMicrosecondsPerSecond);
132 : }
133 :
134 :
135 203332 : TimeDelta TimeDelta::FromMilliseconds(int64_t milliseconds) {
136 203332 : return TimeDelta(milliseconds * Time::kMicrosecondsPerMillisecond);
137 : }
138 :
139 :
140 36 : TimeDelta TimeDelta::FromNanoseconds(int64_t nanoseconds) {
141 36 : return TimeDelta(nanoseconds / Time::kNanosecondsPerMicrosecond);
142 : }
143 :
144 :
145 1 : int TimeDelta::InDays() const {
146 1 : return static_cast<int>(delta_ / Time::kMicrosecondsPerDay);
147 : }
148 :
149 :
150 1 : int TimeDelta::InHours() const {
151 1 : return static_cast<int>(delta_ / Time::kMicrosecondsPerHour);
152 : }
153 :
154 :
155 1 : int TimeDelta::InMinutes() const {
156 1 : return static_cast<int>(delta_ / Time::kMicrosecondsPerMinute);
157 : }
158 :
159 :
160 1 : double TimeDelta::InSecondsF() const {
161 1 : return static_cast<double>(delta_) / Time::kMicrosecondsPerSecond;
162 : }
163 :
164 :
165 1 : int64_t TimeDelta::InSeconds() const {
166 1 : return delta_ / Time::kMicrosecondsPerSecond;
167 : }
168 :
169 :
170 1328071 : double TimeDelta::InMillisecondsF() const {
171 1328071 : return static_cast<double>(delta_) / Time::kMicrosecondsPerMillisecond;
172 : }
173 :
174 :
175 1 : int64_t TimeDelta::InMilliseconds() const {
176 1 : return delta_ / Time::kMicrosecondsPerMillisecond;
177 : }
178 :
179 :
180 0 : int64_t TimeDelta::InNanoseconds() const {
181 0 : return delta_ * Time::kNanosecondsPerMicrosecond;
182 : }
183 :
184 :
185 : #if V8_OS_MACOSX
186 :
187 : TimeDelta TimeDelta::FromMachTimespec(struct mach_timespec ts) {
188 : DCHECK_GE(ts.tv_nsec, 0);
189 : DCHECK_LT(ts.tv_nsec,
190 : static_cast<long>(Time::kNanosecondsPerSecond)); // NOLINT
191 : return TimeDelta(ts.tv_sec * Time::kMicrosecondsPerSecond +
192 : ts.tv_nsec / Time::kNanosecondsPerMicrosecond);
193 : }
194 :
195 :
196 : struct mach_timespec TimeDelta::ToMachTimespec() const {
197 : struct mach_timespec ts;
198 : DCHECK_GE(delta_, 0);
199 : ts.tv_sec = static_cast<unsigned>(delta_ / Time::kMicrosecondsPerSecond);
200 : ts.tv_nsec = (delta_ % Time::kMicrosecondsPerSecond) *
201 : Time::kNanosecondsPerMicrosecond;
202 : return ts;
203 : }
204 :
205 : #endif // V8_OS_MACOSX
206 :
207 :
208 : #if V8_OS_POSIX
209 :
210 0 : TimeDelta TimeDelta::FromTimespec(struct timespec ts) {
211 : DCHECK_GE(ts.tv_nsec, 0);
212 : DCHECK_LT(ts.tv_nsec,
213 : static_cast<long>(Time::kNanosecondsPerSecond)); // NOLINT
214 0 : return TimeDelta(ts.tv_sec * Time::kMicrosecondsPerSecond +
215 0 : ts.tv_nsec / Time::kNanosecondsPerMicrosecond);
216 : }
217 :
218 :
219 0 : struct timespec TimeDelta::ToTimespec() const {
220 : struct timespec ts;
221 0 : ts.tv_sec = static_cast<time_t>(delta_ / Time::kMicrosecondsPerSecond);
222 0 : ts.tv_nsec = (delta_ % Time::kMicrosecondsPerSecond) *
223 : Time::kNanosecondsPerMicrosecond;
224 0 : return ts;
225 : }
226 :
227 : #endif // V8_OS_POSIX
228 :
229 :
230 : #if V8_OS_WIN
231 :
232 : // We implement time using the high-resolution timers so that we can get
233 : // timeouts which are smaller than 10-15ms. To avoid any drift, we
234 : // periodically resync the internal clock to the system clock.
235 : class Clock final {
236 : public:
237 : Clock() : initial_ticks_(GetSystemTicks()), initial_time_(GetSystemTime()) {}
238 :
239 : Time Now() {
240 : // Time between resampling the un-granular clock for this API (1 minute).
241 : const TimeDelta kMaxElapsedTime = TimeDelta::FromMinutes(1);
242 :
243 : LockGuard<Mutex> lock_guard(&mutex_);
244 :
245 : // Determine current time and ticks.
246 : TimeTicks ticks = GetSystemTicks();
247 : Time time = GetSystemTime();
248 :
249 : // Check if we need to synchronize with the system clock due to a backwards
250 : // time change or the amount of time elapsed.
251 : TimeDelta elapsed = ticks - initial_ticks_;
252 : if (time < initial_time_ || elapsed > kMaxElapsedTime) {
253 : initial_ticks_ = ticks;
254 : initial_time_ = time;
255 : return time;
256 : }
257 :
258 : return initial_time_ + elapsed;
259 : }
260 :
261 : Time NowFromSystemTime() {
262 : LockGuard<Mutex> lock_guard(&mutex_);
263 : initial_ticks_ = GetSystemTicks();
264 : initial_time_ = GetSystemTime();
265 : return initial_time_;
266 : }
267 :
268 : private:
269 : static TimeTicks GetSystemTicks() {
270 : return TimeTicks::Now();
271 : }
272 :
273 : static Time GetSystemTime() {
274 : FILETIME ft;
275 : ::GetSystemTimeAsFileTime(&ft);
276 : return Time::FromFiletime(ft);
277 : }
278 :
279 : TimeTicks initial_ticks_;
280 : Time initial_time_;
281 : Mutex mutex_;
282 : };
283 :
284 :
285 : static LazyStaticInstance<Clock, DefaultConstructTrait<Clock>,
286 : ThreadSafeInitOnceTrait>::type clock =
287 : LAZY_STATIC_INSTANCE_INITIALIZER;
288 :
289 :
290 : Time Time::Now() {
291 : return clock.Pointer()->Now();
292 : }
293 :
294 :
295 : Time Time::NowFromSystemTime() {
296 : return clock.Pointer()->NowFromSystemTime();
297 : }
298 :
299 :
300 : // Time between windows epoch and standard epoch.
301 : static const int64_t kTimeToEpochInMicroseconds = V8_INT64_C(11644473600000000);
302 :
303 :
304 : Time Time::FromFiletime(FILETIME ft) {
305 : if (ft.dwLowDateTime == 0 && ft.dwHighDateTime == 0) {
306 : return Time();
307 : }
308 : if (ft.dwLowDateTime == std::numeric_limits<DWORD>::max() &&
309 : ft.dwHighDateTime == std::numeric_limits<DWORD>::max()) {
310 : return Max();
311 : }
312 : int64_t us = (static_cast<uint64_t>(ft.dwLowDateTime) +
313 : (static_cast<uint64_t>(ft.dwHighDateTime) << 32)) / 10;
314 : return Time(us - kTimeToEpochInMicroseconds);
315 : }
316 :
317 :
318 : FILETIME Time::ToFiletime() const {
319 : DCHECK_GE(us_, 0);
320 : FILETIME ft;
321 : if (IsNull()) {
322 : ft.dwLowDateTime = 0;
323 : ft.dwHighDateTime = 0;
324 : return ft;
325 : }
326 : if (IsMax()) {
327 : ft.dwLowDateTime = std::numeric_limits<DWORD>::max();
328 : ft.dwHighDateTime = std::numeric_limits<DWORD>::max();
329 : return ft;
330 : }
331 : uint64_t us = static_cast<uint64_t>(us_ + kTimeToEpochInMicroseconds) * 10;
332 : ft.dwLowDateTime = static_cast<DWORD>(us);
333 : ft.dwHighDateTime = static_cast<DWORD>(us >> 32);
334 : return ft;
335 : }
336 :
337 : #elif V8_OS_POSIX
338 :
339 184588 : Time Time::Now() {
340 : struct timeval tv;
341 184588 : int result = gettimeofday(&tv, nullptr);
342 : DCHECK_EQ(0, result);
343 : USE(result);
344 184588 : return FromTimeval(tv);
345 : }
346 :
347 :
348 214 : Time Time::NowFromSystemTime() {
349 214 : return Now();
350 : }
351 :
352 :
353 34 : Time Time::FromTimespec(struct timespec ts) {
354 : DCHECK_GE(ts.tv_nsec, 0);
355 : DCHECK_LT(ts.tv_nsec, kNanosecondsPerSecond);
356 34 : if (ts.tv_nsec == 0 && ts.tv_sec == 0) {
357 2 : return Time();
358 : }
359 32 : if (ts.tv_nsec == static_cast<long>(kNanosecondsPerSecond - 1) && // NOLINT
360 : ts.tv_sec == std::numeric_limits<time_t>::max()) {
361 : return Max();
362 : }
363 31 : return Time(ts.tv_sec * kMicrosecondsPerSecond +
364 31 : ts.tv_nsec / kNanosecondsPerMicrosecond);
365 : }
366 :
367 :
368 246 : struct timespec Time::ToTimespec() const {
369 : struct timespec ts;
370 246 : if (IsNull()) {
371 : ts.tv_sec = 0;
372 : ts.tv_nsec = 0;
373 2 : return ts;
374 : }
375 244 : if (IsMax()) {
376 : ts.tv_sec = std::numeric_limits<time_t>::max();
377 : ts.tv_nsec = static_cast<long>(kNanosecondsPerSecond - 1); // NOLINT
378 1 : return ts;
379 : }
380 243 : ts.tv_sec = static_cast<time_t>(us_ / kMicrosecondsPerSecond);
381 243 : ts.tv_nsec = (us_ % kMicrosecondsPerSecond) * kNanosecondsPerMicrosecond;
382 243 : return ts;
383 : }
384 :
385 :
386 5 : Time Time::FromTimeval(struct timeval tv) {
387 : DCHECK_GE(tv.tv_usec, 0);
388 : DCHECK(tv.tv_usec < static_cast<suseconds_t>(kMicrosecondsPerSecond));
389 184593 : if (tv.tv_usec == 0 && tv.tv_sec == 0) {
390 2 : return Time();
391 : }
392 184591 : if (tv.tv_usec == static_cast<suseconds_t>(kMicrosecondsPerSecond - 1) &&
393 : tv.tv_sec == std::numeric_limits<time_t>::max()) {
394 : return Max();
395 : }
396 184590 : return Time(tv.tv_sec * kMicrosecondsPerSecond + tv.tv_usec);
397 : }
398 :
399 :
400 5 : struct timeval Time::ToTimeval() const {
401 : struct timeval tv;
402 5 : if (IsNull()) {
403 : tv.tv_sec = 0;
404 : tv.tv_usec = 0;
405 2 : return tv;
406 : }
407 3 : if (IsMax()) {
408 : tv.tv_sec = std::numeric_limits<time_t>::max();
409 : tv.tv_usec = static_cast<suseconds_t>(kMicrosecondsPerSecond - 1);
410 1 : return tv;
411 : }
412 2 : tv.tv_sec = static_cast<time_t>(us_ / kMicrosecondsPerSecond);
413 2 : tv.tv_usec = us_ % kMicrosecondsPerSecond;
414 2 : return tv;
415 : }
416 :
417 : #endif // V8_OS_WIN
418 :
419 :
420 1 : Time Time::FromJsTime(double ms_since_epoch) {
421 : // The epoch is a valid time, so this constructor doesn't interpret
422 : // 0 as the null time.
423 1 : if (ms_since_epoch == std::numeric_limits<double>::max()) {
424 : return Max();
425 : }
426 : return Time(
427 1 : static_cast<int64_t>(ms_since_epoch * kMicrosecondsPerMillisecond));
428 : }
429 :
430 :
431 184369 : double Time::ToJsTime() const {
432 184369 : if (IsNull()) {
433 : // Preserve 0 so the invalid result doesn't depend on the platform.
434 : return 0;
435 : }
436 184369 : if (IsMax()) {
437 : // Preserve max without offset to prevent overflow.
438 : return std::numeric_limits<double>::max();
439 : }
440 184369 : return static_cast<double>(us_) / kMicrosecondsPerMillisecond;
441 : }
442 :
443 :
444 0 : std::ostream& operator<<(std::ostream& os, const Time& time) {
445 0 : return os << time.ToJsTime();
446 : }
447 :
448 :
449 : #if V8_OS_WIN
450 :
451 : class TickClock {
452 : public:
453 : virtual ~TickClock() {}
454 : virtual int64_t Now() = 0;
455 : virtual bool IsHighResolution() = 0;
456 : };
457 :
458 :
459 : // Overview of time counters:
460 : // (1) CPU cycle counter. (Retrieved via RDTSC)
461 : // The CPU counter provides the highest resolution time stamp and is the least
462 : // expensive to retrieve. However, the CPU counter is unreliable and should not
463 : // be used in production. Its biggest issue is that it is per processor and it
464 : // is not synchronized between processors. Also, on some computers, the counters
465 : // will change frequency due to thermal and power changes, and stop in some
466 : // states.
467 : //
468 : // (2) QueryPerformanceCounter (QPC). The QPC counter provides a high-
469 : // resolution (100 nanoseconds) time stamp but is comparatively more expensive
470 : // to retrieve. What QueryPerformanceCounter actually does is up to the HAL.
471 : // (with some help from ACPI).
472 : // According to http://blogs.msdn.com/oldnewthing/archive/2005/09/02/459952.aspx
473 : // in the worst case, it gets the counter from the rollover interrupt on the
474 : // programmable interrupt timer. In best cases, the HAL may conclude that the
475 : // RDTSC counter runs at a constant frequency, then it uses that instead. On
476 : // multiprocessor machines, it will try to verify the values returned from
477 : // RDTSC on each processor are consistent with each other, and apply a handful
478 : // of workarounds for known buggy hardware. In other words, QPC is supposed to
479 : // give consistent result on a multiprocessor computer, but it is unreliable in
480 : // reality due to bugs in BIOS or HAL on some, especially old computers.
481 : // With recent updates on HAL and newer BIOS, QPC is getting more reliable but
482 : // it should be used with caution.
483 : //
484 : // (3) System time. The system time provides a low-resolution (typically 10ms
485 : // to 55 milliseconds) time stamp but is comparatively less expensive to
486 : // retrieve and more reliable.
487 : class HighResolutionTickClock final : public TickClock {
488 : public:
489 : explicit HighResolutionTickClock(int64_t ticks_per_second)
490 : : ticks_per_second_(ticks_per_second) {
491 : DCHECK_LT(0, ticks_per_second);
492 : }
493 : virtual ~HighResolutionTickClock() {}
494 :
495 : int64_t Now() override {
496 : uint64_t now = QPCNowRaw();
497 :
498 : // Intentionally calculate microseconds in a round about manner to avoid
499 : // overflow and precision issues. Think twice before simplifying!
500 : int64_t whole_seconds = now / ticks_per_second_;
501 : int64_t leftover_ticks = now % ticks_per_second_;
502 : int64_t ticks = (whole_seconds * Time::kMicrosecondsPerSecond) +
503 : ((leftover_ticks * Time::kMicrosecondsPerSecond) / ticks_per_second_);
504 :
505 : // Make sure we never return 0 here, so that TimeTicks::HighResolutionNow()
506 : // will never return 0.
507 : return ticks + 1;
508 : }
509 :
510 : bool IsHighResolution() override { return true; }
511 :
512 : private:
513 : int64_t ticks_per_second_;
514 : };
515 :
516 :
517 : class RolloverProtectedTickClock final : public TickClock {
518 : public:
519 : RolloverProtectedTickClock() : rollover_(0) {}
520 : virtual ~RolloverProtectedTickClock() {}
521 :
522 : int64_t Now() override {
523 : // We use timeGetTime() to implement TimeTicks::Now(), which rolls over
524 : // every ~49.7 days. We try to track rollover ourselves, which works if
525 : // TimeTicks::Now() is called at least every 24 days.
526 : // Note that we do not use GetTickCount() here, since timeGetTime() gives
527 : // more predictable delta values, as described here:
528 : // http://blogs.msdn.com/b/larryosterman/archive/2009/09/02/what-s-the-difference-between-gettickcount-and-timegettime.aspx
529 : // timeGetTime() provides 1ms granularity when combined with
530 : // timeBeginPeriod(). If the host application for V8 wants fast timers, it
531 : // can use timeBeginPeriod() to increase the resolution.
532 : // We use a lock-free version because the sampler thread calls it
533 : // while having the rest of the world stopped, that could cause a deadlock.
534 : base::Atomic32 rollover = base::Acquire_Load(&rollover_);
535 : uint32_t now = static_cast<uint32_t>(timeGetTime());
536 : if ((now >> 31) != static_cast<uint32_t>(rollover & 1)) {
537 : base::Release_CompareAndSwap(&rollover_, rollover, rollover + 1);
538 : ++rollover;
539 : }
540 : uint64_t ms = (static_cast<uint64_t>(rollover) << 31) | now;
541 : return static_cast<int64_t>(ms * Time::kMicrosecondsPerMillisecond);
542 : }
543 :
544 : bool IsHighResolution() override { return false; }
545 :
546 : private:
547 : base::Atomic32 rollover_;
548 : };
549 :
550 :
551 : static LazyStaticInstance<RolloverProtectedTickClock,
552 : DefaultConstructTrait<RolloverProtectedTickClock>,
553 : ThreadSafeInitOnceTrait>::type tick_clock =
554 : LAZY_STATIC_INSTANCE_INITIALIZER;
555 :
556 :
557 : struct CreateHighResTickClockTrait {
558 : static TickClock* Create() {
559 : // Check if the installed hardware supports a high-resolution performance
560 : // counter, and if not fallback to the low-resolution tick clock.
561 : LARGE_INTEGER ticks_per_second;
562 : if (!QueryPerformanceFrequency(&ticks_per_second)) {
563 : return tick_clock.Pointer();
564 : }
565 :
566 : // If QPC not reliable, fallback to low-resolution tick clock.
567 : if (IsQPCReliable()) {
568 : return tick_clock.Pointer();
569 : }
570 :
571 : return new HighResolutionTickClock(ticks_per_second.QuadPart);
572 : }
573 : };
574 :
575 :
576 : static LazyDynamicInstance<TickClock, CreateHighResTickClockTrait,
577 : ThreadSafeInitOnceTrait>::type high_res_tick_clock =
578 : LAZY_DYNAMIC_INSTANCE_INITIALIZER;
579 :
580 :
581 : TimeTicks TimeTicks::Now() {
582 : // Make sure we never return 0 here.
583 : TimeTicks ticks(tick_clock.Pointer()->Now());
584 : DCHECK(!ticks.IsNull());
585 : return ticks;
586 : }
587 :
588 :
589 : TimeTicks TimeTicks::HighResolutionNow() {
590 : // Make sure we never return 0 here.
591 : TimeTicks ticks(high_res_tick_clock.Pointer()->Now());
592 : DCHECK(!ticks.IsNull());
593 : return ticks;
594 : }
595 :
596 :
597 : // static
598 : bool TimeTicks::IsHighResolutionClockWorking() {
599 : return high_res_tick_clock.Pointer()->IsHighResolution();
600 : }
601 :
602 : #else // V8_OS_WIN
603 :
604 186494 : TimeTicks TimeTicks::Now() {
605 186494 : return HighResolutionNow();
606 : }
607 :
608 :
609 28111095 : TimeTicks TimeTicks::HighResolutionNow() {
610 : int64_t ticks;
611 : #if V8_OS_MACOSX
612 : static struct mach_timebase_info info;
613 : if (info.denom == 0) {
614 : kern_return_t result = mach_timebase_info(&info);
615 : DCHECK_EQ(KERN_SUCCESS, result);
616 : USE(result);
617 : }
618 : ticks = (mach_absolute_time() / Time::kNanosecondsPerMicrosecond *
619 : info.numer / info.denom);
620 : #elif V8_OS_SOLARIS
621 : ticks = (gethrtime() / Time::kNanosecondsPerMicrosecond);
622 : #elif V8_OS_POSIX
623 : ticks = ClockNow(CLOCK_MONOTONIC);
624 : #else
625 : #error platform does not implement TimeTicks::HighResolutionNow.
626 : #endif // V8_OS_MACOSX
627 : // Make sure we never return 0 here.
628 28112130 : return TimeTicks(ticks + 1);
629 : }
630 :
631 :
632 : // static
633 1 : bool TimeTicks::IsHighResolutionClockWorking() {
634 1 : return true;
635 : }
636 :
637 : #endif // V8_OS_WIN
638 :
639 :
640 1 : 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 1 : return true;
644 : #elif defined(V8_OS_WIN)
645 : return IsSupportedWin();
646 : #else
647 : return false;
648 : #endif
649 : }
650 :
651 :
652 943 : 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 943 : 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 : #endif
665 : }
666 :
667 :
668 : #if V8_OS_WIN
669 : ThreadTicks ThreadTicks::GetForThread(const HANDLE& thread_handle) {
670 : DCHECK(IsSupported());
671 :
672 : // Get the number of TSC ticks used by the current thread.
673 : ULONG64 thread_cycle_time = 0;
674 : ::QueryThreadCycleTime(thread_handle, &thread_cycle_time);
675 :
676 : // Get the frequency of the TSC.
677 : double tsc_ticks_per_second = TSCTicksPerSecond();
678 : if (tsc_ticks_per_second == 0)
679 : return ThreadTicks();
680 :
681 : // Return the CPU time of the current thread.
682 : double thread_time_seconds = thread_cycle_time / tsc_ticks_per_second;
683 : return ThreadTicks(
684 : static_cast<int64_t>(thread_time_seconds * Time::kMicrosecondsPerSecond));
685 : }
686 :
687 : // static
688 : bool ThreadTicks::IsSupportedWin() {
689 : static bool is_supported = base::CPU().has_non_stop_time_stamp_counter() &&
690 : !IsQPCReliable();
691 : return is_supported;
692 : }
693 :
694 : // static
695 : void ThreadTicks::WaitUntilInitializedWin() {
696 : while (TSCTicksPerSecond() == 0)
697 : ::Sleep(10);
698 : }
699 :
700 : double ThreadTicks::TSCTicksPerSecond() {
701 : DCHECK(IsSupported());
702 :
703 : // The value returned by QueryPerformanceFrequency() cannot be used as the TSC
704 : // frequency, because there is no guarantee that the TSC frequency is equal to
705 : // the performance counter frequency.
706 :
707 : // The TSC frequency is cached in a static variable because it takes some time
708 : // to compute it.
709 : static double tsc_ticks_per_second = 0;
710 : if (tsc_ticks_per_second != 0)
711 : return tsc_ticks_per_second;
712 :
713 : // Increase the thread priority to reduces the chances of having a context
714 : // switch during a reading of the TSC and the performance counter.
715 : int previous_priority = ::GetThreadPriority(::GetCurrentThread());
716 : ::SetThreadPriority(::GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
717 :
718 : // The first time that this function is called, make an initial reading of the
719 : // TSC and the performance counter.
720 : static const uint64_t tsc_initial = __rdtsc();
721 : static const uint64_t perf_counter_initial = QPCNowRaw();
722 :
723 : // Make a another reading of the TSC and the performance counter every time
724 : // that this function is called.
725 : uint64_t tsc_now = __rdtsc();
726 : uint64_t perf_counter_now = QPCNowRaw();
727 :
728 : // Reset the thread priority.
729 : ::SetThreadPriority(::GetCurrentThread(), previous_priority);
730 :
731 : // Make sure that at least 50 ms elapsed between the 2 readings. The first
732 : // time that this function is called, we don't expect this to be the case.
733 : // Note: The longer the elapsed time between the 2 readings is, the more
734 : // accurate the computed TSC frequency will be. The 50 ms value was
735 : // chosen because local benchmarks show that it allows us to get a
736 : // stddev of less than 1 tick/us between multiple runs.
737 : // Note: According to the MSDN documentation for QueryPerformanceFrequency(),
738 : // this will never fail on systems that run XP or later.
739 : // https://msdn.microsoft.com/library/windows/desktop/ms644905.aspx
740 : LARGE_INTEGER perf_counter_frequency = {};
741 : ::QueryPerformanceFrequency(&perf_counter_frequency);
742 : DCHECK_GE(perf_counter_now, perf_counter_initial);
743 : uint64_t perf_counter_ticks = perf_counter_now - perf_counter_initial;
744 : double elapsed_time_seconds =
745 : perf_counter_ticks / static_cast<double>(perf_counter_frequency.QuadPart);
746 :
747 : const double kMinimumEvaluationPeriodSeconds = 0.05;
748 : if (elapsed_time_seconds < kMinimumEvaluationPeriodSeconds)
749 : return 0;
750 :
751 : // Compute the frequency of the TSC.
752 : DCHECK_GE(tsc_now, tsc_initial);
753 : uint64_t tsc_ticks = tsc_now - tsc_initial;
754 : tsc_ticks_per_second = tsc_ticks / elapsed_time_seconds;
755 :
756 : return tsc_ticks_per_second;
757 : }
758 : #endif // V8_OS_WIN
759 :
760 : } // namespace base
761 : } // namespace v8
|