time.cc 17.4 KB
Newer Older
1
// Copyright 2013 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// 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 12 13 14 15
#endif
#if V8_OS_MACOSX
#include <mach/mach_time.h>
#endif

16 17
#include <cstring>
#include <ostream>
18

19 20 21 22
#if V8_OS_WIN
#include "src/base/lazy-instance.h"
#include "src/base/win32-headers.h"
#endif
23 24 25
#include "src/base/cpu.h"
#include "src/base/logging.h"
#include "src/base/platform/platform.h"
26 27

namespace v8 {
28
namespace base {
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99

TimeDelta TimeDelta::FromDays(int days) {
  return TimeDelta(days * Time::kMicrosecondsPerDay);
}


TimeDelta TimeDelta::FromHours(int hours) {
  return TimeDelta(hours * Time::kMicrosecondsPerHour);
}


TimeDelta TimeDelta::FromMinutes(int minutes) {
  return TimeDelta(minutes * Time::kMicrosecondsPerMinute);
}


TimeDelta TimeDelta::FromSeconds(int64_t seconds) {
  return TimeDelta(seconds * Time::kMicrosecondsPerSecond);
}


TimeDelta TimeDelta::FromMilliseconds(int64_t milliseconds) {
  return TimeDelta(milliseconds * Time::kMicrosecondsPerMillisecond);
}


TimeDelta TimeDelta::FromNanoseconds(int64_t nanoseconds) {
  return TimeDelta(nanoseconds / Time::kNanosecondsPerMicrosecond);
}


int TimeDelta::InDays() const {
  return static_cast<int>(delta_ / Time::kMicrosecondsPerDay);
}


int TimeDelta::InHours() const {
  return static_cast<int>(delta_ / Time::kMicrosecondsPerHour);
}


int TimeDelta::InMinutes() const {
  return static_cast<int>(delta_ / Time::kMicrosecondsPerMinute);
}


double TimeDelta::InSecondsF() const {
  return static_cast<double>(delta_) / Time::kMicrosecondsPerSecond;
}


int64_t TimeDelta::InSeconds() const {
  return delta_ / Time::kMicrosecondsPerSecond;
}


double TimeDelta::InMillisecondsF() const {
  return static_cast<double>(delta_) / Time::kMicrosecondsPerMillisecond;
}


int64_t TimeDelta::InMilliseconds() const {
  return delta_ / Time::kMicrosecondsPerMillisecond;
}


int64_t TimeDelta::InNanoseconds() const {
  return delta_ * Time::kNanosecondsPerMicrosecond;
}


100 101 102
#if V8_OS_MACOSX

TimeDelta TimeDelta::FromMachTimespec(struct mach_timespec ts) {
103 104
  DCHECK_GE(ts.tv_nsec, 0);
  DCHECK_LT(ts.tv_nsec,
105
            static_cast<long>(Time::kNanosecondsPerSecond));  // NOLINT
106 107 108 109 110 111 112
  return TimeDelta(ts.tv_sec * Time::kMicrosecondsPerSecond +
                   ts.tv_nsec / Time::kNanosecondsPerMicrosecond);
}


struct mach_timespec TimeDelta::ToMachTimespec() const {
  struct mach_timespec ts;
113
  DCHECK(delta_ >= 0);
114
  ts.tv_sec = static_cast<unsigned>(delta_ / Time::kMicrosecondsPerSecond);
115 116 117 118 119 120 121 122
  ts.tv_nsec = (delta_ % Time::kMicrosecondsPerSecond) *
      Time::kNanosecondsPerMicrosecond;
  return ts;
}

#endif  // V8_OS_MACOSX


123 124 125
#if V8_OS_POSIX

TimeDelta TimeDelta::FromTimespec(struct timespec ts) {
126 127
  DCHECK_GE(ts.tv_nsec, 0);
  DCHECK_LT(ts.tv_nsec,
128 129 130 131 132 133 134 135
            static_cast<long>(Time::kNanosecondsPerSecond));  // NOLINT
  return TimeDelta(ts.tv_sec * Time::kMicrosecondsPerSecond +
                   ts.tv_nsec / Time::kNanosecondsPerMicrosecond);
}


struct timespec TimeDelta::ToTimespec() const {
  struct timespec ts;
136
  ts.tv_sec = static_cast<time_t>(delta_ / Time::kMicrosecondsPerSecond);
137 138 139 140 141 142 143 144
  ts.tv_nsec = (delta_ % Time::kMicrosecondsPerSecond) *
      Time::kNanosecondsPerMicrosecond;
  return ts;
}

#endif  // V8_OS_POSIX


145 146 147 148 149
#if V8_OS_WIN

// We implement time using the high-resolution timers so that we can get
// timeouts which are smaller than 10-15ms. To avoid any drift, we
// periodically resync the internal clock to the system clock.
150
class Clock final {
151
 public:
152
  Clock() : initial_ticks_(GetSystemTicks()), initial_time_(GetSystemTime()) {}
153 154

