counters.h 27.1 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
#ifndef V8_LOGGING_COUNTERS_H_
#define V8_LOGGING_COUNTERS_H_
7

8 9
#include <memory>

10
#include "include/v8.h"
11
#include "src/base/atomic-utils.h"
12
#include "src/base/optional.h"
13
#include "src/base/platform/elapsed-timer.h"
14
#include "src/base/platform/time.h"
15
#include "src/common/globals.h"
16
#include "src/execution/isolate.h"
17
#include "src/logging/counters-definitions.h"
18
#include "src/logging/runtime-call-stats.h"
19
#include "src/objects/objects.h"
20
#include "src/utils/allocation.h"
21

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

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

29 30
class Counters;

31
class StatsTable {
32
 public:
33 34 35
  StatsTable(const StatsTable&) = delete;
  StatsTable& operator=(const StatsTable&) = delete;

36 37
  // Register an application-defined function for recording
  // subsequent counter statistics.
38
  void SetCounterFunction(CounterLookupCallback f);
39

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

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

52
  bool HasCounterFunction() const { return lookup_function_ != nullptr; }
53 54

  // Lookup the location of a counter by name.  If the lookup
55
  // is successful, returns a non-nullptr pointer for writing the
56 57 58 59
  // 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.
60
  int* FindLocation(const char* name) {
61
    if (!lookup_function_) return nullptr;
62 63 64
    return lookup_function_(name);
  }

65
  // Create a histogram by name. If the create is successful,
66
  // returns a non-nullptr pointer for use with AddHistogramSample
67 68 69
  // 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.
70
  void* CreateHistogram(const char* name, int min, int max, size_t buckets) {
71
    if (!create_histogram_function_) return nullptr;
72 73 74 75 76
    return create_histogram_function_(name, min, max, buckets);
  }

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

82
 private:
83 84
  friend class Counters;

85
  explicit StatsTable(Counters* counters);
86 87 88 89

  CounterLookupCallback lookup_function_;
  CreateHistogramCallback create_histogram_function_;
  AddHistogramSampleCallback add_histogram_sample_function_;
90 91
};

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

99
  StatsCounterBase() = default;
100 101 102
  StatsCounterBase(Counters* counters, const char* name)
      : counters_(counters), name_(name), ptr_(nullptr) {}

103 104 105 106 107 108
  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; }

109
  V8_EXPORT_PRIVATE int* FindLocationInStatsTable() const;
110 111
};

112 113 114 115 116 117 118
// 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
119 120
// thread-specific, this class cannot be shared across threads. Note: This
// class is not thread safe.
121
class StatsCounter : public StatsCounterBase {
122
 public:
123 124
  // Sets the counter to a specific value.
  void Set(int value) {
125
    if (int* loc = GetPtr()) SetLoc(loc, value);
126 127 128 129
  }

  // Increments the counter.
  void Increment() {
130
    if (int* loc = GetPtr()) IncrementLoc(loc);
131 132 133
  }

  void Increment(int value) {
134
    if (int* loc = GetPtr()) IncrementLoc(loc, value);
135 136 137 138
  }

  // Decrements the counter.
  void Decrement() {
139
    if (int* loc = GetPtr()) DecrementLoc(loc);
140 141 142
  }

  void Decrement(int value) {
143
    if (int* loc = GetPtr()) DecrementLoc(loc, value);
144 145 146 147
  }

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

  // 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();
155
    DCHECK_NOT_NULL(loc);
156 157 158
    return loc;
  }

159 160 161
 private:
  friend class Counters;

162
  StatsCounter() = default;
163 164 165
  StatsCounter(Counters* counters, const char* name)
      : StatsCounterBase(counters, name), lookup_done_(false) {}

166 167 168
  // Reset the cached internal pointer.
  void Reset() { lookup_done_ = false; }

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

177 178 179
  bool lookup_done_;
};

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

194
 private:
195 196 197 198
  friend class Counters;

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

200 201 202
  base::Mutex mutex_;

  DISALLOW_IMPLICIT_CONSTRUCTORS(StatsCounterThreadSafe);
203 204
};

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

212
  // Returns true if this histogram is enabled.
213
  bool Enabled() { return histogram_ != nullptr; }
214

215 216
  const char* name() { return name_; }

217 218 219 220
  int min() const { return min_; }
  int max() const { return max_; }
  int num_buckets() const { return num_buckets_; }

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

227
 protected:
228
  Histogram() = default;
229 230 231 232 233 234 235
  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),
236 237 238
        counters_(counters) {
    DCHECK(counters_);
  }
239

240
  Counters* counters() const { return counters_; }
241

242 243 244
  // Reset the cached internal pointer.
  void Reset() { histogram_ = CreateHistogram(); }

245
 private:
246 247
  friend class Counters;

248
  void* CreateHistogram() const;
249

250 251 252 253 254
  const char* name_;
  int min_;
  int max_;
  int num_buckets_;
  void* histogram_;
255
  Counters* counters_;
256
};
257

258 259 260 261
enum class HistogramTimerResolution { MILLISECOND, MICROSECOND };

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

