counters.h 72.9 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4 5 6 7

#ifndef V8_COUNTERS_H_
#define V8_COUNTERS_H_

8 9
#include "include/v8.h"
#include "src/allocation.h"
10
#include "src/base/atomic-utils.h"
11
#include "src/base/optional.h"
12
#include "src/base/platform/elapsed-timer.h"
13
#include "src/base/platform/time.h"
14
#include "src/globals.h"
15
#include "src/heap-symbols.h"
16
#include "src/isolate.h"
17
#include "src/objects.h"
18
#include "src/runtime/runtime.h"
19
#include "src/tracing/trace-event.h"
20
#include "src/tracing/traced-value.h"
21
#include "src/tracing/tracing-category-observer.h"
22

23 24
namespace v8 {
namespace internal {
25 26 27 28 29

// StatsCounters is an interface for plugging into external
// counters for monitoring.  Counters can be looked up and
// manipulated by name.

30 31
class Counters;

32
class StatsTable {
33
 public:
34 35
  // Register an application-defined function for recording
  // subsequent counter statistics.
36
  void SetCounterFunction(CounterLookupCallback f);
37

38 39
  // Register an application-defined function to create histograms for
  // recording subsequent histogram samples.
40
  void SetCreateHistogramFunction(CreateHistogramCallback f) {
41 42 43 44
    create_histogram_function_ = f;
  }

  // Register an application-defined function to add a sample
45
  // to a histogram created with CreateHistogram function.
46
  void SetAddHistogramSampleFunction(AddHistogramSampleCallback f) {
47 48 49
    add_histogram_sample_function_ = f;
  }

50
  bool HasCounterFunction() const { return lookup_function_ != nullptr; }
51 52

  // Lookup the location of a counter by name.  If the lookup
53
  // is successful, returns a non-nullptr pointer for writing the
54 55 56 57
  // value of the counter.  Each thread calling this function
  // may receive a different location to store it's counter.
  // The return value must not be cached and re-used across
  // threads, although a single thread is free to cache it.
58
  int* FindLocation(const char* name) {
59
    if (!lookup_function_) return nullptr;
60 61 62
    return lookup_function_(name);
  }

63
  // Create a histogram by name. If the create is successful,
64
  // returns a non-nullptr pointer for use with AddHistogramSample
65 66 67
  // function. min and max define the expected minimum and maximum
  // sample values. buckets is the maximum number of buckets
  // that the samples will be grouped into.
68 69 70 71
  void* CreateHistogram(const char* name,
                        int min,
                        int max,
                        size_t buckets) {
72
    if (!create_histogram_function_) return nullptr;
73 74 75 76 77
    return create_histogram_function_(name, min, max, buckets);
  }

  // Add a sample to a histogram created with the CreateHistogram
  // function.
78
  void AddHistogramSample(void* histogram, int sample) {
79 80 81 82
    if (!add_histogram_sample_function_) return;
    return add_histogram_sample_function_(histogram, sample);
  }

83
 private:
84 85
  friend class Counters;

86
  explicit StatsTable(Counters* counters);
87 88 89 90 91 92

  CounterLookupCallback lookup_function_;
  CreateHistogramCallback create_histogram_function_;
  AddHistogramSampleCallback add_histogram_sample_function_;

  DISALLOW_COPY_AND_ASSIGN(StatsTable);
93 94
};

95 96 97
// Base class for stats counters.
class StatsCounterBase {
 protected:
98
  Counters* counters_;
99 100 101
  const char* name_;
  int* ptr_;

102
  StatsCounterBase() = default;
103 104 105
  StatsCounterBase(Counters* counters, const char* name)
      : counters_(counters), name_(name), ptr_(nullptr) {}

106 107 108 109 110 111 112 113 114
  void SetLoc(int* loc, int value) { *loc = value; }
  void IncrementLoc(int* loc) { (*loc)++; }
  void IncrementLoc(int* loc, int value) { (*loc) += value; }
  void DecrementLoc(int* loc) { (*loc)--; }
  void DecrementLoc(int* loc, int value) { (*loc) -= value; }

  int* FindLocationInStatsTable() const;
};

115 116 117 118 119 120 121
// StatsCounters are dynamically created values which can be tracked in
// the StatsTable.  They are designed to be lightweight to create and
// easy to use.
//
// Internally, a counter represents a value in a row of a StatsTable.
// The row has a 32bit value for each process/thread in the table and also
// a name (stored in the table metadata).  Since the storage location can be
122 123
// thread-specific, this class cannot be shared across threads. Note: This
// class is not thread safe.
124
class StatsCounter : public StatsCounterBase {
125
 public:
126 127
  // Sets the counter to a specific value.
  void Set(int value) {
128
    if (int* loc = GetPtr()) SetLoc(loc, value);
129 130 131 132
  }

  // Increments the counter.
  void Increment() {
133
    if (int* loc = GetPtr()) IncrementLoc(loc);
134 135 136
  }

  void Increment(int value) {
137
    if (int* loc = GetPtr()) IncrementLoc(loc, value);
138 139 140 141
  }

  // Decrements the counter.
  void Decrement() {
142
    if (int* loc = GetPtr()) DecrementLoc(loc);
143 144 145
  }

  void Decrement(int value) {
146
    if (int* loc = GetPtr()) DecrementLoc(loc, value);
147 148 149 150
  }

  // Is this counter enabled?
  // Returns false if table is full.
151
  bool Enabled() { return GetPtr() != nullptr; }
152 153 154 155 156 157

  // Get the internal pointer to the counter. This is used
  // by the code generator to emit code that manipulates a
  // given counter without calling the runtime system.
  int* GetInternalPointer() {
    int* loc = GetPtr();
158
    DCHECK_NOT_NULL(loc);
159 160 161
    return loc;
  }

162 163 164
 private:
  friend class Counters;

165
  StatsCounter() = default;
166 167 168
  StatsCounter(Counters* counters, const char* name)
      : StatsCounterBase(counters, name), lookup_done_(false) {}

169 170 171
  // Reset the cached internal pointer.
  void Reset() { lookup_done_ = false; }

172 173
  // Returns the cached address of this counter location.
  int* GetPtr() {
174
    if (lookup_done_) return ptr_;
175
    lookup_done_ = true;
176
    ptr_ = FindLocationInStatsTable();
177 178
    return ptr_;
  }
179

180 181 182
  bool lookup_done_;
};

183
// Thread safe version of StatsCounter.
184 185 186 187 188 189 190
class StatsCounterThreadSafe : public StatsCounterBase {
 public:
  void Set(int Value);
  void Increment();
  void Increment(int value);
  void Decrement();
  void Decrement(int value);
191
  bool Enabled() { return ptr_ != nullptr; }
192
  int* GetInternalPointer() {
193
    DCHECK_NOT_NULL(ptr_);
194 195 196
    return ptr_;
  }

197
 private:
198 199 200 201
  friend class Counters;

  StatsCounterThreadSafe(Counters* counters, const char* name);
  void Reset() { ptr_ = FindLocationInStatsTable(); }
202

203 204 205
  base::Mutex mutex_;

  DISALLOW_IMPLICIT_CONSTRUCTORS(StatsCounterThreadSafe);
206 207
};

208 209
// A Histogram represents a dynamically created histogram in the
// StatsTable.  Note: This class is thread safe.
210 211
class Histogram {
 public:
212 213
  // Add a single sample to this histogram.
  void AddSample(int sample);
214

215
  // Returns true if this histogram is enabled.
216
  bool Enabled() { return histogram_ != nullptr; }
217

218 219
  const char* name() { return name_; }

220 221 222 223
  int min() const { return min_; }
  int max() const { return max_; }
  int num_buckets() const { return num_buckets_; }

224 225 226 227 228 229
  // Asserts that |expected_counters| are the same as the Counters this
  // Histogram reports to.
  void AssertReportsToCounters(Counters* expected_counters) {
    DCHECK_EQ(counters_, expected_counters);
  }

230
 protected:
231
  Histogram() = default;
232 233 234 235 236 237 238
  Histogram(const char* name, int min, int max, int num_buckets,
            Counters* counters)
      : name_(name),
        min_(min),
        max_(max),
        num_buckets_(num_buckets),
        histogram_(nullptr),
239 240 241
        counters_(counters) {
    DCHECK(counters_);
  }
242

243
  Counters* counters() const { return counters_; }
244

245 246 247
  // Reset the cached internal pointer.
  void Reset() { histogram_ = CreateHistogram(); }

248
 private:
249 250
  friend class Counters;

251
  void* CreateHistogram() const;
252

253 254 255 256 257
  const char* name_;
  int min_;
  int max_;
  int num_buckets_;
  void* histogram_;
258
  Counters* counters_;
259
};
260

261 262 263 264
enum class HistogramTimerResolution { MILLISECOND, MICROSECOND };

// A thread safe histogram timer. It also allows distributions of
// nested timed results.
265
class TimedHistogram : public Histogram {
266
 public:
267 268
  // Start the timer. Log if isolate non-null.
  void Start(base::ElapsedTimer* timer, Isolate* isolate);
269

270 271 272
  // Stop the timer and record the results. Log if isolate non-null.
  void Stop(base::ElapsedTimer* timer, Isolate* isolate);

273 274 275 276
  // Records a TimeDelta::Max() result. Useful to record percentage of tasks
  // that never got to run in a given scenario. Log if isolate non-null.
  void RecordAbandon(base::ElapsedTimer* timer, Isolate* isolate);

277 278 279 280
 protected:
  friend class Counters;
  HistogramTimerResolution resolution_;

281
  TimedHistogram() = default;
282 283 284
  TimedHistogram(const char* name, int min, int max,
                 HistogramTimerResolution resolution, int num_buckets,
                 Counters* counters)
285
      : Histogram(name, min, max, num_buckets, counters),
yangguo's avatar
yangguo committed
286
        resolution_(resolution) {}
287 288 289 290 291 292 293 294 295 296 297
  void AddTimeSample();
};

// Helper class for scoping a TimedHistogram.
class TimedHistogramScope {
 public:
  explicit TimedHistogramScope(TimedHistogram* histogram,
                               Isolate* isolate = nullptr)
      : histogram_(histogram), isolate_(isolate) {
    histogram_->Start(&timer_, isolate);
  }
298

299 300 301 302 303 304
  ~TimedHistogramScope() { histogram_->Stop(&timer_, isolate_); }

