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 #include "src/utils.h"
9 
10 namespace v8 {
11 namespace internal {
12 
13 namespace {
14 
MonotonicallyIncreasingTimeInMs()15 double MonotonicallyIncreasingTimeInMs() {
16   return V8::GetCurrentPlatform()->MonotonicallyIncreasingTime() *
17          static_cast<double>(base::Time::kMillisecondsPerSecond);
18 }
19 
20 const double kEstimatedRuntimeWithoutData = 1.0;
21 
22 }  // namespace
23 
Scope(CompilerDispatcherTracer * tracer,ScopeID scope_id,size_t num)24 CompilerDispatcherTracer::Scope::Scope(CompilerDispatcherTracer* tracer,
25                                        ScopeID scope_id, size_t num)
26     : tracer_(tracer), scope_id_(scope_id), num_(num) {
27   start_time_ = MonotonicallyIncreasingTimeInMs();
28 }
29 
~Scope()30 CompilerDispatcherTracer::Scope::~Scope() {
31   double elapsed = MonotonicallyIncreasingTimeInMs() - start_time_;
32   switch (scope_id_) {
33     case ScopeID::kPrepare:
34       tracer_->RecordPrepare(elapsed);
35       break;
36     case ScopeID::kCompile:
37       tracer_->RecordCompile(elapsed, num_);
38       break;
39     case ScopeID::kFinalize:
40       tracer_->RecordFinalize(elapsed);
41       break;
42   }
43 }
44 
45 // static
Name(ScopeID scope_id)46 const char* CompilerDispatcherTracer::Scope::Name(ScopeID scope_id) {
47   switch (scope_id) {
48     case ScopeID::kPrepare:
49       return "V8.BackgroundCompile_Prepare";
50     case ScopeID::kCompile:
51       return "V8.BackgroundCompile_Compile";
52     case ScopeID::kFinalize:
53       return "V8.BackgroundCompile_Finalize";
54   }
55   UNREACHABLE();
56 }
57 
CompilerDispatcherTracer(Isolate * isolate)58 CompilerDispatcherTracer::CompilerDispatcherTracer(Isolate* isolate)
59     : runtime_call_stats_(nullptr) {
60   // isolate might be nullptr during unittests.
61   if (isolate) {
62     runtime_call_stats_ = isolate->counters()->runtime_call_stats();
63   }
64 }
65 
~CompilerDispatcherTracer()66 CompilerDispatcherTracer::~CompilerDispatcherTracer() {}
67 
RecordPrepare(double duration_ms)68 void CompilerDispatcherTracer::RecordPrepare(double duration_ms) {
69   base::LockGuard<base::Mutex> lock(&mutex_);
70   prepare_events_.Push(duration_ms);
71 }
72 
RecordCompile(double duration_ms,size_t source_length)73 void CompilerDispatcherTracer::RecordCompile(double duration_ms,
74                                              size_t source_length) {
75   base::LockGuard<base::Mutex> lock(&mutex_);
76   compile_events_.Push(std::make_pair(source_length, duration_ms));
77 }
78 
RecordFinalize(double duration_ms)79 void CompilerDispatcherTracer::RecordFinalize(double duration_ms) {
80   base::LockGuard<base::Mutex> lock(&mutex_);
81   finalize_events_.Push(duration_ms);
82 }
83 
EstimatePrepareInMs() const84 double CompilerDispatcherTracer::EstimatePrepareInMs() const {
85   base::LockGuard<base::Mutex> lock(&mutex_);
86   return Average(prepare_events_);
87 }
88 
EstimateCompileInMs(size_t source_length) const89 double CompilerDispatcherTracer::EstimateCompileInMs(
90     size_t source_length) const {
91   base::LockGuard<base::Mutex> lock(&mutex_);
92   return Estimate(compile_events_, source_length);
93 }
94 
EstimateFinalizeInMs() const95 double CompilerDispatcherTracer::EstimateFinalizeInMs() const {
96   base::LockGuard<base::Mutex> lock(&mutex_);
97   return Average(finalize_events_);
98 }
99 
DumpStatistics() const100 void CompilerDispatcherTracer::DumpStatistics() const {
101   PrintF(
102       "CompilerDispatcherTracer: "
103       "prepare=%.2lfms compiling=%.2lfms/kb finalize=%.2lfms\n",
104       EstimatePrepareInMs(), EstimateCompileInMs(1 * KB),
105       EstimateFinalizeInMs());
106 }
107 
Average(const base::RingBuffer<double> & buffer)108 double CompilerDispatcherTracer::Average(
109     const base::RingBuffer<double>& buffer) {
110   if (buffer.Count() == 0) return 0.0;
111   double sum = buffer.Sum([](double a, double b) { return a + b; }, 0.0);
112   return sum / buffer.Count();
113 }
114 
Estimate(const base::RingBuffer<std::pair<size_t,double>> & buffer,size_t num)115 double CompilerDispatcherTracer::Estimate(
116     const base::RingBuffer<std::pair<size_t, double>>& buffer, size_t num) {
117   if (buffer.Count() == 0) return kEstimatedRuntimeWithoutData;
118   std::pair<size_t, double> sum = buffer.Sum(
119       [](std::pair<size_t, double> a, std::pair<size_t, double> b) {
120         return std::make_pair(a.first + b.first, a.second + b.second);
121       },
122       std::make_pair(0, 0.0));
123   return num * (sum.second / sum.first);
124 }
125 
126 }  // namespace internal
127 }  // namespace v8
128