  Time Now() {
155 156
    // Time between resampling the un-granular clock for this API (1 minute).
    const TimeDelta kMaxElapsedTime = TimeDelta::FromMinutes(1);
157

158
    LockGuard<Mutex> lock_guard(&mutex_);
159

160 161 162 163 164 165 166 167 168 169 170
    // Determine current time and ticks.
    TimeTicks ticks = GetSystemTicks();
    Time time = GetSystemTime();

    // Check if we need to synchronize with the system clock due to a backwards
    // time change or the amount of time elapsed.
    TimeDelta elapsed = ticks - initial_ticks_;
    if (time < initial_time_ || elapsed > kMaxElapsedTime) {
      initial_ticks_ = ticks;
      initial_time_ = time;
      return time;
171 172
    }

173
    return initial_time_ + elapsed;
174 175 176
  }

  Time NowFromSystemTime() {
177
    LockGuard<Mutex> lock_guard(&mutex_);
178 179
    initial_ticks_ = GetSystemTicks();
    initial_time_ = GetSystemTime();
180 181 182 183
    return initial_time_;
  }

 private:
184 185 186
  static TimeTicks GetSystemTicks() {
    return TimeTicks::Now();
  }
187

188
  static Time GetSystemTime() {
189 190 191 192 193 194 195
    FILETIME ft;
    ::GetSystemTimeAsFileTime(&ft);
    return Time::FromFiletime(ft);
  }