 private:
  base::ElapsedTimer timer_;
  TimedHistogram* histogram_;
  Isolate* isolate_;
305

306 307 308
  DISALLOW_IMPLICIT_CONSTRUCTORS(TimedHistogramScope);
};

309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
enum class OptionalTimedHistogramScopeMode { TAKE_TIME, DONT_TAKE_TIME };

// Helper class for scoping a TimedHistogram.
// It will not take time for mode = DONT_TAKE_TIME.
class OptionalTimedHistogramScope {
 public:
  OptionalTimedHistogramScope(TimedHistogram* histogram, Isolate* isolate,
                              OptionalTimedHistogramScopeMode mode)
      : histogram_(histogram), isolate_(isolate), mode_(mode) {
    if (mode == OptionalTimedHistogramScopeMode::TAKE_TIME) {
      histogram_->Start(&timer_, isolate);
    }
  }

  ~OptionalTimedHistogramScope() {
    if (mode_ == OptionalTimedHistogramScopeMode::TAKE_TIME) {
      histogram_->Stop(&timer_, isolate_);
    }
  }

 private:
  base::ElapsedTimer timer_;
  TimedHistogram* const histogram_;
  Isolate* const isolate_;
  const OptionalTimedHistogramScopeMode mode_;
  DISALLOW_IMPLICIT_CONSTRUCTORS(OptionalTimedHistogramScope);
};

337 338 339 340 341 342 343 344
// Helper class for recording a TimedHistogram asynchronously with manual
// controls (it will not generate a report if destroyed without explicitly
// triggering a report). |async_counters| should be a shared_ptr to
// |histogram->counters()|, making it is safe to report to an
// AsyncTimedHistogram after the associated isolate has been destroyed.
// AsyncTimedHistogram can be moved/copied to avoid computing Now() multiple
// times when the times of multiple tasks are identical; each copy will generate
// its own report.
345
class AsyncTimedHistogram {
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
 public:
  explicit AsyncTimedHistogram(TimedHistogram* histogram,
                               std::shared_ptr<Counters> async_counters)
      : histogram_(histogram), async_counters_(std::move(async_counters)) {
    histogram_->AssertReportsToCounters(async_counters_.get());
    histogram_->Start(&timer_, nullptr);
  }

  // Records the time elapsed to |histogram_| and stops |timer_|.
  void RecordDone() { histogram_->Stop(&timer_, nullptr); }

  // Records TimeDelta::Max() to |histogram_| and stops |timer_|.
  void RecordAbandon() { histogram_->RecordAbandon(&timer_, nullptr); }

 private:
  base::ElapsedTimer timer_;
  TimedHistogram* histogram_;
  std::shared_ptr<Counters> async_counters_;
};

366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
// Helper class for scoping a TimedHistogram, where the histogram is selected at
// stop time rather than start time.
// TODO(leszeks): This is heavily reliant on TimedHistogram::Start() doing
// nothing but starting the timer, and TimedHistogram::Stop() logging the sample
// correctly even if Start() was not called. This happens to be true iff Stop()
// is passed a null isolate, but that's an implementation detail of
// TimedHistogram, and we shouldn't rely on it.
class LazyTimedHistogramScope {
 public:
  LazyTimedHistogramScope() : histogram_(nullptr) { timer_.Start(); }
  ~LazyTimedHistogramScope() {
    // We should set the histogram before this scope exits.
    DCHECK_NOT_NULL(histogram_);
    histogram_->Stop(&timer_, nullptr);
  }

  void set_histogram(TimedHistogram* histogram) { histogram_ = histogram; }

 private:
  base::ElapsedTimer timer_;
  TimedHistogram* histogram_;
};

389 390 391 392 393 394 395 396 397 398
// A HistogramTimer allows distributions of non-nested timed results
// to be created. WARNING: This class is not thread safe and can only
// be run on the foreground thread.
class HistogramTimer : public TimedHistogram {
 public:
  // Note: public for testing purposes only.
  HistogramTimer(const char* name, int min, int max,
                 HistogramTimerResolution resolution, int num_buckets,
                 Counters* counters)
      : TimedHistogram(name, min, max, resolution, num_buckets, counters) {}
399

400 401
  inline void Start();
  inline void Stop();
402 403 404

  // Returns true if the timer is running.
  bool Running() {
405
    return Enabled() && timer_.IsStarted();
406
  }
407

408 409
  // TODO(bmeurer): Remove this when HistogramTimerScope is fixed.
#ifdef DEBUG
410
  base::ElapsedTimer* timer() { return &timer_; }
411 412
#endif

413
 private:
414 415
  friend class Counters;

416
  base::ElapsedTimer timer_;
417

418
  HistogramTimer() = default;
419 420
};

421
// Helper class for scoping a HistogramTimer.
422 423 424 425
// TODO(bmeurer): The ifdeffery is an ugly hack around the fact that the
// Parser is currently reentrant (when it throws an error, we call back
// into JavaScript and all bets are off), but ElapsedTimer is not
// reentry-safe. Fix this properly and remove |allow_nesting|.
426
class HistogramTimerScope {
427
 public:
428 429 430
  explicit HistogramTimerScope(HistogramTimer* timer,
                               bool allow_nesting = false)
#ifdef DEBUG
431
      : timer_(timer), skipped_timer_start_(false) {
432 433 434 435 436
    if (timer_->timer()->IsStarted() && allow_nesting) {
      skipped_timer_start_ = true;
    } else {
      timer_->Start();
    }
437
  }
438 439
#else
      : timer_(timer) {
440
    timer_->Start();
441
  }
442
#endif
443
  ~HistogramTimerScope() {
444 445 446 447 448
#ifdef DEBUG
    if (!skipped_timer_start_) {
      timer_->Stop();
    }
#else
449
    timer_->Stop();
450
#endif
451
  }
452

453
 private:
454
  HistogramTimer* timer_;
455 456 457
#ifdef DEBUG
  bool skipped_timer_start_;
#endif
458 459
};

460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476
// A histogram timer that can aggregate events within a larger scope.
//
// Intended use of this timer is to have an outer (aggregating) and an inner
// (to be aggregated) scope, where the inner scope measure the time of events,
// and all those inner scope measurements will be summed up by the outer scope.
// An example use might be to aggregate the time spent in lazy compilation
// while running a script.
//
// Helpers:
// - AggregatingHistogramTimerScope, the "outer" scope within which
//     times will be summed up.
// - AggregatedHistogramTimerScope, the "inner" scope which defines the
//     events to be timed.
class AggregatableHistogramTimer : public Histogram {
 public:
  // Start/stop the "outer" scope.
  void Start() { time_ = base::TimeDelta(); }
477 478 479 480 481 482 483
  void Stop() {
    if (time_ != base::TimeDelta()) {
      // Only add non-zero samples, since zero samples represent situations
      // where there were no aggregated samples added.
      AddSample(static_cast<int>(time_.InMicroseconds()));
    }
  }
484 485 486 487 488

  // Add a time value ("inner" scope).
  void Add(base::TimeDelta other) { time_ += other; }

 private:
489 490
  friend class Counters;

491
  AggregatableHistogramTimer() = default;
492 493 494 495
  AggregatableHistogramTimer(const char* name, int min, int max,
                             int num_buckets, Counters* counters)
      : Histogram(name, min, max, num_buckets, counters) {}

496 497 498
  base::TimeDelta time_;
};

499
// A helper class for use with AggregatableHistogramTimer. This is the
500 501
// // outer-most timer scope used with an AggregatableHistogramTimer. It will
// // aggregate the information from the inner AggregatedHistogramTimerScope.
502 503 504 505 506 507 508 509 510 511 512 513
class AggregatingHistogramTimerScope {
 public:
  explicit AggregatingHistogramTimerScope(AggregatableHistogramTimer* histogram)
      : histogram_(histogram) {
    histogram_->Start();
  }
  ~AggregatingHistogramTimerScope() { histogram_->Stop(); }

 private:
  AggregatableHistogramTimer* histogram_;
};

514
// A helper class for use with AggregatableHistogramTimer, the "inner" scope
515
// // which defines the events to be timed.
516 517 518 519 520 521 522 523 524 525 526 527 528 529
class AggregatedHistogramTimerScope {
 public:
  explicit AggregatedHistogramTimerScope(AggregatableHistogramTimer* histogram)
      : histogram_(histogram) {
    timer_.Start();
  }
  ~AggregatedHistogramTimerScope() { histogram_->Add(timer_.Elapsed()); }

 private:
  base::ElapsedTimer timer_;
  AggregatableHistogramTimer* histogram_;
};


530 531 532 533 534 535 536 537 538 539 540 541
// AggretatedMemoryHistogram collects (time, value) sample pairs and turns
// them into time-uniform samples for the backing historgram, such that the
// backing histogram receives one sample every T ms, where the T is controlled
// by the FLAG_histogram_interval.
//
// More formally: let F be a real-valued function that maps time to sample
// values. We define F as a linear interpolation between adjacent samples. For
// each time interval [x; x + T) the backing histogram gets one sample value
// that is the average of F(t) in the interval.
template <typename Histogram>
class AggregatedMemoryHistogram {
 public:
542
  // Note: public for testing purposes only.
543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559
  explicit AggregatedMemoryHistogram(Histogram* backing_histogram)
      : AggregatedMemoryHistogram() {
    backing_histogram_ = backing_histogram;
  }

  // Invariants that hold before and after AddSample if
  // is_initialized_ is true:
  //
  // 1) For we processed samples that came in before start_ms_ and sent the
  // corresponding aggregated samples to backing histogram.
  // 2) (last_ms_, last_value_) is the last received sample.
  // 3) last_ms_ < start_ms_ + FLAG_histogram_interval.
  // 4) aggregate_value_ is the average of the function that is constructed by
  // linearly interpolating samples received between start_ms_ and last_ms_.
  void AddSample(double current_ms, double current_value);

 private:
560 561 562 563 564 565 566 567
  friend class Counters;

