// Copyright 2016 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/compiler-dispatcher/compiler-dispatcher-tracer.h" #include "src/isolate.h" #include "src/utils.h" namespace v8 { namespace internal { namespace { double MonotonicallyIncreasingTimeInMs() { return V8::GetCurrentPlatform()->MonotonicallyIncreasingTime() * static_cast<double>(base::Time::kMillisecondsPerSecond); } const double kEstimatedRuntimeWithoutData = 1.0; } // namespace CompilerDispatcherTracer::Scope::Scope(CompilerDispatcherTracer* tracer, ScopeID scope_id, size_t num) : tracer_(tracer), scope_id_(scope_id), num_(num) { start_time_ = MonotonicallyIncreasingTimeInMs(); } CompilerDispatcherTracer::Scope::~Scope() { double elapsed = MonotonicallyIncreasingTimeInMs() - start_time_; switch (scope_id_) { case ScopeID::kPrepareToParse: tracer_->RecordPrepareToParse(elapsed); break; case ScopeID::kParse: tracer_->RecordParse(elapsed, num_); break; case ScopeID::kFinalizeParsing: tracer_->RecordFinalizeParsing(elapsed); break; case ScopeID::kAnalyze: tracer_->RecordAnalyze(elapsed); break; case ScopeID::kPrepareToCompile: tracer_->RecordPrepareToCompile(elapsed); break; case ScopeID::kCompile: tracer_->RecordCompile(elapsed); break; case ScopeID::kFinalizeCompiling: tracer_->RecordFinalizeCompiling(elapsed); break; } } // static const char* CompilerDispatcherTracer::Scope::Name(ScopeID scope_id) { switch (scope_id) { case ScopeID::kPrepareToParse: return "V8.BackgroundCompile_PrepareToParse"; case ScopeID::kParse: return "V8.BackgroundCompile_Parse"; case ScopeID::kFinalizeParsing: return "V8.BackgroundCompile_FinalizeParsing"; case ScopeID::kAnalyze: return "V8.BackgroundCompile_Analyze"; case ScopeID::kPrepareToCompile: return "V8.BackgroundCompile_PrepareToCompile"; case ScopeID::kCompile: return "V8.BackgroundCompile_Compile"; case ScopeID::kFinalizeCompiling: return "V8.BackgroundCompile_FinalizeCompiling"; } UNREACHABLE(); } CompilerDispatcherTracer::CompilerDispatcherTracer(Isolate* isolate) : runtime_call_stats_(nullptr) { // isolate might be nullptr during unittests. if (isolate) { runtime_call_stats_ = isolate->counters()->runtime_call_stats(); } } CompilerDispatcherTracer::~CompilerDispatcherTracer() {} void CompilerDispatcherTracer::RecordPrepareToParse(double duration_ms) { base::LockGuard<base::Mutex> lock(&mutex_); prepare_parse_events_.Push(duration_ms); } void CompilerDispatcherTracer::RecordParse(double duration_ms, size_t source_length) { base::LockGuard<base::Mutex> lock(&mutex_); parse_events_.Push(std::make_pair(source_length, duration_ms)); } void CompilerDispatcherTracer::RecordFinalizeParsing(double duration_ms) { base::LockGuard<base::Mutex> lock(&mutex_); finalize_parsing_events_.Push(duration_ms); } void CompilerDispatcherTracer::RecordAnalyze(double duration_ms) { base::LockGuard<base::Mutex> lock(&mutex_); analyze_events_.Push(duration_ms); } void CompilerDispatcherTracer::RecordPrepareToCompile(double duration_ms) { base::LockGuard<base::Mutex> lock(&mutex_); prepare_compile_events_.Push(duration_ms); } void CompilerDispatcherTracer::RecordCompile(double duration_ms) { base::LockGuard<base::Mutex> lock(&mutex_); compile_events_.Push(duration_ms); } void CompilerDispatcherTracer::RecordFinalizeCompiling(double duration_ms) { base::LockGuard<base::Mutex> lock(&mutex_); finalize_compiling_events_.Push(duration_ms); } double CompilerDispatcherTracer::EstimatePrepareToParseInMs() const { base::LockGuard<base::Mutex> lock(&mutex_); return Average(prepare_parse_events_); } double CompilerDispatcherTracer::EstimateParseInMs(size_t source_length) const { base::LockGuard<base::Mutex> lock(&mutex_); return Estimate(parse_events_, source_length); } double CompilerDispatcherTracer::EstimateFinalizeParsingInMs() const { base::LockGuard<base::Mutex> lock(&mutex_); return Average(finalize_parsing_events_); } double CompilerDispatcherTracer::EstimateAnalyzeInMs() const { base::LockGuard<base::Mutex> lock(&mutex_); return Average(analyze_events_); } double CompilerDispatcherTracer::EstimatePrepareToCompileInMs() const { base::LockGuard<base::Mutex> lock(&mutex_); return Average(prepare_compile_events_); } double CompilerDispatcherTracer::EstimateCompileInMs() const { base::LockGuard<base::Mutex> lock(&mutex_); return Average(compile_events_); } double CompilerDispatcherTracer::EstimateFinalizeCompilingInMs() const { base::LockGuard<base::Mutex> lock(&mutex_); return Average(finalize_compiling_events_); } void CompilerDispatcherTracer::DumpStatistics() const { PrintF( "CompilerDispatcherTracer: " "prepare_parsing=%.2lfms parsing=%.2lfms/kb finalize_parsing=%.2lfms " "analyze=%.2lfms prepare_compiling=%.2lfms compiling=%.2lfms/kb " "finalize_compiling=%.2lfms\n", EstimatePrepareToParseInMs(), EstimateParseInMs(1 * KB), EstimateFinalizeParsingInMs(), EstimateAnalyzeInMs(), EstimatePrepareToCompileInMs(), EstimateCompileInMs(), EstimateFinalizeCompilingInMs()); } double CompilerDispatcherTracer::Average( const base::RingBuffer<double>& buffer) { if (buffer.Count() == 0) return 0.0; double sum = buffer.Sum([](double a, double b) { return a + b; }, 0.0); return sum / buffer.Count(); } double CompilerDispatcherTracer::Estimate( const base::RingBuffer<std::pair<size_t, double>>& buffer, size_t num) { if (buffer.Count() == 0) return kEstimatedRuntimeWithoutData; std::pair<size_t, double> sum = buffer.Sum( [](std::pair<size_t, double> a, std::pair<size_t, double> b) { return std::make_pair(a.first + b.first, a.second + b.second); }, std::make_pair(0, 0.0)); return num * (sum.second / sum.first); } } // namespace internal } // namespace v8