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(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 33702237 : if (clock_gettime(clk_id, &ts) != 0) {
72 0 : UNREACHABLE();
73 : return 0;
74 : }
75 33704354 : v8::base::internal::CheckedNumeric<int64_t> result(ts.tv_sec);
76 33704354 : 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 33704416 : result += (ts.tv_nsec / v8::base::Time::kNanosecondsPerMicrosecond);
85 : #endif
86 33704351 : 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 :
117 2 : TimeDelta TimeDelta::FromDays(int days) {
118 2 : return TimeDelta(days * Time::kMicrosecondsPerDay);
119 : }
120 :
121 :
122 3 : TimeDelta TimeDelta::FromHours(int hours) {
123 3 : return TimeDelta(hours * Time::kMicrosecondsPerHour);
124 : }
125 :
126 :
127 3 : TimeDelta TimeDelta::FromMinutes(int minutes) {
128 3 : return TimeDelta(minutes * Time::kMicrosecondsPerMinute);
129 : }
130 :
131 :
132 13 : TimeDelta TimeDelta::FromSeconds(int64_t seconds) {
133 13 : return TimeDelta(seconds * Time::kMicrosecondsPerSecond);
134 : }
135 :
136 :
137 204331 : TimeDelta TimeDelta::FromMilliseconds(int64_t milliseconds) {
138 204331 : return TimeDelta(milliseconds * Time::kMicrosecondsPerMillisecond);
139 : }
140 :
141 :
142 56 : TimeDelta TimeDelta::FromNanoseconds(int64_t nanoseconds) {
143 56 : return TimeDelta(nanoseconds / Time::kNanosecondsPerMicrosecond);
144 : }
145 :
146 :
147 1 : int TimeDelta::InDays() const {
148 1 : return static_cast<int>(delta_ / Time::kMicrosecondsPerDay);
149 : }
150 :
151 :
152 1 : int TimeDelta::InHours() const {
153 1 : return static_cast<int>(delta_ / Time::kMicrosecondsPerHour);
154 : }
155 :
156 :
157 1 : int TimeDelta::InMinutes() const {
158 1 : return static_cast<int>(delta_ / Time::kMicrosecondsPerMinute);
159 : }
160 :
161 :
162 1 : double TimeDelta::InSecondsF() const {
163 1 : return static_cast<double>(delta_) / Time::kMicrosecondsPerSecond;
164 : }
165 :
166 :
167 1 : int64_t TimeDelta::InSeconds() const {
168 1 : return delta_ / Time::kMicrosecondsPerSecond;
169 : }
170 :
171 :
172 1940821 : double TimeDelta::InMillisecondsF() const {
173 1940821 : return static_cast<double>(delta_) / Time::kMicrosecondsPerMillisecond;
174 : }
175 :
176 :
177 1 : int64_t TimeDelta::InMilliseconds() const {
178 1 : return delta_ / Time::kMicrosecondsPerMillisecond;
179 : }
180 :
181 :
182 0 : int64_t TimeDelta::InNanoseconds() const {
183 0 : return delta_ * Time::kNanosecondsPerMicrosecond;
184 : }
185 :
186 :
187 : #if V8_OS_MACOSX
188 :
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 :
198 : 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 :
212 0 : 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 0 : return TimeDelta(ts.tv_sec * Time::kMicrosecondsPerSecond +
217 0 : ts.tv_nsec / Time::kNanosecondsPerMicrosecond);
218 : }
219 :
220 :
221 0 : struct timespec TimeDelta::ToTimespec() const {
222 : struct timespec ts;
223 0 : ts.tv_sec = static_cast<time_t>(delta_ / Time::kMicrosecondsPerSecond);
224 0 : ts.tv_nsec = (delta_ % Time::kMicrosecondsPerSecond) *
225 : Time::kNanosecondsPerMicrosecond;
226 0 : 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:
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 :
287 : static LazyStaticInstance<Clock, DefaultConstructTrait<Clock>,
288 : ThreadSafeInitOnceTrait>::type clock =
289 : LAZY_STATIC_INSTANCE_INITIALIZER;
290 :
291 :
292 : Time Time::Now() {
293 : return clock.Pointer()->Now();
294 : }
295 :
296 :
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 :
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 :
320 : 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 :
341 28133129 : Time Time::Now() {
342 : struct timeval tv;
343 28133129 : int result = gettimeofday(&tv, NULL);
344 : DCHECK_EQ(0, result);
345 : USE(result);
346 28133129 : return FromTimeval(tv);
347 : }
348 :
349 :
350 215 : Time Time::NowFromSystemTime() {
351 215 : return Now();
352 : }
353 :
354 :
355 39 : Time Time::FromTimespec(struct timespec ts) {
356 : DCHECK(ts.tv_nsec >= 0);
357 : DCHECK(ts.tv_nsec < static_cast<long>(kNanosecondsPerSecond)); // NOLINT
358 39 : if (ts.tv_nsec == 0 && ts.tv_sec == 0) {
359 2 : return Time();
360 : }
361 37 : 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 36 : return Time(ts.tv_sec * kMicrosecondsPerSecond +
366 36 : ts.tv_nsec / kNanosecondsPerMicrosecond);
367 : }
368 :
369 :
370 252 : struct timespec Time::ToTimespec() const {
371 : struct timespec ts;
372 252 : if (IsNull()) {
373 : ts.tv_sec = 0;
374 : ts.tv_nsec = 0;
375 2 : return ts;
376 : }
377 250 : if (IsMax()) {
378 : ts.tv_sec = std::numeric_limits<time_t>::max();
379 : ts.tv_nsec = static_cast<long>(kNanosecondsPerSecond - 1); // NOLINT
380 1 : return ts;
381 : }
382 249 : ts.tv_sec = static_cast<time_t>(us_ / kMicrosecondsPerSecond);
383 249 : ts.tv_nsec = (us_ % kMicrosecondsPerSecond) * kNanosecondsPerMicrosecond;
384 249 : return ts;
385 : }
386 :
387 :
388 5 : Time Time::FromTimeval(struct timeval tv) {
389 : DCHECK(tv.tv_usec >= 0);
390 : DCHECK(tv.tv_usec < static_cast<suseconds_t>(kMicrosecondsPerSecond));
391 28133134 : if (tv.tv_usec == 0 && tv.tv_sec == 0) {
392 2 : return Time();
393 : }
394 28133132 : 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 28133131 : return Time(tv.tv_sec * kMicrosecondsPerSecond + tv.tv_usec);
399 : }
400 :
401 :
402 5 : struct timeval Time::ToTimeval() const {
403 : struct timeval tv;
404 5 : if (IsNull()) {
405 : tv.tv_sec = 0;
406 : tv.tv_usec = 0;
407 2 : return tv;
408 : }
409 3 : if (IsMax()) {
410 : tv.tv_sec = std::numeric_limits<time_t>::max();
411 : tv.tv_usec = static_cast<suseconds_t>(kMicrosecondsPerSecond - 1);
412 1 : return tv;
413 : }
414 2 : tv.tv_sec = static_cast<time_t>(us_ / kMicrosecondsPerSecond);
415 2 : tv.tv_usec = us_ % kMicrosecondsPerSecond;
416 2 : return tv;
417 : }
418 :
419 : #endif // V8_OS_WIN
420 :
421 :
422 1 : 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 1 : if (ms_since_epoch == std::numeric_limits<double>::max()) {
426 : return Max();
427 : }
428 : return Time(
429 1 : static_cast<int64_t>(ms_since_epoch * kMicrosecondsPerMillisecond));
430 : }
431 :
432 :
433 28132908 : double Time::ToJsTime() const {
434 28132908 : if (IsNull()) {
435 : // Preserve 0 so the invalid result doesn't depend on the platform.
436 : return 0;
437 : }
438 28132908 : if (IsMax()) {
439 : // Preserve max without offset to prevent overflow.
440 : return std::numeric_limits<double>::max();
441 : }
442 28132908 : return static_cast<double>(us_) / kMicrosecondsPerMillisecond;
443 : }
444 :
445 :
446 0 : std::ostream& operator<<(std::ostream& os, const Time& time) {
447 0 : return os << time.ToJsTime();
448 : }
449 :
450 :
451 : #if V8_OS_WIN
452 :
453 : class 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.
489 : class HighResolutionTickClock final : public TickClock {
490 : 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 :
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 :
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:
521 : RolloverProtectedTickClock() : rollover_(0) {}
522 : virtual ~RolloverProtectedTickClock() {}
523 :
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 :
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 {
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 :
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 :
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 :
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
600 : bool TimeTicks::IsHighResolutionClockWorking() {
601 : return high_res_tick_clock.Pointer()->IsHighResolution();
602 : }
603 :
604 : #else // V8_OS_WIN
605 :
606 175798 : TimeTicks TimeTicks::Now() {
607 175798 : return HighResolutionNow();
608 : }
609 :
610 :
611 33701137 : 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 33703195 : 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 1100 : 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 1100 : 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
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
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
696 : void ThreadTicks::WaitUntilInitializedWin() {
697 : while (TSCTicksPerSecond() == 0)
698 : ::Sleep(10);
699 : }
700 :
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
|