  AggregatedMemoryHistogram()
      : is_initialized_(false),
        start_ms_(0.0),
        last_ms_(0.0),
        aggregate_value_(0.0),
        last_value_(0.0),
568
        backing_histogram_(nullptr) {}
569
  double Aggregate(double current_ms, double current_value);
570

571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649
  bool is_initialized_;
  double start_ms_;
  double last_ms_;
  double aggregate_value_;
  double last_value_;
  Histogram* backing_histogram_;
};


template <typename Histogram>
void AggregatedMemoryHistogram<Histogram>::AddSample(double current_ms,
                                                     double current_value) {
  if (!is_initialized_) {
    aggregate_value_ = current_value;
    start_ms_ = current_ms;
    last_value_ = current_value;
    last_ms_ = current_ms;
    is_initialized_ = true;
  } else {
    const double kEpsilon = 1e-6;
    const int kMaxSamples = 1000;
    if (current_ms < last_ms_ + kEpsilon) {
      // Two samples have the same time, remember the last one.
      last_value_ = current_value;
    } else {
      double sample_interval_ms = FLAG_histogram_interval;
      double end_ms = start_ms_ + sample_interval_ms;
      if (end_ms <= current_ms + kEpsilon) {
        // Linearly interpolate between the last_ms_ and the current_ms.
        double slope = (current_value - last_value_) / (current_ms - last_ms_);
        int i;
        // Send aggregated samples to the backing histogram from the start_ms
        // to the current_ms.
        for (i = 0; i < kMaxSamples && end_ms <= current_ms + kEpsilon; i++) {
          double end_value = last_value_ + (end_ms - last_ms_) * slope;
          double sample_value;
          if (i == 0) {
            // Take aggregate_value_ into account.
            sample_value = Aggregate(end_ms, end_value);
          } else {
            // There is no aggregate_value_ for i > 0.
            sample_value = (last_value_ + end_value) / 2;
          }
          backing_histogram_->AddSample(static_cast<int>(sample_value + 0.5));
          last_value_ = end_value;
          last_ms_ = end_ms;
          end_ms += sample_interval_ms;
        }
        if (i == kMaxSamples) {
          // We hit the sample limit, ignore the remaining samples.
          aggregate_value_ = current_value;
          start_ms_ = current_ms;
        } else {
          aggregate_value_ = last_value_;
          start_ms_ = last_ms_;
        }
      }
      aggregate_value_ = current_ms > start_ms_ + kEpsilon
                             ? Aggregate(current_ms, current_value)
                             : aggregate_value_;
      last_value_ = current_value;
      last_ms_ = current_ms;
    }
  }
}


template <typename Histogram>
double AggregatedMemoryHistogram<Histogram>::Aggregate(double current_ms,
                                                       double current_value) {
  double interval_ms = current_ms - start_ms_;
  double value = (current_value + last_value_) / 2;
  // The aggregate_value_ is the average for [start_ms_; last_ms_].
  // The value is the average for [last_ms_; current_ms].
  // Return the weighted average of the aggregate_value_ and the value.
  return aggregate_value_ * ((last_ms_ - start_ms_) / interval_ms) +
         value * ((current_ms - last_ms_) / interval_ms);
}

650 651
class RuntimeCallCounter final {
 public:
652
  RuntimeCallCounter() : RuntimeCallCounter(nullptr) {}
653 654
  explicit RuntimeCallCounter(const char* name)
      : name_(name), count_(0), time_(0) {}
655
  V8_NOINLINE void Reset();
656
  V8_NOINLINE void Dump(v8::tracing::TracedValue* value);
657
  void Add(RuntimeCallCounter* other);
658

659 660
  const char* name() const { return name_; }
  int64_t count() const { return count_; }
661 662 663
  base::TimeDelta time() const {
    return base::TimeDelta::FromMicroseconds(time_);
  }
664
  void Increment() { count_++; }
665
  void Add(base::TimeDelta delta) { time_ += delta.InMicroseconds(); }
666 667

