The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / platform / time.cc @ f230a1cf

History | View | Annotate | Download (17.1 KB)

1
// Copyright 2013 the V8 project authors. All rights reserved.
2
// Redistribution and use in source and binary forms, with or without
3
// modification, are permitted provided that the following conditions are
4
// met:
5
//
6
//     * Redistributions of source code must retain the above copyright
7
//       notice, this list of conditions and the following disclaimer.
8
//     * Redistributions in binary form must reproduce the above
9
//       copyright notice, this list of conditions and the following
10
//       disclaimer in the documentation and/or other materials provided
11
//       with the distribution.
12
//     * Neither the name of Google Inc. nor the names of its
13
//       contributors may be used to endorse or promote products derived
14
//       from this software without specific prior written permission.
15
//
16
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27

    
28
#include "platform/time.h"
29

    
30
#if V8_OS_POSIX
31
#include <sys/time.h>
32
#endif
33
#if V8_OS_MACOSX
34
#include <mach/mach_time.h>
35
#endif
36

    
37
#include <cstring>
38

    
39
#include "checks.h"
40
#include "cpu.h"
41
#include "platform.h"
42
#if V8_OS_WIN
43
#include "win32-headers.h"
44
#endif
45

    
46
namespace v8 {
47
namespace internal {
48

    
49
TimeDelta TimeDelta::FromDays(int days) {
50
  return TimeDelta(days * Time::kMicrosecondsPerDay);
51
}
52

    
53

    
54
TimeDelta TimeDelta::FromHours(int hours) {
55
  return TimeDelta(hours * Time::kMicrosecondsPerHour);
56
}
57

    
58

    
59
TimeDelta TimeDelta::FromMinutes(int minutes) {
60
  return TimeDelta(minutes * Time::kMicrosecondsPerMinute);
61
}
62

    
63

    
64
TimeDelta TimeDelta::FromSeconds(int64_t seconds) {
65
  return TimeDelta(seconds * Time::kMicrosecondsPerSecond);
66
}
67

    
68

    
69
TimeDelta TimeDelta::FromMilliseconds(int64_t milliseconds) {
70
  return TimeDelta(milliseconds * Time::kMicrosecondsPerMillisecond);
71
}
72

    
73

    
74
TimeDelta TimeDelta::FromNanoseconds(int64_t nanoseconds) {
75
  return TimeDelta(nanoseconds / Time::kNanosecondsPerMicrosecond);
76
}
77

    
78

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

    
83

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

    
88

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

    
93

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

    
98

    
99
int64_t TimeDelta::InSeconds() const {
100
  return delta_ / Time::kMicrosecondsPerSecond;
101
}
102

    
103

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

    
108

    
109
int64_t TimeDelta::InMilliseconds() const {
110
  return delta_ / Time::kMicrosecondsPerMillisecond;
111
}
112

    
113

    
114
int64_t TimeDelta::InNanoseconds() const {
115
  return delta_ * Time::kNanosecondsPerMicrosecond;
116
}
117

    
118

    
119
#if V8_OS_MACOSX
120

    
121
TimeDelta TimeDelta::FromMachTimespec(struct mach_timespec ts) {
122
  ASSERT_GE(ts.tv_nsec, 0);
123
  ASSERT_LT(ts.tv_nsec,
124
            static_cast<long>(Time::kNanosecondsPerSecond));  // NOLINT
125
  return TimeDelta(ts.tv_sec * Time::kMicrosecondsPerSecond +
126
                   ts.tv_nsec / Time::kNanosecondsPerMicrosecond);
127
}
128

    
129

    
130
struct mach_timespec TimeDelta::ToMachTimespec() const {
131
  struct mach_timespec ts;
132
  ASSERT(delta_ >= 0);
133
  ts.tv_sec = delta_ / Time::kMicrosecondsPerSecond;
134
  ts.tv_nsec = (delta_ % Time::kMicrosecondsPerSecond) *
135
      Time::kNanosecondsPerMicrosecond;
136
  return ts;
137
}
138

    
139
#endif  // V8_OS_MACOSX
140

    
141

    
142
#if V8_OS_POSIX
143

    
144
TimeDelta TimeDelta::FromTimespec(struct timespec ts) {
145
  ASSERT_GE(ts.tv_nsec, 0);
146
  ASSERT_LT(ts.tv_nsec,
147
            static_cast<long>(Time::kNanosecondsPerSecond));  // NOLINT
148
  return TimeDelta(ts.tv_sec * Time::kMicrosecondsPerSecond +
149
                   ts.tv_nsec / Time::kNanosecondsPerMicrosecond);
150
}
151

    
152

    
153
struct timespec TimeDelta::ToTimespec() const {
154
  struct timespec ts;
155
  ts.tv_sec = delta_ / Time::kMicrosecondsPerSecond;
156
  ts.tv_nsec = (delta_ % Time::kMicrosecondsPerSecond) *
157
      Time::kNanosecondsPerMicrosecond;
158
  return ts;
159
}
160

    
161
#endif  // V8_OS_POSIX
162

    
163

    
164
#if V8_OS_WIN
165

    
166
// We implement time using the high-resolution timers so that we can get
167
// timeouts which are smaller than 10-15ms. To avoid any drift, we
168
// periodically resync the internal clock to the system clock.
169
class Clock V8_FINAL {
170
 public:
171
  Clock() : initial_ticks_(GetSystemTicks()), initial_time_(GetSystemTime()) {}
172

    
173
  Time Now() {
174
    // Time between resampling the un-granular clock for this API (1 minute).
175
    const TimeDelta kMaxElapsedTime = TimeDelta::FromMinutes(1);
176

    
177
    LockGuard<Mutex> lock_guard(&mutex_);
178

    
179
    // Determine current time and ticks.
180
    TimeTicks ticks = GetSystemTicks();
181
    Time time = GetSystemTime();
182

    
183
    // Check if we need to synchronize with the system clock due to a backwards
184
    // time change or the amount of time elapsed.
185
    TimeDelta elapsed = ticks - initial_ticks_;
186
    if (time < initial_time_ || elapsed > kMaxElapsedTime) {
187
      initial_ticks_ = ticks;
188
      initial_time_ = time;
189
      return time;
190
    }
191

    
192
    return initial_time_ + elapsed;
193
  }
194

    
195
  Time NowFromSystemTime() {
196
    LockGuard<Mutex> lock_guard(&mutex_);
197
    initial_ticks_ = GetSystemTicks();
198
    initial_time_ = GetSystemTime();
199
    return initial_time_;
200
  }
201

    
202
 private:
203
  static TimeTicks GetSystemTicks() {
204
    return TimeTicks::Now();
205
  }
206

    
207
  static Time GetSystemTime() {
208
    FILETIME ft;
209
    ::GetSystemTimeAsFileTime(&ft);
210
    return Time::FromFiletime(ft);
211
  }
212

    
213
  TimeTicks initial_ticks_;
214
  Time initial_time_;
215
  Mutex mutex_;
216
};
217

    
218

    
219
static LazyStaticInstance<Clock,
220
    DefaultConstructTrait<Clock>,
221
    ThreadSafeInitOnceTrait>::type clock = LAZY_STATIC_INSTANCE_INITIALIZER;
222

    
223

    
224
Time Time::Now() {
225
  return clock.Pointer()->Now();
226
}
227

    
228

    
229
Time Time::NowFromSystemTime() {
230
  return clock.Pointer()->NowFromSystemTime();
231
}
232

    
233

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

    
237

    
238
Time Time::FromFiletime(FILETIME ft) {
239
  if (ft.dwLowDateTime == 0 && ft.dwHighDateTime == 0) {
240
    return Time();
241
  }
242
  if (ft.dwLowDateTime == std::numeric_limits<DWORD>::max() &&
243
      ft.dwHighDateTime == std::numeric_limits<DWORD>::max()) {
244
    return Max();
245
  }
246
  int64_t us = (static_cast<uint64_t>(ft.dwLowDateTime) +
247
                (static_cast<uint64_t>(ft.dwHighDateTime) << 32)) / 10;
248
  return Time(us - kTimeToEpochInMicroseconds);
249
}
250

    
251

    
252
FILETIME Time::ToFiletime() const {
253
  ASSERT(us_ >= 0);
254
  FILETIME ft;
255
  if (IsNull()) {
256
    ft.dwLowDateTime = 0;
257
    ft.dwHighDateTime = 0;
258
    return ft;
259
  }
260
  if (IsMax()) {
261
    ft.dwLowDateTime = std::numeric_limits<DWORD>::max();
262
    ft.dwHighDateTime = std::numeric_limits<DWORD>::max();
263
    return ft;
264
  }
265
  uint64_t us = static_cast<uint64_t>(us_ + kTimeToEpochInMicroseconds) * 10;
266
  ft.dwLowDateTime = static_cast<DWORD>(us);
267
  ft.dwHighDateTime = static_cast<DWORD>(us >> 32);
268
  return ft;
269
}
270

    
271
#elif V8_OS_POSIX
272

    
273
Time Time::Now() {
274
  struct timeval tv;
275
  int result = gettimeofday(&tv, NULL);
276
  ASSERT_EQ(0, result);
277
  USE(result);
278
  return FromTimeval(tv);
279
}
280

    
281

    
282
Time Time::NowFromSystemTime() {
283
  return Now();
284
}
285

    
286

    
287
Time Time::FromTimespec(struct timespec ts) {
288
  ASSERT(ts.tv_nsec >= 0);
289
  ASSERT(ts.tv_nsec < static_cast<long>(kNanosecondsPerSecond));  // NOLINT
290
  if (ts.tv_nsec == 0 && ts.tv_sec == 0) {
291
    return Time();
292
  }
293
  if (ts.tv_nsec == static_cast<long>(kNanosecondsPerSecond - 1) &&  // NOLINT
294
      ts.tv_sec == std::numeric_limits<time_t>::max()) {
295
    return Max();
296
  }
297
  return Time(ts.tv_sec * kMicrosecondsPerSecond +
298
              ts.tv_nsec / kNanosecondsPerMicrosecond);
299
}
300

    
301

    
302
struct timespec Time::ToTimespec() const {
303
  struct timespec ts;
304
  if (IsNull()) {
305
    ts.tv_sec = 0;
306
    ts.tv_nsec = 0;
307
    return ts;
308
  }
309
  if (IsMax()) {
310
    ts.tv_sec = std::numeric_limits<time_t>::max();
311
    ts.tv_nsec = static_cast<long>(kNanosecondsPerSecond - 1);  // NOLINT
312
    return ts;
313
  }
314
  ts.tv_sec = us_ / kMicrosecondsPerSecond;
315
  ts.tv_nsec = (us_ % kMicrosecondsPerSecond) * kNanosecondsPerMicrosecond;
316
  return ts;
317
}
318

    
319

    
320
Time Time::FromTimeval(struct timeval tv) {
321
  ASSERT(tv.tv_usec >= 0);
322
  ASSERT(tv.tv_usec < static_cast<suseconds_t>(kMicrosecondsPerSecond));
323
  if (tv.tv_usec == 0 && tv.tv_sec == 0) {
324
    return Time();
325
  }
326
  if (tv.tv_usec == static_cast<suseconds_t>(kMicrosecondsPerSecond - 1) &&
327
      tv.tv_sec == std::numeric_limits<time_t>::max()) {
328
    return Max();
329
  }
330
  return Time(tv.tv_sec * kMicrosecondsPerSecond + tv.tv_usec);
331
}
332

    
333

    
334
struct timeval Time::ToTimeval() const {
335
  struct timeval tv;
336
  if (IsNull()) {
337
    tv.tv_sec = 0;
338
    tv.tv_usec = 0;
339
    return tv;
340
  }
341
  if (IsMax()) {
342
    tv.tv_sec = std::numeric_limits<time_t>::max();
343
    tv.tv_usec = static_cast<suseconds_t>(kMicrosecondsPerSecond - 1);
344
    return tv;
345
  }
346
  tv.tv_sec = us_ / kMicrosecondsPerSecond;
347
  tv.tv_usec = us_ % kMicrosecondsPerSecond;
348
  return tv;
349
}
350

    
351
#endif  // V8_OS_WIN
352

    
353

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

    
364

    
365
double Time::ToJsTime() const {
366
  if (IsNull()) {
367
    // Preserve 0 so the invalid result doesn't depend on the platform.
368
    return 0;
369
  }
370
  if (IsMax()) {
371
    // Preserve max without offset to prevent overflow.
372
    return std::numeric_limits<double>::max();
373
  }
374
  return static_cast<double>(us_) / kMicrosecondsPerMillisecond;
375
}
376

    
377

    
378
#if V8_OS_WIN
379

    
380
class TickClock {
381
 public:
382
  virtual ~TickClock() {}
383
  virtual int64_t Now() = 0;
384
  virtual bool IsHighResolution() = 0;
385
};
386

    
387

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

    
424
  virtual int64_t Now() V8_OVERRIDE {
425
    LARGE_INTEGER now;
426
    BOOL result = QueryPerformanceCounter(&now);
427
    ASSERT(result);
428
    USE(result);
429

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

    
437
    // Make sure we never return 0 here, so that TimeTicks::HighResolutionNow()
438
    // will never return 0.
439
    return ticks + 1;
440
  }
441

    
442
  virtual bool IsHighResolution() V8_OVERRIDE {
443
    return true;
444
  }
445

    
446
 private:
447
  int64_t ticks_per_second_;
448
};
449

    
450

    
451
class RolloverProtectedTickClock V8_FINAL : public TickClock {
452
 public:
453
  // We initialize rollover_ms_ to 1 to ensure that we will never
454
  // return 0 from TimeTicks::HighResolutionNow() and TimeTicks::Now() below.
455
  RolloverProtectedTickClock() : last_seen_now_(0), rollover_ms_(1) {}
456
  virtual ~RolloverProtectedTickClock() {}
457

    
458
  virtual int64_t Now() V8_OVERRIDE {
459
    LockGuard<Mutex> lock_guard(&mutex_);
460
    // We use timeGetTime() to implement TimeTicks::Now(), which rolls over
461
    // every ~49.7 days. We try to track rollover ourselves, which works if
462
    // TimeTicks::Now() is called at least every 49 days.
463
    // Note that we do not use GetTickCount() here, since timeGetTime() gives
464
    // more predictable delta values, as described here:
465
    // http://blogs.msdn.com/b/larryosterman/archive/2009/09/02/what-s-the-difference-between-gettickcount-and-timegettime.aspx
466
    // timeGetTime() provides 1ms granularity when combined with
467
    // timeBeginPeriod(). If the host application for V8 wants fast timers, it
468
    // can use timeBeginPeriod() to increase the resolution.
469
    DWORD now = timeGetTime();
470
    if (now < last_seen_now_) {
471
      rollover_ms_ += V8_INT64_C(0x100000000);  // ~49.7 days.
472
    }
473
    last_seen_now_ = now;
474
    return (now + rollover_ms_) * Time::kMicrosecondsPerMillisecond;
475
  }
476

    
477
  virtual bool IsHighResolution() V8_OVERRIDE {
478
    return false;
479
  }
480

    
481
 private:
482
  Mutex mutex_;
483
  DWORD last_seen_now_;
484
  int64_t rollover_ms_;
485
};
486

    
487

    
488
static LazyStaticInstance<RolloverProtectedTickClock,
489
    DefaultConstructTrait<RolloverProtectedTickClock>,
490
    ThreadSafeInitOnceTrait>::type tick_clock =
491
        LAZY_STATIC_INSTANCE_INITIALIZER;
492

    
493

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

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

    
510
    return new HighResolutionTickClock(ticks_per_second.QuadPart);
511
  }
