1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/compiler-dispatcher/compiler-dispatcher-tracer.h"
6 
7 #include "src/isolate.h"
8 
9 namespace v8 {
10 namespace internal {
11 
12 namespace {
13 
MonotonicallyIncreasingTimeInMs()14 double MonotonicallyIncreasingTimeInMs() {
15   return V8::GetCurrentPlatform()->MonotonicallyIncreasingTime() *
16          static_cast<double>(base::Time::kMillisecondsPerSecond);
17 }
18 
19 }  // namespace
20 
Scope(CompilerDispatcherTracer * tracer,ScopeID scope_id,size_t num)21 CompilerDispatcherTracer::Scope::Scope(CompilerDispatcherTracer* tracer,
22                                        ScopeID scope_id, size_t num)
23     : tracer_(tracer), scope_id_(scope_id), num_(num) {
24   start_time_ = MonotonicallyIncreasingTimeInMs();
25   // TODO(cbruni): remove once we fully moved to a trace-based system.
26   if (V8_UNLIKELY(FLAG_runtime_stats)) {
27     RuntimeCallStats::Enter(tracer_->runtime_call_stats_, &timer_,
28                             &RuntimeCallStats::CompilerDispatcher);
29   }
30 }
31 
~Scope()32 CompilerDispatcherTracer::Scope::~Scope() {
33   double elapsed = MonotonicallyIncreasingTimeInMs() - start_time_;
34   switch (scope_id_) {
35     case ScopeID::kPrepareToParse:
36       tracer_->RecordPrepareToParse(elapsed);
37       break;
38     case ScopeID::kParse:
39       tracer_->RecordParse(elapsed, num_);
40       break;
41     case ScopeID::kFinalizeParsing:
42       tracer_->RecordFinalizeParsing(elapsed);
43       break;
44     case ScopeID::kPrepareToCompile:
45       tracer_->RecordPrepareToCompile(elapsed);
46       break;
47     case ScopeID::kCompile:
48       tracer_->RecordCompile(elapsed, num_);
49       break;
50     case ScopeID::kFinalizeCompiling:
51       tracer_->RecordFinalizeCompiling(elapsed);
52       break;
53   }
54   // TODO(cbruni): remove once we fully moved to a trace-based system.
55   if (V8_UNLIKELY(FLAG_runtime_stats)) {
56     RuntimeCallStats::Leave(tracer_->runtime_call_stats_, &timer_);
57   }
58 }
59 
60 // static
Name(ScopeID scope_id)61 const char* CompilerDispatcherTracer::Scope::Name(ScopeID scope_id) {
62   switch (scope_id) {
63     case ScopeID::kPrepareToParse:
64       return "V8.BackgroundCompile_PrepareToParse";
65     case ScopeID::kParse:
66       return "V8.BackgroundCompile_Parse";
67     case ScopeID::kFinalizeParsing:
68       return "V8.BackgroundCompile_FinalizeParsing";
69     case ScopeID::kPrepareToCompile:
70       return "V8.BackgroundCompile_PrepareToCompile";
71     case ScopeID::kCompile:
72       return "V8.BackgroundCompile_Compile";
73     case ScopeID::kFinalizeCompiling:
74       return "V8.BackgroundCompile_FinalizeCompiling";
75   }
76   UNREACHABLE();
77   return nullptr;
78 }
79 
CompilerDispatcherTracer(Isolate * isolate)80 CompilerDispatcherTracer::CompilerDispatcherTracer(Isolate* isolate)
81     : runtime_call_stats_(nullptr) {
82   // isolate might be nullptr during unittests.
83   if (isolate) {
84     runtime_call_stats_ = isolate->counters()->runtime_call_stats();
85   }
86 }
87 
~CompilerDispatcherTracer()88 CompilerDispatcherTracer::~CompilerDispatcherTracer() {}
89 
RecordPrepareToParse(double duration_ms)90 void CompilerDispatcherTracer::RecordPrepareToParse(double duration_ms) {
91   base::LockGuard<base::Mutex> lock(&mutex_);
92   prepare_parse_events_.Push(duration_ms);
93 }
94 
RecordParse(double duration_ms,size_t source_length)95 void CompilerDispatcherTracer::RecordParse(double duration_ms,
96                                            size_t source_length) {
97   base::LockGuard<base::Mutex> lock(&mutex_);
98   parse_events_.Push(std::make_pair(source_length, duration_ms));
99 }
100 
RecordFinalizeParsing(double duration_ms)101 void CompilerDispatcherTracer::RecordFinalizeParsing(double duration_ms) {
102   base::LockGuard<base::Mutex> lock(&mutex_);
103   finalize_parsing_events_.Push(duration_ms);
104 }
105 
RecordPrepareToCompile(double duration_ms)106 void CompilerDispatcherTracer::RecordPrepareToCompile(double duration_ms) {
107   base::LockGuard<base::Mutex> lock(&mutex_);
108   prepare_compile_events_.Push(duration_ms);
109 }
110 
RecordCompile(double duration_ms,size_t ast_size_in_bytes)111 void CompilerDispatcherTracer::RecordCompile(double duration_ms,
112                                              size_t ast_size_in_bytes) {
113   base::LockGuard<base::Mutex> lock(&mutex_);
114   compile_events_.Push(std::make_pair(ast_size_in_bytes, duration_ms));
115 }
116 
RecordFinalizeCompiling(double duration_ms)117 void CompilerDispatcherTracer::RecordFinalizeCompiling(double duration_ms) {
118   base::LockGuard<base::Mutex> lock(&mutex_);
119   finalize_compiling_events_.Push(duration_ms);
120 }
121 
EstimatePrepareToParseInMs() const122 double CompilerDispatcherTracer::EstimatePrepareToParseInMs() const {
123   base::LockGuard<base::Mutex> lock(&mutex_);
124   return Average(prepare_parse_events_);
125 }
126 
EstimateParseInMs(size_t source_length) const127 double CompilerDispatcherTracer::EstimateParseInMs(size_t source_length) const {
128   base::LockGuard<base::Mutex> lock(&mutex_);
129   return Estimate(parse_events_, source_length);
130 }
131 
EstimateFinalizeParsingInMs()132 double CompilerDispatcherTracer::EstimateFinalizeParsingInMs() {
133   base::LockGuard<base::Mutex> lock(&mutex_);
134   return Average(finalize_parsing_events_);
135 }
136 
EstimatePrepareToCompileInMs()137 double CompilerDispatcherTracer::EstimatePrepareToCompileInMs() {
138   base::LockGuard<base::Mutex> lock(&mutex_);
139   return Average(prepare_compile_events_);
140 }
141 
EstimateCompileInMs(size_t ast_size_in_bytes)142 double CompilerDispatcherTracer::EstimateCompileInMs(size_t ast_size_in_bytes) {
143   base::LockGuard<base::Mutex> lock(&mutex_);
144   return Estimate(compile_events_, ast_size_in_bytes);
145 }
146 
EstimateFinalizeCompilingInMs()147 double CompilerDispatcherTracer::EstimateFinalizeCompilingInMs() {
148   base::LockGuard<base::Mutex> lock(&mutex_);
149   return Average(finalize_compiling_events_);
150 }
151 
Average(const base::RingBuffer<double> & buffer)152 double CompilerDispatcherTracer::Average(
153     const base::RingBuffer<double>& buffer) {
154   if (buffer.Count() == 0) return 0.0;
155   double sum = buffer.Sum([](double a, double b) { return a + b; }, 0.0);
156   return sum / buffer.Count();
157 }
158 
Estimate(const base::RingBuffer<std::pair<size_t,double>> & buffer,size_t num)159 double CompilerDispatcherTracer::Estimate(
160     const base::RingBuffer<std::pair<size_t, double>>& buffer, size_t num) {
161   if (buffer.Count() == 0) return 0.0;
162   std::pair<size_t, double> sum = buffer.Sum(
163       [](std::pair<size_t, double> a, std::pair<size_t, double> b) {
164         return std::make_pair(a.first + b.first, a.second + b.second);
165       },
166       std::make_pair(0, 0.0));
167   return num * (sum.second / sum.first);
168 }
169 
170 }  // namespace internal
171 }  // namespace v8
172