 private:
668 669
  friend class RuntimeCallStats;

670
  const char* name_;
671 672 673
  int64_t count_;
  // Stored as int64_t so that its initialization can be deferred.
  int64_t time_;
674 675 676 677
};

// RuntimeCallTimer is used to keep track of the stack of currently active
// timers used for properly measuring the own time of a RuntimeCallCounter.
678
class RuntimeCallTimer final {
679
 public:
680
  RuntimeCallCounter* counter() { return counter_; }
681
  void set_counter(RuntimeCallCounter* counter) { counter_ = counter; }
682
  RuntimeCallTimer* parent() const { return parent_.Value(); }
683 684
  void set_parent(RuntimeCallTimer* timer) { parent_.SetValue(timer); }
  const char* name() const { return counter_->name(); }
685

686
  inline bool IsStarted();
687

688 689 690
  inline void Start(RuntimeCallCounter* counter, RuntimeCallTimer* parent);
  void Snapshot();
  inline RuntimeCallTimer* Stop();
691

692 693 694
  // Make the time source configurable for testing purposes.
  V8_EXPORT_PRIVATE static base::TimeTicks (*Now)();

695 696 697 698
 private:
  inline void Pause(base::TimeTicks now);
  inline void Resume(base::TimeTicks now);
  inline void CommitTimeToCounter();
699

700
  RuntimeCallCounter* counter_ = nullptr;
701
  base::AtomicValue<RuntimeCallTimer*> parent_;
702 703
  base::TimeTicks start_ticks_;
  base::TimeDelta elapsed_;
704 705
};

706 707 708
#define FOR_EACH_GC_COUNTER(V) \
  TRACER_SCOPES(V)             \
  TRACER_BACKGROUND_SCOPES(V)
709

710 711
#define FOR_EACH_API_COUNTER(V)                            \
  V(ArrayBuffer_Cast)                                      \
712
  V(ArrayBuffer_Detach)                                    \
713 714 715
  V(ArrayBuffer_New)                                       \
  V(Array_CloneElementAt)                                  \
  V(Array_New)                                             \
716
  V(BigInt64Array_New)                                     \
717
  V(BigInt_NewFromWords)                                   \
718
  V(BigIntObject_BigIntValue)                              \
719 720
  V(BigIntObject_New)                                      \
  V(BigUint64Array_New)                                    \
721 722 723
  V(BooleanObject_BooleanValue)                            \
  V(BooleanObject_New)                                     \
  V(Context_New)                                           \
724
  V(Context_NewRemoteContext)                              \
725 726 727 728 729 730 731 732 733 734 735 736 737 738
  V(DataView_New)                                          \
  V(Date_DateTimeConfigurationChangeNotification)          \
  V(Date_New)                                              \
  V(Date_NumberValue)                                      \
  V(Debug_Call)                                            \
  V(Error_New)                                             \
  V(External_New)                                          \
  V(Float32Array_New)                                      \
  V(Float64Array_New)                                      \
  V(Function_Call)                                         \
  V(Function_New)                                          \
  V(Function_NewInstance)                                  \
  V(FunctionTemplate_GetFunction)                          \
  V(FunctionTemplate_New)                                  \
739
  V(FunctionTemplate_NewRemoteInstance)                    \
740
  V(FunctionTemplate_NewWithCache)                         \
741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757
  V(FunctionTemplate_NewWithFastHandler)                   \
  V(Int16Array_New)                                        \
  V(Int32Array_New)                                        \
  V(Int8Array_New)                                         \
  V(JSON_Parse)                                            \
  V(JSON_Stringify)                                        \
  V(Map_AsArray)                                           \
  V(Map_Clear)                                             \
  V(Map_Delete)                                            \
  V(Map_Get)                                               \
  V(Map_Has)                                               \
  V(Map_New)                                               \
  V(Map_Set)                                               \
  V(Message_GetEndColumn)                                  \
  V(Message_GetLineNumber)                                 \
  V(Message_GetSourceLine)                                 \
  V(Message_GetStartColumn)                                \
758
  V(Module_Evaluate)                                       \
759
  V(Module_InstantiateModule)                              \
760 761 762 763 764 765
  V(NumberObject_New)                                      \
  V(NumberObject_NumberValue)                              \
  V(Object_CallAsConstructor)                              \
  V(Object_CallAsFunction)                                 \
  V(Object_CreateDataProperty)                             \
  V(Object_DefineOwnProperty)                              \
766
  V(Object_DefineProperty)                                 \
767 768 769 770 771 772 773 774 775 776 777 778
  V(Object_Delete)                                         \
  V(Object_DeleteProperty)                                 \
  V(Object_ForceSet)                                       \
  V(Object_Get)                                            \
  V(Object_GetOwnPropertyDescriptor)                       \
  V(Object_GetOwnPropertyNames)                            \
  V(Object_GetPropertyAttributes)                          \
  V(Object_GetPropertyNames)                               \
  V(Object_GetRealNamedProperty)                           \
  V(Object_GetRealNamedPropertyAttributes)                 \
  V(Object_GetRealNamedPropertyAttributesInPrototypeChain) \
  V(Object_GetRealNamedPropertyInPrototypeChain)           \
779
  V(Object_Has)                                            \
780 781 782 783 784 785 786 787 788 789 790 791 792 793
  V(Object_HasOwnProperty)                                 \
  V(Object_HasRealIndexedProperty)                         \
  V(Object_HasRealNamedCallbackProperty)                   \
  V(Object_HasRealNamedProperty)                           \
  V(Object_New)                                            \
  V(Object_ObjectProtoToString)                            \
  V(Object_Set)                                            \
  V(Object_SetAccessor)                                    \
  V(Object_SetIntegrityLevel)                              \
  V(Object_SetPrivate)                                     \
  V(Object_SetPrototype)                                   \
  V(ObjectTemplate_New)                                    \
  V(ObjectTemplate_NewInstance)                            \
  V(Object_ToArrayIndex)                                   \
794
  V(Object_ToBigInt)                                       \
795 796 797 798 799 800 801 802 803 804 805 806 807
  V(Object_ToDetailString)                                 \
  V(Object_ToInt32)                                        \
  V(Object_ToInteger)                                      \
  V(Object_ToNumber)                                       \
  V(Object_ToObject)                                       \
  V(Object_ToString)                                       \
  V(Object_ToUint32)                                       \
  V(Persistent_New)                                        \
  V(Private_New)                                           \
  V(Promise_Catch)                                         \
  V(Promise_Chain)                                         \
  V(Promise_HasRejectHandler)                              \
  V(Promise_Resolver_New)                                  \
808
  V(Promise_Resolver_Reject)                               \
809
  V(Promise_Resolver_Resolve)                              \
810 811
  V(Promise_Result)                                        \
  V(Promise_Status)                                        \
812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841
  V(Promise_Then)                                          \
  V(Proxy_New)                                             \
  V(RangeError_New)                                        \
  V(ReferenceError_New)                                    \
  V(RegExp_New)                                            \
  V(ScriptCompiler_Compile)                                \
  V(ScriptCompiler_CompileFunctionInContext)               \
  V(ScriptCompiler_CompileUnbound)                         \
  V(Script_Run)                                            \
  V(Set_Add)                                               \
  V(Set_AsArray)                                           \
  V(Set_Clear)                                             \
  V(Set_Delete)                                            \
  V(Set_Has)                                               \
  V(Set_New)                                               \
  V(SharedArrayBuffer_New)                                 \
  V(String_Concat)                                         \
  V(String_NewExternalOneByte)                             \
  V(String_NewExternalTwoByte)                             \
  V(String_NewFromOneByte)                                 \
  V(String_NewFromTwoByte)                                 \
  V(String_NewFromUtf8)                                    \
  V(StringObject_New)                                      \
  V(StringObject_StringValue)                              \
  V(String_Write)                                          \
  V(String_WriteUtf8)                                      \
  V(Symbol_New)                                            \
  V(SymbolObject_New)                                      \
  V(SymbolObject_SymbolValue)                              \
  V(SyntaxError_New)                                       \
842
  V(TracedGlobal_New)                                      \
843 844 845 846 847 848 849 850 851 852 853
  V(TryCatch_StackTrace)                                   \
  V(TypeError_New)                                         \
  V(Uint16Array_New)                                       \
  V(Uint32Array_New)                                       \
  V(Uint8Array_New)                                        \
  V(Uint8ClampedArray_New)                                 \
  V(UnboundScript_GetId)                                   \
  V(UnboundScript_GetLineNumber)                           \
  V(UnboundScript_GetName)                                 \
  V(UnboundScript_GetSourceMappingURL)                     \
  V(UnboundScript_GetSourceURL)                            \
854 855 856
  V(ValueDeserializer_ReadHeader)                          \
  V(ValueDeserializer_ReadValue)                           \
  V(ValueSerializer_WriteValue)                            \
857
  V(Value_InstanceOf)                                      \
858
  V(Value_Int32Value)                                      \
859
  V(Value_IntegerValue)                                    \
860
  V(Value_NumberValue)                                     \
861
  V(Value_TypeOf)                                          \
862
  V(Value_Uint32Value)                                     \
863 864 865
  V(WeakMap_Get)                                           \
  V(WeakMap_New)                                           \
  V(WeakMap_Set)
866

867 868
#define FOR_EACH_MANUAL_COUNTER(V)             \
  V(AccessorGetterCallback)                    \
869
  V(AccessorSetterCallback)                    \
870 871 872
  V(ArrayLengthGetter)                         \
  V(ArrayLengthSetter)                         \
  V(BoundFunctionLengthGetter)                 \
873 874
  V(BoundFunctionNameGetter)                   \
  V(CompileAnalyse)                            \
875
  V(CompileBackgroundAnalyse)                  \
876
  V(CompileBackgroundCompileTask)              \
877
  V(CompileBackgroundEval)                     \
878
  V(CompileBackgroundFunction)                 \
879
  V(CompileBackgroundIgnition)                 \
880 881
  V(CompileBackgroundRewriteReturnResult)      \
  V(CompileBackgroundScopeAnalysis)            \
882
  V(CompileBackgroundScript)                   \
883
  V(CompileCollectSourcePositions)             \
884
  V(CompileDeserialize)                        \
885
  V(CompileEnqueueOnDispatcher)                \
886
  V(CompileEval)                               \
887
  V(CompileFinalizeBackgroundCompileTask)      \
888
  V(CompileFinishNowOnDispatcher)              \
889 890 891 892 893 894 895 896 897 898
  V(CompileFunction)                           \
  V(CompileGetFromOptimizedCodeMap)            \
  V(CompileIgnition)                           \
  V(CompileIgnitionFinalization)               \
  V(CompileRewriteReturnResult)                \
  V(CompileScopeAnalysis)                      \
  V(CompileScript)                             \
  V(CompileSerialize)                          \
  V(CompileWaitForDispatcher)                  \
  V(DeoptimizeCode)                            \
899 900
  V(DeserializeContext)                        \
  V(DeserializeIsolate)                        \
901
  V(FunctionCallback)                          \
902
  V(FunctionLengthGetter)                      \
903 904 905 906 907 908 909
  V(FunctionPrototypeGetter)                   \
  V(FunctionPrototypeSetter)                   \
  V(GC_Custom_AllAvailableGarbage)             \
  V(GC_Custom_IncrementalMarkingObserver)      \
  V(GC_Custom_SlowAllocateRaw)                 \
  V(GCEpilogueCallback)                        \
  V(GCPrologueCallback)                        \
910
  V(Genesis)                                   \
911
  V(GetMoreDataCallback)                       \
912 913 914
  V(IndexedDefinerCallback)                    \
  V(IndexedDeleterCallback)                    \
  V(IndexedDescriptorCallback)                 \
915
  V(IndexedEnumeratorCallback)                 \
916 917 918
  V(IndexedGetterCallback)                     \
  V(IndexedQueryCallback)                      \
  V(IndexedSetterCallback)                     \
919 920
  V(Invoke)                                    \
  V(InvokeApiFunction)                         \
921 922 923 924 925 926
  V(InvokeApiInterruptCallbacks)               \
  V(InvokeFunctionCallback)                    \
  V(JS_Execution)                              \
  V(Map_SetPrototype)                          \
  V(Map_TransitionToAccessorProperty)          \
  V(Map_TransitionToDataProperty)              \
927 928 929 930 931 932 933 934
  V(MessageListenerCallback)                   \
  V(NamedDefinerCallback)                      \
  V(NamedDeleterCallback)                      \
  V(NamedDescriptorCallback)                   \
  V(NamedEnumeratorCallback)                   \
  V(NamedGetterCallback)                       \
  V(NamedQueryCallback)                        \
  V(NamedSetterCallback)                       \
935
  V(Object_DeleteProperty)                     \
936
  V(ObjectVerify)                              \
937 938 939 940
  V(OptimizeCode)                              \
  V(ParseArrowFunctionLiteral)                 \
  V(ParseBackgroundArrowFunctionLiteral)       \
  V(ParseBackgroundFunctionLiteral)            \
941
  V(ParseBackgroundProgram)                    \
942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960
  V(ParseEval)                                 \
  V(ParseFunction)                             \
  V(ParseFunctionLiteral)                      \
  V(ParseProgram)                              \
  V(PreParseArrowFunctionLiteral)              \
  V(PreParseBackgroundArrowFunctionLiteral)    \
  V(PreParseBackgroundWithVariableResolution)  \
  V(PreParseWithVariableResolution)            \
  V(PropertyCallback)                          \
  V(PrototypeMap_TransitionToAccessorProperty) \
  V(PrototypeMap_TransitionToDataProperty)     \
  V(PrototypeObject_DeleteProperty)            \
  V(RecompileConcurrent)                       \
  V(RecompileSynchronous)                      \
  V(ReconfigureToDataProperty)                 \
  V(StringLengthGetter)                        \
  V(TestCounter1)                              \
  V(TestCounter2)                              \
  V(TestCounter3)
961

962 963 964
#define FOR_EACH_HANDLER_COUNTER(V)               \
  V(KeyedLoadIC_KeyedLoadSloppyArgumentsStub)     \
  V(KeyedLoadIC_LoadElementDH)                    \
965
  V(KeyedLoadIC_LoadIndexedInterceptorStub)       \
966 967 968 969 970 971
  V(KeyedLoadIC_LoadIndexedStringDH)              \
  V(KeyedLoadIC_SlowStub)                         \
  V(KeyedStoreIC_ElementsTransitionAndStoreStub)  \
  V(KeyedStoreIC_KeyedStoreSloppyArgumentsStub)   \
  V(KeyedStoreIC_SlowStub)                        \
  V(KeyedStoreIC_StoreElementStub)                \
972
  V(KeyedStoreIC_StoreFastElementStub)            \
973 974
  V(LoadGlobalIC_LoadScriptContextField)          \
  V(LoadGlobalIC_SlowStub)                        \
975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992
  V(LoadIC_FunctionPrototypeStub)                 \
  V(LoadIC_HandlerCacheHit_Accessor)              \
  V(LoadIC_LoadAccessorDH)                        \
  V(LoadIC_LoadAccessorFromPrototypeDH)           \
  V(LoadIC_LoadApiGetterFromPrototypeDH)          \
  V(LoadIC_LoadCallback)                          \
  V(LoadIC_LoadConstantDH)                        \
  V(LoadIC_LoadConstantFromPrototypeDH)           \
  V(LoadIC_LoadFieldDH)                           \
  V(LoadIC_LoadFieldFromPrototypeDH)              \
  V(LoadIC_LoadGlobalDH)                          \
  V(LoadIC_LoadGlobalFromPrototypeDH)             \
  V(LoadIC_LoadIntegerIndexedExoticDH)            \
  V(LoadIC_LoadInterceptorDH)                     \
  V(LoadIC_LoadInterceptorFromPrototypeDH)        \
  V(LoadIC_LoadNativeDataPropertyDH)              \
  V(LoadIC_LoadNativeDataPropertyFromPrototypeDH) \
  V(LoadIC_LoadNonexistentDH)                     \
993
  V(LoadIC_LoadNonMaskingInterceptorDH)           \
994 995 996 997 998 999
  V(LoadIC_LoadNormalDH)                          \
  V(LoadIC_LoadNormalFromPrototypeDH)             \
  V(LoadIC_NonReceiver)                           \
  V(LoadIC_Premonomorphic)                        \
  V(LoadIC_SlowStub)                              \
  V(LoadIC_StringLength)                          \
1000
  V(LoadIC_StringWrapperLength)                   \
1001
  V(StoreGlobalIC_SlowStub)                       \
1002
  V(StoreGlobalIC_StoreScriptContextField)        \
1003
  V(StoreGlobalIC_Premonomorphic)                 \
1004 1005 1006 1007
  V(StoreIC_HandlerCacheHit_Accessor)             \
  V(StoreIC_NonReceiver)                          \
  V(StoreIC_Premonomorphic)                       \
  V(StoreIC_SlowStub)                             \
1008 1009
  V(StoreIC_StoreAccessorDH)                      \
  V(StoreIC_StoreAccessorOnPrototypeDH)           \
1010
  V(StoreIC_StoreApiSetterOnPrototypeDH)          \
1011 1012 1013 1014
  V(StoreIC_StoreFieldDH)                         \
  V(StoreIC_StoreGlobalDH)                        \
  V(StoreIC_StoreGlobalTransitionDH)              \
  V(StoreIC_StoreInterceptorStub)                 \
1015 1016
  V(StoreIC_StoreNativeDataPropertyDH)            \
  V(StoreIC_StoreNativeDataPropertyOnPrototypeDH) \
1017
  V(StoreIC_StoreNormalDH)                        \
1018 1019
  V(StoreIC_StoreTransitionDH)                    \
  V(StoreInArrayLiteralIC_SlowStub)
1020

1021 1022
enum RuntimeCallCounterId {
#define CALL_RUNTIME_COUNTER(name) kGC_##name,
1023 1024
  FOR_EACH_GC_COUNTER(CALL_RUNTIME_COUNTER)
#undef CALL_RUNTIME_COUNTER
1025 1026
#define CALL_RUNTIME_COUNTER(name) k##name,
      FOR_EACH_MANUAL_COUNTER(CALL_RUNTIME_COUNTER)
1027
#undef CALL_RUNTIME_COUNTER
1028 1029
#define CALL_RUNTIME_COUNTER(name, nargs, ressize) kRuntime_##name,
          FOR_EACH_INTRINSIC(CALL_RUNTIME_COUNTER)
1030
#undef CALL_RUNTIME_COUNTER
1031 1032
#define CALL_BUILTIN_COUNTER(name) kBuiltin_##name,
              BUILTIN_LIST_C(CALL_BUILTIN_COUNTER)
1033
#undef CALL_BUILTIN_COUNTER
1034 1035
#define CALL_BUILTIN_COUNTER(name) kAPI_##name,
                  FOR_EACH_API_COUNTER(CALL_BUILTIN_COUNTER)
1036
#undef CALL_BUILTIN_COUNTER
1037 1038
#define CALL_BUILTIN_COUNTER(name) kHandler_##name,
                      FOR_EACH_HANDLER_COUNTER(CALL_BUILTIN_COUNTER)
1039
#undef CALL_BUILTIN_COUNTER
1040 1041
                          kNumberOfCounters
};
1042

1043
class RuntimeCallStats final {
1044 1045
 public:
  V8_EXPORT_PRIVATE RuntimeCallStats();
1046

1047 1048
  // Starting measuring the time for a function. This will establish the
  // connection to the parent counter for properly calculating the own times.
1049 1050
  V8_EXPORT_PRIVATE void Enter(RuntimeCallTimer* timer,
                               RuntimeCallCounterId counter_id);
1051

1052 1053 1054
  // Leave a scope for a measured runtime function. This will properly add
  // the time delta to the current_counter and subtract the delta from its
  // parent.
1055
  V8_EXPORT_PRIVATE void Leave(RuntimeCallTimer* timer);
1056

1057 1058
  // Set counter id for the innermost measurement. It can be used to refine
  // event kind when a runtime entry counter is too generic.
1059 1060
  V8_EXPORT_PRIVATE void CorrectCurrentCounterId(
      RuntimeCallCounterId counter_id);
1061

1062
  V8_EXPORT_PRIVATE void Reset();
1063 1064
  // Add all entries from another stats object.
  void Add(RuntimeCallStats* other);
1065
  V8_EXPORT_PRIVATE void Print(std::ostream& os);
1066
  V8_EXPORT_PRIVATE void Print();
1067
  V8_NOINLINE void Dump(v8::tracing::TracedValue* value);
1068

1069
  ThreadId thread_id() const { return thread_id_; }
1070
  RuntimeCallTimer* current_timer() { return current_timer_.Value(); }
1071
  RuntimeCallCounter* current_counter() { return current_counter_.Value(); }
1072
  bool InUse() { return in_use_; }
1073
  bool IsCalledOnTheSameThread();
1074

1075 1076 1077 1078 1079 1080 1081 1082 1083
  static const int kNumberOfCounters =
      static_cast<int>(RuntimeCallCounterId::kNumberOfCounters);
  RuntimeCallCounter* GetCounter(RuntimeCallCounterId counter_id) {
    return &counters_[static_cast<int>(counter_id)];
  }
  RuntimeCallCounter* GetCounter(int counter_id) {
    return &counters_[counter_id];
  }

1084
 private:
1085
  // Top of a stack of active timers.
1086
  base::AtomicValue<RuntimeCallTimer*> current_timer_;
1087 1088
  // Active counter object associated with current timer.
  base::AtomicValue<RuntimeCallCounter*> current_counter_;
1089
  // Used to track nested tracing scopes.
1090
  bool in_use_;
1091
  ThreadId thread_id_;
1092
  RuntimeCallCounter counters_[kNumberOfCounters];
1093 1094
};

1095 1096 1097 1098 1099 1100
class WorkerThreadRuntimeCallStats final {
 public:
  WorkerThreadRuntimeCallStats();
  ~WorkerThreadRuntimeCallStats();