267
  // Stop the timer and record the results. Log if isolate non-null.
268
  V8_EXPORT_PRIVATE void Stop(base::ElapsedTimer* timer, Isolate* isolate);
269

270 271 272 273
  // 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);

274 275 276
  // Add a single sample to this histogram.
  void AddTimedSample(base::TimeDelta sample);

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
  void AddTimeSample();
};

// Helper class for scoping a TimedHistogram.
291
class V8_NODISCARD TimedHistogramScope {
292 293 294 295 296 297
 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
enum class OptionalTimedHistogramScopeMode { TAKE_TIME, DONT_TAKE_TIME };

// Helper class for scoping a TimedHistogram.
// It will not take time for mode = DONT_TAKE_TIME.
313
class V8_NODISCARD OptionalTimedHistogramScope {
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
 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
// 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.
373
class V8_NODISCARD LazyTimedHistogramScope {
374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
 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

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

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

411
 private:
412 413
  friend class Counters;

414
  base::ElapsedTimer timer_;
415

416
  HistogramTimer() = default;
417 418
};

419
// Helper class for scoping a HistogramTimer.
420 421 422 423
// 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|.
424
class V8_NODISCARD HistogramTimerScope {
425
 public:
426 427 428
  explicit HistogramTimerScope(HistogramTimer* timer,
                               bool allow_nesting = false)
#ifdef DEBUG
429
      : timer_(timer), skipped_timer_start_(false) {
430 431 432 433 434
    if (timer_->timer()->IsStarted() && allow_nesting) {
      skipped_timer_start_ = true;
    } else {
      timer_->Start();
    }
435
  }
436 437
#else
      : timer_(timer) {
438
    timer_->Start();
439
  }
440
#endif
441
  ~HistogramTimerScope() {
442 443 444 445 446
#ifdef DEBUG
    if (!skipped_timer_start_) {
      timer_->Stop();
    }
#else
447
    timer_->Stop();
448
#endif
449
  }
450

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

458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474
// 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(); }
475 476 477 478 479 480 481
  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()));
    }
  }
482 483 484 485 486

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

 private:
487 488
  friend class Counters;

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

494 495 496
  base::TimeDelta time_;
};

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

 private:
  AggregatableHistogramTimer* histogram_;
};

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

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

527 528 529 530 531 532 533 534 535 536 537 538
// 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:
539
  // Note: public for testing purposes only.
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556
  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:
557 558 559 560 561 562 563 564
  friend class Counters;

  AggregatedMemoryHistogram()
      : is_initialized_(false),
        start_ms_(0.0),
        last_ms_(0.0),
        aggregate_value_(0.0),
        last_value_(0.0),
565
        backing_histogram_(nullptr) {}
566
  double Aggregate(double current_ms, double current_value);
567

568 569 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
  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);
}

645
// This file contains all the v8 counters that are in use.
646
class Counters : public std::enable_shared_from_this<Counters> {
647
 public:
648 649
  explicit Counters(Isolate* isolate);

650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666
  // 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);
  }