  TimeTicks initial_ticks_;
  Time initial_time_;
196
  Mutex mutex_;
197 198 199
};


200 201
static LazyStaticInstance<Clock, DefaultConstructTrait<Clock>,
                          ThreadSafeInitOnceTrait>::type clock =
202
    LAZY_STATIC_INSTANCE_INITIALIZER;
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233


Time Time::Now() {
  return clock.Pointer()->Now();
}


Time Time::NowFromSystemTime() {
  return clock.Pointer()->NowFromSystemTime();
}


// Time between windows epoch and standard epoch.
static const int64_t kTimeToEpochInMicroseconds = V8_INT64_C(11644473600000000);


Time Time::FromFiletime(FILETIME ft) {
  if (ft.dwLowDateTime == 0 && ft.dwHighDateTime == 0) {
    return Time();
  }
  if (ft.dwLowDateTime == std::numeric_limits<DWORD>::max() &&
      ft.dwHighDateTime == std::numeric_limits<DWORD>::max()) {
    return Max();
  }
  int64_t us = (static_cast<uint64_t>(ft.dwLowDateTime) +
                (static_cast<uint64_t>(ft.dwHighDateTime) << 32)) / 10;
  return Time(us - kTimeToEpochInMicroseconds);
}


FILETIME Time::ToFiletime() const {
234
  DCHECK(us_ >= 0);
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
  FILETIME ft;
  if (IsNull()) {
    ft.dwLowDateTime = 0;
    ft.dwHighDateTime = 0;
    return ft;
  }
  if (IsMax()) {
    ft.dwLowDateTime = std::numeric_limits<DWORD>::max();
    ft.dwHighDateTime = std::numeric_limits<DWORD>::max();
    return ft;
  }
  uint64_t us = static_cast<uint64_t>(us_ + kTimeToEpochInMicroseconds) * 10;
  ft.dwLowDateTime = static_cast<DWORD>(us);
  ft.dwHighDateTime = static_cast<DWORD>(us >> 32);
  return ft;
}

#elif V8_OS_POSIX

Time Time::Now() {
  struct timeval tv;
  int result = gettimeofday(&tv, NULL);
257
  DCHECK_EQ(0, result);
258 259 260 261 262 263 264 265 266 267
  USE(result);
  return FromTimeval(tv);
}


Time Time::NowFromSystemTime() {
  return Now();
}


268
Time Time::FromTimespec(struct timespec ts) {
269 270
  DCHECK(ts.tv_nsec >= 0);
  DCHECK(ts.tv_nsec < static_cast<long>(kNanosecondsPerSecond));  // NOLINT
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
  if (ts.tv_nsec == 0 && ts.tv_sec == 0) {
    return Time();
  }
  if (ts.tv_nsec == static_cast<long>(kNanosecondsPerSecond - 1) &&  // NOLINT
      ts.tv_sec == std::numeric_limits<time_t>::max()) {
    return Max();
  }
  return Time(ts.tv_sec * kMicrosecondsPerSecond +
              ts.tv_nsec / kNanosecondsPerMicrosecond);
}


struct timespec Time::ToTimespec() const {
  struct timespec ts;
  if (IsNull()) {
    ts.tv_sec = 0;
    ts.tv_nsec = 0;
    return ts;
  }
  if (IsMax()) {
    ts.tv_sec = std::numeric_limits<time_t>::max();
    ts.tv_nsec = static_cast<long>(kNanosecondsPerSecond - 1);  // NOLINT
    return ts;
  }
295
  ts.tv_sec = static_cast<time_t>(us_ / kMicrosecondsPerSecond);
296 297 298 299 300
  ts.tv_nsec = (us_ % kMicrosecondsPerSecond) * kNanosecondsPerMicrosecond;
  return ts;
}


301
Time Time::FromTimeval(struct timeval tv) {
302 303
  DCHECK(tv.tv_usec >= 0);
  DCHECK(tv.tv_usec < static_cast<suseconds_t>(kMicrosecondsPerSecond));
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
  if (tv.tv_usec == 0 && tv.tv_sec == 0) {
    return Time();
  }
  if (tv.tv_usec == static_cast<suseconds_t>(kMicrosecondsPerSecond - 1) &&
      tv.tv_sec == std::numeric_limits<time_t>::max()) {
    return Max();
  }
  return Time(tv.tv_sec * kMicrosecondsPerSecond + tv.tv_usec);
}


struct timeval Time::ToTimeval() const {
  struct timeval tv;
  if (IsNull()) {
    tv.tv_sec = 0;
    tv.tv_usec = 0;
    return tv;
  }
  if (IsMax()) {
    tv.tv_sec = std::numeric_limits<time_t>::max();
    tv.tv_usec = static_cast<suseconds_t>(kMicrosecondsPerSecond - 1);
    return tv;
  }
327
  tv.tv_sec = static_cast<time_t>(us_ / kMicrosecondsPerSecond);
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
  tv.tv_usec = us_ % kMicrosecondsPerSecond;
  return tv;
}

#endif  // V8_OS_WIN


Time Time::FromJsTime(double ms_since_epoch) {
  // The epoch is a valid time, so this constructor doesn't interpret
  // 0 as the null time.
  if (ms_since_epoch == std::numeric_limits<double>::max()) {
    return Max();
  }
  return Time(
      static_cast<int64_t>(ms_since_epoch * kMicrosecondsPerMillisecond));
}


double Time::ToJsTime() const {
  if (IsNull()) {
    // Preserve 0 so the invalid result doesn't depend on the platform.
    return 0;
  }
  if (IsMax()) {
    // Preserve max without offset to prevent overflow.
    return std::numeric_limits<double>::max();
  }
  return static_cast<double>(us_) / kMicrosecondsPerMillisecond;
}


359 360 361 362 363
std::ostream& operator<<(std::ostream& os, const Time& time) {
  return os << time.ToJsTime();
}


364 365 366 367 368 369
#if V8_OS_WIN

class TickClock {
 public:
  virtual ~TickClock() {}
  virtual int64_t Now() = 0;
370
  virtual bool IsHighResolution() = 0;
371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
};


// Overview of time counters:
// (1) CPU cycle counter. (Retrieved via RDTSC)
// The CPU counter provides the highest resolution time stamp and is the least
// expensive to retrieve. However, the CPU counter is unreliable and should not
// be used in production. Its biggest issue is that it is per processor and it
// is not synchronized between processors. Also, on some computers, the counters
// will change frequency due to thermal and power changes, and stop in some
// states.
//
// (2) QueryPerformanceCounter (QPC). The QPC counter provides a high-
// resolution (100 nanoseconds) time stamp but is comparatively more expensive
// to retrieve. What QueryPerformanceCounter actually does is up to the HAL.
// (with some help from ACPI).
// According to http://blogs.msdn.com/oldnewthing/archive/2005/09/02/459952.aspx
// in the worst case, it gets the counter from the rollover interrupt on the
// programmable interrupt timer. In best cases, the HAL may conclude that the
// RDTSC counter runs at a constant frequency, then it uses that instead. On
// multiprocessor machines, it will try to verify the values returned from
// RDTSC on each processor are consistent with each other, and apply a handful
// of workarounds for known buggy hardware. In other words, QPC is supposed to
// give consistent result on a multiprocessor computer, but it is unreliable in
// reality due to bugs in BIOS or HAL on some, especially old computers.
// With recent updates on HAL and newer BIOS, QPC is getting more reliable but
// it should be used with caution.
//
// (3) System time. The system time provides a low-resolution (typically 10ms
// to 55 milliseconds) time stamp but is comparatively less expensive to
// retrieve and more reliable.
402
class HighResolutionTickClock final : public TickClock {
403 404 405
 public:
  explicit HighResolutionTickClock(int64_t ticks_per_second)
      : ticks_per_second_(ticks_per_second) {
406
    DCHECK_LT(0, ticks_per_second);
407 408 409
  }
  virtual ~HighResolutionTickClock() {}

410
  int64_t Now() override {
411 412
    LARGE_INTEGER now;
    BOOL result = QueryPerformanceCounter(&now);
413
    DCHECK(result);
414 415 416 417 418 419 420 421 422
    USE(result);

    // Intentionally calculate microseconds in a round about manner to avoid
    // overflow and precision issues. Think twice before simplifying!
    int64_t whole_seconds = now.QuadPart / ticks_per_second_;
    int64_t leftover_ticks = now.QuadPart % ticks_per_second_;
    int64_t ticks = (whole_seconds * Time::kMicrosecondsPerSecond) +
        ((leftover_ticks * Time::kMicrosecondsPerSecond) / ticks_per_second_);

423
    // Make sure we never return 0 here, so that TimeTicks::HighResolutionNow()
424 425 426 427
    // will never return 0.
    return ticks + 1;
  }

428
  bool IsHighResolution() override { return true; }
429 430

