counters.h 22.7 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-callbacks.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/logging/counters-definitions.h"
17
#include "src/logging/runtime-call-stats.h"
18 19
#include "src/objects/code-kind.h"
#include "src/objects/fixed-array.h"
20
#include "src/objects/objects.h"
21
#include "src/utils/allocation.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
class Counters;
31
class Isolate;
32

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

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

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

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

54
  bool HasCounterFunction() const { return lookup_function_ != nullptr; }
55 56

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

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

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

84
 private:
85 86
  friend class Counters;

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

  CounterLookupCallback lookup_function_;
  CreateHistogramCallback create_histogram_function_;
  AddHistogramSampleCallback add_histogram_sample_function_;
92 93
};

94 95
// StatsCounters are dynamically created values which can be tracked in the
// StatsTable. They are designed to be lightweight to create and easy to use.
96 97 98
//
// 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
99 100 101 102
// a name (stored in the table metadata). Since the storage location can be
// thread-specific, this class cannot be shared across threads.
// This class is thread-safe.
class StatsCounter {
103
 public:
104
  void Set(int value) { GetPtr()->store(value, std::memory_order_relaxed); }
105

106
  void Increment(int value = 1) {
107
    GetPtr()->fetch_add(value, std::memory_order_relaxed);
108 109
  }

110
  void Decrement(int value = 1) {
111
    GetPtr()->fetch_sub(value, std::memory_order_relaxed);
112 113
  }

114 115 116
  // Returns true if this counter is enabled (a lookup function was provided and
  // it returned a non-null pointer).
  V8_EXPORT_PRIVATE bool Enabled();
117 118 119 120

  // 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.
121
  std::atomic<int>* GetInternalPointer() { return GetPtr(); }
122

123 124 125
 private:
  friend class Counters;

126 127 128 129 130 131 132
  void Init(Counters* counters, const char* name) {
    DCHECK_NULL(counters_);
    DCHECK_NOT_NULL(counters);
    // Counter names always start with "c:V8.".
    DCHECK_EQ(0, memcmp(name, "c:V8.", 5));
    counters_ = counters;
    name_ = name;
133
  }
134

135
  V8_NOINLINE V8_EXPORT_PRIVATE std::atomic<int>* SetupPtrFromStatsTable();
136

137
  // Reset the cached internal pointer.
138
  void Reset() { ptr_.store(nullptr, std::memory_order_relaxed); }
139

140 141 142 143
  // Returns the cached address of this counter location.
  std::atomic<int>* GetPtr() {
    auto* ptr = ptr_.load(std::memory_order_acquire);
    if (V8_LIKELY(ptr)) return ptr;
144
    return SetupPtrFromStatsTable();
145
  }
146

147 148 149 150
  Counters* counters_ = nullptr;
  const char* name_ = nullptr;
  // A pointer to an atomic, set atomically in {GetPtr}.
  std::atomic<std::atomic<int>*> ptr_{nullptr};
151 152
};

153 154
// A Histogram represents a dynamically created histogram in the
// StatsTable.  Note: This class is thread safe.
155 156
class Histogram {
 public:
157 158
  // Add a single sample to this histogram.
  void AddSample(int sample);
159

160
  // Returns true if this histogram is enabled.
161
  bool Enabled() { return histogram_ != nullptr; }
162

163
  const char* name() const { return name_; }
164

165 166 167 168
  int min() const { return min_; }
  int max() const { return max_; }
  int num_buckets() const { return num_buckets_; }

169 170 171 172 173 174
  // Asserts that |expected_counters| are the same as the Counters this
  // Histogram reports to.
  void AssertReportsToCounters(Counters* expected_counters) {
    DCHECK_EQ(counters_, expected_counters);
  }

175
 protected:
176
  Histogram() = default;
177 178 179 180 181 182 183 184 185 186 187 188
  Histogram(const Histogram&) = delete;
  Histogram& operator=(const Histogram&) = delete;

  void Initialize(const char* name, int min, int max, int num_buckets,
                  Counters* counters) {
    name_ = name;
    min_ = min;
    max_ = max;
    num_buckets_ = num_buckets;
    histogram_ = nullptr;
    counters_ = counters;
    DCHECK_NOT_NULL(counters_);
189
  }
190

191
  Counters* counters() const { return counters_; }
192

193 194 195 196 197 198 199 200 201 202 203
  // Reset the cached internal pointer to nullptr; the histogram will be
  // created lazily, the first time it is needed.
  void Reset() { histogram_ = nullptr; }

