Add Chromium-style TimeDelta, Time and TimeTicks classes, and a new ElapsedTimer...
authorbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 28 Aug 2013 11:06:11 +0000 (11:06 +0000)
committerbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 28 Aug 2013 11:06:11 +0000 (11:06 +0000)
These classes are meant to replace OS::Ticks() and OS::TimeCurrentMillis(),
which are broken in several ways. The ElapsedTimer class implements a
stopwatch using TimeTicks::HighResNow() for high resolution, monotonic
timing.

Also fix the CpuProfile::GetStartTime() and CpuProfile::GetEndTime()
methods to actually return the time relative to the unix epoch as stated
in the documentation (previously that was relative to some arbitrary
point in time, i.e. boot time).

BUG=v8:2853
R=machenbach@chromium.org, yurys@chromium.org

Committed: https://code.google.com/p/v8/source/detail?r=16388

Review URL: https://codereview.chromium.org/23295034

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16390 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

31 files changed:
src/api.cc
src/compiler.cc
src/compiler.h
src/counters.cc
src/counters.h
src/cpu-profiler.cc
src/cpu-profiler.h
src/deoptimizer.cc
src/hydrogen.cc
src/hydrogen.h
src/lithium-allocator.cc
src/log.cc
src/log.h
src/optimizing-compiler-thread.cc
src/optimizing-compiler-thread.h
src/parser.cc
src/platform-linux.cc
src/platform-macos.cc
src/platform-openbsd.cc
src/platform-posix.cc
src/platform-win32.cc
src/platform.h
src/profile-generator.cc
src/profile-generator.h
src/time/elapsed-timer.h [new file with mode: 0644]
src/time/time.cc [new file with mode: 0644]
src/time/time.h [new file with mode: 0644]
test/cctest/cctest.gyp
test/cctest/test-cpu-profiler.cc
test/cctest/test-time.cc [new file with mode: 0644]
tools/gyp/v8.gyp

