Revert "Add Chromium-style TimeDelta, Time and TimeTicks classes, and a new ElapsedTimer class."
This reverts commit r16390 for breaking the Windows build. Will reland fixed version, which also uses the platform/ folder instead of time/ folder as per offline discussion. TBR=machenbach@chromium.org Review URL: https://codereview.chromium.org/23690003 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16391 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
fa5216a145
commit
1d3f6815e3
@ -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() - i::Time::UnixEpoch()).InMicroseconds();
|
||||
return profile->start_time_us();
|
||||
}
|
||||
|
||||
|
||||
int64_t CpuProfile::GetEndTime() const {
|
||||
const i::CpuProfile* profile = reinterpret_cast<const i::CpuProfile*>(this);
|
||||
return (profile->end_time() - i::Time::UnixEpoch()).InMicroseconds();
|
||||
return profile->end_time_us();
|
||||
}
|
||||
|
||||
|
||||
|
@ -260,9 +260,10 @@ 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 = time_taken_to_create_graph_.InMillisecondsF();
|
||||
double ms_optimize = time_taken_to_optimize_.InMillisecondsF();
|
||||
double ms_codegen = time_taken_to_codegen_.InMillisecondsF();
|
||||
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;
|
||||
if (FLAG_trace_opt) {
|
||||
PrintF("[optimizing ");
|
||||
function->ShortPrint();
|
||||
@ -372,9 +373,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) {
|
||||
ElapsedTimer timer;
|
||||
int64_t start_ticks = 0;
|
||||
if (FLAG_hydrogen_stats) {
|
||||
timer.Start();
|
||||
start_ticks = OS::Ticks();
|
||||
}
|
||||
CompilationInfoWithZone unoptimized(info()->shared_info());
|
||||
// Note that we use the same AST that we will use for generating the
|
||||
@ -393,7 +394,8 @@ OptimizingCompiler::Status OptimizingCompiler::CreateGraph() {
|
||||
Logger::LAZY_COMPILE_TAG, &unoptimized, shared);
|
||||
}
|
||||
if (FLAG_hydrogen_stats) {
|
||||
isolate()->GetHStatistics()->IncrementFullCodeGen(timer.Elapsed());
|
||||
int64_t ticks = OS::Ticks() - start_ticks;
|
||||
isolate()->GetHStatistics()->IncrementFullCodeGen(ticks);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1242,7 +1244,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();
|
||||
timer_.Start();
|
||||
start_ticks_ = OS::Ticks();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1251,7 +1253,8 @@ CompilationPhase::~CompilationPhase() {
|
||||
if (FLAG_hydrogen_stats) {
|
||||
unsigned size = zone()->allocation_size();
|
||||
size += info_->zone()->allocation_size() - info_zone_start_allocation_size_;
|
||||
isolate()->GetHStatistics()->SaveTiming(name_, timer_.Elapsed(), size);
|
||||
int64_t ticks = OS::Ticks() - start_ticks_;
|
||||
isolate()->GetHStatistics()->SaveTiming(name_, ticks, size);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,6 @@
|
||||
|
||||
#include "allocation.h"
|
||||
#include "ast.h"
|
||||
#include "time/elapsed-timer.h"
|
||||
#include "zone.h"
|
||||
|
||||
namespace v8 {
|
||||
@ -502,6 +501,9 @@ 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 {
|
||||
@ -527,9 +529,9 @@ class OptimizingCompiler: public ZoneObject {
|
||||
HOptimizedGraphBuilder* graph_builder_;
|
||||
HGraph* graph_;
|
||||
LChunk* chunk_;
|
||||
TimeDelta time_taken_to_create_graph_;
|
||||
TimeDelta time_taken_to_optimize_;
|
||||
TimeDelta time_taken_to_codegen_;
|
||||
int64_t time_taken_to_create_graph_;
|
||||
int64_t time_taken_to_optimize_;
|
||||
int64_t time_taken_to_codegen_;
|
||||
Status last_status_;
|
||||
|
||||
MUST_USE_RESULT Status SetLastStatus(Status status) {
|
||||
@ -539,20 +541,18 @@ class OptimizingCompiler: public ZoneObject {
|
||||
void RecordOptimizationStats();
|
||||
|
||||
struct Timer {
|
||||
Timer(OptimizingCompiler* compiler, TimeDelta* location)
|
||||
Timer(OptimizingCompiler* compiler, int64_t* location)
|
||||
: compiler_(compiler),
|
||||
location_(location) {
|
||||
ASSERT(location_ != NULL);
|
||||
timer_.Start();
|
||||
}
|
||||
start_(OS::Ticks()),
|
||||
location_(location) { }
|
||||
|
||||
~Timer() {
|
||||
*location_ += timer_.Elapsed();
|
||||
*location_ += (OS::Ticks() - start_);
|
||||
}
|
||||
|
||||
OptimizingCompiler* compiler_;
|
||||
ElapsedTimer timer_;
|
||||
TimeDelta* location_;
|
||||
int64_t start_;
|
||||
int64_t* location_;
|
||||
};
|
||||
};
|
||||
|
||||
@ -644,7 +644,7 @@ class CompilationPhase BASE_EMBEDDED {
|
||||
CompilationInfo* info_;
|
||||
Zone zone_;
|
||||
unsigned info_zone_start_allocation_size_;
|
||||
ElapsedTimer timer_;
|
||||
int64_t start_ticks_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CompilationPhase);
|
||||
};
|
||||
|
@ -60,7 +60,8 @@ void* Histogram::CreateHistogram() const {
|
||||
// Start the timer.
|
||||
void HistogramTimer::Start() {
|
||||
if (Enabled()) {
|
||||
timer_.Start();
|
||||
stop_time_ = 0;
|
||||
start_time_ = OS::Ticks();
|
||||
}
|
||||
if (FLAG_log_internal_timer_events) {
|
||||
LOG(isolate(), TimerEvent(Logger::START, name()));
|
||||
@ -71,9 +72,10 @@ 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.
|
||||
AddSample(static_cast<int>(timer_.Elapsed().InMilliseconds()));
|
||||
timer_.Stop();
|
||||
int milliseconds = static_cast<int>(stop_time_ - start_time_) / 1000;
|
||||
AddSample(milliseconds);
|
||||
}
|
||||
if (FLAG_log_internal_timer_events) {
|
||||
LOG(isolate(), TimerEvent(Logger::END, name()));
|
||||
|
@ -245,7 +245,9 @@ class HistogramTimer : public Histogram {
|
||||
int max,
|
||||
int num_buckets,
|
||||
Isolate* isolate)
|
||||
: Histogram(name, min, max, num_buckets, isolate) {}
|
||||
: Histogram(name, min, max, num_buckets, isolate),
|
||||
start_time_(0),
|
||||
stop_time_(0) { }
|
||||
|
||||
// Start the timer.
|
||||
void Start();
|
||||
@ -255,11 +257,12 @@ class HistogramTimer : public Histogram {
|
||||
|
||||
// Returns true if the timer is running.
|
||||
bool Running() {
|
||||
return Enabled() && timer_.IsStarted();
|
||||
return Enabled() && (start_time_ != 0) && (stop_time_ == 0);
|
||||
}
|
||||
|
||||
private:
|
||||
ElapsedTimer timer_;
|
||||
int64_t start_time_;
|
||||
int64_t stop_time_;
|
||||
};
|
||||
|
||||
// Helper class for scoping a HistogramTimer.
|
||||
|
@ -46,12 +46,12 @@ static const int kProfilerStackSize = 64 * KB;
|
||||
ProfilerEventsProcessor::ProfilerEventsProcessor(
|
||||
ProfileGenerator* generator,
|
||||
Sampler* sampler,
|
||||
TimeDelta period)
|
||||
int period_in_useconds)
|
||||
: Thread(Thread::Options("v8:ProfEvntProc", kProfilerStackSize)),
|
||||
generator_(generator),
|
||||
sampler_(sampler),
|
||||
running_(true),
|
||||
period_(period),
|
||||
period_in_useconds_(period_in_useconds),
|
||||
last_code_event_id_(0), last_processed_code_event_id_(0) {
|
||||
}
|
||||
|
||||
@ -124,10 +124,9 @@ bool ProfilerEventsProcessor::ProcessTicks() {
|
||||
|
||||
|
||||
void ProfilerEventsProcessor::ProcessEventsAndDoSample() {
|
||||
ElapsedTimer timer;
|
||||
timer.Start();
|
||||
int64_t stop_time = OS::Ticks() + period_in_useconds_;
|
||||
// Keep processing existing events until we need to do next sample.
|
||||
while (!timer.HasExpired(period_)) {
|
||||
while (OS::Ticks() < stop_time) {
|
||||
if (ProcessTicks()) {
|
||||
// All ticks of the current dequeue_order are processed,
|
||||
// proceed to the next code event.
|
||||
@ -435,8 +434,7 @@ void CpuProfiler::StartProcessorIfNotStarted() {
|
||||
generator_ = new ProfileGenerator(profiles_);
|
||||
Sampler* sampler = logger->sampler();
|
||||
processor_ = new ProfilerEventsProcessor(
|
||||
generator_, sampler,
|
||||
TimeDelta::FromMicroseconds(FLAG_cpu_profiler_sampling_interval));
|
||||
generator_, sampler, FLAG_cpu_profiler_sampling_interval);
|
||||
is_profiling_ = true;
|
||||
// Enumerate stuff we already have in the heap.
|
||||
ASSERT(isolate_->heap()->HasBeenSetUp());
|
||||
|
@ -138,7 +138,7 @@ class ProfilerEventsProcessor : public Thread {
|
||||
public:
|
||||
ProfilerEventsProcessor(ProfileGenerator* generator,
|
||||
Sampler* sampler,
|
||||
TimeDelta period);
|
||||
int period_in_useconds);
|
||||
virtual ~ProfilerEventsProcessor() {}
|
||||
|
||||
// Thread control.
|
||||
@ -169,7 +169,7 @@ class ProfilerEventsProcessor : public Thread {
|
||||
Sampler* sampler_;
|
||||
bool running_;
|
||||
// Sampling period in microseconds.
|
||||
const TimeDelta period_;
|
||||
const int period_in_useconds_;
|
||||
UnboundQueue<CodeEventsContainer> events_buffer_;
|
||||
static const size_t kTickSampleBufferSize = 1 * MB;
|
||||
static const size_t kTickSampleQueueLength =
|
||||
|
@ -784,13 +784,12 @@ 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_));
|
||||
@ -871,7 +870,7 @@ void Deoptimizer::DoComputeOutputFrames() {
|
||||
|
||||
// Print some helpful diagnostic information.
|
||||
if (trace_) {
|
||||
double ms = timer.Elapsed().InMillisecondsF();
|
||||
double ms = static_cast<double>(OS::Ticks() - start) / 1000;
|
||||
int index = output_count_ - 1; // Index of the topmost frame.
|
||||
JSFunction* function = output_[index]->GetFunction();
|
||||
PrintF("[deoptimizing (%s): end 0x%08" V8PRIxPTR " ",
|
||||
|
@ -9815,15 +9815,15 @@ void HStatistics::Initialize(CompilationInfo* info) {
|
||||
|
||||
void HStatistics::Print() {
|
||||
PrintF("Timing results:\n");
|
||||
TimeDelta sum;
|
||||
for (int i = 0; i < times_.length(); ++i) {
|
||||
sum += times_[i];
|
||||
int64_t sum = 0;
|
||||
for (int i = 0; i < timing_.length(); ++i) {
|
||||
sum += timing_[i];
|
||||
}
|
||||
|
||||
for (int i = 0; i < names_.length(); ++i) {
|
||||
PrintF("%32s", names_[i]);
|
||||
double ms = times_[i].InMillisecondsF();
|
||||
double percent = times_[i].PercentOf(sum);
|
||||
double ms = static_cast<double>(timing_[i]) / 1000;
|
||||
double percent = static_cast<double>(timing_[i]) * 100 / sum;
|
||||
PrintF(" %8.3f ms / %4.1f %% ", ms, percent);
|
||||
|
||||
unsigned size = sizes_[i];
|
||||
@ -9833,29 +9833,29 @@ void HStatistics::Print() {
|
||||
|
||||
PrintF("----------------------------------------"
|
||||
"---------------------------------------\n");
|
||||
TimeDelta total = create_graph_ + optimize_graph_ + generate_code_;
|
||||
int64_t total = create_graph_ + optimize_graph_ + generate_code_;
|
||||
PrintF("%32s %8.3f ms / %4.1f %% \n",
|
||||
"Create graph",
|
||||
create_graph_.InMillisecondsF(),
|
||||
create_graph_.PercentOf(total));
|
||||
static_cast<double>(create_graph_) / 1000,
|
||||
static_cast<double>(create_graph_) * 100 / total);
|
||||
PrintF("%32s %8.3f ms / %4.1f %% \n",
|
||||
"Optimize graph",
|
||||
optimize_graph_.InMillisecondsF(),
|
||||
optimize_graph_.PercentOf(total));
|
||||
static_cast<double>(optimize_graph_) / 1000,
|
||||
static_cast<double>(optimize_graph_) * 100 / total);
|
||||
PrintF("%32s %8.3f ms / %4.1f %% \n",
|
||||
"Generate and install code",
|
||||
generate_code_.InMillisecondsF(),
|
||||
generate_code_.PercentOf(total));
|
||||
static_cast<double>(generate_code_) / 1000,
|
||||
static_cast<double>(generate_code_) * 100 / total);
|
||||
PrintF("----------------------------------------"
|
||||
"---------------------------------------\n");
|
||||
PrintF("%32s %8.3f ms (%.1f times slower than full code gen)\n",
|
||||
"Total",
|
||||
total.InMillisecondsF(),
|
||||
total.TimesOf(full_code_gen_));
|
||||
static_cast<double>(total) / 1000,
|
||||
static_cast<double>(total) / full_code_gen_);
|
||||
|
||||
double source_size_in_kb = static_cast<double>(source_size_) / 1024;
|
||||
double normalized_time = source_size_in_kb > 0
|
||||
? total.InMillisecondsF() / source_size_in_kb
|
||||
? (static_cast<double>(total) / 1000) / 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, TimeDelta time, unsigned size) {
|
||||
void HStatistics::SaveTiming(const char* name, int64_t ticks, unsigned size) {
|
||||
total_size_ += size;
|
||||
for (int i = 0; i < names_.length(); ++i) {
|
||||
if (strcmp(names_[i], name) == 0) {
|
||||
times_[i] += time;
|
||||
timing_[i] += ticks;
|
||||
sizes_[i] += size;
|
||||
return;
|
||||
}
|
||||
}
|
||||
names_.Add(name);
|
||||
times_.Add(time);
|
||||
timing_.Add(ticks);
|
||||
sizes_.Add(size);
|
||||
}
|
||||
|
||||
|
@ -2165,37 +2165,41 @@ Zone* AstContext::zone() const { return owner_->zone(); }
|
||||
class HStatistics V8_FINAL: public Malloced {
|
||||
public:
|
||||
HStatistics()
|
||||
: times_(5),
|
||||
: timing_(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, TimeDelta time, unsigned size);
|
||||
void SaveTiming(const char* name, int64_t ticks, unsigned size);
|
||||
|
||||
void IncrementFullCodeGen(TimeDelta full_code_gen) {
|
||||
void IncrementFullCodeGen(int64_t full_code_gen) {
|
||||
full_code_gen_ += full_code_gen;
|
||||
}
|
||||
|
||||
void IncrementSubtotals(TimeDelta create_graph,
|
||||
TimeDelta optimize_graph,
|
||||
TimeDelta generate_code) {
|
||||
void IncrementSubtotals(int64_t create_graph,
|
||||
int64_t optimize_graph,
|
||||
int64_t generate_code) {
|
||||
create_graph_ += create_graph;
|
||||
optimize_graph_ += optimize_graph;
|
||||
generate_code_ += generate_code;
|
||||
}
|
||||
|
||||
private:
|
||||
List<TimeDelta> times_;
|
||||
List<int64_t> timing_;
|
||||
List<const char*> names_;
|
||||
List<unsigned> sizes_;
|
||||
TimeDelta create_graph_;
|
||||
TimeDelta optimize_graph_;
|
||||
TimeDelta generate_code_;
|
||||
int64_t create_graph_;
|
||||
int64_t optimize_graph_;
|
||||
int64_t generate_code_;
|
||||
unsigned total_size_;
|
||||
TimeDelta full_code_gen_;
|
||||
int64_t full_code_gen_;
|
||||
double source_size_;
|
||||
};
|
||||
|
||||
|
@ -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(), TimeDelta(), size);
|
||||
isolate()->GetHStatistics()->SaveTiming(name(), 0, size);
|
||||
}
|
||||
|
||||
if (ShouldProduceTraceOutput()) {
|
||||
|
11
src/log.cc
11
src/log.cc
@ -716,7 +716,8 @@ Logger::Logger(Isolate* isolate)
|
||||
ll_logger_(NULL),
|
||||
jit_logger_(NULL),
|
||||
listeners_(5),
|
||||
is_initialized_(false) {
|
||||
is_initialized_(false),
|
||||
epoch_(0) {
|
||||
}
|
||||
|
||||
|
||||
@ -867,7 +868,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>(timer_.Elapsed().InMicroseconds());
|
||||
int since_epoch = static_cast<int>(OS::Ticks() - epoch_);
|
||||
msg.Append("code-deopt,%ld,%d\n", since_epoch, code->CodeSize());
|
||||
msg.WriteToLogFile();
|
||||
}
|
||||
@ -877,7 +878,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>(timer_.Elapsed().InMicroseconds());
|
||||
int since_epoch = static_cast<int>(OS::Ticks() - epoch_);
|
||||
const char* format = (se == START) ? "timer-event-start,\"%s\",%ld\n"
|
||||
: "timer-event-end,\"%s\",%ld\n";
|
||||
msg.Append(format, name, since_epoch);
|
||||
@ -1500,7 +1501,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>(timer_.Elapsed().InMicroseconds()));
|
||||
msg.Append(",%ld", static_cast<int>(OS::Ticks() - epoch_));
|
||||
if (sample->has_external_callback) {
|
||||
msg.Append(",1,");
|
||||
msg.AppendAddress(sample->external_callback);
|
||||
@ -1895,7 +1896,7 @@ bool Logger::SetUp(Isolate* isolate) {
|
||||
}
|
||||
}
|
||||
|
||||
if (FLAG_log_internal_timer_events || FLAG_prof) timer_.Start();
|
||||
if (FLAG_log_internal_timer_events || FLAG_prof) epoch_ = OS::Ticks();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -31,7 +31,6 @@
|
||||
#include "allocation.h"
|
||||
#include "objects.h"
|
||||
#include "platform.h"
|
||||
#include "time/elapsed-timer.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@ -451,7 +450,7 @@ class Logger {
|
||||
// 'true' between SetUp() and TearDown().
|
||||
bool is_initialized_;
|
||||
|
||||
ElapsedTimer timer_;
|
||||
int64_t epoch_;
|
||||
|
||||
friend class CpuProfiler;
|
||||
};
|
||||
|
@ -48,8 +48,8 @@ void OptimizingCompilerThread::Run() {
|
||||
DisallowHandleAllocation no_handles;
|
||||
DisallowHandleDereference no_deref;
|
||||
|
||||
ElapsedTimer total_timer;
|
||||
if (FLAG_trace_concurrent_recompilation) total_timer.Start();
|
||||
int64_t epoch = 0;
|
||||
if (FLAG_trace_concurrent_recompilation) epoch = OS::Ticks();
|
||||
|
||||
while (true) {
|
||||
input_queue_semaphore_->Wait();
|
||||
@ -65,7 +65,7 @@ void OptimizingCompilerThread::Run() {
|
||||
break;
|
||||
case STOP:
|
||||
if (FLAG_trace_concurrent_recompilation) {
|
||||
time_spent_total_ = total_timer.Elapsed();
|
||||
time_spent_total_ = OS::Ticks() - epoch;
|
||||
}
|
||||
stop_semaphore_->Signal();
|
||||
return;
|
||||
@ -81,13 +81,13 @@ void OptimizingCompilerThread::Run() {
|
||||
continue;
|
||||
}
|
||||
|
||||
ElapsedTimer compiling_timer;
|
||||
if (FLAG_trace_concurrent_recompilation) compiling_timer.Start();
|
||||
int64_t compiling_start = 0;
|
||||
if (FLAG_trace_concurrent_recompilation) compiling_start = OS::Ticks();
|
||||
|
||||
CompileNext();
|
||||
|
||||
if (FLAG_trace_concurrent_recompilation) {
|
||||
time_spent_compiling_ += compiling_timer.Elapsed();
|
||||
time_spent_compiling_ += OS::Ticks() - compiling_start;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -175,7 +175,9 @@ void OptimizingCompilerThread::Stop() {
|
||||
}
|
||||
|
||||
if (FLAG_trace_concurrent_recompilation) {
|
||||
double percentage = time_spent_compiling_.PercentOf(time_spent_total_);
|
||||
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;
|
||||
PrintF(" ** Compiler thread did %.2f%% useful work\n", percentage);
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,6 @@
|
||||
#include "flags.h"
|
||||
#include "platform.h"
|
||||
#include "unbound-queue-inl.h"
|
||||
#include "time/time.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@ -52,7 +51,9 @@ class OptimizingCompilerThread : public Thread {
|
||||
isolate_(isolate),
|
||||
stop_semaphore_(OS::CreateSemaphore(0)),
|
||||
input_queue_semaphore_(OS::CreateSemaphore(0)),
|
||||
install_mutex_(OS::CreateMutex()) {
|
||||
install_mutex_(OS::CreateMutex()),
|
||||
time_spent_compiling_(0),
|
||||
time_spent_total_(0) {
|
||||
NoBarrier_Store(&stop_thread_, static_cast<AtomicWord>(CONTINUE));
|
||||
NoBarrier_Store(&queue_length_, static_cast<AtomicWord>(0));
|
||||
}
|
||||
@ -111,8 +112,8 @@ class OptimizingCompilerThread : public Thread {
|
||||
Mutex* install_mutex_;
|
||||
volatile AtomicWord stop_thread_;
|
||||
volatile Atomic32 queue_length_;
|
||||
TimeDelta time_spent_compiling_;
|
||||
TimeDelta time_spent_total_;
|
||||
int64_t time_spent_compiling_;
|
||||
int64_t time_spent_total_;
|
||||
};
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
@ -569,13 +569,10 @@ Parser::Parser(CompilationInfo* info)
|
||||
|
||||
|
||||
FunctionLiteral* Parser::ParseProgram() {
|
||||
HistogramTimerScope timer_scope(isolate()->counters()->parse());
|
||||
HistogramTimerScope timer(isolate()->counters()->parse());
|
||||
Handle<String> source(String::cast(script_->source()));
|
||||
isolate()->counters()->total_parse_size()->Increment(source->length());
|
||||
ElapsedTimer timer;
|
||||
if (FLAG_trace_parse) {
|
||||
timer.Start();
|
||||
}
|
||||
int64_t start = FLAG_trace_parse ? OS::Ticks() : 0;
|
||||
fni_ = new(zone()) FuncNameInferrer(isolate(), zone());
|
||||
|
||||
// Initialize parser state.
|
||||
@ -596,7 +593,7 @@ FunctionLiteral* Parser::ParseProgram() {
|
||||
}
|
||||
|
||||
if (FLAG_trace_parse && result != NULL) {
|
||||
double ms = timer.Elapsed().InMillisecondsF();
|
||||
double ms = static_cast<double>(OS::Ticks() - start) / 1000;
|
||||
if (info()->is_eval()) {
|
||||
PrintF("[parsing eval");
|
||||
} else if (info()->script()->name()->IsString()) {
|
||||
@ -700,13 +697,10 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info,
|
||||
|
||||
|
||||
FunctionLiteral* Parser::ParseLazy() {
|
||||
HistogramTimerScope timer_scope(isolate()->counters()->parse_lazy());
|
||||
HistogramTimerScope timer(isolate()->counters()->parse_lazy());
|
||||
Handle<String> source(String::cast(script_->source()));
|
||||
isolate()->counters()->total_parse_size()->Increment(source->length());
|
||||
ElapsedTimer timer;
|
||||
if (FLAG_trace_parse) {
|
||||
timer.Start();
|
||||
}
|
||||
int64_t start = FLAG_trace_parse ? OS::Ticks() : 0;
|
||||
Handle<SharedFunctionInfo> shared_info = info()->shared_info();
|
||||
|
||||
// Initialize parser state.
|
||||
@ -726,7 +720,7 @@ FunctionLiteral* Parser::ParseLazy() {
|
||||
}
|
||||
|
||||
if (FLAG_trace_parse && result != NULL) {
|
||||
double ms = timer.Elapsed().InMillisecondsF();
|
||||
double ms = static_cast<double>(OS::Ticks() - start) / 1000;
|
||||
SmartArrayPointer<char> name_chars = result->debug_name()->ToCString();
|
||||
PrintF("[parsing function: %s - took %0.3f ms]\n", *name_chars, ms);
|
||||
}
|
||||
|
@ -569,7 +569,7 @@ Semaphore* OS::CreateSemaphore(int count) {
|
||||
|
||||
void OS::SetUp() {
|
||||
// Seed the random number generator. We preserve microsecond resolution.
|
||||
uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()) ^ (getpid() << 16);
|
||||
uint64_t seed = Ticks() ^ (getpid() << 16);
|
||||
srandom(static_cast<unsigned int>(seed));
|
||||
limit_mutex = CreateMutex();
|
||||
}
|
||||
|
@ -441,7 +441,7 @@ Semaphore* OS::CreateSemaphore(int count) {
|
||||
|
||||
void OS::SetUp() {
|
||||
// Seed the random number generator. We preserve microsecond resolution.
|
||||
uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()) ^ (getpid() << 16);
|
||||
uint64_t seed = Ticks() ^ (getpid() << 16);
|
||||
srandom(static_cast<unsigned int>(seed));
|
||||
limit_mutex = CreateMutex();
|
||||
}
|
||||
|
@ -500,7 +500,7 @@ Semaphore* OS::CreateSemaphore(int count) {
|
||||
|
||||
void OS::SetUp() {
|
||||
// Seed the random number generator. We preserve microsecond resolution.
|
||||
uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()) ^ (getpid() << 16);
|
||||
uint64_t seed = Ticks() ^ (getpid() << 16);
|
||||
srandom(static_cast<unsigned int>(seed));
|
||||
limit_mutex = CreateMutex();
|
||||
}
|
||||
|
@ -318,7 +318,19 @@ int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) {
|
||||
|
||||
|
||||
double OS::TimeCurrentMillis() {
|
||||
return Time::Now().ToJsTime();
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -246,15 +246,19 @@ void MathSetup() {
|
||||
// timestamps are represented as a doubles in milliseconds since 00:00:00 UTC,
|
||||
// January 1, 1970.
|
||||
|
||||
class Win32Time {
|
||||
class Time {
|
||||
public:
|
||||
// Constructors.
|
||||
explicit Win32Time(double jstime);
|
||||
Win32Time(int year, int mon, int day, int hour, int min, int sec);
|
||||
Time();
|
||||
explicit Time(double jstime);
|
||||
Time(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
|
||||
@ -296,6 +300,10 @@ class Win32Time {
|
||||
// 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_; }
|
||||
|
||||
@ -317,20 +325,26 @@ class Win32Time {
|
||||
|
||||
|
||||
// Static variables.
|
||||
bool Win32Time::tz_initialized_ = false;
|
||||
TIME_ZONE_INFORMATION Win32Time::tzinfo_;
|
||||
char Win32Time::std_tz_name_[kTzNameSize];
|
||||
char Win32Time::dst_tz_name_[kTzNameSize];
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
// Initialize timestamp from a JavaScript timestamp.
|
||||
Win32Time::Win32Time(double jstime) {
|
||||
Time::Time(double jstime) {
|
||||
t() = static_cast<int64_t>(jstime) * kTimeScaler + kTimeEpoc;
|
||||
}
|
||||
|
||||
|
||||
// Initialize timestamp from date/time components.
|
||||
Win32Time::Win32Time(int year, int mon, int day, int hour, int min, int sec) {
|
||||
Time::Time(int year, int mon, int day, int hour, int min, int sec) {
|
||||
SYSTEMTIME st;
|
||||
st.wYear = year;
|
||||
st.wMonth = mon;
|
||||
@ -344,14 +358,14 @@ Win32Time::Win32Time(int year, int mon, int day, int hour, int min, int sec) {
|
||||
|
||||
|
||||
// Convert timestamp to JavaScript timestamp.
|
||||
double Win32Time::ToJSTime() {
|
||||
double Time::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* Win32Time::GuessTimezoneNameFromBias(int bias) {
|
||||
const char* Time::GuessTimezoneNameFromBias(int bias) {
|
||||
static const int kHour = 60;
|
||||
switch (-bias) {
|
||||
case -9*kHour: return "Alaska";
|
||||
@ -376,7 +390,7 @@ const char* Win32Time::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 Win32Time::TzSet() {
|
||||
void Time::TzSet() {
|
||||
// Just return if timezone information has already been initialized.
|
||||
if (tz_initialized_) return;
|
||||
|
||||
@ -425,16 +439,78 @@ void Win32Time::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 Win32Time::LocalOffset() {
|
||||
int64_t Time::LocalOffset() {
|
||||
// Initialize timezone information, if needed.
|
||||
TzSet();
|
||||
|
||||
Win32Time rounded_to_second(*this);
|
||||
Time rounded_to_second(*this);
|
||||
rounded_to_second.t() = rounded_to_second.t() / 1000 / kTimeScaler *
|
||||
1000 * kTimeScaler;
|
||||
// Convert to local time using POSIX localtime function.
|
||||
@ -465,7 +541,7 @@ int64_t Win32Time::LocalOffset() {
|
||||
|
||||
|
||||
// Return whether or not daylight savings time is in effect at this time.
|
||||
bool Win32Time::InDST() {
|
||||
bool Time::InDST() {
|
||||
// Initialize timezone information, if needed.
|
||||
TzSet();
|
||||
|
||||
@ -489,14 +565,14 @@ bool Win32Time::InDST() {
|
||||
|
||||
|
||||
// Return the daylight savings time offset for this time.
|
||||
int64_t Win32Time::DaylightSavingsOffset() {
|
||||
int64_t Time::DaylightSavingsOffset() {
|
||||
return InDST() ? 60 * kMsPerMinute : 0;
|
||||
}
|
||||
|
||||
|
||||
// Returns a string identifying the current timezone for the
|
||||
// timestamp taking into account daylight saving.
|
||||
char* Win32Time::LocalTimezone() {
|
||||
char* Time::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_;
|
||||
@ -538,14 +614,22 @@ 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() {
|
||||
return Time::Now().ToJsTime();
|
||||
Time t;
|
||||
t.SetToCurrentTime();
|
||||
return t.ToJSTime();
|
||||
}
|
||||
|
||||
|
||||
// Returns the tickcounter based on timeGetTime.
|
||||
int64_t OS::Ticks() {
|
||||
return timeGetTime() * 1000; // Convert to microseconds.
|
||||
}
|
||||
|
||||
|
||||
// Returns a string identifying the current timezone taking into
|
||||
// account daylight saving.
|
||||
const char* OS::LocalTimezone(double time) {
|
||||
return Win32Time(time).LocalTimezone();
|
||||
return Time(time).LocalTimezone();
|
||||
}
|
||||
|
||||
|
||||
@ -553,7 +637,7 @@ const char* OS::LocalTimezone(double time) {
|
||||
// taking daylight savings time into account.
|
||||
double OS::LocalTimeOffset() {
|
||||
// Use current time, rounded to the millisecond.
|
||||
Win32Time t(TimeCurrentMillis());
|
||||
Time t(TimeCurrentMillis());
|
||||
// Time::LocalOffset inlcudes any daylight savings offset, so subtract it.
|
||||
return static_cast<double>(t.LocalOffset() - t.DaylightSavingsOffset());
|
||||
}
|
||||
@ -562,7 +646,7 @@ double OS::LocalTimeOffset() {
|
||||
// Returns the daylight savings offset in milliseconds for the given
|
||||
// time.
|
||||
double OS::DaylightSavingsOffset(double time) {
|
||||
int64_t offset = Win32Time(time).DaylightSavingsOffset();
|
||||
int64_t offset = Time(time).DaylightSavingsOffset();
|
||||
return static_cast<double>(offset);
|
||||
}
|
||||
|
||||
|
@ -192,6 +192,10 @@ 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();
|
||||
|
@ -334,8 +334,8 @@ CpuProfile::CpuProfile(const char* title, unsigned uid, bool record_samples)
|
||||
: title_(title),
|
||||
uid_(uid),
|
||||
record_samples_(record_samples),
|
||||
start_time_(Time::NowFromSystemTime()) {
|
||||
timer_.Start();
|
||||
start_time_us_(OS::Ticks()),
|
||||
end_time_us_(0) {
|
||||
}
|
||||
|
||||
|
||||
@ -346,7 +346,7 @@ void CpuProfile::AddPath(const Vector<CodeEntry*>& path) {
|
||||
|
||||
|
||||
void CpuProfile::CalculateTotalTicksAndSamplingRate() {
|
||||
end_time_ = start_time_ + timer_.Elapsed();
|
||||
end_time_us_ = OS::Ticks();
|
||||
}
|
||||
|
||||
|
||||
|
@ -30,7 +30,6 @@
|
||||
|
||||
#include "allocation.h"
|
||||
#include "hashmap.h"
|
||||
#include "time/time.h"
|
||||
#include "../include/v8-profiler.h"
|
||||
|
||||
namespace v8 {
|
||||
@ -203,8 +202,8 @@ class CpuProfile {
|
||||
int samples_count() const { return samples_.length(); }
|
||||
ProfileNode* sample(int index) const { return samples_.at(index); }
|
||||
|
||||
Time start_time() const { return start_time_; }
|
||||
Time end_time() const { return end_time_; }
|
||||
int64_t start_time_us() const { return start_time_us_; }
|
||||
int64_t end_time_us() const { return end_time_us_; }
|
||||
|
||||
void UpdateTicksScale();
|
||||
|
||||
@ -214,9 +213,8 @@ class CpuProfile {
|
||||
const char* title_;
|
||||
unsigned uid_;
|
||||
bool record_samples_;
|
||||
Time start_time_;
|
||||
Time end_time_;
|
||||
ElapsedTimer timer_;
|
||||
int64_t start_time_us_;
|
||||
int64_t end_time_us_;
|
||||
List<ProfileNode*> samples_;
|
||||
ProfileTree top_down_;
|
||||
|
||||
|
@ -1,120 +0,0 @@
|
||||
// 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_
|
483
src/time/time.cc
483
src/time/time.cc
@ -1,483 +0,0 @@
|
||||
// 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
|
381
src/time/time.h
381
src/time/time.h
@ -1,381 +0,0 @@
|
||||
// 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_
|
@ -100,7 +100,6 @@
|
||||
'test-strtod.cc',
|
||||
'test-thread-termination.cc',
|
||||
'test-threads.cc',
|
||||
'test-time.cc',
|
||||
'test-types.cc',
|
||||
'test-unbound-queue.cc',
|
||||
'test-utils.cc',
|
||||
|
@ -44,15 +44,14 @@ 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, TimeDelta::FromMicroseconds(100)));
|
||||
SmartPointer<ProfilerEventsProcessor> processor(
|
||||
new ProfilerEventsProcessor(&generator, NULL, 100));
|
||||
processor->Start();
|
||||
processor->StopSynchronously();
|
||||
}
|
||||
@ -143,8 +142,8 @@ TEST(CodeEvents) {
|
||||
CpuProfilesCollection* profiles = new CpuProfilesCollection;
|
||||
profiles->StartProfiling("", 1, false);
|
||||
ProfileGenerator generator(profiles);
|
||||
SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor(
|
||||
&generator, NULL, TimeDelta::FromMicroseconds(100)));
|
||||
SmartPointer<ProfilerEventsProcessor> processor(
|
||||
new ProfilerEventsProcessor(&generator, NULL, 100));
|
||||
processor->Start();
|
||||
CpuProfiler profiler(isolate, profiles, &generator, *processor);
|
||||
|
||||
@ -205,8 +204,8 @@ TEST(TickEvents) {
|
||||
CpuProfilesCollection* profiles = new CpuProfilesCollection;
|
||||
profiles->StartProfiling("", 1, false);
|
||||
ProfileGenerator generator(profiles);
|
||||
SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor(
|
||||
&generator, NULL, TimeDelta::FromMicroseconds(100)));
|
||||
SmartPointer<ProfilerEventsProcessor> processor(
|
||||
new ProfilerEventsProcessor(&generator, NULL, 100));
|
||||
processor->Start();
|
||||
CpuProfiler profiler(isolate, profiles, &generator, *processor);
|
||||
|
||||
@ -274,8 +273,8 @@ TEST(Issue1398) {
|
||||
CpuProfilesCollection* profiles = new CpuProfilesCollection;
|
||||
profiles->StartProfiling("", 1, false);
|
||||
ProfileGenerator generator(profiles);
|
||||
SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor(
|
||||
&generator, NULL, TimeDelta::FromMicroseconds(100)));
|
||||
SmartPointer<ProfilerEventsProcessor> processor(
|
||||
new ProfilerEventsProcessor(&generator, NULL, 100));
|
||||
processor->Start();
|
||||
CpuProfiler profiler(isolate, profiles, &generator, *processor);
|
||||
|
||||
@ -420,10 +419,13 @@ 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());
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,116 +0,0 @@
|
||||
// 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;
|
||||
}
|
||||
}
|
@ -500,9 +500,6 @@
|
||||
'../../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',
|
||||
@ -691,9 +688,6 @@
|
||||
]
|
||||
}],
|
||||
],
|
||||
'libraries': [
|
||||
'-lrt'
|
||||
]
|
||||
},
|
||||
'sources': [ ### gcmole(os:linux) ###
|
||||
'../../src/platform-linux.cc',
|
||||
@ -706,7 +700,7 @@
|
||||
'CAN_USE_VFP_INSTRUCTIONS',
|
||||
],
|
||||
'sources': [
|
||||
'../../src/platform-posix.cc'
|
||||
'../../src/platform-posix.cc',
|
||||
],
|
||||
'conditions': [
|
||||
['host_os=="mac"', {
|
||||
@ -769,7 +763,7 @@
|
||||
]},
|
||||
'sources': [
|
||||
'../../src/platform-solaris.cc',
|
||||
'../../src/platform-posix.cc'
|
||||
'../../src/platform-posix.cc',
|
||||
],
|
||||
}
|
||||
],
|
||||
@ -792,13 +786,13 @@
|
||||
['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'
|
||||
],
|
||||
}],
|
||||
],
|
||||
@ -808,8 +802,8 @@
|
||||
}, {
|
||||
'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': {
|
||||
|
Loading…
Reference in New Issue
Block a user