  // Lazily create the histogram, if it has not been created yet.
  void EnsureCreated(bool create_new = true) {
    if (create_new && histogram_.load(std::memory_order_acquire) == nullptr) {
      base::MutexGuard Guard(&mutex_);
      if (histogram_.load(std::memory_order_relaxed) == nullptr)
        histogram_.store(CreateHistogram(), std::memory_order_release);
    }
204
  }
205

206
 private:
207 208
  friend class Counters;

209
  V8_EXPORT_PRIVATE void* CreateHistogram() const;
210

211 212 213 214
  const char* name_;
  int min_;
  int max_;
  int num_buckets_;
215
  std::atomic<void*> histogram_;
216
  Counters* counters_;
217
  base::Mutex mutex_;
218
};
219

220
enum class TimedHistogramResolution { MILLISECOND, MICROSECOND };
221 222 223

// A thread safe histogram timer. It also allows distributions of
// nested timed results.
224
class TimedHistogram : public Histogram {
225
 public:
226 227 228 229
  // 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);

230
  // Add a single sample to this histogram.
231 232 233 234 235 236 237 238 239 240
  V8_EXPORT_PRIVATE void AddTimedSample(base::TimeDelta sample);

#ifdef DEBUG
  // Ensures that we don't have nested timers for TimedHistogram per thread, use
  // NestedTimedHistogram which correctly pause and resume timers.
  // This method assumes that each timer is alternating between stopped and
  // started on a single thread. Multiple timers can be active on different
  // threads.
  bool ToggleRunningState(bool expected_is_running) const;
#endif  // DEBUG
241

242
 protected:
243 244 245 246
  void Stop(base::ElapsedTimer* timer);
  void LogStart(Isolate* isolate);
  void LogEnd(Isolate* isolate);

247
  friend class Counters;
248
  TimedHistogramResolution resolution_;
249

250
  TimedHistogram() = default;
251 252 253 254 255 256 257 258 259
  TimedHistogram(const TimedHistogram&) = delete;
  TimedHistogram& operator=(const TimedHistogram&) = delete;

  void Initialize(const char* name, int min, int max,
                  TimedHistogramResolution resolution, int num_buckets,
                  Counters* counters) {
    Histogram::Initialize(name, min, max, num_buckets, counters);
    resolution_ = resolution;
  }
260 261
};

262 263
class NestedTimedHistogramScope;
class PauseNestedTimedHistogramScope;
264

265 266
// A NestedTimedHistogram allows distributions of nested timed results.
class NestedTimedHistogram : public TimedHistogram {
267 268
 public:
  // Note: public for testing purposes only.
269 270 271
  NestedTimedHistogram(const char* name, int min, int max,
                       TimedHistogramResolution resolution, int num_buckets,
                       Counters* counters)
272 273 274
      : NestedTimedHistogram() {
    Initialize(name, min, max, resolution, num_buckets, counters);
  }
275

276
 private:
277
  friend class Counters;
278 279
  friend class NestedTimedHistogramScope;
  friend class PauseNestedTimedHistogramScope;
280

281 282 283 284
  inline NestedTimedHistogramScope* Enter(NestedTimedHistogramScope* next) {
    NestedTimedHistogramScope* previous = current_;
    current_ = next;
    return previous;
285
  }
286 287 288

  inline void Leave(NestedTimedHistogramScope* previous) {
    current_ = previous;
289
  }
290

291 292 293
  NestedTimedHistogramScope* current_ = nullptr;

  NestedTimedHistogram() = default;
294 295
  NestedTimedHistogram(const NestedTimedHistogram&) = delete;
  NestedTimedHistogram& operator=(const NestedTimedHistogram&) = delete;
296 297
};

298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
// 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(); }
315 316 317 318 319 320 321
  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()));
    }
  }
322 323 324 325 326

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

 private:
327 328
  friend class Counters;

329
  AggregatableHistogramTimer() = default;
330 331 332
  AggregatableHistogramTimer(const AggregatableHistogramTimer&) = delete;
  AggregatableHistogramTimer& operator=(const AggregatableHistogramTimer&) =
      delete;
333

334 335 336
  base::TimeDelta time_;
};