index 9c0ac7b..ebd2b81 100644 (file)
@@ -7310,13 +7310,13 @@ const CpuProfileNode* CpuProfile::GetSample(int index) const {
 
 int64_t CpuProfile::GetStartTime() const {
   const i::CpuProfile* profile = reinterpret_cast<const i::CpuProfile*>(this);
-  return profile->start_time_us();
+  return (profile->start_time() - i::Time::UnixEpoch()).InMicroseconds();
 }
 
 
 int64_t CpuProfile::GetEndTime() const {
   const i::CpuProfile* profile = reinterpret_cast<const i::CpuProfile*>(this);
-  return profile->end_time_us();
+  return (profile->end_time() - i::Time::UnixEpoch()).InMicroseconds();
 }
 
 
index 6c2bdce..93898b1 100644 (file)
@@ -260,10 +260,9 @@ void OptimizingCompiler::RecordOptimizationStats() {
   Handle<JSFunction> function = info()->closure();
   int opt_count = function->shared()->opt_count();
   function->shared()->set_opt_count(opt_count + 1);
-  double ms_creategraph =
-      static_cast<double>(time_taken_to_create_graph_) / 1000;
-  double ms_optimize = static_cast<double>(time_taken_to_optimize_) / 1000;
-  double ms_codegen = static_cast<double>(time_taken_to_codegen_) / 1000;
+  double ms_creategraph = time_taken_to_create_graph_.InMillisecondsF();
+  double ms_optimize = time_taken_to_optimize_.InMillisecondsF();
+  double ms_codegen = time_taken_to_codegen_.InMillisecondsF();
   if (FLAG_trace_opt) {
     PrintF("[optimizing ");
     function->ShortPrint();
@@ -373,9 +372,9 @@ OptimizingCompiler::Status OptimizingCompiler::CreateGraph() {
   // performance of the hydrogen-based compiler.
   bool should_recompile = !info()->shared_info()->has_deoptimization_support();
   if (should_recompile || FLAG_hydrogen_stats) {
-    int64_t start_ticks = 0;
+    ElapsedTimer timer;
     if (FLAG_hydrogen_stats) {
-      start_ticks = OS::Ticks();
+      timer.Start();
     }
     CompilationInfoWithZone unoptimized(info()->shared_info());
     // Note that we use the same AST that we will use for generating the
@@ -394,8 +393,7 @@ OptimizingCompiler::Status OptimizingCompiler::CreateGraph() {
           Logger::LAZY_COMPILE_TAG, &unoptimized, shared);
     }
     if (FLAG_hydrogen_stats) {
-      int64_t ticks = OS::Ticks() - start_ticks;
-      isolate()->GetHStatistics()->IncrementFullCodeGen(ticks);
+      isolate()->GetHStatistics()->IncrementFullCodeGen(timer.Elapsed());
     }
   }
 
@@ -1244,7 +1242,7 @@ CompilationPhase::CompilationPhase(const char* name, CompilationInfo* info)
     : name_(name), info_(info), zone_(info->isolate()) {
   if (FLAG_hydrogen_stats) {
     info_zone_start_allocation_size_ = info->zone()->allocation_size();
-    start_ticks_ = OS::Ticks();
+    timer_.Start();
   }
 }
 
@@ -1253,8 +1251,7 @@ CompilationPhase::~CompilationPhase() {
   if (FLAG_hydrogen_stats) {
     unsigned size = zone()->allocation_size();
     size += info_->zone()->allocation_size() - info_zone_start_allocation_size_;
-    int64_t ticks = OS::Ticks() - start_ticks_;
-    isolate()->GetHStatistics()->SaveTiming(name_, ticks, size);
+    isolate()->GetHStatistics()->SaveTiming(name_, timer_.Elapsed(), size);
   }
 }
 
index 469698e..1f13b8f 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "allocation.h"
 #include "ast.h"
+#include "time/elapsed-timer.h"
 #include "zone.h"
 
 namespace v8 {
@@ -501,9 +502,6 @@ class OptimizingCompiler: public ZoneObject {
         graph_builder_(NULL),
         graph_(NULL),
         chunk_(NULL),
-        time_taken_to_create_graph_(0),
-        time_taken_to_optimize_(0),
-        time_taken_to_codegen_(0),
         last_status_(FAILED) { }
 
   enum Status {
@@ -529,9 +527,9 @@ class OptimizingCompiler: public ZoneObject {
   HOptimizedGraphBuilder* graph_builder_;
   HGraph* graph_;
   LChunk* chunk_;
-  int64_t time_taken_to_create_graph_;
-  int64_t time_taken_to_optimize_;
-  int64_t time_taken_to_codegen_;
+  TimeDelta time_taken_to_create_graph_;
+  TimeDelta time_taken_to_optimize_;
+  TimeDelta time_taken_to_codegen_;
   Status last_status_;
 
   MUST_USE_RESULT Status SetLastStatus(Status status) {
@@ -541,18 +539,20 @@ class OptimizingCompiler: public ZoneObject {
   void RecordOptimizationStats();
 
   struct Timer {
-    Timer(OptimizingCompiler* compiler, int64_t* location)
+    Timer(OptimizingCompiler* compiler, TimeDelta* location)
         : compiler_(compiler),
-          start_(OS::Ticks()),
-          location_(location) { }
+          location_(location) {
+      ASSERT(location_ != NULL);
+      timer_.Start();
+    }
 
     ~Timer() {
-      *location_ += (OS::Ticks() - start_);
+      *location_ += timer_.Elapsed();
     }
 
     OptimizingCompiler* compiler_;
-    int64_t start_;
-    int64_t* location_;
+    ElapsedTimer timer_;
+    TimeDelta* location_;
   };
 };
 
@@ -644,7 +644,7 @@ class CompilationPhase BASE_EMBEDDED {
   CompilationInfo* info_;
   Zone zone_;
   unsigned info_zone_start_allocation_size_;
-  int64_t start_ticks_;
+  ElapsedTimer timer_;
 
   DISALLOW_COPY_AND_ASSIGN(CompilationPhase);
 };
index 1839412..e2530a8 100644 (file)
@@ -60,8 +60,7 @@ void* Histogram::CreateHistogram() const {
 // Start the timer.
 void HistogramTimer::Start() {
   if (Enabled()) {
-    stop_time_ = 0;
-    start_time_ = OS::Ticks();
+    timer_.Start();
   }
   if (FLAG_log_internal_timer_events) {
     LOG(isolate(), TimerEvent(Logger::START, name()));
@@ -72,10 +71,9 @@ void HistogramTimer::Start() {
 // Stop the timer and record the results.
 void HistogramTimer::Stop() {
   if (Enabled()) {
-    stop_time_ = OS::Ticks();
     // Compute the delta between start and stop, in milliseconds.
-    int milliseconds = static_cast<int>(stop_time_ - start_time_) / 1000;
-    AddSample(milliseconds);
+    AddSample(static_cast<int>(timer_.Elapsed().InMilliseconds()));
+    timer_.Stop();
   }
   if (FLAG_log_internal_timer_events) {
     LOG(isolate(), TimerEvent(Logger::END, name()));
index a633fea..8cfe6c5 100644 (file)
@@ -245,9 +245,7 @@ class HistogramTimer : public Histogram {
                  int max,
                  int num_buckets,
                  Isolate* isolate)
-      : Histogram(name, min, max, num_buckets, isolate),
-        start_time_(0),
-        stop_time_(0) { }
+      : Histogram(name, min, max, num_buckets, isolate) {}
 
   // Start the timer.
   void Start();
@@ -257,12 +255,11 @@ class HistogramTimer : public Histogram {
 
   // Returns true if the timer is running.
   bool Running() {
-    return Enabled() && (start_time_ != 0) && (stop_time_ == 0);
+    return Enabled() && timer_.IsStarted();
   }
 
  private:
-  int64_t start_time_;
-  int64_t stop_time_;
+  ElapsedTimer timer_;
 };
 
 // Helper class for scoping a HistogramTimer.
index f8698b3..0802687 100644 (file)
@@ -46,12 +46,12 @@ static const int kProfilerStackSize = 64 * KB;
 ProfilerEventsProcessor::ProfilerEventsProcessor(
     ProfileGenerator* generator,
     Sampler* sampler,
-    int period_in_useconds)
+    TimeDelta period)
     : Thread(Thread::Options("v8:ProfEvntProc", kProfilerStackSize)),
       generator_(generator),
       sampler_(sampler),
       running_(true),
-      period_in_useconds_(period_in_useconds),
+      period_(period),
       last_code_event_id_(0), last_processed_code_event_id_(0) {
 }
 
@@ -124,9 +124,10 @@ bool ProfilerEventsProcessor::ProcessTicks() {
 
 
 void ProfilerEventsProcessor::ProcessEventsAndDoSample() {
-  int64_t stop_time = OS::Ticks() + period_in_useconds_;
+  ElapsedTimer timer;
+  timer.Start();
   // Keep processing existing events until we need to do next sample.
-  while (OS::Ticks() < stop_time) {
+  while (!timer.HasExpired(period_)) {
     if (ProcessTicks()) {
       // All ticks of the current dequeue_order are processed,
       // proceed to the next code event.
@@ -434,7 +435,8 @@ void CpuProfiler::StartProcessorIfNotStarted() {
     generator_ = new ProfileGenerator(profiles_);
     Sampler* sampler = logger->sampler();
     processor_ = new ProfilerEventsProcessor(
-        generator_, sampler, FLAG_cpu_profiler_sampling_interval);
+        generator_, sampler,
+        TimeDelta::FromMicroseconds(FLAG_cpu_profiler_sampling_interval));
     is_profiling_ = true;
     // Enumerate stuff we already have in the heap.
     ASSERT(isolate_->heap()->HasBeenSetUp());
index 84e34e4..41473d7 100644 (file)
@@ -138,7 +138,7 @@ class ProfilerEventsProcessor : public Thread {
  public:
   ProfilerEventsProcessor(ProfileGenerator* generator,
                           Sampler* sampler,
-                          int period_in_useconds);
+                          TimeDelta period);
   virtual ~ProfilerEventsProcessor() {}
 
   // Thread control.
@@ -169,7 +169,7 @@ class ProfilerEventsProcessor : public Thread {
   Sampler* sampler_;
   bool running_;
   // Sampling period in microseconds.
-  const int period_in_useconds_;
+  const TimeDelta period_;
   UnboundQueue<CodeEventsContainer> events_buffer_;
   static const size_t kTickSampleBufferSize = 1 * MB;
   static const size_t kTickSampleQueueLength =
index dc9ffc5..f797565 100644 (file)
@@ -784,12 +784,13 @@ void Deoptimizer::DoComputeOutputFrames() {
   }
 
   // Print some helpful diagnostic information.
-  int64_t start = OS::Ticks();
   if (FLAG_log_timer_events &&
       compiled_code_->kind() == Code::OPTIMIZED_FUNCTION) {
     LOG(isolate(), CodeDeoptEvent(compiled_code_));
   }
+  ElapsedTimer timer;
   if (trace_) {
+    timer.Start();
     PrintF("[deoptimizing (DEOPT %s): begin 0x%08" V8PRIxPTR " ",
            MessageFor(bailout_type_),
            reinterpret_cast<intptr_t>(function_));
@@ -870,7 +871,7 @@ void Deoptimizer::DoComputeOutputFrames() {
 
   // Print some helpful diagnostic information.
   if (trace_) {
-    double ms = static_cast<double>(OS::Ticks() - start) / 1000;
+    double ms = timer.Elapsed().InMillisecondsF();
     int index = output_count_ - 1;  // Index of the topmost frame.
     JSFunction* function = output_[index]->GetFunction();
     PrintF("[deoptimizing (%s): end 0x%08" V8PRIxPTR " ",
index 4847f1a..bffbcce 100644 (file)
@@ -9815,15 +9815,15 @@ void HStatistics::Initialize(CompilationInfo* info) {
 
 void HStatistics::Print() {
   PrintF("Timing results:\n");
-  int64_t sum = 0;
-  for (int i = 0; i < timing_.length(); ++i) {
-    sum += timing_[i];
+  TimeDelta sum;
+  for (int i = 0; i < times_.length(); ++i) {
+    sum += times_[i];
   }
 
   for (int i = 0; i < names_.length(); ++i) {
     PrintF("%32s", names_[i]);
-    double ms = static_cast<double>(timing_[i]) / 1000;
-    double percent = static_cast<double>(timing_[i]) * 100 / sum;
+    double ms = times_[i].InMillisecondsF();
+    double percent = times_[i].PercentOf(sum);
     PrintF(" %8.3f ms / %4.1f %% ", ms, percent);
 
     unsigned size = sizes_[i];
@@ -9833,29 +9833,29 @@ void HStatistics::Print() {
 
   PrintF("----------------------------------------"
          "---------------------------------------\n");
-  int64_t total = create_graph_ + optimize_graph_ + generate_code_;
+  TimeDelta total = create_graph_ + optimize_graph_ + generate_code_;
   PrintF("%32s %8.3f ms / %4.1f %% \n",
          "Create graph",
-         static_cast<double>(create_graph_) / 1000,
-         static_cast<double>(create_graph_) * 100 / total);
+         create_graph_.InMillisecondsF(),
+         create_graph_.PercentOf(total));
   PrintF("%32s %8.3f ms / %4.1f %% \n",
          "Optimize graph",
-         static_cast<double>(optimize_graph_) / 1000,
-         static_cast<double>(optimize_graph_) * 100 / total);
+         optimize_graph_.InMillisecondsF(),
+         optimize_graph_.PercentOf(total));
   PrintF("%32s %8.3f ms / %4.1f %% \n",
          "Generate and install code",
-         static_cast<double>(generate_code_) / 1000,
-         static_cast<double>(generate_code_) * 100 / total);
+         generate_code_.InMillisecondsF(),
+         generate_code_.PercentOf(total));
   PrintF("----------------------------------------"
          "---------------------------------------\n");
   PrintF("%32s %8.3f ms (%.1f times slower than full code gen)\n",
          "Total",
-         static_cast<double>(total) / 1000,
-         static_cast<double>(total) / full_code_gen_);
+         total.InMillisecondsF(),
+         total.TimesOf(full_code_gen_));
 
   double source_size_in_kb = static_cast<double>(source_size_) / 1024;
   double normalized_time =  source_size_in_kb > 0
-      ? (static_cast<double>(total) / 1000) / source_size_in_kb
+      ? total.InMillisecondsF() / source_size_in_kb
       : 0;
   double normalized_size_in_kb = source_size_in_kb > 0
       ? total_size_ / 1024 / source_size_in_kb
@@ -9866,17 +9866,17 @@ void HStatistics::Print() {
 }
 
 
-void HStatistics::SaveTiming(const char* name, int64_t ticks, unsigned size) {
+void HStatistics::SaveTiming(const char* name, TimeDelta time, unsigned size) {
   total_size_ += size;
   for (int i = 0; i < names_.length(); ++i) {
     if (strcmp(names_[i], name) == 0) {
-      timing_[i] += ticks;
+      times_[i] += time;
       sizes_[i] += size;
       return;
     }
   }
   names_.Add(name);
-  timing_.Add(ticks);
+  times_.Add(time);
   sizes_.Add(size);
 }
 
index 22bffd1..369e092 100644 (file)
@@ -2165,41 +2165,37 @@ Zone* AstContext::zone() const { return owner_->zone(); }
 class HStatistics V8_FINAL: public Malloced {
  public:
   HStatistics()
-      : timing_(5),
+      : times_(5),
         names_(5),
         sizes_(5),
-        create_graph_(0),
-        optimize_graph_(0),
-        generate_code_(0),
         total_size_(0),
-        full_code_gen_(0),
         source_size_(0) { }
 
   void Initialize(CompilationInfo* info);
   void Print();
-  void SaveTiming(const char* name, int64_t ticks, unsigned size);
+  void SaveTiming(const char* name, TimeDelta time, unsigned size);
 
-  void IncrementFullCodeGen(int64_t full_code_gen) {
+  void IncrementFullCodeGen(TimeDelta full_code_gen) {
     full_code_gen_ += full_code_gen;
   }
 
-  void IncrementSubtotals(int64_t create_graph,
-                          int64_t optimize_graph,
-                          int64_t generate_code) {
+  void IncrementSubtotals(TimeDelta create_graph,
+                          TimeDelta optimize_graph,
+                          TimeDelta generate_code) {
     create_graph_ += create_graph;
     optimize_graph_ += optimize_graph;
     generate_code_ += generate_code;
   }
 
  private:
-  List<int64_t> timing_;
+  List<TimeDelta> times_;
   List<const char*> names_;
   List<unsigned> sizes_;
-  int64_t create_graph_;
-  int64_t optimize_graph_;
-  int64_t generate_code_;
+  TimeDelta create_graph_;
+  TimeDelta optimize_graph_;
+  TimeDelta generate_code_;
   unsigned total_size_;
-  int64_t full_code_gen_;
+  TimeDelta full_code_gen_;
   double source_size_;
 };
 
index 2e2f802..3c5abd1 100644 (file)
@@ -2189,7 +2189,7 @@ LAllocatorPhase::~LAllocatorPhase() {
   if (FLAG_hydrogen_stats) {
     unsigned size = allocator_->zone()->allocation_size() -
                     allocator_zone_start_allocation_size_;
-    isolate()->GetHStatistics()->SaveTiming(name(), 0, size);
+    isolate()->GetHStatistics()->SaveTiming(name(), TimeDelta(), size);
   }
 
   if (ShouldProduceTraceOutput()) {
index ff67d10..59d494a 100644 (file)
@@ -716,8 +716,7 @@ Logger::Logger(Isolate* isolate)
     ll_logger_(NULL),
     jit_logger_(NULL),
     listeners_(5),
-    is_initialized_(false),
-    epoch_(0) {
+    is_initialized_(false) {
 }
 
 
@@ -868,7 +867,7 @@ void Logger::CodeDeoptEvent(Code* code) {
   if (!log_->IsEnabled()) return;
   ASSERT(FLAG_log_internal_timer_events);
   Log::MessageBuilder msg(log_);
-  int since_epoch = static_cast<int>(OS::Ticks() - epoch_);
+  int since_epoch = static_cast<int>(timer_.Elapsed().InMicroseconds());
   msg.Append("code-deopt,%ld,%d\n", since_epoch, code->CodeSize());
   msg.WriteToLogFile();
 }
@@ -878,7 +877,7 @@ void Logger::TimerEvent(StartEnd se, const char* name) {
   if (!log_->IsEnabled()) return;
   ASSERT(FLAG_log_internal_timer_events);
   Log::MessageBuilder msg(log_);
-  int since_epoch = static_cast<int>(OS::Ticks() - epoch_);
+  int since_epoch = static_cast<int>(timer_.Elapsed().InMicroseconds());
   const char* format = (se == START) ? "timer-event-start,\"%s\",%ld\n"
                                      : "timer-event-end,\"%s\",%ld\n";
   msg.Append(format, name, since_epoch);
@@ -1501,7 +1500,7 @@ void Logger::TickEvent(TickSample* sample, bool overflow) {
   Log::MessageBuilder msg(log_);
   msg.Append("%s,", kLogEventsNames[TICK_EVENT]);
   msg.AppendAddress(sample->pc);
-  msg.Append(",%ld", static_cast<int>(OS::Ticks() - epoch_));
+  msg.Append(",%ld", static_cast<int>(timer_.Elapsed().InMicroseconds()));
   if (sample->has_external_callback) {
     msg.Append(",1,");
     msg.AppendAddress(sample->external_callback);
@@ -1896,7 +1895,7 @@ bool Logger::SetUp(Isolate* isolate) {
     }
   }
 
-  if (FLAG_log_internal_timer_events || FLAG_prof) epoch_ = OS::Ticks();
+  if (FLAG_log_internal_timer_events || FLAG_prof) timer_.Start();
 
   return true;
 }
index 76e3cee..aa0d279 100644 (file)
--- a/src/log.h
+++ b/src/log.h
@@ -31,6 +31,7 @@
 #include "allocation.h"
 #include "objects.h"
 #include "platform.h"
+#include "time/elapsed-timer.h"
 
 namespace v8 {
 namespace internal {
@@ -450,7 +451,7 @@ class Logger {
   // 'true' between SetUp() and TearDown().
   bool is_initialized_;
 
-  int64_t epoch_;
+  ElapsedTimer timer_;
 
   friend class CpuProfiler;
 };
index 788f027..added33 100644 (file)
@@ -48,8 +48,8 @@ void OptimizingCompilerThread::Run() {
   DisallowHandleAllocation no_handles;
   DisallowHandleDereference no_deref;
 
-  int64_t epoch = 0;
-  if (FLAG_trace_concurrent_recompilation) epoch = OS::Ticks();
+  ElapsedTimer total_timer;
+  if (FLAG_trace_concurrent_recompilation) total_timer.Start();
 
   while (true) {
     input_queue_semaphore_->Wait();
@@ -65,7 +65,7 @@ void OptimizingCompilerThread::Run() {
         break;
       case STOP:
         if (FLAG_trace_concurrent_recompilation) {
-          time_spent_total_ = OS::Ticks() - epoch;
+          time_spent_total_ = total_timer.Elapsed();
         }
         stop_semaphore_->Signal();
         return;
@@ -81,13 +81,13 @@ void OptimizingCompilerThread::Run() {
         continue;
     }
 
-    int64_t compiling_start = 0;
-    if (FLAG_trace_concurrent_recompilation) compiling_start = OS::Ticks();
+    ElapsedTimer compiling_timer;
+    if (FLAG_trace_concurrent_recompilation) compiling_timer.Start();
 
     CompileNext();
 
     if (FLAG_trace_concurrent_recompilation) {
-      time_spent_compiling_ += OS::Ticks() - compiling_start;
+      time_spent_compiling_ += compiling_timer.Elapsed();
     }
   }
 }
@@ -175,9 +175,7 @@ void OptimizingCompilerThread::Stop() {
   }
 
   if (FLAG_trace_concurrent_recompilation) {
-    double compile_time = static_cast<double>(time_spent_compiling_);
-    double total_time = static_cast<double>(time_spent_total_);
-    double percentage = (compile_time * 100) / total_time;
+    double percentage = time_spent_compiling_.PercentOf(time_spent_total_);
     PrintF("  ** Compiler thread did %.2f%% useful work\n", percentage);
   }
 
index aff94ed..80e7f6f 100644 (file)
@@ -32,6 +32,7 @@
 #include "flags.h"
 #include "platform.h"
 #include "unbound-queue-inl.h"
+#include "time/time.h"
 
 namespace v8 {
 namespace internal {
@@ -51,9 +52,7 @@ class OptimizingCompilerThread : public Thread {
       isolate_(isolate),
       stop_semaphore_(OS::CreateSemaphore(0)),
       input_queue_semaphore_(OS::CreateSemaphore(0)),
-      install_mutex_(OS::CreateMutex()),
-      time_spent_compiling_(0),
-      time_spent_total_(0) {
+      install_mutex_(OS::CreateMutex()) {
     NoBarrier_Store(&stop_thread_, static_cast<AtomicWord>(CONTINUE));
     NoBarrier_Store(&queue_length_, static_cast<AtomicWord>(0));
   }
@@ -112,8 +111,8 @@ class OptimizingCompilerThread : public Thread {
   Mutex* install_mutex_;
   volatile AtomicWord stop_thread_;
   volatile Atomic32 queue_length_;
-  int64_t time_spent_compiling_;
-  int64_t time_spent_total_;
+  TimeDelta time_spent_compiling_;
+  TimeDelta time_spent_total_;
 };
 
 } }  // namespace v8::internal
index ccab7ec..e4a6bb2 100644 (file)
@@ -569,10 +569,13 @@ Parser::Parser(CompilationInfo* info)
 
 
 FunctionLiteral* Parser::ParseProgram() {
-  HistogramTimerScope timer(isolate()->counters()->parse());
+  HistogramTimerScope timer_scope(isolate()->counters()->parse());
   Handle<String> source(String::cast(script_->source()));
   isolate()->counters()->total_parse_size()->Increment(source->length());
-  int64_t start = FLAG_trace_parse ? OS::Ticks() : 0;
+  ElapsedTimer timer;
+  if (FLAG_trace_parse) {
+    timer.Start();
+  }
   fni_ = new(zone()) FuncNameInferrer(isolate(), zone());
 
   // Initialize parser state.
@@ -593,7 +596,7 @@ FunctionLiteral* Parser::ParseProgram() {
   }
 
   if (FLAG_trace_parse && result != NULL) {
-    double ms = static_cast<double>(OS::Ticks() - start) / 1000;
+    double ms = timer.Elapsed().InMillisecondsF();
     if (info()->is_eval()) {
       PrintF("[parsing eval");
     } else if (info()->script()->name()->IsString()) {
@@ -697,10 +700,13 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info,
 
 
 FunctionLiteral* Parser::ParseLazy() {
-  HistogramTimerScope timer(isolate()->counters()->parse_lazy());
+  HistogramTimerScope timer_scope(isolate()->counters()->parse_lazy());
   Handle<String> source(String::cast(script_->source()));
   isolate()->counters()->total_parse_size()->Increment(source->length());
-  int64_t start = FLAG_trace_parse ? OS::Ticks() : 0;
+  ElapsedTimer timer;
+  if (FLAG_trace_parse) {
+    timer.Start();
+  }
   Handle<SharedFunctionInfo> shared_info = info()->shared_info();
 
   // Initialize parser state.
@@ -720,7 +726,7 @@ FunctionLiteral* Parser::ParseLazy() {
   }
 
   if (FLAG_trace_parse && result != NULL) {
-    double ms = static_cast<double>(OS::Ticks() - start) / 1000;
+    double ms = timer.Elapsed().InMillisecondsF();
     SmartArrayPointer<char> name_chars = result->debug_name()->ToCString();
     PrintF("[parsing function: %s - took %0.3f ms]\n", *name_chars, ms);
   }
index ef97449..b27c1fd 100644 (file)
@@ -569,7 +569,7 @@ Semaphore* OS::CreateSemaphore(int count) {
 
 void OS::SetUp() {
   // Seed the random number generator. We preserve microsecond resolution.
-  uint64_t seed = Ticks() ^ (getpid() << 16);
+  uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()) ^ (getpid() << 16);
   srandom(static_cast<unsigned int>(seed));
   limit_mutex = CreateMutex();
 }
index 6135cd1..9d8d076 100644 (file)
@@ -441,7 +441,7 @@ Semaphore* OS::CreateSemaphore(int count) {
 
 void OS::SetUp() {
   // Seed the random number generator. We preserve microsecond resolution.
-  uint64_t seed = Ticks() ^ (getpid() << 16);
+  uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()) ^ (getpid() << 16);
   srandom(static_cast<unsigned int>(seed));
   limit_mutex = CreateMutex();
 }
index e591601..a027944 100644 (file)
@@ -500,7 +500,7 @@ Semaphore* OS::CreateSemaphore(int count) {
 
 void OS::SetUp() {
   // Seed the random number generator. We preserve microsecond resolution.
-  uint64_t seed = Ticks() ^ (getpid() << 16);
+  uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()) ^ (getpid() << 16);
   srandom(static_cast<unsigned int>(seed));
   limit_mutex = CreateMutex();
 }
index 1244493..5ef92b1 100644 (file)
@@ -318,19 +318,7 @@ int OS::GetUserTime(uint32_t* secs,  uint32_t* usecs) {
 
 
 double OS::TimeCurrentMillis() {
-  struct timeval tv;
-  if (gettimeofday(&tv, NULL) < 0) return 0.0;
-  return (static_cast<double>(tv.tv_sec) * 1000) +
-         (static_cast<double>(tv.tv_usec) / 1000);
-}
-
-
-int64_t OS::Ticks() {
-  // gettimeofday has microsecond resolution.
-  struct timeval tv;
-  if (gettimeofday(&tv, NULL) < 0)
-    return 0;
-  return (static_cast<int64_t>(tv.tv_sec) * 1000000) + tv.tv_usec;
+  return Time::Now().ToJsTime();
 }
 
 
index f52bb43..f822049 100644 (file)
@@ -246,19 +246,15 @@ void MathSetup() {
 // timestamps are represented as a doubles in milliseconds since 00:00:00 UTC,
 // January 1, 1970.
 
-class Time {
+class Win32Time {
  public:
   // Constructors.
-  Time();
-  explicit Time(double jstime);
-  Time(int year, int mon, int day, int hour, int min, int sec);
+  explicit Win32Time(double jstime);
+  Win32Time(int year, int mon, int day, int hour, int min, int sec);
 
   // Convert timestamp to JavaScript representation.
   double ToJSTime();
 
-  // Set timestamp to current time.
-  void SetToCurrentTime();
-
   // Returns the local timezone offset in milliseconds east of UTC. This is
   // the number of milliseconds you must add to UTC to get local time, i.e.
   // LocalOffset(CET) = 3600000 and LocalOffset(PST) = -28800000. This
@@ -300,10 +296,6 @@ class Time {
   // Return whether or not daylight savings time is in effect at this time.
   bool InDST();
 
-  // Return the difference (in milliseconds) between this timestamp and
-  // another timestamp.
-  int64_t Diff(Time* other);
-
   // Accessor for FILETIME representation.
   FILETIME& ft() { return time_.ft_; }
 
@@ -325,26 +317,20 @@ class Time {
 
 
 // Static variables.
-bool Time::tz_initialized_ = false;
-TIME_ZONE_INFORMATION Time::tzinfo_;
-char Time::std_tz_name_[kTzNameSize];
-char Time::dst_tz_name_[kTzNameSize];
-
-
-// Initialize timestamp to start of epoc.
-Time::Time() {
-  t() = 0;
-}
+bool Win32Time::tz_initialized_ = false;
+TIME_ZONE_INFORMATION Win32Time::tzinfo_;
+char Win32Time::std_tz_name_[kTzNameSize];
+char Win32Time::dst_tz_name_[kTzNameSize];
 
 
 // Initialize timestamp from a JavaScript timestamp.
-Time::Time(double jstime) {
+Win32Time::Win32Time(double jstime) {
   t() = static_cast<int64_t>(jstime) * kTimeScaler + kTimeEpoc;
 }
 
 
 // Initialize timestamp from date/time components.
-Time::Time(int year, int mon, int day, int hour, int min, int sec) {
+Win32Time::Win32Time(int year, int mon, int day, int hour, int min, int sec) {
   SYSTEMTIME st;
   st.wYear = year;
   st.wMonth = mon;
@@ -358,14 +344,14 @@ Time::Time(int year, int mon, int day, int hour, int min, int sec) {
 
 
 // Convert timestamp to JavaScript timestamp.
-double Time::ToJSTime() {
+double Win32Time::ToJSTime() {
   return static_cast<double>((t() - kTimeEpoc) / kTimeScaler);
 }
 
 
 // Guess the name of the timezone from the bias.
 // The guess is very biased towards the northern hemisphere.
-const char* Time::GuessTimezoneNameFromBias(int bias) {
+const char* Win32Time::GuessTimezoneNameFromBias(int bias) {
   static const int kHour = 60;
   switch (-bias) {
     case -9*kHour: return "Alaska";
@@ -390,7 +376,7 @@ const char* Time::GuessTimezoneNameFromBias(int bias) {
 // Initialize timezone information. The timezone information is obtained from
 // windows. If we cannot get the timezone information we fall back to CET.
 // Please notice that this code is not thread-safe.
-void Time::TzSet() {
+void Win32Time::TzSet() {
   // Just return if timezone information has already been initialized.
   if (tz_initialized_) return;
 
@@ -439,78 +425,16 @@ void Time::TzSet() {
 }
 
 
-// Return the difference in milliseconds between this and another timestamp.
-int64_t Time::Diff(Time* other) {
-  return (t() - other->t()) / kTimeScaler;
-}
-
-
-// Set timestamp to current time.
-void Time::SetToCurrentTime() {
-  // The default GetSystemTimeAsFileTime has a ~15.5ms resolution.
-  // Because we're fast, we like fast timers which have at least a
-  // 1ms resolution.
-  //
-  // 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.
-  //
-  // Using timeGetTime() has a drawback because it is a 32bit value
-  // and hence rolls-over every ~49days.
-  //
-  // To use the clock, we use GetSystemTimeAsFileTime as our base;
-  // and then use timeGetTime to extrapolate current time from the
-  // start time.  To deal with rollovers, we resync the clock
-  // any time when more than kMaxClockElapsedTime has passed or
-  // whenever timeGetTime creates a rollover.
-
-  static bool initialized = false;
-  static TimeStamp init_time;
-  static DWORD init_ticks;
-  static const int64_t kHundredNanosecondsPerSecond = 10000000;
-  static const int64_t kMaxClockElapsedTime =
-      60*kHundredNanosecondsPerSecond;  // 1 minute
-
-  // If we are uninitialized, we need to resync the clock.
-  bool needs_resync = !initialized;
-
-  // Get the current time.
-  TimeStamp time_now;
-  GetSystemTimeAsFileTime(&time_now.ft_);
-  DWORD ticks_now = timeGetTime();
-
-  // Check if we need to resync due to clock rollover.
-  needs_resync |= ticks_now < init_ticks;
-
-  // Check if we need to resync due to elapsed time.
-  needs_resync |= (time_now.t_ - init_time.t_) > kMaxClockElapsedTime;
-
-  // Check if we need to resync due to backwards time change.
-  needs_resync |= time_now.t_ < init_time.t_;
-
-  // Resync the clock if necessary.
-  if (needs_resync) {
-    GetSystemTimeAsFileTime(&init_time.ft_);
-    init_ticks = ticks_now = timeGetTime();
-    initialized = true;
-  }
-
-  // Finally, compute the actual time.  Why is this so hard.
-  DWORD elapsed = ticks_now - init_ticks;
-  this->time_.t_ = init_time.t_ + (static_cast<int64_t>(elapsed) * 10000);
-}
-
-
 // Return the local timezone offset in milliseconds east of UTC. This
 // takes into account whether daylight saving is in effect at the time.
 // Only times in the 32-bit Unix range may be passed to this function.
 // Also, adding the time-zone offset to the input must not overflow.
 // The function EquivalentTime() in date.js guarantees this.
-int64_t Time::LocalOffset() {
+int64_t Win32Time::LocalOffset() {
   // Initialize timezone information, if needed.
   TzSet();
 
-  Time rounded_to_second(*this);
+  Win32Time rounded_to_second(*this);
   rounded_to_second.t() = rounded_to_second.t() / 1000 / kTimeScaler *
       1000 * kTimeScaler;
   // Convert to local time using POSIX localtime function.
@@ -541,7 +465,7 @@ int64_t Time::LocalOffset() {
 
 
 // Return whether or not daylight savings time is in effect at this time.
-bool Time::InDST() {
+bool Win32Time::InDST() {
   // Initialize timezone information, if needed.
   TzSet();
 
@@ -565,14 +489,14 @@ bool Time::InDST() {
 
 
 // Return the daylight savings time offset for this time.
-int64_t Time::DaylightSavingsOffset() {
+int64_t Win32Time::DaylightSavingsOffset() {
   return InDST() ? 60 * kMsPerMinute : 0;
 }
 
 
 // Returns a string identifying the current timezone for the
 // timestamp taking into account daylight saving.
-char* Time::LocalTimezone() {
+char* Win32Time::LocalTimezone() {
   // Return the standard or DST time zone name based on whether daylight
   // saving is in effect at the given time.
   return InDST() ? dst_tz_name_ : std_tz_name_;
@@ -614,22 +538,14 @@ int OS::GetUserTime(uint32_t* secs,  uint32_t* usecs) {
 // Returns current time as the number of milliseconds since
 // 00:00:00 UTC, January 1, 1970.
 double OS::TimeCurrentMillis() {
-  Time t;
-  t.SetToCurrentTime();
-  return t.ToJSTime();
-}
-
-
-// Returns the tickcounter based on timeGetTime.
-int64_t OS::Ticks() {
-  return timeGetTime() * 1000;  // Convert to microseconds.
+  return Time::Now().ToJsTime();
 }
 
 
 // Returns a string identifying the current timezone taking into
 // account daylight saving.
 const char* OS::LocalTimezone(double time) {
-  return Time(time).LocalTimezone();
+  return Win32Time(time).LocalTimezone();
 }
 
 
@@ -637,7 +553,7 @@ const char* OS::LocalTimezone(double time) {
 // taking daylight savings time into account.
 double OS::LocalTimeOffset() {
   // Use current time, rounded to the millisecond.
-  Time t(TimeCurrentMillis());
+  Win32Time t(TimeCurrentMillis());
   // Time::LocalOffset inlcudes any daylight savings offset, so subtract it.
   return static_cast<double>(t.LocalOffset() - t.DaylightSavingsOffset());
 }
@@ -646,7 +562,7 @@ double OS::LocalTimeOffset() {
 // Returns the daylight savings offset in milliseconds for the given
 // time.
 double OS::DaylightSavingsOffset(double time) {
-  int64_t offset = Time(time).DaylightSavingsOffset();
+  int64_t offset = Win32Time(time).DaylightSavingsOffset();
   return static_cast<double>(offset);
 }
 
index 3576d83..eb67e7e 100644 (file)
@@ -192,10 +192,6 @@ class OS {
   // micro-second resolution.
   static int GetUserTime(uint32_t* secs,  uint32_t* usecs);
 
-  // Get a tick counter normalized to one tick per microsecond.
-  // Used for calculating time intervals.
-  static int64_t Ticks();
-
   // Returns current time as the number of milliseconds since
   // 00:00:00 UTC, January 1, 1970.
   static double TimeCurrentMillis();
index b1dadc1..def0097 100644 (file)
@@ -334,8 +334,8 @@ CpuProfile::CpuProfile(const char* title, unsigned uid, bool record_samples)
     : title_(title),
       uid_(uid),
       record_samples_(record_samples),
-      start_time_us_(OS::Ticks()),
-      end_time_us_(0) {
+      start_time_(Time::NowFromSystemTime()) {
+  timer_.Start();
 }
 
 
@@ -346,7 +346,7 @@ void CpuProfile::AddPath(const Vector<CodeEntry*>& path) {
 
 
 void CpuProfile::CalculateTotalTicksAndSamplingRate() {
-  end_time_us_ = OS::Ticks();
+  end_time_ = start_time_ + timer_.Elapsed();
 }
 
 
index a282af2..928ec33 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "allocation.h"
 #include "hashmap.h"
+#include "time/time.h"
 #include "../include/v8-profiler.h"
 
 namespace v8 {
@@ -202,8 +203,8 @@ class CpuProfile {
   int samples_count() const { return samples_.length(); }
   ProfileNode* sample(int index) const { return samples_.at(index); }
 
-  int64_t start_time_us() const { return start_time_us_; }
-  int64_t end_time_us() const { return end_time_us_; }
+  Time start_time() const { return start_time_; }
+  Time end_time() const { return end_time_; }
 
   void UpdateTicksScale();
 
@@ -213,8 +214,9 @@ class CpuProfile {
   const char* title_;
   unsigned uid_;
   bool record_samples_;
-  int64_t start_time_us_;
-  int64_t end_time_us_;
+  Time start_time_;
+  Time end_time_;
+  ElapsedTimer timer_;
   List<ProfileNode*> samples_;
   ProfileTree top_down_;
 
diff --git a/src/time/elapsed-timer.h b/src/time/elapsed-timer.h
new file mode 100644 (file)
index 0000000..02e28e8
--- /dev/null
@@ -0,0 +1,120 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_TIME_ELAPSED_TIMER_H_
+#define V8_TIME_ELAPSED_TIMER_H_
+
+#include "checks.h"
+#include "time/time.h"
+
+namespace v8 {
+namespace internal {
+
+class ElapsedTimer V8_FINAL BASE_EMBEDDED {
+ public:
+#ifdef DEBUG
+  ElapsedTimer() : started_(false) {}
+#endif
+
+  // Starts this timer. Once started a timer can be checked with
+  // |Elapsed()| or |HasExpired()|, and may be restarted using |Restart()|.
+  // This method must not be called on an already started timer.
+  void Start() {
+    ASSERT(!IsStarted());
+    start_ticks_ = Now();
+#ifdef DEBUG
+    started_ = true;
+#endif
+    ASSERT(IsStarted());
+  }
+
+  // Stops this timer. Must not be called on a timer that was not
+  // started before.
+  void Stop() {
+    ASSERT(IsStarted());
+    start_ticks_ = TimeTicks();
+#ifdef DEBUG
+    started_ = false;
+#endif
+    ASSERT(!IsStarted());
+  }
+
+  // Returns |true| if this timer was started previously.
+  bool IsStarted() const {
+    ASSERT(started_ || start_ticks_.IsNull());
+    ASSERT(!started_ || !start_ticks_.IsNull());
+    return !start_ticks_.IsNull();
+  }
+
+  // Restarts the timer and returns the time elapsed since the previous start.
+  // This method is equivalent to obtaining the elapsed time with |Elapsed()|
+  // and then starting the timer again, but does so in one single operation,
+  // avoiding the need to obtain the clock value twice. It may only be called
+  // on a previously started timer.
+  TimeDelta Restart() {
+    ASSERT(IsStarted());
+    TimeTicks ticks = Now();
+    TimeDelta elapsed = ticks - start_ticks_;
+    ASSERT(elapsed.InMicroseconds() >= 0);
+    start_ticks_ = ticks;
+    ASSERT(IsStarted());
+    return elapsed;
+  }
+
+  // Returns the time elapsed since the previous start. This method may only
+  // be called on a previously started timer.
+  MUST_USE_RESULT TimeDelta Elapsed() const {
+    ASSERT(IsStarted());
+    TimeDelta elapsed = Now() - start_ticks_;
+    ASSERT(elapsed.InMicroseconds() >= 0);
+    return elapsed;
+  }
+
+  // Returns |true| if the specified |time_delta| has elapsed since the
+  // previous start, or |false| if not. This method may only be called on
+  // a previously started timer.
+  MUST_USE_RESULT bool HasExpired(TimeDelta time_delta) const {
+    ASSERT(IsStarted());
+    return Elapsed() >= time_delta;
+  }
+
+ private:
+  MUST_USE_RESULT V8_INLINE(static TimeTicks Now()) {
+    TimeTicks now = TimeTicks::HighResNow();
+    ASSERT(!now.IsNull());
+    return now;
+  }
+
+  TimeTicks start_ticks_;
+#ifdef DEBUG
+  bool started_;
+#endif
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_TIME_ELAPSED_TIMER_H_
diff --git a/src/time/time.cc b/src/time/time.cc
new file mode 100644 (file)
index 0000000..1742f30
--- /dev/null
@@ -0,0 +1,483 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "time.h"
+
+#if V8_OS_POSIX
+#include <sys/time.h>
+#endif
+#if V8_OS_MACOSX
+#include <mach/mach_time.h>
+#endif
+
+#include <cstring>
+
+#include "checks.h"
+#include "cpu.h"
+#include "platform.h"
+#if V8_OS_WIN
+#define V8_WIN32_HEADERS_FULL
+#include "win32-headers.h"
+#endif
+
+namespace v8 {
+namespace internal {
+
+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;
+}
+
+
+#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.
+class Clock V8_FINAL {
+ public:
+  Clock() : initial_time_(CurrentWallclockTime()),
+            initial_ticks_(TimeTicks::Now()),
+            mutex_(OS::CreateMutex()) {}
+
+  ~Clock() { delete mutex_; }
+
+  Time Now() {
+    // This must be executed under lock.
+    ScopedLock sl(mutex_);
+
+    // Calculate the time elapsed since we started our timer.
+    TimeDelta elapsed = TimeTicks::Now() - initial_ticks_;
+
+    // Check if we don't need to synchronize with the wallclock yet.
+    if (elapsed.InMicroseconds() <= kMaxMicrosecondsToAvoidDrift) {
+      return initial_time_ + elapsed;
+    }
+
+    // Resynchronize with the wallclock.
+    initial_ticks_ = TimeTicks::Now();
+    initial_time_ = CurrentWallclockTime();
+    return initial_time_;
+  }
+
+  Time NowFromSystemTime() {
+    ScopedLock sl(mutex_);
+    initial_ticks_ = TimeTicks::Now();
+    initial_time_ = CurrentWallclockTime();
+    return initial_time_;
+  }
+
+ private:
+  // Time between resampling the un-granular clock for this API (1 minute).
+  static const int64_t kMaxMicrosecondsToAvoidDrift =
+      Time::kMicrosecondsPerMinute;
+
+  static Time CurrentWallclockTime() {
+    FILETIME ft;
+    ::GetSystemTimeAsFileTime(&ft);
+    return Time::FromFiletime(ft);
+  }
+
+  TimeTicks initial_ticks_;
+  Time initial_time_;
+  Mutex* mutex_;
+};
+
+
+static LazyDynamicInstance<Clock,
+    DefaultCreateTrait<Clock>,
+    ThreadSafeInitOnceTrait>::type clock = LAZY_DYNAMIC_INSTANCE_INITIALIZER;
+
+
+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 {
+  ASSERT(us_ >= 0);
+  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);
+  ASSERT_EQ(0, result);
+  USE(result);
+  return FromTimeval(tv);
+}
+
+
+Time Time::NowFromSystemTime() {
+  return Now();
+}
+
+
+Time Time::FromTimeval(struct timeval tv) {
+  ASSERT(tv.tv_usec >= 0);
+  ASSERT(tv.tv_usec < static_cast<suseconds_t>(kMicrosecondsPerSecond));
+  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;
+  }
+  tv.tv_sec = us_ / kMicrosecondsPerSecond;
+  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;
+}
+
+
+#if V8_OS_WIN
+
+class TickClock {
+ public:
+  virtual ~TickClock() {}
+  virtual int64_t Now() = 0;
+};
+
+
+// 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.
+class HighResolutionTickClock V8_FINAL : public TickClock {
+ public:
+  explicit HighResolutionTickClock(int64_t ticks_per_second)
+      : ticks_per_second_(ticks_per_second) {
+    ASSERT_NE(0, ticks_per_second);
+  }
+  virtual ~HighResolutionTickClock() {}
+
+  virtual int64_t Now() V8_OVERRIDE {
+    LARGE_INTEGER now;
+    BOOL result = QueryPerformanceCounter(&now);
+    ASSERT(result);
+    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_);
+
+    // Make sure we never return 0 here, so that TimeTicks::HighResNow()
+    // will never return 0.
+    return ticks + 1;
+  }
+
+ private:
+  int64_t ticks_per_second_;
+};
+
+
+class RolloverProtectedTickClock V8_FINAL : public TickClock {
+ public:
+  RolloverProtectedTickClock()
+      : mutex_(OS::CreateMutex()), last_seen_now_(0), rollover_ms_(1) {
+    // We initialize rollover_ms_ to 1 to ensure that we will never
+    // return 0 from TimeTicks::HighResNow() and TimeTicks::Now() below.
+  }
+  virtual ~RolloverProtectedTickClock() { delete mutex_; }
+
+  virtual int64_t Now() V8_OVERRIDE {
+    ScopedLock sl(mutex_);
+    // 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
+    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_;
+  }
+
+ private:
+  Mutex* mutex_;
+  DWORD last_seen_now_;
+  int64_t rollover_ms_;
+};
+
+
+static LazyDynamicInstance<RolloverProtectedTickClock,
+    DefaultCreateTrait<RolloverProtectedTickClock>,
+    ThreadSafeInitOnceTrait>::type tick_clock =
+        LAZY_DYNAMIC_INSTANCE_INITIALIZER;
+
+
+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);
+  }
+};
+
+
+static LazyDynamicInstance<TickClock,
+    CreateHighResTickClockTrait,
+    ThreadSafeInitOnceTrait>::type high_res_tick_clock =
+        LAZY_DYNAMIC_INSTANCE_INITIALIZER;
+
+
+TimeTicks TimeTicks::Now() {
+  // Make sure we never return 0 here.
+  TimeTicks ticks(tick_clock.Pointer()->Now());
+  ASSERT(!ticks.IsNull());
+  return ticks;
+}
+
+
+TimeTicks TimeTicks::HighResNow() {
+  // Make sure we never return 0 here.
+  TimeTicks ticks(high_res_tick_clock.Pointer()->Now());
+  ASSERT(!ticks.IsNull());
+  return ticks;
+}
+
+#else  // V8_OS_WIN
+
+TimeTicks TimeTicks::Now() {
+  return HighResNow();
+}
+
+
+TimeTicks TimeTicks::HighResNow() {
+  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);
+    ASSERT_EQ(KERN_SUCCESS, result);
+    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;
+  int result = clock_gettime(CLOCK_MONOTONIC, &ts);
+  ASSERT_EQ(0, result);
+  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);
+}
+
+#endif  // V8_OS_WIN
+
+} }  // namespace v8::internal
diff --git a/src/time/time.h b/src/time/time.h
new file mode 100644 (file)
index 0000000..5ef19c6
--- /dev/null
@@ -0,0 +1,381 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_TIME_TIME_H_
+#define V8_TIME_TIME_H_
+
+#include <ctime>
+#include <limits>
+
+#include "allocation.h"
+
+// Forward declarations.
+extern "C" {
+struct _FILETIME;
+struct timeval;
+}
+
+namespace v8 {
+namespace internal {
+
+class Time;
+class TimeTicks;
+
+// -----------------------------------------------------------------------------
+// TimeDelta
+//
+// This class represents a duration of time, internally represented in
+// microseonds.
+
+class TimeDelta V8_FINAL BASE_EMBEDDED {
+ public:
+  TimeDelta() : delta_(0) {}
+
+  // Converts units of time to TimeDeltas.
+  static TimeDelta FromDays(int days);
+  static TimeDelta FromHours(int hours);
+  static TimeDelta FromMinutes(int minutes);
+  static TimeDelta FromSeconds(int64_t seconds);
+  static TimeDelta FromMilliseconds(int64_t milliseconds);
+  static TimeDelta FromMicroseconds(int64_t microseconds) {
+    return TimeDelta(microseconds);
+  }
+  static TimeDelta FromNanoseconds(int64_t nanoseconds);
+
+  // Returns the time delta in some unit. The F versions return a floating
+  // point value, the "regular" versions return a rounded-down value.
+  //
+  // InMillisecondsRoundedUp() instead returns an integer that is rounded up
+  // to the next full millisecond.
+  int InDays() const;
+  int InHours() const;
+  int InMinutes() const;
+  double InSecondsF() const;
+  int64_t InSeconds() const;
+  double InMillisecondsF() const;
+  int64_t InMilliseconds() const;
+  int64_t InMillisecondsRoundedUp() const;
+  int64_t InMicroseconds() const { return delta_; }
+  int64_t InNanoseconds() const;
+
+  TimeDelta& operator=(const TimeDelta& other) {
+    delta_ = other.delta_;
+    return *this;
+  }
+
+  // Computations with other deltas.
+  TimeDelta operator+(const TimeDelta& other) const {
+    return TimeDelta(delta_ + other.delta_);
+  }
+  TimeDelta operator-(const TimeDelta& other) const {
+    return TimeDelta(delta_ - other.delta_);
+  }
+
+  TimeDelta& operator+=(const TimeDelta& other) {
+    delta_ += other.delta_;
+    return *this;
+  }
+  TimeDelta& operator-=(const TimeDelta& other) {
+    delta_ -= other.delta_;
+    return *this;
+  }
+  TimeDelta operator-() const {
+    return TimeDelta(-delta_);
+  }
+
+  double TimesOf(const TimeDelta& other) const {
+    return static_cast<double>(delta_) / static_cast<double>(other.delta_);
+  }
+  double PercentOf(const TimeDelta& other) const {
+    return TimesOf(other) * 100.0;
+  }
+
+  // Computations with ints, note that we only allow multiplicative operations
+  // with ints, and additive operations with other deltas.
+  TimeDelta operator*(int64_t a) const {
+    return TimeDelta(delta_ * a);
+  }
+  TimeDelta operator/(int64_t a) const {
+    return TimeDelta(delta_ / a);
+  }
+  TimeDelta& operator*=(int64_t a) {
+    delta_ *= a;
+    return *this;
+  }
+  TimeDelta& operator/=(int64_t a) {
+    delta_ /= a;
+    return *this;
+  }
+  int64_t operator/(const TimeDelta& other) const {
+    return delta_ / other.delta_;
+  }
+
+  // Comparison operators.
+  bool operator==(const TimeDelta& other) const {
+    return delta_ == other.delta_;
+  }
+  bool operator!=(const TimeDelta& other) const {
+    return delta_ != other.delta_;
+  }
+  bool operator<(const TimeDelta& other) const {
+    return delta_ < other.delta_;
+  }
+  bool operator<=(const TimeDelta& other) const {
+    return delta_ <= other.delta_;
+  }
+  bool operator>(const TimeDelta& other) const {
+    return delta_ > other.delta_;
+  }
+  bool operator>=(const TimeDelta& other) const {
+    return delta_ >= other.delta_;
+  }
+
+ private:
+  // Constructs a delta given the duration in microseconds. This is private
+  // to avoid confusion by callers with an integer constructor. Use
+  // FromSeconds, FromMilliseconds, etc. instead.
+  explicit TimeDelta(int64_t delta) : delta_(delta) {}
+
+  // Delta in microseconds.
+  int64_t delta_;
+};
+
+
+// -----------------------------------------------------------------------------
+// Time
+//
+// This class represents an absolute point in time, internally represented as
+// microseconds (s/1,000,000) since 00:00:00 UTC, January 1, 1970.
+
+class Time V8_FINAL BASE_EMBEDDED {
+ public:
+  static const int64_t kMillisecondsPerSecond = 1000;
+  static const int64_t kMicrosecondsPerMillisecond = 1000;
+  static const int64_t kMicrosecondsPerSecond = kMicrosecondsPerMillisecond *
+                                                kMillisecondsPerSecond;
+  static const int64_t kMicrosecondsPerMinute = kMicrosecondsPerSecond * 60;
+  static const int64_t kMicrosecondsPerHour = kMicrosecondsPerMinute * 60;
+  static const int64_t kMicrosecondsPerDay = kMicrosecondsPerHour * 24;
+  static const int64_t kMicrosecondsPerWeek = kMicrosecondsPerDay * 7;
+  static const int64_t kNanosecondsPerMicrosecond = 1000;
+  static const int64_t kNanosecondsPerSecond = kNanosecondsPerMicrosecond *
+                                               kMicrosecondsPerSecond;
+
+  // Contains the NULL time. Use Time::Now() to get the current time.
+  Time() : us_(0) {}
+
+  // Returns true if the time object has not been initialized.
+  bool IsNull() const { return us_ == 0; }
+
+  // Returns true if the time object is the maximum time.
+  bool IsMax() const { return us_ == std::numeric_limits<int64_t>::max(); }
+
+  // Returns the current time. Watch out, the system might adjust its clock
+  // in which case time will actually go backwards. We don't guarantee that
+  // times are increasing, or that two calls to Now() won't be the same.
+  static Time Now();
+
+  // Returns the current time. Same as Now() except that this function always
+  // uses system time so that there are no discrepancies between the returned
+  // time and system time even on virtual environments including our test bot.
+  // For timing sensitive unittests, this function should be used.
+  static Time NowFromSystemTime();
+
+  // Returns the time for epoch in Unix-like system (Jan 1, 1970).
+  static Time UnixEpoch() { return Time(0); }
+
+  // Returns the maximum time, which should be greater than any reasonable time
+  // with which we might compare it.
+  static Time Max() { return Time(std::numeric_limits<int64_t>::max()); }
+
+  // Converts to/from POSIX time values.
+  static Time FromTimeval(struct timeval tv);
+  struct timeval ToTimeval() const;
+
+  // Converts to/from Windows file times.
+  static Time FromFiletime(struct _FILETIME ft);
+  struct _FILETIME ToFiletime() const;
+
+  // Converts to/from the Javascript convention for times, a number of
+  // milliseconds since the epoch:
+  static Time FromJsTime(double ms_since_epoch);
+  double ToJsTime() const;
+
+  Time& operator=(const Time& other) {
+    us_ = other.us_;
+    return *this;
+  }
+
+  // Compute the difference between two times.
+  TimeDelta operator-(const Time& other) const {
+    return TimeDelta::FromMicroseconds(us_ - other.us_);
+  }
+
+  // Modify by some time delta.
+  Time& operator+=(const TimeDelta& delta) {
+    us_ += delta.InMicroseconds();
+    return *this;
+  }
+  Time& operator-=(const TimeDelta& delta) {
+    us_ -= delta.InMicroseconds();
+    return *this;
+  }
+
+  // Return a new time modified by some delta.
+  Time operator+(const TimeDelta& delta) const {
+    return Time(us_ + delta.InMicroseconds());
+  }
+  Time operator-(const TimeDelta& delta) const {
+    return Time(us_ - delta.InMicroseconds());
+  }
+
+  // Comparison operators
+  bool operator==(const Time& other) const {
+    return us_ == other.us_;
+  }
+  bool operator!=(const Time& other) const {
+    return us_ != other.us_;
+  }
+  bool operator<(const Time& other) const {
+    return us_ < other.us_;
+  }
+  bool operator<=(const Time& other) const {
+    return us_ <= other.us_;
+  }
+  bool operator>(const Time& other) const {
+    return us_ > other.us_;
+  }
+  bool operator>=(const Time& other) const {
+    return us_ >= other.us_;
+  }
+
+ private:
+  explicit Time(int64_t us) : us_(us) {}
+
+  // Time in microseconds in UTC.
+  int64_t us_;
+};
+
+inline Time operator+(const TimeDelta& delta, const Time& time) {
+  return time + delta;
+}
+
+
+// -----------------------------------------------------------------------------
+// TimeTicks
+//
+// This class represents an abstract time that is most of the time incrementing
+// for use in measuring time durations. It is internally represented in
+// microseconds.  It can not be converted to a human-readable time, but is
+// guaranteed not to decrease (if the user changes the computer clock,
+// Time::Now() may actually decrease or jump).  But note that TimeTicks may
+// "stand still", for example if the computer suspended.
+
+class TimeTicks V8_FINAL BASE_EMBEDDED {
+ public:
+  TimeTicks() : ticks_(0) {}
+
+  // Platform-dependent tick count representing "right now."
+  // The resolution of this clock is ~1-15ms.  Resolution varies depending
+  // on hardware/operating system configuration.
+  // This method never returns a null TimeTicks.
+  static TimeTicks Now();
+
+  // Returns a platform-dependent high-resolution tick count. Implementation
+  // is hardware dependent and may or may not return sub-millisecond
+  // resolution.  THIS CALL IS GENERALLY MUCH MORE EXPENSIVE THAN Now() AND
+  // SHOULD ONLY BE USED WHEN IT IS REALLY NEEDED.
+  // This method never returns a null TimeTicks.
+  static TimeTicks HighResNow();
+
+  // Returns true if this object has not been initialized.
+  bool IsNull() const { return ticks_ == 0; }
+
+  TimeTicks& operator=(const TimeTicks other) {
+    ticks_ = other.ticks_;
+    return *this;
+  }
+
+  // Compute the difference between two times.
+  TimeDelta operator-(const TimeTicks other) const {
+    return TimeDelta::FromMicroseconds(ticks_ - other.ticks_);
+  }
+
+  // Modify by some time delta.
+  TimeTicks& operator+=(const TimeDelta& delta) {
+    ticks_ += delta.InMicroseconds();
+    return *this;
+  }
+  TimeTicks& operator-=(const TimeDelta& delta) {
+    ticks_ -= delta.InMicroseconds();
+    return *this;
+  }
+
+  // Return a new TimeTicks modified by some delta.
+  TimeTicks operator+(const TimeDelta& delta) const {
+    return TimeTicks(ticks_ + delta.InMicroseconds());
+  }
+  TimeTicks operator-(const TimeDelta& delta) const {
+    return TimeTicks(ticks_ - delta.InMicroseconds());
+  }
+
+  // Comparison operators
+  bool operator==(const TimeTicks& other) const {
+    return ticks_ == other.ticks_;
+  }
+  bool operator!=(const TimeTicks& other) const {
+    return ticks_ != other.ticks_;
+  }
+  bool operator<(const TimeTicks& other) const {
+    return ticks_ < other.ticks_;
+  }
+  bool operator<=(const TimeTicks& other) const {
+    return ticks_ <= other.ticks_;
+  }
+  bool operator>(const TimeTicks& other) const {
+    return ticks_ > other.ticks_;
+  }
+  bool operator>=(const TimeTicks& other) const {
+    return ticks_ >= other.ticks_;
+  }
+
+ private:
+  // Please use Now() to create a new object. This is for internal use
+  // and testing. Ticks is in microseconds.
+  explicit TimeTicks(int64_t ticks) : ticks_(ticks) {}
+
+  // Tick count in microseconds.
+  int64_t ticks_;
+};
+
+inline TimeTicks operator+(const TimeDelta& delta, const TimeTicks& ticks) {
+  return ticks + delta;
+}
+
+} }  // namespace v8::internal
+
+#endif  // V8_TIME_TIME_H_
index b7e0771..47efae1 100644 (file)
         'test-strtod.cc',
         'test-thread-termination.cc',
         'test-threads.cc',
+        'test-time.cc',
         'test-types.cc',
         'test-unbound-queue.cc',
         'test-utils.cc',
index 6d3c2ee..6d66c5e 100644 (file)
@@ -44,14 +44,15 @@ using i::ProfileNode;
 using i::ProfilerEventsProcessor;
 using i::ScopedVector;
 using i::SmartPointer;
+using i::TimeDelta;
 using i::Vector;
 
 
 TEST(StartStop) {
   CpuProfilesCollection profiles;
   ProfileGenerator generator(&profiles);
-  SmartPointer<ProfilerEventsProcessor> processor(
-      new ProfilerEventsProcessor(&generator, NULL, 100));
+  SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor(
+          &generator, NULL, TimeDelta::FromMicroseconds(100)));
   processor->Start();
   processor->StopSynchronously();
 }
@@ -142,8 +143,8 @@ TEST(CodeEvents) {
   CpuProfilesCollection* profiles = new CpuProfilesCollection;
   profiles->StartProfiling("", 1, false);
   ProfileGenerator generator(profiles);
-  SmartPointer<ProfilerEventsProcessor> processor(
-      new ProfilerEventsProcessor(&generator, NULL, 100));
+  SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor(
+          &generator, NULL, TimeDelta::FromMicroseconds(100)));
   processor->Start();
   CpuProfiler profiler(isolate, profiles, &generator, *processor);
 
@@ -204,8 +205,8 @@ TEST(TickEvents) {
   CpuProfilesCollection* profiles = new CpuProfilesCollection;
   profiles->StartProfiling("", 1, false);
   ProfileGenerator generator(profiles);
-  SmartPointer<ProfilerEventsProcessor> processor(
-      new ProfilerEventsProcessor(&generator, NULL, 100));
+  SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor(
+          &generator, NULL, TimeDelta::FromMicroseconds(100)));
   processor->Start();
   CpuProfiler profiler(isolate, profiles, &generator, *processor);
 
@@ -273,8 +274,8 @@ TEST(Issue1398) {
   CpuProfilesCollection* profiles = new CpuProfilesCollection;
   profiles->StartProfiling("", 1, false);
   ProfileGenerator generator(profiles);
-  SmartPointer<ProfilerEventsProcessor> processor(
-      new ProfilerEventsProcessor(&generator, NULL, 100));
+  SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor(
+          &generator, NULL, TimeDelta::FromMicroseconds(100)));
   processor->Start();
   CpuProfiler profiler(isolate, profiles, &generator, *processor);
 
@@ -419,13 +420,10 @@ TEST(ProfileStartEndTime) {
   v8::HandleScope scope(env->GetIsolate());
   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
 
-  int64_t time_before_profiling = i::OS::Ticks();
   v8::Local<v8::String> profile_name = v8::String::New("test");
   cpu_profiler->StartCpuProfiling(profile_name);
   const v8::CpuProfile* profile = cpu_profiler->StopCpuProfiling(profile_name);
-  CHECK(time_before_profiling <= profile->GetStartTime());
   CHECK(profile->GetStartTime() <= profile->GetEndTime());
-  CHECK(profile->GetEndTime() <= i::OS::Ticks());
 }
 
 
diff --git a/test/cctest/test-time.cc b/test/cctest/test-time.cc
new file mode 100644 (file)
index 0000000..b53ee73
--- /dev/null
@@ -0,0 +1,116 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <cstdlib>
+
+#include "v8.h"
+
+#include "cctest.h"
+#if V8_OS_WIN
+#include "win32-headers.h"
+#endif
+
+using namespace v8::internal;
+
+
+TEST(TimeDeltaFromAndIn) {
+  CHECK(TimeDelta::FromDays(2) == TimeDelta::FromHours(48));
+  CHECK(TimeDelta::FromHours(3) == TimeDelta::FromMinutes(180));
+  CHECK(TimeDelta::FromMinutes(2) == TimeDelta::FromSeconds(120));
+  CHECK(TimeDelta::FromSeconds(2) == TimeDelta::FromMilliseconds(2000));
+  CHECK(TimeDelta::FromMilliseconds(2) == TimeDelta::FromMicroseconds(2000));
+  CHECK_EQ(static_cast<int>(13), TimeDelta::FromDays(13).InDays());
+  CHECK_EQ(static_cast<int>(13), TimeDelta::FromHours(13).InHours());
+  CHECK_EQ(static_cast<int>(13), TimeDelta::FromMinutes(13).InMinutes());
+  CHECK_EQ(static_cast<int64_t>(13), TimeDelta::FromSeconds(13).InSeconds());
+  CHECK_EQ(13.0, TimeDelta::FromSeconds(13).InSecondsF());
+  CHECK_EQ(static_cast<int64_t>(13),
+           TimeDelta::FromMilliseconds(13).InMilliseconds());
+  CHECK_EQ(13.0, TimeDelta::FromMilliseconds(13).InMillisecondsF());
+  CHECK_EQ(static_cast<int64_t>(13),
+           TimeDelta::FromMicroseconds(13).InMicroseconds());
+}
+
+
+TEST(TimeJsTime) {
+  Time t = Time::FromJsTime(700000.3);
+  CHECK_EQ(700000.3, t.ToJsTime());
+}
+
+
+#if V8_OS_POSIX
+TEST(TimeFromTimeVal) {
+  Time null;
+  CHECK(null.IsNull());
+  CHECK(null == Time::FromTimeval(null.ToTimeval()));
+  Time now = Time::Now();
+  CHECK(now == Time::FromTimeval(now.ToTimeval()));
+  Time now_sys = Time::NowFromSystemTime();
+  CHECK(now_sys == Time::FromTimeval(now_sys.ToTimeval()));
+  Time unix_epoch = Time::UnixEpoch();
+  CHECK(unix_epoch == Time::FromTimeval(unix_epoch.ToTimeval()));
+  Time max = Time::Max();
+  CHECK(max.IsMax());
+  CHECK(max == Time::FromTimeval(max.ToTimeval()));
+}
+#endif
+
+
+#if V8_OS_WIN
+TEST(TimeFromFiletime) {
+  Time null;
+  CHECK(null.IsNull());
+  CHECK(null == Time::FromFiletime(null.ToFiletime()));
+  Time now = Time::Now();
+  CHECK(now == Time::FromFiletime(now.ToFiletime()));
+  Time now_sys = Time::NowFromSystemTime();
+  CHECK(now_sys == Time::FromFiletime(now_sys.ToFiletime()));
+  Time unix_epoch = Time::UnixEpoch();
+  CHECK(unix_epoch == Time::FromFiletime(unix_epoch.ToFiletime()));
+  Time max = Time::Max();
+  CHECK(max.IsMax());
+  CHECK(max == Time::FromFiletime(max.ToFiletime()));
+}
+#endif
+
+
+TEST(TimeTicksIsMonotonic) {
+  TimeTicks previous_normal_ticks;
+  TimeTicks previous_highres_ticks;
+  ElapsedTimer timer;
+  timer.Start();
+  while (!timer.HasExpired(TimeDelta::FromMilliseconds(100))) {
+    TimeTicks normal_ticks = TimeTicks::Now();
+    TimeTicks highres_ticks = TimeTicks::HighResNow();
+    CHECK_GE(normal_ticks, previous_normal_ticks);
+    CHECK_GE((normal_ticks - previous_normal_ticks).InMicroseconds(), 0);
+    CHECK_GE(highres_ticks, previous_highres_ticks);
+    CHECK_GE((highres_ticks - previous_highres_ticks).InMicroseconds(), 0);
+    previous_normal_ticks = normal_ticks;
+    previous_highres_ticks = highres_ticks;
+  }
+}
index eefd142..4f5af11 100644 (file)
         '../../src/stub-cache.h',
         '../../src/sweeper-thread.h',
         '../../src/sweeper-thread.cc',
+        '../../src/time/elapsed-timer.h',
+        '../../src/time/time.cc',
+        '../../src/time/time.h',
         '../../src/token.cc',
         '../../src/token.h',
         '../../src/transitions-inl.h',
                   ]
                 }],
               ],
+              'libraries': [
+                '-lrt'
+              ]
             },
             'sources': [  ### gcmole(os:linux) ###
               '../../src/platform-linux.cc',
               'CAN_USE_VFP_INSTRUCTIONS',
             ],
             'sources': [
-              '../../src/platform-posix.cc',
+              '../../src/platform-posix.cc'
             ],
             'conditions': [
               ['host_os=="mac"', {
             ]},
             'sources': [
               '../../src/platform-solaris.cc',
-              '../../src/platform-posix.cc',
+              '../../src/platform-posix.cc'
             ],
           }
         ],
                 ['build_env=="Cygwin"', {
                   'sources': [
                     '../../src/platform-cygwin.cc',
-                    '../../src/platform-posix.cc',
+                    '../../src/platform-posix.cc'
                   ],
                 }, {
                   'sources': [
                     '../../src/platform-win32.cc',
-                    '../../src/win32-math.h',
                     '../../src/win32-math.cc',
+                    '../../src/win32-math.h'
                   ],
                 }],
               ],
             }, {
               'sources': [
                 '../../src/platform-win32.cc',
-                '../../src/win32-math.h',
                 '../../src/win32-math.cc',
+                '../../src/win32-math.h'
               ],
               'msvs_disabled_warnings': [4351, 4355, 4800],
               'link_settings':  {