 private:
431
  int64_t ticks_per_second_;
432 433 434
};


435
class RolloverProtectedTickClock final : public TickClock {
436
 public:
437
  // We initialize rollover_ms_ to 1 to ensure that we will never
438
  // return 0 from TimeTicks::HighResolutionNow() and TimeTicks::Now() below.
439 440
  RolloverProtectedTickClock() : last_seen_now_(0), rollover_ms_(1) {}
  virtual ~RolloverProtectedTickClock() {}
441

442
  int64_t Now() override {
443
    LockGuard<Mutex> lock_guard(&mutex_);
444 445 446 447 448 449
    // We use timeGetTime() to implement TimeTicks::Now(), which rolls over
    // every ~49.7 days. We try to track rollover ourselves, which works if
    // TimeTicks::Now() is called at least every 49 days.
    // Note that we do not use GetTickCount() here, since timeGetTime() gives
    // more predictable delta values, as described here:
    // http://blogs.msdn.com/b/larryosterman/archive/2009/09/02/what-s-the-difference-between-gettickcount-and-timegettime.aspx
450 451 452
    // timeGetTime() provides 1ms granularity when combined with
    // timeBeginPeriod(). If the host application for V8 wants fast timers, it
    // can use timeBeginPeriod() to increase the resolution.
453 454 455 456 457 458 459 460
    DWORD now = timeGetTime();
    if (now < last_seen_now_) {
      rollover_ms_ += V8_INT64_C(0x100000000);  // ~49.7 days.
    }
    last_seen_now_ = now;
    return (now + rollover_ms_) * Time::kMicrosecondsPerMillisecond;
  }

461
  bool IsHighResolution() override { return false; }
462

463
 private:
464
  Mutex mutex_;
465 466 467 468 469
  DWORD last_seen_now_;
  int64_t rollover_ms_;
};


470 471 472
static LazyStaticInstance<RolloverProtectedTickClock,
                          DefaultConstructTrait<RolloverProtectedTickClock>,
                          ThreadSafeInitOnceTrait>::type tick_clock =
473
    LAZY_STATIC_INSTANCE_INITIALIZER;
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496


struct CreateHighResTickClockTrait {
  static TickClock* Create() {
    // Check if the installed hardware supports a high-resolution performance
    // counter, and if not fallback to the low-resolution tick clock.
    LARGE_INTEGER ticks_per_second;
    if (!QueryPerformanceFrequency(&ticks_per_second)) {
      return tick_clock.Pointer();
    }

    // On Athlon X2 CPUs (e.g. model 15) the QueryPerformanceCounter
    // is unreliable, fallback to the low-resolution tick clock.
    CPU cpu;
    if (strcmp(cpu.vendor(), "AuthenticAMD") == 0 && cpu.family() == 15) {
      return tick_clock.Pointer();
    }

    return new HighResolutionTickClock(ticks_per_second.QuadPart);
  }
};


497 498 499
static LazyDynamicInstance<TickClock, CreateHighResTickClockTrait,
                           ThreadSafeInitOnceTrait>::type high_res_tick_clock =
    LAZY_DYNAMIC_INSTANCE_INITIALIZER;
500 501 502 503 504


TimeTicks TimeTicks::Now() {
  // Make sure we never return 0 here.
  TimeTicks ticks(tick_clock.Pointer()->Now());
505
  DCHECK(!ticks.IsNull());
506 507 508 509
  return ticks;
}


510
TimeTicks TimeTicks::HighResolutionNow() {
511 512
  // Make sure we never return 0 here.
  TimeTicks ticks(high_res_tick_clock.Pointer()->Now());
513
  DCHECK(!ticks.IsNull());
514 515 516
  return ticks;
}

517 518 519 520 521 522

// static
bool TimeTicks::IsHighResolutionClockWorking() {
  return high_res_tick_clock.Pointer()->IsHighResolution();
}

523 524 525 526 527 528 529 530

// static
TimeTicks TimeTicks::KernelTimestampNow() { return TimeTicks(0); }


// static
bool TimeTicks::KernelTimestampAvailable() { return false; }

531 532 533
#else  // V8_OS_WIN

TimeTicks TimeTicks::Now() {
534
  return HighResolutionNow();
535 536 537
}


538
TimeTicks TimeTicks::HighResolutionNow() {
539 540 541 542 543
  int64_t ticks;
#if V8_OS_MACOSX
  static struct mach_timebase_info info;
  if (info.denom == 0) {
    kern_return_t result = mach_timebase_info(&info);
544
    DCHECK_EQ(KERN_SUCCESS, result);
545 546 547 548 549 550 551 552
    USE(result);
  }
  ticks = (mach_absolute_time() / Time::kNanosecondsPerMicrosecond *
           info.numer / info.denom);
#elif V8_OS_SOLARIS
  ticks = (gethrtime() / Time::kNanosecondsPerMicrosecond);
#elif V8_OS_POSIX
  struct timespec ts;
553
  int result = clock_gettime(CLOCK_MONOTONIC, &ts);
554
  DCHECK_EQ(0, result);
555 556 557 558 559 560 561 562
  USE(result);
  ticks = (ts.tv_sec * Time::kMicrosecondsPerSecond +
           ts.tv_nsec / Time::kNanosecondsPerMicrosecond);
#endif  // V8_OS_MACOSX
  // Make sure we never return 0 here.
  return TimeTicks(ticks + 1);
}

563 564 565 566 567 568

// static
bool TimeTicks::IsHighResolutionClockWorking() {
  return true;
}

569

570
#if V8_OS_LINUX
571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625

class KernelTimestampClock {
 public:
  KernelTimestampClock() : clock_fd_(-1), clock_id_(kClockInvalid) {
    clock_fd_ = open(kTraceClockDevice, O_RDONLY);
    if (clock_fd_ == -1) {
      return;
    }
    clock_id_ = get_clockid(clock_fd_);
  }

