Line data Source code
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/counters.h"
6 :
7 : #include <iomanip>
8 :
9 : #include "src/base/platform/platform.h"
10 : #include "src/builtins/builtins-definitions.h"
11 : #include "src/counters-inl.h"
12 : #include "src/isolate.h"
13 : #include "src/log-inl.h"
14 : #include "src/log.h"
15 : #include "src/ostreams.h"
16 :
17 : namespace v8 {
18 : namespace internal {
19 :
20 : std::atomic_uint TracingFlags::runtime_stats{0};
21 : std::atomic_uint TracingFlags::gc_stats{0};
22 : std::atomic_uint TracingFlags::ic_stats{0};
23 :
24 0 : StatsTable::StatsTable(Counters* counters)
25 : : lookup_function_(nullptr),
26 : create_histogram_function_(nullptr),
27 62422 : add_histogram_sample_function_(nullptr) {}
28 :
29 0 : void StatsTable::SetCounterFunction(CounterLookupCallback f) {
30 1276 : lookup_function_ = f;
31 0 : }
32 :
33 1830983 : int* StatsCounterBase::FindLocationInStatsTable() const {
34 3668346 : return counters_->FindLocation(name_);
35 : }
36 :
37 0 : StatsCounterThreadSafe::StatsCounterThreadSafe(Counters* counters,
38 : const char* name)
39 312110 : : StatsCounterBase(counters, name) {}
40 :
41 0 : void StatsCounterThreadSafe::Set(int Value) {
42 0 : if (ptr_) {
43 0 : base::MutexGuard Guard(&mutex_);
44 0 : SetLoc(ptr_, Value);
45 : }
46 0 : }
47 :
48 449516 : void StatsCounterThreadSafe::Increment() {
49 449516 : if (ptr_) {
50 0 : base::MutexGuard Guard(&mutex_);
51 0 : IncrementLoc(ptr_);
52 : }
53 449516 : }
54 :
55 2575984 : void StatsCounterThreadSafe::Increment(int value) {
56 2575984 : if (ptr_) {
57 0 : base::MutexGuard Guard(&mutex_);
58 0 : IncrementLoc(ptr_, value);
59 : }
60 2575984 : }
61 :
62 0 : void StatsCounterThreadSafe::Decrement() {
63 0 : if (ptr_) {
64 0 : base::MutexGuard Guard(&mutex_);
65 0 : DecrementLoc(ptr_);
66 : }
67 0 : }
68 :
69 0 : void StatsCounterThreadSafe::Decrement(int value) {
70 0 : if (ptr_) {
71 0 : base::MutexGuard Guard(&mutex_);
72 0 : DecrementLoc(ptr_, value);
73 : }
74 0 : }
75 :
76 8340333 : void Histogram::AddSample(int sample) {
77 8340333 : if (Enabled()) {
78 11 : counters_->AddHistogramSample(histogram_, sample);
79 : }
80 8340333 : }
81 :
82 0 : void* Histogram::CreateHistogram() const {
83 944 : return counters_->CreateHistogram(name_, min_, max_, num_buckets_);
84 : }
85 :
86 5167478 : void TimedHistogram::Start(base::ElapsedTimer* timer, Isolate* isolate) {
87 5167478 : if (Enabled()) timer->Start();
88 5167478 : if (isolate) Logger::CallEventLogger(isolate, name(), Logger::START, true);
89 5167478 : }
90 :
91 5451836 : void TimedHistogram::Stop(base::ElapsedTimer* timer, Isolate* isolate) {
92 5451836 : if (Enabled()) {
93 0 : int64_t sample = resolution_ == HistogramTimerResolution::MICROSECOND
94 0 : ? timer->Elapsed().InMicroseconds()
95 0 : : timer->Elapsed().InMilliseconds();
96 : timer->Stop();
97 0 : AddSample(static_cast<int>(sample));
98 : }
99 5452037 : if (isolate != nullptr) {
100 : Logger::CallEventLogger(isolate, name(), Logger::END, true);
101 : }
102 5452037 : }
103 :
104 0 : void TimedHistogram::RecordAbandon(base::ElapsedTimer* timer,
105 : Isolate* isolate) {
106 0 : if (Enabled()) {
107 : DCHECK(timer->IsStarted());
108 : timer->Stop();
109 0 : int64_t sample = resolution_ == HistogramTimerResolution::MICROSECOND
110 0 : ? base::TimeDelta::Max().InMicroseconds()
111 0 : : base::TimeDelta::Max().InMilliseconds();
112 0 : AddSample(static_cast<int>(sample));
113 : }
114 0 : if (isolate != nullptr) {
115 : Logger::CallEventLogger(isolate, name(), Logger::END, true);
116 : }
117 0 : }
118 :
119 62422 : Counters::Counters(Isolate* isolate)
120 : : isolate_(isolate),
121 : stats_table_(this),
122 : // clang format off
123 : #define SC(name, caption) name##_(this, "c:" #caption),
124 : STATS_COUNTER_TS_LIST(SC)
125 : #undef SC
126 : // clang format on
127 : runtime_call_stats_(),
128 62422 : worker_thread_runtime_call_stats_() {
129 : static const struct {
130 : Histogram Counters::*member;
131 : const char* caption;
132 : int min;
133 : int max;
134 : int num_buckets;
135 : } kHistograms[] = {
136 : #define HR(name, caption, min, max, num_buckets) \
137 : {&Counters::name##_, #caption, min, max, num_buckets},
138 : HISTOGRAM_RANGE_LIST(HR)
139 : #undef HR
140 : };
141 6179582 : for (const auto& histogram : kHistograms) {
142 3058580 : this->*histogram.member =
143 3058580 : Histogram(histogram.caption, histogram.min, histogram.max,
144 6117160 : histogram.num_buckets, this);
145 : }
146 :
147 : const int DefaultTimedHistogramNumBuckets = 50;
148 :
149 : static const struct {
150 : HistogramTimer Counters::*member;
151 : const char* caption;
152 : int max;
153 : HistogramTimerResolution res;
154 : } kHistogramTimers[] = {
155 : #define HT(name, caption, max, res) \
156 : {&Counters::name##_, #caption, max, HistogramTimerResolution::res},
157 : HISTOGRAM_TIMER_LIST(HT)
158 : #undef HT
159 : };
160 1935052 : for (const auto& timer : kHistogramTimers) {
161 1872630 : this->*timer.member = HistogramTimer(timer.caption, 0, timer.max, timer.res,
162 1872630 : DefaultTimedHistogramNumBuckets, this);
163 : }
164 :
165 : static const struct {
166 : TimedHistogram Counters::*member;
167 : const char* caption;
168 : int max;
169 : HistogramTimerResolution res;
170 : } kTimedHistograms[] = {
171 : #define HT(name, caption, max, res) \
172 : {&Counters::name##_, #caption, max, HistogramTimerResolution::res},
173 : TIMED_HISTOGRAM_LIST(HT)
174 : #undef HT
175 : };
176 5430456 : for (const auto& timer : kTimedHistograms) {
177 5368034 : this->*timer.member = TimedHistogram(timer.caption, 0, timer.max, timer.res,
178 5368034 : DefaultTimedHistogramNumBuckets, this);
179 : }
180 :
181 : static const struct {
182 : AggregatableHistogramTimer Counters::*member;
183 : const char* caption;
184 : } kAggregatableHistogramTimers[] = {
185 : #define AHT(name, caption) {&Counters::name##_, #caption},
186 : AGGREGATABLE_HISTOGRAM_TIMER_LIST(AHT)
187 : #undef AHT
188 : };
189 187264 : for (const auto& aht : kAggregatableHistogramTimers) {
190 62421 : this->*aht.member = AggregatableHistogramTimer(
191 62421 : aht.caption, 0, 10000000, DefaultTimedHistogramNumBuckets, this);
192 : }
193 :
194 : static const struct {
195 : Histogram Counters::*member;
196 : const char* caption;
197 : } kHistogramPercentages[] = {
198 : #define HP(name, caption) {&Counters::name##_, #caption},
199 : HISTOGRAM_PERCENTAGE_LIST(HP)
200 : #undef HP
201 : };
202 686622 : for (const auto& percentage : kHistogramPercentages) {
203 312100 : this->*percentage.member = Histogram(percentage.caption, 0, 101, 100, this);
204 : }
205 :
206 : // Exponential histogram assigns bucket limits to points
207 : // p[1], p[2], ... p[n] such that p[i+1] / p[i] = constant.
208 : // The constant factor is equal to the n-th root of (high / low),
209 : // where the n is the number of buckets, the low is the lower limit,
210 : // the high is the upper limit.
211 : // For n = 50, low = 1000, high = 500000: the factor = 1.13.
212 : static const struct {
213 : Histogram Counters::*member;
214 : const char* caption;
215 : } kLegacyMemoryHistograms[] = {
216 : #define HM(name, caption) {&Counters::name##_, #caption},
217 : HISTOGRAM_LEGACY_MEMORY_LIST(HM)
218 : #undef HM
219 : };
220 686622 : for (const auto& histogram : kLegacyMemoryHistograms) {
221 312100 : this->*histogram.member =
222 312100 : Histogram(histogram.caption, 1000, 500000, 50, this);
223 : }
224 :
225 : // clang-format off
226 : static const struct {
227 : StatsCounter Counters::*member;
228 : const char* caption;
229 : } kStatsCounters[] = {
230 : #define SC(name, caption) {&Counters::name##_, "c:" #caption},
231 : STATS_COUNTER_LIST_1(SC)
232 : STATS_COUNTER_LIST_2(SC)
233 : STATS_COUNTER_NATIVE_CODE_LIST(SC)
234 : #undef SC
235 : #define SC(name) \
236 : {&Counters::count_of_##name##_, "c:" "V8.CountOf_" #name}, \
237 : {&Counters::size_of_##name##_, "c:" "V8.SizeOf_" #name},
238 : INSTANCE_TYPE_LIST(SC)
239 : #undef SC
240 : #define SC(name) \
241 : {&Counters::count_of_CODE_TYPE_##name##_, \
242 : "c:" "V8.CountOf_CODE_TYPE-" #name}, \
243 : {&Counters::size_of_CODE_TYPE_##name##_, \
244 : "c:" "V8.SizeOf_CODE_TYPE-" #name},
245 : CODE_KIND_LIST(SC)
246 : #undef SC
247 : #define SC(name) \
248 : {&Counters::count_of_FIXED_ARRAY_##name##_, \
249 : "c:" "V8.CountOf_FIXED_ARRAY-" #name}, \
250 : {&Counters::size_of_FIXED_ARRAY_##name##_, \
251 : "c:" "V8.SizeOf_FIXED_ARRAY-" #name},
252 : FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(SC)
253 : #undef SC
254 : };
255 : // clang-format on
256 66829798 : for (const auto& counter : kStatsCounters) {
257 33383688 : this->*counter.member = StatsCounter(this, counter.caption);
258 : }
259 62422 : }
260 :
261 1276 : void Counters::ResetCounterFunction(CounterLookupCallback f) {
262 : stats_table_.SetCounterFunction(f);
263 :
264 : #define SC(name, caption) name##_.Reset();
265 : STATS_COUNTER_LIST_1(SC)
266 : STATS_COUNTER_LIST_2(SC)
267 : STATS_COUNTER_TS_LIST(SC)
268 : STATS_COUNTER_NATIVE_CODE_LIST(SC)
269 : #undef SC
270 :
271 : #define SC(name) \
272 : count_of_##name##_.Reset(); \
273 : size_of_##name##_.Reset();
274 : INSTANCE_TYPE_LIST(SC)
275 : #undef SC
276 :
277 : #define SC(name) \
278 : count_of_CODE_TYPE_##name##_.Reset(); \
279 : size_of_CODE_TYPE_##name##_.Reset();
280 : CODE_KIND_LIST(SC)
281 : #undef SC
282 :
283 : #define SC(name) \
284 : count_of_FIXED_ARRAY_##name##_.Reset(); \
285 : size_of_FIXED_ARRAY_##name##_.Reset();
286 : FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(SC)
287 : #undef SC
288 1276 : }
289 :
290 8 : void Counters::ResetCreateHistogramFunction(CreateHistogramCallback f) {
291 : stats_table_.SetCreateHistogramFunction(f);
292 :
293 : #define HR(name, caption, min, max, num_buckets) name##_.Reset();
294 : HISTOGRAM_RANGE_LIST(HR)
295 : #undef HR
296 :
297 : #define HT(name, caption, max, res) name##_.Reset();
298 : HISTOGRAM_TIMER_LIST(HT)
299 : #undef HT
300 :
301 : #define HT(name, caption, max, res) name##_.Reset();
302 : TIMED_HISTOGRAM_LIST(HT)
303 : #undef HT
304 :
305 : #define AHT(name, caption) name##_.Reset();
306 : AGGREGATABLE_HISTOGRAM_TIMER_LIST(AHT)
307 : #undef AHT
308 :
309 : #define HP(name, caption) name##_.Reset();
310 : HISTOGRAM_PERCENTAGE_LIST(HP)
311 : #undef HP
312 :
313 : #define HM(name, caption) name##_.Reset();
314 : HISTOGRAM_LEGACY_MEMORY_LIST(HM)
315 : #undef HM
316 8 : }
317 :
318 : base::TimeTicks (*RuntimeCallTimer::Now)() =
319 : &base::TimeTicks::HighResolutionNow;
320 :
321 20 : class RuntimeCallStatEntries {
322 : public:
323 10 : void Print(std::ostream& os) {
324 10 : if (total_call_count == 0) return;
325 : std::sort(entries.rbegin(), entries.rend());
326 : os << std::setw(50) << "Runtime Function/C++ Builtin" << std::setw(12)
327 : << "Time" << std::setw(18) << "Count" << std::endl
328 5 : << std::string(88, '=') << std::endl;
329 111 : for (Entry& entry : entries) {
330 106 : entry.SetTotal(total_time, total_call_count);
331 106 : entry.Print(os);
332 : }
333 5 : os << std::string(88, '-') << std::endl;
334 10 : Entry("Total", total_time, total_call_count).Print(os);
335 : }
336 :
337 : // By default, the compiler will usually inline this, which results in a large
338 : // binary size increase: std::vector::push_back expands to a large amount of
339 : // instructions, and this function is invoked repeatedly by macros.
340 11480 : V8_NOINLINE void Add(RuntimeCallCounter* counter) {
341 11480 : if (counter->count() == 0) return;
342 318 : entries.push_back(
343 : Entry(counter->name(), counter->time(), counter->count()));
344 : total_time += counter->time();
345 106 : total_call_count += counter->count();
346 : }
347 :
348 : private:
349 : class Entry {
350 : public:
351 : Entry(const char* name, base::TimeDelta time, uint64_t count)
352 : : name_(name),
353 111 : time_(time.InMicroseconds()),
354 : count_(count),
355 : time_percent_(100),
356 222 : count_percent_(100) {}
357 :
358 : bool operator<(const Entry& other) const {
359 487 : if (time_ < other.time_) return true;
360 435 : if (time_ > other.time_) return false;
361 414 : return count_ < other.count_;
362 : }
363 :
364 111 : V8_NOINLINE void Print(std::ostream& os) {
365 111 : os.precision(2);
366 : os << std::fixed << std::setprecision(2);
367 222 : os << std::setw(50) << name_;
368 222 : os << std::setw(10) << static_cast<double>(time_) / 1000 << "ms ";
369 222 : os << std::setw(6) << time_percent_ << "%";
370 222 : os << std::setw(10) << count_ << " ";
371 222 : os << std::setw(6) << count_percent_ << "%";
372 : os << std::endl;
373 111 : }
374 :
375 106 : V8_NOINLINE void SetTotal(base::TimeDelta total_time,
376 : uint64_t total_count) {
377 106 : if (total_time.InMicroseconds() == 0) {
378 0 : time_percent_ = 0;
379 : } else {
380 106 : time_percent_ = 100.0 * time_ / total_time.InMicroseconds();
381 : }
382 106 : count_percent_ = 100.0 * count_ / total_count;
383 106 : }
384 :
385 : private:
386 : const char* name_;
387 : int64_t time_;
388 : uint64_t count_;
389 : double time_percent_;
390 : double count_percent_;
391 : };
392 :
393 : uint64_t total_call_count = 0;
394 : base::TimeDelta total_time;
395 : std::vector<Entry> entries;
396 : };
397 :
398 15100 : void RuntimeCallCounter::Reset() {
399 15100 : count_ = 0;
400 15100 : time_ = 0;
401 15100 : }
402 :
403 0 : void RuntimeCallCounter::Dump(v8::tracing::TracedValue* value) {
404 0 : value->BeginArray(name_);
405 0 : value->AppendDouble(count_);
406 0 : value->AppendDouble(time_);
407 0 : value->EndArray();
408 0 : }
409 :
410 0 : void RuntimeCallCounter::Add(RuntimeCallCounter* other) {
411 0 : count_ += other->count();
412 0 : time_ += other->time().InMicroseconds();
413 0 : }
414 :
415 4 : void RuntimeCallTimer::Snapshot() {
416 4 : base::TimeTicks now = Now();
417 : // Pause only / topmost timer in the timer stack.
418 : Pause(now);
419 : // Commit all the timer's elapsed time to the counters.
420 : RuntimeCallTimer* timer = this;
421 18 : while (timer != nullptr) {
422 : timer->CommitTimeToCounter();
423 : timer = timer->parent();
424 : }
425 : Resume(now);
426 4 : }
427 :
428 71595880 : RuntimeCallStats::RuntimeCallStats() : in_use_(false) {
429 : static const char* const kNames[] = {
430 : #define CALL_BUILTIN_COUNTER(name) "GC_" #name,
431 : FOR_EACH_GC_COUNTER(CALL_BUILTIN_COUNTER) //
432 : #undef CALL_BUILTIN_COUNTER
433 : #define CALL_RUNTIME_COUNTER(name) #name,
434 : FOR_EACH_MANUAL_COUNTER(CALL_RUNTIME_COUNTER) //
435 : #undef CALL_RUNTIME_COUNTER
436 : #define CALL_RUNTIME_COUNTER(name, nargs, ressize) #name,
437 : FOR_EACH_INTRINSIC(CALL_RUNTIME_COUNTER) //
438 : #undef CALL_RUNTIME_COUNTER
439 : #define CALL_BUILTIN_COUNTER(name) #name,
440 : BUILTIN_LIST_C(CALL_BUILTIN_COUNTER) //
441 : #undef CALL_BUILTIN_COUNTER
442 : #define CALL_BUILTIN_COUNTER(name) "API_" #name,
443 : FOR_EACH_API_COUNTER(CALL_BUILTIN_COUNTER) //
444 : #undef CALL_BUILTIN_COUNTER
445 : #define CALL_BUILTIN_COUNTER(name) #name,
446 : FOR_EACH_HANDLER_COUNTER(CALL_BUILTIN_COUNTER) //
447 : #undef CALL_BUILTIN_COUNTER
448 : };
449 143362670 : for (int i = 0; i < kNumberOfCounters; i++) {
450 71650124 : this->counters_[i] = RuntimeCallCounter(kNames[i]);
451 : }
452 0 : }
453 :
454 27429 : void RuntimeCallStats::Enter(RuntimeCallTimer* timer,
455 : RuntimeCallCounterId counter_id) {
456 : DCHECK(IsCalledOnTheSameThread());
457 : RuntimeCallCounter* counter = GetCounter(counter_id);
458 : DCHECK_NOT_NULL(counter->name());
459 27429 : timer->Start(counter, current_timer());
460 : current_timer_.SetValue(timer);
461 : current_counter_.SetValue(counter);
462 27429 : }
463 :
464 27429 : void RuntimeCallStats::Leave(RuntimeCallTimer* timer) {
465 : DCHECK(IsCalledOnTheSameThread());
466 : RuntimeCallTimer* stack_top = current_timer();
467 27429 : if (stack_top == nullptr) return; // Missing timer is a result of Reset().
468 27429 : CHECK(stack_top == timer);
469 27429 : current_timer_.SetValue(timer->Stop());
470 : RuntimeCallTimer* cur_timer = current_timer();
471 27429 : current_counter_.SetValue(cur_timer ? cur_timer->counter() : nullptr);
472 : }
473 :
474 0 : void RuntimeCallStats::Add(RuntimeCallStats* other) {
475 0 : for (int i = 0; i < kNumberOfCounters; i++) {
476 : GetCounter(i)->Add(other->GetCounter(i));
477 : }
478 0 : }
479 :
480 : // static
481 13 : void RuntimeCallStats::CorrectCurrentCounterId(
482 : RuntimeCallCounterId counter_id) {
483 : DCHECK(IsCalledOnTheSameThread());
484 : RuntimeCallTimer* timer = current_timer();
485 13 : if (timer == nullptr) return;
486 : RuntimeCallCounter* counter = GetCounter(counter_id);
487 : timer->set_counter(counter);
488 : current_counter_.SetValue(counter);
489 : }
490 :
491 0 : bool RuntimeCallStats::IsCalledOnTheSameThread() {
492 0 : if (thread_id_.IsValid()) return thread_id_ == ThreadId::Current();
493 0 : thread_id_ = ThreadId::Current();
494 0 : return true;
495 : }
496 :
497 4 : void RuntimeCallStats::Print() {
498 8 : StdoutStream os;
499 4 : Print(os);
500 4 : }
501 :
502 10 : void RuntimeCallStats::Print(std::ostream& os) {
503 : RuntimeCallStatEntries entries;
504 10 : if (current_timer_.Value() != nullptr) {
505 4 : current_timer_.Value()->Snapshot();
506 : }
507 22970 : for (int i = 0; i < kNumberOfCounters; i++) {
508 11480 : entries.Add(GetCounter(i));
509 : }
510 10 : entries.Print(os);
511 10 : }
512 :
513 18 : void RuntimeCallStats::Reset() {
514 18 : if (V8_LIKELY(!TracingFlags::is_runtime_stats_enabled())) return;
515 :
516 : // In tracing, we only what to trace the time spent on top level trace events,
517 : // if runtime counter stack is not empty, we should clear the whole runtime
518 : // counter stack, and then reset counters so that we can dump counters into
519 : // top level trace events accurately.
520 13 : while (current_timer_.Value()) {
521 0 : current_timer_.SetValue(current_timer_.Value()->Stop());
522 : }
523 :
524 29861 : for (int i = 0; i < kNumberOfCounters; i++) {
525 14924 : GetCounter(i)->Reset();
526 : }
527 :
528 13 : in_use_ = true;
529 : }
530 :
531 5 : void RuntimeCallStats::Dump(v8::tracing::TracedValue* value) {
532 11485 : for (int i = 0; i < kNumberOfCounters; i++) {
533 5740 : if (GetCounter(i)->count() > 0) GetCounter(i)->Dump(value);
534 : }
535 5 : in_use_ = false;
536 5 : }
537 :
538 62422 : WorkerThreadRuntimeCallStats::WorkerThreadRuntimeCallStats() {}
539 :
540 124812 : WorkerThreadRuntimeCallStats::~WorkerThreadRuntimeCallStats() {
541 62406 : if (tls_key_) base::Thread::DeleteThreadLocalKey(*tls_key_);
542 62406 : }
543 :
544 0 : base::Thread::LocalStorageKey WorkerThreadRuntimeCallStats::GetKey() {
545 : DCHECK(TracingFlags::is_runtime_stats_enabled());
546 0 : if (!tls_key_) tls_key_ = base::Thread::CreateThreadLocalKey();
547 0 : return *tls_key_;
548 : }
549 :
550 0 : RuntimeCallStats* WorkerThreadRuntimeCallStats::NewTable() {
551 : DCHECK(TracingFlags::is_runtime_stats_enabled());
552 : std::unique_ptr<RuntimeCallStats> new_table =
553 0 : base::make_unique<RuntimeCallStats>();
554 : RuntimeCallStats* result = new_table.get();
555 :
556 0 : base::MutexGuard lock(&mutex_);
557 0 : tables_.push_back(std::move(new_table));
558 0 : return result;
559 : }
560 :
561 0 : void WorkerThreadRuntimeCallStats::AddToMainTable(
562 : RuntimeCallStats* main_call_stats) {
563 0 : base::MutexGuard lock(&mutex_);
564 0 : for (auto& worker_stats : tables_) {
565 : DCHECK_NE(main_call_stats, worker_stats.get());
566 0 : main_call_stats->Add(worker_stats.get());
567 0 : worker_stats->Reset();
568 : }
569 0 : }
570 :
571 20319 : WorkerThreadRuntimeCallStatsScope::WorkerThreadRuntimeCallStatsScope(
572 : WorkerThreadRuntimeCallStats* worker_stats)
573 20319 : : table_(nullptr) {
574 20319 : if (V8_LIKELY(!TracingFlags::is_runtime_stats_enabled())) return;
575 :
576 : table_ = reinterpret_cast<RuntimeCallStats*>(
577 0 : base::Thread::GetThreadLocal(worker_stats->GetKey()));
578 0 : if (table_ == nullptr) {
579 0 : table_ = worker_stats->NewTable();
580 0 : base::Thread::SetThreadLocal(worker_stats->GetKey(), table_);
581 : }
582 :
583 0 : if ((TracingFlags::runtime_stats.load(std::memory_order_relaxed) &
584 : v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING)) {
585 0 : table_->Reset();
586 : }
587 : }
588 :
589 20318 : WorkerThreadRuntimeCallStatsScope::~WorkerThreadRuntimeCallStatsScope() {
590 20318 : if (V8_LIKELY(table_ == nullptr)) return;
591 :
592 0 : if ((TracingFlags::runtime_stats.load(std::memory_order_relaxed) &
593 : v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING)) {
594 0 : auto value = v8::tracing::TracedValue::Create();
595 0 : table_->Dump(value.get());
596 0 : TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8.runtime_stats"),
597 : "V8.RuntimeStats", TRACE_EVENT_SCOPE_THREAD,
598 : "runtime-call-stats", std::move(value));
599 : }
600 20318 : }
601 :
602 : } // namespace internal
603 121996 : } // namespace v8
|