512
};
513

    
514

    
515
static LazyDynamicInstance<TickClock,
516
    CreateHighResTickClockTrait,
517
    ThreadSafeInitOnceTrait>::type high_res_tick_clock =
518
        LAZY_DYNAMIC_INSTANCE_INITIALIZER;
519

    
520

    
521
TimeTicks TimeTicks::Now() {
522
  // Make sure we never return 0 here.
523
  TimeTicks ticks(tick_clock.Pointer()->Now());
524
  ASSERT(!ticks.IsNull());
525
  return ticks;
526
}
527

    
528

    
529
TimeTicks TimeTicks::HighResolutionNow() {
530
  // Make sure we never return 0 here.
531
  TimeTicks ticks(high_res_tick_clock.Pointer()->Now());
532
  ASSERT(!ticks.IsNull());
533
  return ticks;
534
}
535

    
536

    
537
// static
538
bool TimeTicks::IsHighResolutionClockWorking() {
539
  return high_res_tick_clock.Pointer()->IsHighResolution();
540
}
541

    
542
#else  // V8_OS_WIN
543

    
544
TimeTicks TimeTicks::Now() {
545
  return HighResolutionNow();
546
}
547

    
548

    
549
TimeTicks TimeTicks::HighResolutionNow() {
550
  int64_t ticks;
551
#if V8_OS_MACOSX
552
  static struct mach_timebase_info info;
553
  if (info.denom == 0) {
554
    kern_return_t result = mach_timebase_info(&info);
555
    ASSERT_EQ(KERN_SUCCESS, result);
556
    USE(result);
557
  }
558
  ticks = (mach_absolute_time() / Time::kNanosecondsPerMicrosecond *
559
           info.numer / info.denom);
560
#elif V8_OS_SOLARIS
561
  ticks = (gethrtime() / Time::kNanosecondsPerMicrosecond);
562
#elif V8_LIBRT_NOT_AVAILABLE
563
  // TODO(bmeurer): This is a temporary hack to support cross-compiling
564
  // Chrome for Android in AOSP. Remove this once AOSP is fixed, also
565
  // cleanup the tools/gyp/v8.gyp file.
566
  struct timeval tv;
567
  int result = gettimeofday(&tv, NULL);
568
  ASSERT_EQ(0, result);
569
  USE(result);
570
  ticks = (tv.tv_sec * Time::kMicrosecondsPerSecond + tv.tv_usec);
571
#elif V8_OS_POSIX
572
  struct timespec ts;
573
  int result = clock_gettime(CLOCK_MONOTONIC, &ts);
574
  ASSERT_EQ(0, result);
575
  USE(result);
576
  ticks = (ts.tv_sec * Time::kMicrosecondsPerSecond +
577
           ts.tv_nsec / Time::kNanosecondsPerMicrosecond);
578
#endif  // V8_OS_MACOSX
579
  // Make sure we never return 0 here.
580
  return TimeTicks(ticks + 1);
581
}
582

    
583

    
584
// static
585
bool TimeTicks::IsHighResolutionClockWorking() {
586
  return true;
587
}
588

    
589
#endif  // V8_OS_WIN
590

    
591
} }  // namespace v8::internal