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