667 668 669 670 671
#define HR(name, caption, min, max, num_buckets) \
  Histogram* name() { return &name##_; }
  HISTOGRAM_RANGE_LIST(HR)
#undef HR

yangguo's avatar
yangguo committed
672
#define HT(name, caption, max, res) \
673 674 675 676
  HistogramTimer* name() { return &name##_; }
  HISTOGRAM_TIMER_LIST(HT)
#undef HT

677 678 679 680 681
#define HT(name, caption, max, res) \
  TimedHistogram* name() { return &name##_; }
  TIMED_HISTOGRAM_LIST(HT)
#undef HT

682 683 684 685 686
#define AHT(name, caption) \
  AggregatableHistogramTimer* name() { return &name##_; }
  AGGREGATABLE_HISTOGRAM_TIMER_LIST(AHT)
#undef AHT

687 688 689 690 691 692 693
#define HP(name, caption) \
  Histogram* name() { return &name##_; }
  HISTOGRAM_PERCENTAGE_LIST(HP)
#undef HP

#define HM(name, caption) \
  Histogram* name() { return &name##_; }
694
  HISTOGRAM_LEGACY_MEMORY_LIST(HM)
695 696 697 698 699 700
#undef HM

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

704 705 706 707 708 709
#define SC(name, caption) \
  StatsCounterThreadSafe* name() { return &name##_; }
  STATS_COUNTER_TS_LIST(SC)
#undef SC

  // clang-format off
710
  enum Id {
yangguo's avatar
yangguo committed
711
#define RATE_ID(name, caption, max, res) k_##name,
712
    HISTOGRAM_TIMER_LIST(RATE_ID)
713
    TIMED_HISTOGRAM_LIST(RATE_ID)
714
#undef RATE_ID
715 716 717
#define AGGREGATABLE_ID(name, caption) k_##name,
    AGGREGATABLE_HISTOGRAM_TIMER_LIST(AGGREGATABLE_ID)
#undef AGGREGATABLE_ID
718 719 720 721
#define PERCENTAGE_ID(name, caption) k_##name,
    HISTOGRAM_PERCENTAGE_LIST(PERCENTAGE_ID)
#undef PERCENTAGE_ID
#define MEMORY_ID(name, caption) k_##name,
722
    HISTOGRAM_LEGACY_MEMORY_LIST(MEMORY_ID)
723 724 725 726
#undef MEMORY_ID
#define COUNTER_ID(name, caption) k_##name,
    STATS_COUNTER_LIST_1(COUNTER_ID)
    STATS_COUNTER_LIST_2(COUNTER_ID)
727
    STATS_COUNTER_TS_LIST(COUNTER_ID)
728
    STATS_COUNTER_NATIVE_CODE_LIST(COUNTER_ID)
729 730 731 732 733 734 735 736 737 738 739 740 741 742
#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
  };
743
  // clang-format on
744

745
#ifdef V8_RUNTIME_CALL_STATS
746
  RuntimeCallStats* runtime_call_stats() { return &runtime_call_stats_; }
747

748 749 750
  WorkerThreadRuntimeCallStats* worker_thread_runtime_call_stats() {
    return &worker_thread_runtime_call_stats_;
  }
751 752 753 754 755 756 757
#else   // V8_RUNTIME_CALL_STATS
  RuntimeCallStats* runtime_call_stats() { return nullptr; }

  WorkerThreadRuntimeCallStats* worker_thread_runtime_call_stats() {
    return nullptr;
  }
#endif  // V8_RUNTIME_CALL_STATS
758

759
 private:
760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778
  friend class StatsTable;
  friend class StatsCounterBase;
  friend class Histogram;
  friend class HistogramTimer;

  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_; }

779 780 781 782
#define HR(name, caption, min, max, num_buckets) Histogram name##_;
  HISTOGRAM_RANGE_LIST(HR)
#undef HR

yangguo's avatar
yangguo committed
783
#define HT(name, caption, max, res) HistogramTimer name##_;
784 785 786
  HISTOGRAM_TIMER_LIST(HT)
#undef HT

787 788 789 790
#define HT(name, caption, max, res) TimedHistogram name##_;
  TIMED_HISTOGRAM_LIST(HT)
#undef HT

791
#define AHT(name, caption) AggregatableHistogramTimer name##_;
792 793 794
  AGGREGATABLE_HISTOGRAM_TIMER_LIST(AHT)
#undef AHT

795
#define HP(name, caption) Histogram name##_;
796 797 798
  HISTOGRAM_PERCENTAGE_LIST(HP)
#undef HP

799
#define HM(name, caption) Histogram name##_;
800
  HISTOGRAM_LEGACY_MEMORY_LIST(HM)
801 802
#undef HM

803
#define SC(name, caption) StatsCounter name##_;
804 805
  STATS_COUNTER_LIST_1(SC)
  STATS_COUNTER_LIST_2(SC)
806
  STATS_COUNTER_NATIVE_CODE_LIST(SC)
807 808
#undef SC

809 810 811 812
#define SC(name, caption) StatsCounterThreadSafe name##_;
  STATS_COUNTER_TS_LIST(SC)
#undef SC

813
#define SC(name)                  \
814 815 816 817 818
  StatsCounter size_of_##name##_; \
  StatsCounter count_of_##name##_;
  INSTANCE_TYPE_LIST(SC)
#undef SC

819
#define SC(name)                            \
820 821 822 823 824
  StatsCounter size_of_CODE_TYPE_##name##_; \
  StatsCounter count_of_CODE_TYPE_##name##_;
  CODE_KIND_LIST(SC)
#undef SC

825
#define SC(name)                              \
826 827 828 829 830
  StatsCounter size_of_FIXED_ARRAY_##name##_; \
  StatsCounter count_of_FIXED_ARRAY_##name##_;
  FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(SC)
#undef SC

831
#ifdef V8_RUNTIME_CALL_STATS
832
  RuntimeCallStats runtime_call_stats_;
833
  WorkerThreadRuntimeCallStats worker_thread_runtime_call_stats_;
834 835 836
#endif
  Isolate* isolate_;
  StatsTable stats_table_;
837

838 839 840
  DISALLOW_IMPLICIT_CONSTRUCTORS(Counters);
};

841 842 843 844 845 846 847 848
void HistogramTimer::Start() {
  TimedHistogram::Start(&timer_, counters()->isolate());
}

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

849
#ifdef V8_RUNTIME_CALL_STATS
850 851
RuntimeCallTimerScope::RuntimeCallTimerScope(Isolate* isolate,
                                             RuntimeCallCounterId counter_id) {
852
  if (V8_LIKELY(!TracingFlags::is_runtime_stats_enabled())) return;
853
  stats_ = isolate->counters()->runtime_call_stats();
854
  stats_->Enter(&timer_, counter_id);
855
}
856
#endif  // defined(V8_RUNTIME_CALL_STATS)
857

858 859
}  // namespace internal
}  // namespace v8
860

861
#endif  // V8_LOGGING_COUNTERS_H_