  virtual ~KernelTimestampClock() {
    if (clock_fd_ != -1) {
      close(clock_fd_);
    }
  }

  int64_t Now() {
    if (clock_id_ == kClockInvalid) {
      return 0;
    }

    struct timespec ts;

    clock_gettime(clock_id_, &ts);
    return ((int64_t)ts.tv_sec * kNsecPerSec) + ts.tv_nsec;
  }

  bool Available() { return clock_id_ != kClockInvalid; }

 private:
  static const clockid_t kClockInvalid = -1;
  static const char kTraceClockDevice[];
  static const uint64_t kNsecPerSec = 1000000000;

  int clock_fd_;
  clockid_t clock_id_;

  static int get_clockid(int fd) { return ((~(clockid_t)(fd) << 3) | 3); }
};


// Timestamp module name
const char KernelTimestampClock::kTraceClockDevice[] = "/dev/trace_clock";

#else

class KernelTimestampClock {
 public:
  KernelTimestampClock() {}

  int64_t Now() { return 0; }
  bool Available() { return false; }
};

626
#endif  // V8_OS_LINUX
627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644

static LazyStaticInstance<KernelTimestampClock,
                          DefaultConstructTrait<KernelTimestampClock>,
                          ThreadSafeInitOnceTrait>::type kernel_tick_clock =
    LAZY_STATIC_INSTANCE_INITIALIZER;


// static
TimeTicks TimeTicks::KernelTimestampNow() {
  return TimeTicks(kernel_tick_clock.Pointer()->Now());
}


// static
bool TimeTicks::KernelTimestampAvailable() {
  return kernel_tick_clock.Pointer()->Available();
}

645 646
#endif  // V8_OS_WIN

647
} }  // namespace v8::base