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