337
// A helper class for use with AggregatableHistogramTimer. This is the
338 339
// // outer-most timer scope used with an AggregatableHistogramTimer. It will
// // aggregate the information from the inner AggregatedHistogramTimerScope.
340
class V8_NODISCARD AggregatingHistogramTimerScope {
341 342 343 344 345 346 347 348 349 350 351
 public:
  explicit AggregatingHistogramTimerScope(AggregatableHistogramTimer* histogram)
      : histogram_(histogram) {
    histogram_->Start();
  }
  ~AggregatingHistogramTimerScope() { histogram_->Stop(); }

 private:
  AggregatableHistogramTimer* histogram_;
};

352
// A helper class for use with AggregatableHistogramTimer, the "inner" scope
353
// // which defines the events to be timed.
354
class V8_NODISCARD AggregatedHistogramTimerScope {
355 356 357 358 359 360 361 362 363 364 365 366
 public:
  explicit AggregatedHistogramTimerScope(AggregatableHistogramTimer* histogram)
      : histogram_(histogram) {
    timer_.Start();
  }
  ~AggregatedHistogramTimerScope() { histogram_->Add(timer_.Elapsed()); }

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

367 368 369 370 371 372 373 374 375 376 377 378
// 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:
379
  // Note: public for testing purposes only.
380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396
  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:
397 398 399 400 401 402 403 404
  friend class Counters;

  AggregatedMemoryHistogram()
      : is_initialized_(false),
        start_ms_(0.0),
        last_ms_(0.0),
        aggregate_value_(0.0),
        last_value_(0.0),
405
        backing_histogram_(nullptr) {}
406
  double Aggregate(double current_ms, double current_value);
407

408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484
  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);
}

485
// This file contains all the v8 counters that are in use.
486
class Counters : public std::enable_shared_from_this<Counters> {
487
 public:
488 489
  explicit Counters(Isolate* isolate);

490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506
  // 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);
  }

507
#define HR(name, caption, min, max, num_buckets) \
508 509 510 511
  Histogram* name() {                            \
    name##_.EnsureCreated();                     \
    return &name##_;                             \
  }
512 513 514
  HISTOGRAM_RANGE_LIST(HR)
#undef HR

yangguo's avatar
yangguo committed
515
#define HT(name, caption, max, res) \
516 517 518 519
  NestedTimedHistogram* name() {    \
    name##_.EnsureCreated();        \
    return &name##_;                \
  }
520
  NESTED_TIMED_HISTOGRAM_LIST(HT)
521 522 523 524 525 526 527
#undef HT

#define HT(name, caption, max, res)              \
  NestedTimedHistogram* name() {                 \
    name##_.EnsureCreated(FLAG_slow_histograms); \
    return &name##_;                             \
  }
528
  NESTED_TIMED_HISTOGRAM_LIST_SLOW(HT)
529 530
#undef HT

531
#define HT(name, caption, max, res) \
532 533 534 535
  TimedHistogram* name() {          \
    name##_.EnsureCreated();        \
    return &name##_;                \
  }
536 537 538
  TIMED_HISTOGRAM_LIST(HT)
#undef HT

539 540 541 542 543
#define AHT(name, caption)             \
  AggregatableHistogramTimer* name() { \
    name##_.EnsureCreated();           \
    return &name##_;                   \
  }
544 545 546
  AGGREGATABLE_HISTOGRAM_TIMER_LIST(AHT)
#undef AHT

547 548 549 550 551
#define HP(name, caption)    \
  Histogram* name() {        \
    name##_.EnsureCreated(); \
    return &name##_;         \
  }
552 553 554
  HISTOGRAM_PERCENTAGE_LIST(HP)
#undef HP

555 556 557 558 559
#define HM(name, caption)    \
  Histogram* name() {        \
    name##_.EnsureCreated(); \
    return &name##_;         \
  }
560
  HISTOGRAM_LEGACY_MEMORY_LIST(HM)
561 562 563 564 565 566
#undef HM

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

570
  // clang-format off