  // Returns the TLS key associated with this WorkerThreadRuntimeCallStats.
1101
  base::Thread::LocalStorageKey GetKey();
1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112

  // Returns a new worker thread runtime call stats table managed by this
  // WorkerThreadRuntimeCallStats.
  RuntimeCallStats* NewTable();

  // Adds the counters from the worker thread tables to |main_call_stats|.
  void AddToMainTable(RuntimeCallStats* main_call_stats);

 private:
  base::Mutex mutex_;
  std::vector<std::unique_ptr<RuntimeCallStats>> tables_;
1113
  base::Optional<base::Thread::LocalStorageKey> tls_key_;
1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130
};

// Creating a WorkerThreadRuntimeCallStatsScope will provide a thread-local
// runtime call stats table, and will dump the table to an immediate trace event
// when it is destroyed.
class WorkerThreadRuntimeCallStatsScope final {
 public:
  WorkerThreadRuntimeCallStatsScope(
      WorkerThreadRuntimeCallStats* off_thread_stats);
  ~WorkerThreadRuntimeCallStatsScope();

  RuntimeCallStats* Get() const { return table_; }

 private:
  RuntimeCallStats* table_;
};

1131 1132
#define CHANGE_CURRENT_RUNTIME_COUNTER(runtime_call_stats, counter_id) \
  do {                                                                 \
1133 1134
    if (V8_UNLIKELY(FLAG_runtime_stats) && runtime_call_stats) {       \
      runtime_call_stats->CorrectCurrentCounterId(counter_id);         \
1135
    }                                                                  \
1136 1137
  } while (false)

1138 1139 1140 1141
#define TRACE_HANDLER_STATS(isolate, counter_name) \
  CHANGE_CURRENT_RUNTIME_COUNTER(                  \
      isolate->counters()->runtime_call_stats(),   \
      RuntimeCallCounterId::kHandler_##counter_name)
1142

1143 1144 1145 1146 1147
// A RuntimeCallTimerScopes wraps around a RuntimeCallTimer to measure the
// the time of C++ scope.
class RuntimeCallTimerScope {
 public:
  inline RuntimeCallTimerScope(Isolate* isolate,
1148
                               RuntimeCallCounterId counter_id);
1149 1150
  // This constructor is here just to avoid calling GetIsolate() when the
  // stats are disabled and the isolate is not directly available.
1151
  inline RuntimeCallTimerScope(Isolate* isolate, HeapObject heap_object,
1152
                               RuntimeCallCounterId counter_id);
1153
  inline RuntimeCallTimerScope(RuntimeCallStats* stats,
1154
                               RuntimeCallCounterId counter_id) {
1155 1156
    if (V8_LIKELY(!FLAG_runtime_stats || stats == nullptr)) return;
    stats_ = stats;
1157
    stats_->Enter(&timer_, counter_id);
1158
  }
1159 1160 1161

  inline ~RuntimeCallTimerScope() {
    if (V8_UNLIKELY(stats_ != nullptr)) {
1162
      stats_->Leave(&timer_);
1163 1164
    }
  }
1165 1166 1167 1168

 private:
  RuntimeCallStats* stats_ = nullptr;
  RuntimeCallTimer timer_;
1169 1170

  DISALLOW_COPY_AND_ASSIGN(RuntimeCallTimerScope);
1171 1172
};

1173 1174
#define HISTOGRAM_RANGE_LIST(HR)                                               \
  /* Generic range histograms: HR(name, caption, min, max, num_buckets) */     \
1175 1176 1177
  HR(background_marking, V8.GCBackgroundMarking, 0, 10000, 101)                \
  HR(background_scavenger, V8.GCBackgroundScavenger, 0, 10000, 101)            \
  HR(background_sweeping, V8.GCBackgroundSweeping, 0, 10000, 101)              \
1178 1179 1180 1181 1182 1183 1184
  HR(detached_context_age_in_gc, V8.DetachedContextAgeInGC, 0, 20, 21)         \
  HR(code_cache_reject_reason, V8.CodeCacheRejectReason, 1, 6, 6)              \
  HR(errors_thrown_per_context, V8.ErrorsThrownPerContext, 0, 200, 20)         \
  HR(debug_feature_usage, V8.DebugFeatureUsage, 1, 7, 7)                       \
  HR(incremental_marking_reason, V8.GCIncrementalMarkingReason, 0, 21, 22)     \
  HR(incremental_marking_sum, V8.GCIncrementalMarkingSum, 0, 10000, 101)       \
  HR(mark_compact_reason, V8.GCMarkCompactReason, 0, 21, 22)                   \
1185 1186 1187 1188 1189 1190 1191
  HR(gc_finalize_clear, V8.GCFinalizeMC.Clear, 0, 10000, 101)                  \
  HR(gc_finalize_epilogue, V8.GCFinalizeMC.Epilogue, 0, 10000, 101)            \
  HR(gc_finalize_evacuate, V8.GCFinalizeMC.Evacuate, 0, 10000, 101)            \
  HR(gc_finalize_finish, V8.GCFinalizeMC.Finish, 0, 10000, 101)                \
  HR(gc_finalize_mark, V8.GCFinalizeMC.Mark, 0, 10000, 101)                    \
  HR(gc_finalize_prologue, V8.GCFinalizeMC.Prologue, 0, 10000, 101)            \
  HR(gc_finalize_sweep, V8.GCFinalizeMC.Sweep, 0, 10000, 101)                  \
1192 1193
  HR(gc_scavenger_scavenge_main, V8.GCScavenger.ScavengeMain, 0, 10000, 101)   \
  HR(gc_scavenger_scavenge_roots, V8.GCScavenger.ScavengeRoots, 0, 10000, 101) \
1194
  HR(gc_mark_compactor, V8.GCMarkCompactor, 0, 10000, 101)                     \
1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226
  HR(scavenge_reason, V8.GCScavengeReason, 0, 21, 22)                          \
  HR(young_generation_handling, V8.GCYoungGenerationHandling, 0, 2, 3)         \
  /* Asm/Wasm. */                                                              \
  HR(wasm_functions_per_asm_module, V8.WasmFunctionsPerModule.asm, 1, 100000,  \
     51)                                                                       \
  HR(wasm_functions_per_wasm_module, V8.WasmFunctionsPerModule.wasm, 1,        \
     100000, 51)                                                               \
  HR(array_buffer_big_allocations, V8.ArrayBufferLargeAllocations, 0, 4096,    \
     13)                                                                       \
  HR(array_buffer_new_size_failures, V8.ArrayBufferNewSizeFailures, 0, 4096,   \
     13)                                                                       \
  HR(shared_array_allocations, V8.SharedArrayAllocationSizes, 0, 4096, 13)     \
  HR(wasm_asm_function_size_bytes, V8.WasmFunctionSizeBytes.asm, 1, GB, 51)    \
  HR(wasm_wasm_function_size_bytes, V8.WasmFunctionSizeBytes.wasm, 1, GB, 51)  \
  HR(wasm_asm_module_size_bytes, V8.WasmModuleSizeBytes.asm, 1, GB, 51)        \
  HR(wasm_wasm_module_size_bytes, V8.WasmModuleSizeBytes.wasm, 1, GB, 51)      \
  HR(wasm_asm_min_mem_pages_count, V8.WasmMinMemPagesCount.asm, 1, 2 << 16,    \
     51)                                                                       \
  HR(wasm_wasm_min_mem_pages_count, V8.WasmMinMemPagesCount.wasm, 1, 2 << 16,  \
     51)                                                                       \
  HR(wasm_wasm_max_mem_pages_count, V8.WasmMaxMemPagesCount.wasm, 1, 2 << 16,  \
     51)                                                                       \
  HR(wasm_decode_asm_module_peak_memory_bytes,                                 \
     V8.WasmDecodeModulePeakMemoryBytes.asm, 1, GB, 51)                        \
  HR(wasm_decode_wasm_module_peak_memory_bytes,                                \
     V8.WasmDecodeModulePeakMemoryBytes.wasm, 1, GB, 51)                       \
  HR(asm_wasm_translation_peak_memory_bytes,                                   \
     V8.AsmWasmTranslationPeakMemoryBytes, 1, GB, 51)                          \
  HR(wasm_compile_function_peak_memory_bytes,                                  \
     V8.WasmCompileFunctionPeakMemoryBytes, 1, GB, 51)                         \
  HR(asm_module_size_bytes, V8.AsmModuleSizeBytes, 1, GB, 51)                  \
  HR(asm_wasm_translation_throughput, V8.AsmWasmTranslationThroughput, 1, 100, \
1227 1228
     20)                                                                       \
  HR(wasm_lazy_compilation_throughput, V8.WasmLazyCompilationThroughput, 1,    \
1229
     10000, 50)                                                                \
1230 1231
  HR(compile_script_cache_behaviour, V8.CompileScript.CacheBehaviour, 0, 20,   \
     21)                                                                       \
1232
  HR(wasm_memory_allocation_result, V8.WasmMemoryAllocationResult, 0, 3, 4)    \
1233 1234
  HR(wasm_address_space_usage_mb, V8.WasmAddressSpaceUsageMiB, 0, 1 << 20,     \
     128)                                                                      \
1235
  HR(wasm_module_code_size_mb, V8.WasmModuleCodeSizeMiB, 0, 1024, 64)
1236

1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249
#define HISTOGRAM_TIMER_LIST(HT)                                               \
  /* Garbage collection timers. */                                             \
  HT(gc_context, V8.GCContext, 10000,                                          \
     MILLISECOND) /* GC context cleanup time */                                \
  HT(gc_idle_notification, V8.GCIdleNotification, 10000, MILLISECOND)          \
  HT(gc_incremental_marking, V8.GCIncrementalMarking, 10000, MILLISECOND)      \
  HT(gc_incremental_marking_start, V8.GCIncrementalMarkingStart, 10000,        \
     MILLISECOND)                                                              \
  HT(gc_incremental_marking_finalize, V8.GCIncrementalMarkingFinalize, 10000,  \
     MILLISECOND)                                                              \
  HT(gc_low_memory_notification, V8.GCLowMemoryNotification, 10000,            \
     MILLISECOND)                                                              \
  /* Compilation times. */                                                     \
1250 1251
  HT(collect_source_positions, V8.CollectSourcePositions, 1000000,             \
     MICROSECOND)                                                              \
1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262
  HT(compile, V8.CompileMicroSeconds, 1000000, MICROSECOND)                    \
  HT(compile_eval, V8.CompileEvalMicroSeconds, 1000000, MICROSECOND)           \
  /* Serialization as part of compilation (code caching) */                    \
  HT(compile_serialize, V8.CompileSerializeMicroSeconds, 100000, MICROSECOND)  \
  HT(compile_deserialize, V8.CompileDeserializeMicroSeconds, 1000000,          \
     MICROSECOND)                                                              \
  /* Total compilation time incl. caching/parsing */                           \
  HT(compile_script, V8.CompileScriptMicroSeconds, 1000000, MICROSECOND)       \
  /* Total JavaScript execution time (including callbacks and runtime calls */ \
  HT(execute, V8.Execute, 1000000, MICROSECOND)                                \
  /* Asm/Wasm */                                                               \
1263
  HT(asm_wasm_translation_time, V8.AsmWasmTranslationMicroSeconds, 1000000,    \
1264
     MICROSECOND)                                                              \
1265
  HT(wasm_lazy_compilation_time, V8.WasmLazyCompilationMicroSeconds, 1000000,  \
1266 1267
     MICROSECOND)                                                              \
  HT(wasm_execution_time, V8.WasmExecutionTimeMicroSeconds, 10000000,          \
1268
     MICROSECOND)
1269

1270
#define TIMED_HISTOGRAM_LIST(HT)                                               \
1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287
  /* Garbage collection timers. */                                             \
  HT(gc_compactor, V8.GCCompactor, 10000, MILLISECOND)                         \
  HT(gc_compactor_background, V8.GCCompactorBackground, 10000, MILLISECOND)    \
  HT(gc_compactor_foreground, V8.GCCompactorForeground, 10000, MILLISECOND)    \
  HT(gc_finalize, V8.GCFinalizeMC, 10000, MILLISECOND)                         \
  HT(gc_finalize_background, V8.GCFinalizeMCBackground, 10000, MILLISECOND)    \
  HT(gc_finalize_foreground, V8.GCFinalizeMCForeground, 10000, MILLISECOND)    \
  HT(gc_finalize_reduce_memory, V8.GCFinalizeMCReduceMemory, 10000,            \
     MILLISECOND)                                                              \
  HT(gc_finalize_reduce_memory_background,                                     \
     V8.GCFinalizeMCReduceMemoryBackground, 10000, MILLISECOND)                \
  HT(gc_finalize_reduce_memory_foreground,                                     \
     V8.GCFinalizeMCReduceMemoryForeground, 10000, MILLISECOND)                \
  HT(gc_scavenger, V8.GCScavenger, 10000, MILLISECOND)                         \
  HT(gc_scavenger_background, V8.GCScavengerBackground, 10000, MILLISECOND)    \
  HT(gc_scavenger_foreground, V8.GCScavengerForeground, 10000, MILLISECOND)    \
  /* Wasm timers. */                                                           \
1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303
  HT(wasm_decode_asm_module_time, V8.WasmDecodeModuleMicroSeconds.asm,         \
     1000000, MICROSECOND)                                                     \
  HT(wasm_decode_wasm_module_time, V8.WasmDecodeModuleMicroSeconds.wasm,       \
     1000000, MICROSECOND)                                                     \
  HT(wasm_decode_asm_function_time, V8.WasmDecodeFunctionMicroSeconds.asm,     \
     1000000, MICROSECOND)                                                     \
  HT(wasm_decode_wasm_function_time, V8.WasmDecodeFunctionMicroSeconds.wasm,   \
     1000000, MICROSECOND)                                                     \
  HT(wasm_compile_asm_module_time, V8.WasmCompileModuleMicroSeconds.asm,       \
     10000000, MICROSECOND)                                                    \
  HT(wasm_compile_wasm_module_time, V8.WasmCompileModuleMicroSeconds.wasm,     \
     10000000, MICROSECOND)                                                    \
  HT(wasm_compile_asm_function_time, V8.WasmCompileFunctionMicroSeconds.asm,   \
     1000000, MICROSECOND)                                                     \
  HT(wasm_compile_wasm_function_time, V8.WasmCompileFunctionMicroSeconds.wasm, \
     1000000, MICROSECOND)                                                     \
1304 1305
  HT(liftoff_compile_time, V8.LiftoffCompileMicroSeconds, 10000000,            \
     MICROSECOND)                                                              \
1306 1307 1308
  HT(wasm_instantiate_wasm_module_time,                                        \
     V8.WasmInstantiateModuleMicroSeconds.wasm, 10000000, MICROSECOND)         \
  HT(wasm_instantiate_asm_module_time,                                         \
1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326
     V8.WasmInstantiateModuleMicroSeconds.asm, 10000000, MICROSECOND)          \
  /* Total compilation time incl. caching/parsing for various cache states. */ \
  HT(compile_script_with_produce_cache,                                        \
     V8.CompileScriptMicroSeconds.ProduceCache, 1000000, MICROSECOND)          \
  HT(compile_script_with_isolate_cache_hit,                                    \
     V8.CompileScriptMicroSeconds.IsolateCacheHit, 1000000, MICROSECOND)       \
  HT(compile_script_with_consume_cache,                                        \
     V8.CompileScriptMicroSeconds.ConsumeCache, 1000000, MICROSECOND)          \
  HT(compile_script_consume_failed,                                            \
     V8.CompileScriptMicroSeconds.ConsumeCache.Failed, 1000000, MICROSECOND)   \
  HT(compile_script_no_cache_other,                                            \
     V8.CompileScriptMicroSeconds.NoCache.Other, 1000000, MICROSECOND)         \
  HT(compile_script_no_cache_because_inline_script,                            \
     V8.CompileScriptMicroSeconds.NoCache.InlineScript, 1000000, MICROSECOND)  \
  HT(compile_script_no_cache_because_script_too_small,                         \
     V8.CompileScriptMicroSeconds.NoCache.ScriptTooSmall, 1000000,             \
     MICROSECOND)                                                              \
  HT(compile_script_no_cache_because_cache_too_cold,                           \
1327 1328
     V8.CompileScriptMicroSeconds.NoCache.CacheTooCold, 1000000, MICROSECOND)  \
  HT(compile_script_on_background,                                             \
1329
     V8.CompileScriptMicroSeconds.BackgroundThread, 1000000, MICROSECOND)      \
1330
  HT(compile_function_on_background,                                           \
1331
     V8.CompileFunctionMicroSeconds.BackgroundThread, 1000000, MICROSECOND)
1332

1333
#define AGGREGATABLE_HISTOGRAM_TIMER_LIST(AHT) \
yangguo's avatar
yangguo committed
1334
  AHT(compile_lazy, V8.CompileLazyMicroSeconds)
1335

1336 1337 1338
#define HISTOGRAM_PERCENTAGE_LIST(HP)                                          \
  /* Heap fragmentation. */                                                    \
  HP(external_fragmentation_total, V8.MemoryExternalFragmentationTotal)        \
1339
  HP(external_fragmentation_old_space, V8.MemoryExternalFragmentationOldSpace) \
1340 1341 1342
  HP(external_fragmentation_code_space,                                        \
     V8.MemoryExternalFragmentationCodeSpace)                                  \
  HP(external_fragmentation_map_space, V8.MemoryExternalFragmentationMapSpace) \
1343
  HP(external_fragmentation_lo_space, V8.MemoryExternalFragmentationLoSpace)
1344

1345
// Note: These use Histogram with options (min=1000, max=500000, buckets=50).
1346 1347 1348 1349 1350 1351 1352
#define HISTOGRAM_LEGACY_MEMORY_LIST(HM)                                      \
  HM(heap_sample_total_committed, V8.MemoryHeapSampleTotalCommitted)          \
  HM(heap_sample_total_used, V8.MemoryHeapSampleTotalUsed)                    \
  HM(heap_sample_map_space_committed, V8.MemoryHeapSampleMapSpaceCommitted)   \
  HM(heap_sample_code_space_committed, V8.MemoryHeapSampleCodeSpaceCommitted) \
  HM(heap_sample_maximum_committed, V8.MemoryHeapSampleMaximumCommitted)

1353 1354 1355 1356 1357
// WARNING: STATS_COUNTER_LIST_* is a very large macro that is causing MSVC
// Intellisense to crash.  It was broken into two macros (each of length 40
// lines) rather than one macro (of length about 80 lines) to work around
// this problem.  Please avoid using recursive macros of this length when
// possible.
1358 1359 1360 1361 1362
#define STATS_COUNTER_LIST_1(SC)                                    \
  /* Global Handle Count*/                                          \
  SC(global_handles, V8.GlobalHandles)                              \
  /* OS Memory allocated */                                         \
  SC(memory_allocated, V8.OsMemoryAllocated)                        \
cbruni's avatar
cbruni committed
1363 1364 1365
  SC(maps_normalized, V8.MapsNormalized)                            \
  SC(maps_created, V8.MapsCreated)                                  \
  SC(elements_transitions, V8.ObjectElementsTransitions)            \
1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395
  SC(props_to_dictionary, V8.ObjectPropertiesToDictionary)          \
  SC(elements_to_dictionary, V8.ObjectElementsToDictionary)         \
  SC(alive_after_last_gc, V8.AliveAfterLastGC)                      \
  SC(objs_since_last_young, V8.ObjsSinceLastYoung)                  \
  SC(objs_since_last_full, V8.ObjsSinceLastFull)                    \
  SC(string_table_capacity, V8.StringTableCapacity)                 \
  SC(number_of_symbols, V8.NumberOfSymbols)                         \
  SC(inlined_copied_elements, V8.InlinedCopiedElements)             \
  SC(compilation_cache_hits, V8.CompilationCacheHits)               \
  SC(compilation_cache_misses, V8.CompilationCacheMisses)           \
  /* Amount of evaled source code. */                               \
  SC(total_eval_size, V8.TotalEvalSize)                             \
  /* Amount of loaded source code. */                               \
  SC(total_load_size, V8.TotalLoadSize)                             \
  /* Amount of parsed source code. */                               \
  SC(total_parse_size, V8.TotalParseSize)                           \
  /* Amount of source code skipped over using preparsing. */        \
  SC(total_preparse_skipped, V8.TotalPreparseSkipped)               \
  /* Amount of compiled source code. */                             \
  SC(total_compile_size, V8.TotalCompileSize)                       \
  /* Amount of source code compiled with the full codegen. */       \
  SC(total_full_codegen_source_size, V8.TotalFullCodegenSourceSize) \
  /* Number of contexts created from scratch. */                    \
  SC(contexts_created_from_scratch, V8.ContextsCreatedFromScratch)  \
  /* Number of contexts created by partial snapshot. */             \
  SC(contexts_created_by_snapshot, V8.ContextsCreatedBySnapshot)    \
  /* Number of code objects found from pc. */                       \
  SC(pc_to_code, V8.PcToCode)                                       \
  SC(pc_to_code_cached, V8.PcToCodeCached)                          \
  /* The store-buffer implementation of the write barrier. */       \
1396 1397
  SC(store_buffer_overflows, V8.StoreBufferOverflows)

1398 1399 1400 1401 1402 1403 1404 1405 1406
#define STATS_COUNTER_LIST_2(SC)                                               \
  /* Amount of (JS) compiled code. */                                          \
  SC(total_compiled_code_size, V8.TotalCompiledCodeSize)                       \
  SC(gc_compactor_caused_by_request, V8.GCCompactorCausedByRequest)            \
  SC(gc_compactor_caused_by_promoted_data, V8.GCCompactorCausedByPromotedData) \
  SC(gc_compactor_caused_by_oldspace_exhaustion,                               \
     V8.GCCompactorCausedByOldspaceExhaustion)                                 \
  SC(gc_last_resort_from_js, V8.GCLastResortFromJS)                            \
  SC(gc_last_resort_from_handles, V8.GCLastResortFromHandles)                  \
cbruni's avatar
cbruni committed
1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418
  SC(ic_keyed_load_generic_smi, V8.ICKeyedLoadGenericSmi)                      \
  SC(ic_keyed_load_generic_symbol, V8.ICKeyedLoadGenericSymbol)                \
  SC(ic_keyed_load_generic_slow, V8.ICKeyedLoadGenericSlow)                    \
  SC(ic_named_load_global_stub, V8.ICNamedLoadGlobalStub)                      \
  SC(ic_store_normal_miss, V8.ICStoreNormalMiss)                               \
  SC(ic_store_normal_hit, V8.ICStoreNormalHit)                                 \
  SC(ic_binary_op_miss, V8.ICBinaryOpMiss)                                     \
  SC(ic_compare_miss, V8.ICCompareMiss)                                        \
  SC(ic_call_miss, V8.ICCallMiss)                                              \
  SC(ic_keyed_call_miss, V8.ICKeyedCallMiss)                                   \
  SC(ic_store_miss, V8.ICStoreMiss)                                            \
  SC(ic_keyed_store_miss, V8.ICKeyedStoreMiss)                                 \
1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434
  SC(cow_arrays_converted, V8.COWArraysConverted)                              \
  SC(constructed_objects, V8.ConstructedObjects)                               \
  SC(constructed_objects_runtime, V8.ConstructedObjectsRuntime)                \
  SC(megamorphic_stub_cache_probes, V8.MegamorphicStubCacheProbes)             \
  SC(megamorphic_stub_cache_misses, V8.MegamorphicStubCacheMisses)             \
  SC(megamorphic_stub_cache_updates, V8.MegamorphicStubCacheUpdates)           \
  SC(enum_cache_hits, V8.EnumCacheHits)                                        \
  SC(enum_cache_misses, V8.EnumCacheMisses)                                    \
  SC(fast_new_closure_total, V8.FastNewClosureTotal)                           \
  SC(string_add_runtime, V8.StringAddRuntime)                                  \
  SC(string_add_native, V8.StringAddNative)                                    \
  SC(string_add_runtime_ext_to_one_byte, V8.StringAddRuntimeExtToOneByte)      \
  SC(sub_string_runtime, V8.SubStringRuntime)                                  \
  SC(sub_string_native, V8.SubStringNative)                                    \
  SC(regexp_entry_runtime, V8.RegExpEntryRuntime)                              \
  SC(regexp_entry_native, V8.RegExpEntryNative)                                \
cbruni's avatar
cbruni committed
1435 1436 1437
  SC(math_exp_runtime, V8.MathExpRuntime)                                      \
  SC(math_log_runtime, V8.MathLogRuntime)                                      \
  SC(math_pow_runtime, V8.MathPowRuntime)                                      \
1438 1439
  SC(stack_interrupts, V8.StackInterrupts)                                     \
  SC(runtime_profiler_ticks, V8.RuntimeProfilerTicks)                          \
1440
  SC(runtime_calls, V8.RuntimeCalls)                                           \
1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451
  SC(bounds_checks_eliminated, V8.BoundsChecksEliminated)                      \
  SC(bounds_checks_hoisted, V8.BoundsChecksHoisted)                            \
  SC(soft_deopts_requested, V8.SoftDeoptsRequested)                            \
  SC(soft_deopts_inserted, V8.SoftDeoptsInserted)                              \
  SC(soft_deopts_executed, V8.SoftDeoptsExecuted)                              \
  /* Number of write barriers in generated code. */                            \
  SC(write_barriers_dynamic, V8.WriteBarriersDynamic)                          \
  SC(write_barriers_static, V8.WriteBarriersStatic)                            \
  SC(new_space_bytes_available, V8.MemoryNewSpaceBytesAvailable)               \
  SC(new_space_bytes_committed, V8.MemoryNewSpaceBytesCommitted)               \
  SC(new_space_bytes_used, V8.MemoryNewSpaceBytesUsed)                         \
1452 1453 1454
  SC(old_space_bytes_available, V8.MemoryOldSpaceBytesAvailable)               \
  SC(old_space_bytes_committed, V8.MemoryOldSpaceBytesCommitted)               \
  SC(old_space_bytes_used, V8.MemoryOldSpaceBytesUsed)                         \
1455 1456 1457 1458 1459 1460 1461 1462
  SC(code_space_bytes_available, V8.MemoryCodeSpaceBytesAvailable)             \
  SC(code_space_bytes_committed, V8.MemoryCodeSpaceBytesCommitted)             \
  SC(code_space_bytes_used, V8.MemoryCodeSpaceBytesUsed)                       \
  SC(map_space_bytes_available, V8.MemoryMapSpaceBytesAvailable)               \
  SC(map_space_bytes_committed, V8.MemoryMapSpaceBytesCommitted)               \
  SC(map_space_bytes_used, V8.MemoryMapSpaceBytesUsed)                         \
  SC(lo_space_bytes_available, V8.MemoryLoSpaceBytesAvailable)                 \
  SC(lo_space_bytes_committed, V8.MemoryLoSpaceBytesCommitted)                 \
1463
  SC(lo_space_bytes_used, V8.MemoryLoSpaceBytesUsed)                           \
1464 1465 1466
  /* Total code size (including metadata) of baseline code or bytecode. */     \
  SC(total_baseline_code_size, V8.TotalBaselineCodeSize)                       \
  /* Total count of functions compiled using the baseline compiler. */         \
1467 1468
  SC(total_baseline_compile_count, V8.TotalBaselineCompileCount)

1469 1470 1471 1472 1473 1474
#define STATS_COUNTER_TS_LIST(SC)                                    \
  SC(wasm_generated_code_size, V8.WasmGeneratedCodeBytes)            \
  SC(wasm_reloc_size, V8.WasmRelocBytes)                             \
  SC(wasm_lazily_compiled_functions, V8.WasmLazilyCompiledFunctions) \
  SC(liftoff_compiled_functions, V8.LiftoffCompiledFunctions)        \
  SC(liftoff_unsupported_functions, V8.LiftoffUnsupportedFunctions)
1475 1476

// This file contains all the v8 counters that are in use.
1477
class Counters : public std::enable_shared_from_this<Counters> {
1478
 public:
1479 1480
  explicit Counters(Isolate* isolate);

1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497
  // Register an application-defined function for recording
  // subsequent counter statistics. Note: Must be called on the main
  // thread.
  void ResetCounterFunction(CounterLookupCallback f);

  // Register an application-defined function to create histograms for
  // recording subsequent histogram samples. Note: Must be called on
  // the main thread.
  void ResetCreateHistogramFunction(CreateHistogramCallback f);

  // Register an application-defined function to add a sample
  // to a histogram. Will be used in all subsequent sample additions.
  // Note: Must be called on the main thread.
  void SetAddHistogramSampleFunction(AddHistogramSampleCallback f) {
    stats_table_.SetAddHistogramSampleFunction(f);
  }

1498 1499 1500 1501 1502
#define HR(name, caption, min, max, num_buckets) \
  Histogram* name() { return &name##_; }
  HISTOGRAM_RANGE_LIST(HR)
#undef HR

yangguo's avatar
yangguo committed
1503
#define HT(name, caption, max, res) \
1504 1505 1506 1507
  HistogramTimer* name() { return &name##_; }
  HISTOGRAM_TIMER_LIST(HT)
#undef HT

1508 1509 1510 1511 1512
#define HT(name, caption, max, res) \
  TimedHistogram* name() { return &name##_; }
  TIMED_HISTOGRAM_LIST(HT)
#undef HT

1513 1514 1515 1516 1517
#define AHT(name, caption) \
  AggregatableHistogramTimer* name() { return &name##_; }
  AGGREGATABLE_HISTOGRAM_TIMER_LIST(AHT)
#undef AHT

1518 1519 1520 1521 1522 1523 1524
#define HP(name, caption) \
  Histogram* name() { return &name##_; }
  HISTOGRAM_PERCENTAGE_LIST(HP)
#undef HP

#define HM(name, caption) \
  Histogram* name() { return &name##_; }
1525
  HISTOGRAM_LEGACY_MEMORY_LIST(HM)
1526 1527 1528 1529 1530 1531 1532 1533
#undef HM

#define SC(name, caption) \
  StatsCounter* name() { return &name##_; }
  STATS_COUNTER_LIST_1(SC)
  STATS_COUNTER_LIST_2(SC)
#undef SC

1534 1535 1536 1537 1538 1539
#define SC(name, caption) \
  StatsCounterThreadSafe* name() { return &name##_; }
  STATS_COUNTER_TS_LIST(SC)
#undef SC

  // clang-format off
1540
  enum Id {
yangguo's avatar
yangguo committed
1541
#define RATE_ID(name, caption, max, res) k_##name,
1542
    HISTOGRAM_TIMER_LIST(RATE_ID)
1543
    TIMED_HISTOGRAM_LIST(RATE_ID)
1544
#undef RATE_ID
1545 1546 1547
#define AGGREGATABLE_ID(name, caption) k_##name,
    AGGREGATABLE_HISTOGRAM_TIMER_LIST(AGGREGATABLE_ID)
#undef AGGREGATABLE_ID
1548 1549 1550 1551
#define PERCENTAGE_ID(name, caption) k_##name,
    HISTOGRAM_PERCENTAGE_LIST(PERCENTAGE_ID)
#undef PERCENTAGE_ID
#define MEMORY_ID(name, caption) k_##name,
1552
    HISTOGRAM_LEGACY_MEMORY_LIST(MEMORY_ID)
1553 1554 1555 1556
#undef MEMORY_ID
#define COUNTER_ID(name, caption) k_##name,
    STATS_COUNTER_LIST_1(COUNTER_ID)
    STATS_COUNTER_LIST_2(COUNTER_ID)
1557
    STATS_COUNTER_TS_LIST(COUNTER_ID)
1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571
#undef COUNTER_ID
#define COUNTER_ID(name) kCountOf##name, kSizeOf##name,
    INSTANCE_TYPE_LIST(COUNTER_ID)
#undef COUNTER_ID
#define COUNTER_ID(name) kCountOfCODE_TYPE_##name, \
    kSizeOfCODE_TYPE_##name,
    CODE_KIND_LIST(COUNTER_ID)
#undef COUNTER_ID
#define COUNTER_ID(name) kCountOfFIXED_ARRAY__##name, \
    kSizeOfFIXED_ARRAY__##name,
    FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(COUNTER_ID)
#undef COUNTER_ID
    stats_counter_count
  };
1572
  // clang-format on
1573

1574
  RuntimeCallStats* runtime_call_stats() { return &runtime_call_stats_; }
1575

1576 1577 1578 1579
  WorkerThreadRuntimeCallStats* worker_thread_runtime_call_stats() {
    return &worker_thread_runtime_call_stats_;
  }

1580
 private:
1581 1582 1583 1584 1585
  friend class StatsTable;
  friend class StatsCounterBase;
  friend class Histogram;
  friend class HistogramTimer;

1586 1587 1588
  Isolate* isolate_;
  StatsTable stats_table_;

1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602
  int* FindLocation(const char* name) {
    return stats_table_.FindLocation(name);
  }

  void* CreateHistogram(const char* name, int min, int max, size_t buckets) {
    return stats_table_.CreateHistogram(name, min, max, buckets);
  }

  void AddHistogramSample(void* histogram, int sample) {
    stats_table_.AddHistogramSample(histogram, sample);
  }

  Isolate* isolate() { return isolate_; }

1603 1604 1605 1606
#define HR(name, caption, min, max, num_buckets) Histogram name##_;
  HISTOGRAM_RANGE_LIST(HR)
#undef HR

yangguo's avatar
yangguo committed
1607
#define HT(name, caption, max, res) HistogramTimer name##_;
1608 1609 1610
  HISTOGRAM_TIMER_LIST(HT)
#undef HT

1611 1612 1613 1614
#define HT(name, caption, max, res) TimedHistogram name##_;
  TIMED_HISTOGRAM_LIST(HT)
#undef HT

1615 1616 1617 1618 1619
#define AHT(name, caption) \
  AggregatableHistogramTimer name##_;
  AGGREGATABLE_HISTOGRAM_TIMER_LIST(AHT)
#undef AHT

1620 1621 1622 1623 1624 1625 1626
#define HP(name, caption) \
  Histogram name##_;
  HISTOGRAM_PERCENTAGE_LIST(HP)
#undef HP

#define HM(name, caption) \
  Histogram name##_;
1627
  HISTOGRAM_LEGACY_MEMORY_LIST(HM)
1628 1629 1630 1631 1632 1633 1634 1635
#undef HM

#define SC(name, caption) \
  StatsCounter name##_;
  STATS_COUNTER_LIST_1(SC)
  STATS_COUNTER_LIST_2(SC)
#undef SC

1636 1637 1638 1639
#define SC(name, caption) StatsCounterThreadSafe name##_;
  STATS_COUNTER_TS_LIST(SC)
#undef SC

1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657
#define SC(name) \
  StatsCounter size_of_##name##_; \
  StatsCounter count_of_##name##_;
  INSTANCE_TYPE_LIST(SC)
#undef SC

#define SC(name) \
  StatsCounter size_of_CODE_TYPE_##name##_; \
  StatsCounter count_of_CODE_TYPE_##name##_;
  CODE_KIND_LIST(SC)
#undef SC

#define SC(name) \
  StatsCounter size_of_FIXED_ARRAY_##name##_; \
  StatsCounter count_of_FIXED_ARRAY_##name##_;
  FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(SC)
#undef SC

1658
  RuntimeCallStats runtime_call_stats_;
1659
  WorkerThreadRuntimeCallStats worker_thread_runtime_call_stats_;
1660

1661 1662 1663
  DISALLOW_IMPLICIT_CONSTRUCTORS(Counters);
};

1664 1665 1666 1667 1668 1669 1670 1671
void HistogramTimer::Start() {
  TimedHistogram::Start(&timer_, counters()->isolate());
}

void HistogramTimer::Stop() {
  TimedHistogram::Stop(&timer_, counters()->isolate());
}

1672 1673
RuntimeCallTimerScope::RuntimeCallTimerScope(Isolate* isolate,
                                             RuntimeCallCounterId counter_id) {
1674 1675
  if (V8_LIKELY(!FLAG_runtime_stats)) return;
  stats_ = isolate->counters()->runtime_call_stats();
1676
  stats_->Enter(&timer_, counter_id);
1677 1678
}

1679 1680
}  // namespace internal
}  // namespace v8
1681 1682

#endif  // V8_COUNTERS_H_