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 12namespace v8 { 13namespace internal { 14 15class BaseTimedHistogramScope { 16 protected: 17 explicit BaseTimedHistogramScope(TimedHistogram* histogram) 18 : histogram_(histogram) {} 19 20 void StartInternal() { 21 DCHECK(histogram_->ToggleRunningState(true)); 22 timer_.Start(); 23 } 24 25 void StopInternal() { 26 DCHECK(histogram_->ToggleRunningState(false)); 27 histogram_->AddTimedSample(timer_.Elapsed()); 28 timer_.Stop(); 29 } 30 31 V8_INLINE void Start() { 32 if (histogram_->Enabled()) StartInternal(); 33 } 34 35 V8_INLINE void Stop() { 36 if (histogram_->Enabled()) StopInternal(); 37 } 38 39 V8_INLINE void LogStart(Isolate* isolate) { 40 Logger::CallEventLogger(isolate, histogram_->name(), 41 v8::LogEventStatus::kStart, true); 42 } 43 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. 54class V8_NODISCARD TimedHistogramScope : public BaseTimedHistogramScope { 55 public: 56 explicit TimedHistogramScope(TimedHistogram* histogram, 57 Isolate* isolate = nullptr) 58 : BaseTimedHistogramScope(histogram), isolate_(isolate) { 59 Start(); 60 if (isolate_) LogStart(isolate_); 61 } 62 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 74enum 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. 78class V8_NODISCARD OptionalTimedHistogramScope 79 : public BaseTimedHistogramScope { 80 public: 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 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. 103class V8_NODISCARD LazyTimedHistogramScope : public BaseTimedHistogramScope { 104 public: 105 LazyTimedHistogramScope() : BaseTimedHistogramScope(nullptr) { 106 timer_.Start(); 107 } 108 ~LazyTimedHistogramScope() { 109 // We should set the histogram before this scope exits. 110 Stop(); 111 } 112 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. 120class V8_NODISCARD NestedTimedHistogramScope : public BaseTimedHistogramScope { 121 public: 122 explicit NestedTimedHistogramScope(NestedTimedHistogram* histogram, 123 Isolate* isolate = nullptr) 124 : BaseTimedHistogramScope(histogram), isolate_(isolate) { 125 Start(); 126 } 127 ~NestedTimedHistogramScope() { Stop(); } 128 129 private: 130 friend NestedTimedHistogram; 131 friend PauseNestedTimedHistogramScope; 132 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 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 154 V8_INLINE void Start() { 155 if (histogram_->Enabled()) StartInteral(); 156 LogStart(timed_histogram()->counters()->isolate()); 157 } 158 159 V8_INLINE void Stop() { 160 if (histogram_->Enabled()) StopInternal(); 161 LogEnd(timed_histogram()->counters()->isolate()); 162 } 163 164 void Pause(base::TimeTicks now) { 165 DCHECK(histogram_->Enabled()); 166 timer_.Pause(now); 167 } 168 169 void Resume(base::TimeTicks now) { 170 DCHECK(histogram_->Enabled()); 171 timer_.Resume(now); 172 } 173 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 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. 191class V8_NODISCARD PauseNestedTimedHistogramScope { 192 public: 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 } 200 ~PauseNestedTimedHistogramScope() { 201 histogram_->Leave(previous_scope_); 202 if (isEnabled()) { 203 previous_scope_->Resume(base::TimeTicks::Now()); 204 } 205 } 206 207 private: 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