• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 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 #ifndef V8_LOGGING_COUNTERS_SCOPES_H_
6 #define V8_LOGGING_COUNTERS_SCOPES_H_
7 
8 #include "src/execution/isolate.h"
9 #include "src/logging/counters.h"
10 #include "src/logging/log.h"
11 
12 namespace v8 {
13 namespace internal {
14 
15 class BaseTimedHistogramScope {
16  protected:
BaseTimedHistogramScope(TimedHistogram * histogram)17   explicit BaseTimedHistogramScope(TimedHistogram* histogram)
18       : histogram_(histogram) {}
19 
StartInternal()20   void StartInternal() {
21     DCHECK(histogram_->ToggleRunningState(true));
22     timer_.Start();
23   }
24 
StopInternal()25   void StopInternal() {
26     DCHECK(histogram_->ToggleRunningState(false));
27     histogram_->AddTimedSample(timer_.Elapsed());
28     timer_.Stop();
29   }
30 
Start()31   V8_INLINE void Start() {
32     if (histogram_->Enabled()) StartInternal();
33   }
34 
Stop()35   V8_INLINE void Stop() {
36     if (histogram_->Enabled()) StopInternal();
37   }
38 
LogStart(Isolate * isolate)39   V8_INLINE void LogStart(Isolate* isolate) {
40     Logger::CallEventLogger(isolate, histogram_->name(),
41                             v8::LogEventStatus::kStart, true);
42   }
43 
LogEnd(Isolate * isolate)44   V8_INLINE void LogEnd(Isolate* isolate) {
45     Logger::CallEventLogger(isolate, histogram_->name(),
46                             v8::LogEventStatus::kEnd, true);
47   }
48 
49   base::ElapsedTimer timer_;
50   TimedHistogram* histogram_;
51 };
52 
53 // Helper class for scoping a TimedHistogram.
54 class V8_NODISCARD TimedHistogramScope : public BaseTimedHistogramScope {
55  public:
56   explicit TimedHistogramScope(TimedHistogram* histogram,
57                                Isolate* isolate = nullptr)
BaseTimedHistogramScope(histogram)58       : BaseTimedHistogramScope(histogram), isolate_(isolate) {
59     Start();
60     if (isolate_) LogStart(isolate_);
61   }
62 
~TimedHistogramScope()63   ~TimedHistogramScope() {
64     Stop();
65     if (isolate_) LogEnd(isolate_);
66   }
67 
68  private:
69   Isolate* const isolate_;
70 
71   DISALLOW_IMPLICIT_CONSTRUCTORS(TimedHistogramScope);
72 };
73 
74 enum class OptionalTimedHistogramScopeMode { TAKE_TIME, DONT_TAKE_TIME };
75 
76 // Helper class for scoping a TimedHistogram.
77 // It will not take time for mode = DONT_TAKE_TIME.
78 class V8_NODISCARD OptionalTimedHistogramScope
79     : public BaseTimedHistogramScope {
80  public:
OptionalTimedHistogramScope(TimedHistogram * histogram,Isolate * isolate,OptionalTimedHistogramScopeMode mode)81   OptionalTimedHistogramScope(TimedHistogram* histogram, Isolate* isolate,
82                               OptionalTimedHistogramScopeMode mode)
83       : BaseTimedHistogramScope(histogram), isolate_(isolate), mode_(mode) {
84     if (mode != OptionalTimedHistogramScopeMode::TAKE_TIME) return;
85     Start();
86     LogStart(isolate_);
87   }
88 
~OptionalTimedHistogramScope()89   ~OptionalTimedHistogramScope() {
90     if (mode_ != OptionalTimedHistogramScopeMode::TAKE_TIME) return;
91     Stop();
92     LogEnd(isolate_);
93   }
94 
95  private:
96   Isolate* const isolate_;
97   const OptionalTimedHistogramScopeMode mode_;
98   DISALLOW_IMPLICIT_CONSTRUCTORS(OptionalTimedHistogramScope);
99 };
100 
101 // Helper class for scoping a TimedHistogram, where the histogram is selected at
102 // stop time rather than start time.
103 class V8_NODISCARD LazyTimedHistogramScope : public BaseTimedHistogramScope {
104  public:
LazyTimedHistogramScope()105   LazyTimedHistogramScope() : BaseTimedHistogramScope(nullptr) {
106     timer_.Start();
107   }
~LazyTimedHistogramScope()108   ~LazyTimedHistogramScope() {
109     // We should set the histogram before this scope exits.
110     Stop();
111   }
112 
set_histogram(TimedHistogram * histogram)113   void set_histogram(TimedHistogram* histogram) {
114     DCHECK_IMPLIES(histogram->Enabled(), histogram->ToggleRunningState(true));
115     histogram_ = histogram;
116   }
117 };
118 
119 // Helper class for scoping a NestedHistogramTimer.
120 class V8_NODISCARD NestedTimedHistogramScope : public BaseTimedHistogramScope {
121  public:
122   explicit NestedTimedHistogramScope(NestedTimedHistogram* histogram,
123                                      Isolate* isolate = nullptr)
BaseTimedHistogramScope(histogram)124       : BaseTimedHistogramScope(histogram), isolate_(isolate) {
125     Start();
126   }
~NestedTimedHistogramScope()127   ~NestedTimedHistogramScope() { Stop(); }
128 
129  private:
130   friend NestedTimedHistogram;
131   friend PauseNestedTimedHistogramScope;
132 
StartInteral()133   void StartInteral() {
134     previous_scope_ = timed_histogram()->Enter(this);
135     base::TimeTicks now = base::TimeTicks::Now();
136     if (previous_scope_) previous_scope_->Pause(now);
137     timer_.Start(now);
138   }
139 
StopInternal()140   void StopInternal() {
141     timed_histogram()->Leave(previous_scope_);
142     base::TimeTicks now = base::TimeTicks::Now();
143     base::TimeDelta elapsed = timer_.Elapsed(now);
144     histogram_->AddTimedSample(elapsed);
145     if (isolate_) RecordLongTaskTime(elapsed);
146 #ifdef DEBUG
147     // StopInternal() is called in the destructor and don't access timer_
148     // after that.
149     timer_.Stop();
150 #endif
151     if (previous_scope_) previous_scope_->Resume(now);
152   }
153 
Start()154   V8_INLINE void Start() {
155     if (histogram_->Enabled()) StartInteral();
156     LogStart(timed_histogram()->counters()->isolate());
157   }
158 
Stop()159   V8_INLINE void Stop() {
160     if (histogram_->Enabled()) StopInternal();
161     LogEnd(timed_histogram()->counters()->isolate());
162   }
163 
Pause(base::TimeTicks now)164   void Pause(base::TimeTicks now) {
165     DCHECK(histogram_->Enabled());
166     timer_.Pause(now);
167   }
168 
Resume(base::TimeTicks now)169   void Resume(base::TimeTicks now) {
170     DCHECK(histogram_->Enabled());
171     timer_.Resume(now);
172   }
173 
RecordLongTaskTime(base::TimeDelta elapsed)174   void RecordLongTaskTime(base::TimeDelta elapsed) const {
175     if (histogram_ == isolate_->counters()->execute()) {
176       isolate_->GetCurrentLongTaskStats()->v8_execute_us +=
177           elapsed.InMicroseconds();
178     }
179   }
180 
timed_histogram()181   NestedTimedHistogram* timed_histogram() {
182     return static_cast<NestedTimedHistogram*>(histogram_);
183   }
184 
185   NestedTimedHistogramScope* previous_scope_;
186   Isolate* isolate_;
187 };
188 
189 // Temporarily pause a NestedTimedHistogram when for instance leaving V8 for
190 // external callbacks.
191 class V8_NODISCARD PauseNestedTimedHistogramScope {
192  public:
PauseNestedTimedHistogramScope(NestedTimedHistogram * histogram)193   explicit PauseNestedTimedHistogramScope(NestedTimedHistogram* histogram)
194       : histogram_(histogram) {
195     previous_scope_ = histogram_->Enter(nullptr);
196     if (isEnabled()) {
197       previous_scope_->Pause(base::TimeTicks::Now());
198     }
199   }
~PauseNestedTimedHistogramScope()200   ~PauseNestedTimedHistogramScope() {
201     histogram_->Leave(previous_scope_);
202     if (isEnabled()) {
203       previous_scope_->Resume(base::TimeTicks::Now());
204     }
205   }
206 
207  private:
isEnabled()208   bool isEnabled() const { return previous_scope_ && histogram_->Enabled(); }
209   NestedTimedHistogram* histogram_;
210   NestedTimedHistogramScope* previous_scope_;
211 };
212 
213 }  // namespace internal
214 }  // namespace v8
215 
216 #endif  // V8_LOGGING_COUNTERS_SCOPES_H_
217