1 // Copyright 2012 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/logging/counters.h"
6
7 #include "src/base/atomic-utils.h"
8 #include "src/base/platform/elapsed-timer.h"
9 #include "src/base/platform/time.h"
10 #include "src/builtins/builtins-definitions.h"
11 #include "src/execution/isolate.h"
12 #include "src/logging/log-inl.h"
13 #include "src/logging/log.h"
14
15 namespace v8 {
16 namespace internal {
17
StatsTable(Counters * counters)18 StatsTable::StatsTable(Counters* counters)
19 : lookup_function_(nullptr),
20 create_histogram_function_(nullptr),
21 add_histogram_sample_function_(nullptr) {}
22
SetCounterFunction(CounterLookupCallback f)23 void StatsTable::SetCounterFunction(CounterLookupCallback f) {
24 lookup_function_ = f;
25 }
26
FindLocationInStatsTable() const27 int* StatsCounterBase::FindLocationInStatsTable() const {
28 return counters_->FindLocation(name_);
29 }
30
StatsCounterThreadSafe(Counters * counters,const char * name)31 StatsCounterThreadSafe::StatsCounterThreadSafe(Counters* counters,
32 const char* name)
33 : StatsCounterBase(counters, name) {}
34
Set(int Value)35 void StatsCounterThreadSafe::Set(int Value) {
36 if (ptr_) {
37 base::MutexGuard Guard(&mutex_);
38 SetLoc(ptr_, Value);
39 }
40 }
41
Increment()42 void StatsCounterThreadSafe::Increment() {
43 if (ptr_) {
44 base::MutexGuard Guard(&mutex_);
45 IncrementLoc(ptr_);
46 }
47 }
48
Increment(int value)49 void StatsCounterThreadSafe::Increment(int value) {
50 if (ptr_) {
51 base::MutexGuard Guard(&mutex_);
52 IncrementLoc(ptr_, value);
53 }
54 }
55
Decrement()56 void StatsCounterThreadSafe::Decrement() {
57 if (ptr_) {
58 base::MutexGuard Guard(&mutex_);
59 DecrementLoc(ptr_);
60 }
61 }
62
Decrement(int value)63 void StatsCounterThreadSafe::Decrement(int value) {
64 if (ptr_) {
65 base::MutexGuard Guard(&mutex_);
66 DecrementLoc(ptr_, value);
67 }
68 }
69
AddSample(int sample)70 void Histogram::AddSample(int sample) {
71 if (Enabled()) {
72 counters_->AddHistogramSample(histogram_, sample);
73 }
74 }
75
CreateHistogram() const76 void* Histogram::CreateHistogram() const {
77 return counters_->CreateHistogram(name_, min_, max_, num_buckets_);
78 }
79
Stop(base::ElapsedTimer * timer)80 void TimedHistogram::Stop(base::ElapsedTimer* timer) {
81 DCHECK(Enabled());
82 AddTimedSample(timer->Elapsed());
83 timer->Stop();
84 }
85
AddTimedSample(base::TimeDelta sample)86 void TimedHistogram::AddTimedSample(base::TimeDelta sample) {
87 if (Enabled()) {
88 int64_t sample_int = resolution_ == TimedHistogramResolution::MICROSECOND
89 ? sample.InMicroseconds()
90 : sample.InMilliseconds();
91 AddSample(static_cast<int>(sample_int));
92 }
93 }
94
RecordAbandon(base::ElapsedTimer * timer,Isolate * isolate)95 void TimedHistogram::RecordAbandon(base::ElapsedTimer* timer,
96 Isolate* isolate) {
97 if (Enabled()) {
98 DCHECK(timer->IsStarted());
99 timer->Stop();
100 int64_t sample = resolution_ == TimedHistogramResolution::MICROSECOND
101 ? base::TimeDelta::Max().InMicroseconds()
102 : base::TimeDelta::Max().InMilliseconds();
103 AddSample(static_cast<int>(sample));
104 }
105 if (isolate != nullptr) {
106 Logger::CallEventLogger(isolate, name(), v8::LogEventStatus::kEnd, true);
107 }
108 }
109
110 #ifdef DEBUG
ToggleRunningState(bool expect_to_run) const111 bool TimedHistogram::ToggleRunningState(bool expect_to_run) const {
112 static thread_local base::LazyInstance<
113 std::unordered_map<const TimedHistogram*, bool>>::type active_timer =
114 LAZY_INSTANCE_INITIALIZER;
115 bool is_running = (*active_timer.Pointer())[this];
116 DCHECK_NE(is_running, expect_to_run);
117 (*active_timer.Pointer())[this] = !is_running;
118 return true;
119 }
120 #endif
121
Counters(Isolate * isolate)122 Counters::Counters(Isolate* isolate)
123 :
124 #define SC(name, caption) name##_(this, "c:" #caption),
125 STATS_COUNTER_TS_LIST(SC)
126 #undef SC
127 #ifdef V8_RUNTIME_CALL_STATS
128 runtime_call_stats_(RuntimeCallStats::kMainIsolateThread),
129 worker_thread_runtime_call_stats_(),
130 #endif
131 isolate_(isolate),
132 stats_table_(this) {
133 static const struct {
134 Histogram Counters::*member;
135 const char* caption;
136 int min;
137 int max;
138 int num_buckets;
139 } kHistograms[] = {
140 #define HR(name, caption, min, max, num_buckets) \
141 {&Counters::name##_, #caption, min, max, num_buckets},
142 HISTOGRAM_RANGE_LIST(HR)
143 #undef HR
144 };
145 for (const auto& histogram : kHistograms) {
146 this->*histogram.member =
147 Histogram(histogram.caption, histogram.min, histogram.max,
148 histogram.num_buckets, this);
149 }
150
151 const int DefaultTimedHistogramNumBuckets = 50;
152
153 static const struct {
154 NestedTimedHistogram Counters::*member;
155 const char* caption;
156 int max;
157 TimedHistogramResolution res;
158 } kNestedTimedHistograms[] = {
159 #define HT(name, caption, max, res) \
160 {&Counters::name##_, #caption, max, TimedHistogramResolution::res},
161 NESTED_TIMED_HISTOGRAM_LIST(HT) NESTED_TIMED_HISTOGRAM_LIST_SLOW(HT)
162 #undef HT
163 };
164 for (const auto& timer : kNestedTimedHistograms) {
165 this->*timer.member =
166 NestedTimedHistogram(timer.caption, 0, timer.max, timer.res,
167 DefaultTimedHistogramNumBuckets, this);
168 }
169
170 static const struct {
171 TimedHistogram Counters::*member;
172 const char* caption;
173 int max;
174 TimedHistogramResolution res;
175 } kTimedHistograms[] = {
176 #define HT(name, caption, max, res) \
177 {&Counters::name##_, #caption, max, TimedHistogramResolution::res},
178 TIMED_HISTOGRAM_LIST(HT)
179 #undef HT
180 };
181 for (const auto& timer : kTimedHistograms) {
182 this->*timer.member = TimedHistogram(timer.caption, 0, timer.max, timer.res,
183 DefaultTimedHistogramNumBuckets, this);
184 }
185
186 static const struct {
187 AggregatableHistogramTimer Counters::*member;
188 const char* caption;
189 } kAggregatableHistogramTimers[] = {
190 #define AHT(name, caption) {&Counters::name##_, #caption},
191 AGGREGATABLE_HISTOGRAM_TIMER_LIST(AHT)
192 #undef AHT
193 };
194 for (const auto& aht : kAggregatableHistogramTimers) {
195 this->*aht.member = AggregatableHistogramTimer(
196 aht.caption, 0, 10000000, DefaultTimedHistogramNumBuckets, this);
197 }
198
199 static const struct {
200 Histogram Counters::*member;
201 const char* caption;
202 } kHistogramPercentages[] = {
203 #define HP(name, caption) {&Counters::name##_, #caption},
204 HISTOGRAM_PERCENTAGE_LIST(HP)
205 #undef HP
206 };
207 for (const auto& percentage : kHistogramPercentages) {
208 this->*percentage.member = Histogram(percentage.caption, 0, 101, 100, this);
209 }
210
211 // Exponential histogram assigns bucket limits to points
212 // p[1], p[2], ... p[n] such that p[i+1] / p[i] = constant.
213 // The constant factor is equal to the n-th root of (high / low),
214 // where the n is the number of buckets, the low is the lower limit,
215 // the high is the upper limit.
216 // For n = 50, low = 1000, high = 500000: the factor = 1.13.
217 static const struct {
218 Histogram Counters::*member;
219 const char* caption;
220 } kLegacyMemoryHistograms[] = {
221 #define HM(name, caption) {&Counters::name##_, #caption},
222 HISTOGRAM_LEGACY_MEMORY_LIST(HM)
223 #undef HM
224 };
225 for (const auto& histogram : kLegacyMemoryHistograms) {
226 this->*histogram.member =
227 Histogram(histogram.caption, 1000, 500000, 50, this);
228 }
229
230 // clang-format off
231 static const struct {
232 StatsCounter Counters::*member;
233 const char* caption;
234 } kStatsCounters[] = {
235 #define SC(name, caption) {&Counters::name##_, "c:" #caption},
236 STATS_COUNTER_LIST_1(SC)
237 STATS_COUNTER_LIST_2(SC)
238 STATS_COUNTER_NATIVE_CODE_LIST(SC)
239 #undef SC
240 #define SC(name) \
241 {&Counters::count_of_##name##_, "c:" "V8.CountOf_" #name}, \
242 {&Counters::size_of_##name##_, "c:" "V8.SizeOf_" #name},
243 INSTANCE_TYPE_LIST(SC)
244 #undef SC
245 #define SC(name) \
246 {&Counters::count_of_CODE_TYPE_##name##_, \
247 "c:" "V8.CountOf_CODE_TYPE-" #name}, \
248 {&Counters::size_of_CODE_TYPE_##name##_, \
249 "c:" "V8.SizeOf_CODE_TYPE-" #name},
250 CODE_KIND_LIST(SC)
251 #undef SC
252 #define SC(name) \
253 {&Counters::count_of_FIXED_ARRAY_##name##_, \
254 "c:" "V8.CountOf_FIXED_ARRAY-" #name}, \
255 {&Counters::size_of_FIXED_ARRAY_##name##_, \
256 "c:" "V8.SizeOf_FIXED_ARRAY-" #name},
257 FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(SC)
258 #undef SC
259 };
260 // clang-format on
261 for (const auto& counter : kStatsCounters) {
262 this->*counter.member = StatsCounter(this, counter.caption);
263 }
264 }
265
ResetCounterFunction(CounterLookupCallback f)266 void Counters::ResetCounterFunction(CounterLookupCallback f) {
267 stats_table_.SetCounterFunction(f);
268
269 #define SC(name, caption) name##_.Reset();
270 STATS_COUNTER_LIST_1(SC)
271 STATS_COUNTER_LIST_2(SC)
272 STATS_COUNTER_TS_LIST(SC)
273 STATS_COUNTER_NATIVE_CODE_LIST(SC)
274 #undef SC
275
276 #define SC(name) \
277 count_of_##name##_.Reset(); \
278 size_of_##name##_.Reset();
279 INSTANCE_TYPE_LIST(SC)
280 #undef SC
281
282 #define SC(name) \
283 count_of_CODE_TYPE_##name##_.Reset(); \
284 size_of_CODE_TYPE_##name##_.Reset();
285 CODE_KIND_LIST(SC)
286 #undef SC
287
288 #define SC(name) \
289 count_of_FIXED_ARRAY_##name##_.Reset(); \
290 size_of_FIXED_ARRAY_##name##_.Reset();
291 FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(SC)
292 #undef SC
293 }
294
ResetCreateHistogramFunction(CreateHistogramCallback f)295 void Counters::ResetCreateHistogramFunction(CreateHistogramCallback f) {
296 stats_table_.SetCreateHistogramFunction(f);
297
298 #define HR(name, caption, min, max, num_buckets) name##_.Reset();
299 HISTOGRAM_RANGE_LIST(HR)
300 #undef HR
301
302 #define HT(name, caption, max, res) name##_.Reset();
303 NESTED_TIMED_HISTOGRAM_LIST(HT)
304 #undef HT
305
306 #define HT(name, caption, max, res) name##_.Reset(FLAG_slow_histograms);
307 NESTED_TIMED_HISTOGRAM_LIST_SLOW(HT)
308 #undef HT
309
310 #define HT(name, caption, max, res) name##_.Reset();
311 TIMED_HISTOGRAM_LIST(HT)
312 #undef HT
313
314 #define AHT(name, caption) name##_.Reset();
315 AGGREGATABLE_HISTOGRAM_TIMER_LIST(AHT)
316 #undef AHT
317
318 #define HP(name, caption) name##_.Reset();
319 HISTOGRAM_PERCENTAGE_LIST(HP)
320 #undef HP
321
322 #define HM(name, caption) name##_.Reset();
323 HISTOGRAM_LEGACY_MEMORY_LIST(HM)
324 #undef HM
325 }
326
327 } // namespace internal
328 } // namespace v8
329