571
  enum Id {
yangguo's avatar
yangguo committed
572
#define RATE_ID(name, caption, max, res) k_##name,
573 574
    NESTED_TIMED_HISTOGRAM_LIST(RATE_ID)
    NESTED_TIMED_HISTOGRAM_LIST_SLOW(RATE_ID)
575
    TIMED_HISTOGRAM_LIST(RATE_ID)
576
#undef RATE_ID
577 578 579
#define AGGREGATABLE_ID(name, caption) k_##name,
    AGGREGATABLE_HISTOGRAM_TIMER_LIST(AGGREGATABLE_ID)
#undef AGGREGATABLE_ID
580 581 582 583
#define PERCENTAGE_ID(name, caption) k_##name,
    HISTOGRAM_PERCENTAGE_LIST(PERCENTAGE_ID)
#undef PERCENTAGE_ID
#define MEMORY_ID(name, caption) k_##name,
584
    HISTOGRAM_LEGACY_MEMORY_LIST(MEMORY_ID)
585 586 587 588
#undef MEMORY_ID
#define COUNTER_ID(name, caption) k_##name,
    STATS_COUNTER_LIST_1(COUNTER_ID)
    STATS_COUNTER_LIST_2(COUNTER_ID)
589
    STATS_COUNTER_NATIVE_CODE_LIST(COUNTER_ID)
590 591 592 593 594 595 596 597 598 599 600 601 602 603
#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
  };
604
  // clang-format on
605

606
#ifdef V8_RUNTIME_CALL_STATS
607
  RuntimeCallStats* runtime_call_stats() { return &runtime_call_stats_; }
608

609 610 611
  WorkerThreadRuntimeCallStats* worker_thread_runtime_call_stats() {
    return &worker_thread_runtime_call_stats_;
  }
612 613 614 615 616 617 618
#else   // V8_RUNTIME_CALL_STATS
  RuntimeCallStats* runtime_call_stats() { return nullptr; }

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

620
 private:
621
  friend class StatsTable;
622
  friend class StatsCounter;
623
  friend class Histogram;
624
  friend class NestedTimedHistogramScope;
625 626 627 628 629 630 631 632 633 634 635 636 637 638 639

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

640 641 642 643
#define HR(name, caption, min, max, num_buckets) Histogram name##_;
  HISTOGRAM_RANGE_LIST(HR)
#undef HR

644 645 646
#define HT(name, caption, max, res) NestedTimedHistogram name##_;
  NESTED_TIMED_HISTOGRAM_LIST(HT)
  NESTED_TIMED_HISTOGRAM_LIST_SLOW(HT)
647 648
#undef HT

649 650 651 652
#define HT(name, caption, max, res) TimedHistogram name##_;
  TIMED_HISTOGRAM_LIST(HT)
#undef HT

653
#define AHT(name, caption) AggregatableHistogramTimer name##_;
654 655 656
  AGGREGATABLE_HISTOGRAM_TIMER_LIST(AHT)
#undef AHT

657
#define HP(name, caption) Histogram name##_;
658 659 660
  HISTOGRAM_PERCENTAGE_LIST(HP)
#undef HP

661
#define HM(name, caption) Histogram name##_;
662
  HISTOGRAM_LEGACY_MEMORY_LIST(HM)
663 664
#undef HM

665
#define SC(name, caption) StatsCounter name##_;
666 667
  STATS_COUNTER_LIST_1(SC)
  STATS_COUNTER_LIST_2(SC)
668
  STATS_COUNTER_NATIVE_CODE_LIST(SC)
669 670
#undef SC

671
#define SC(name)                  \
672 673 674 675 676
  StatsCounter size_of_##name##_; \
  StatsCounter count_of_##name##_;
  INSTANCE_TYPE_LIST(SC)
#undef SC

677
#define SC(name)                            \
678 679 680 681 682
  StatsCounter size_of_CODE_TYPE_##name##_; \
  StatsCounter count_of_CODE_TYPE_##name##_;
  CODE_KIND_LIST(SC)
#undef SC

683
#define SC(name)                              \
684 685 686 687 688
  StatsCounter size_of_FIXED_ARRAY_##name##_; \
  StatsCounter count_of_FIXED_ARRAY_##name##_;
  FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(SC)
#undef SC

689
#ifdef V8_RUNTIME_CALL_STATS
690
  RuntimeCallStats runtime_call_stats_;
691
  WorkerThreadRuntimeCallStats worker_thread_runtime_call_stats_;
692 693 694
#endif
  Isolate* isolate_;
  StatsTable stats_table_;
695

696 697 698
  DISALLOW_IMPLICIT_CONSTRUCTORS(Counters);
};

699

700 701
}  // namespace internal
}  // namespace v8
702

703
#endif  // V8_LOGGING_COUNTERS_H_