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