counters.h 8.86 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef V8_COUNTERS_H_
#define V8_COUNTERS_H_

31 32 33
#include "../include/v8.h"
#include "allocation.h"

34 35
namespace v8 {
namespace internal {
36 37 38 39 40

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

41
class StatsTable {
42 43 44
 public:
  // Register an application-defined function where
  // counters can be looked up.
45
  void SetCounterFunction(CounterLookupCallback f) {
46 47 48
    lookup_function_ = f;
  }

49 50
  // Register an application-defined function to create
  // a histogram for passing to the AddHistogramSample function
51
  void SetCreateHistogramFunction(CreateHistogramCallback f) {
52 53 54 55 56
    create_histogram_function_ = f;
  }

  // Register an application-defined function to add a sample
  // to a histogram created with CreateHistogram function
57
  void SetAddHistogramSampleFunction(AddHistogramSampleCallback f) {
58 59 60
    add_histogram_sample_function_ = f;
  }

61
  bool HasCounterFunction() const {
62 63 64 65 66 67 68 69 70
    return lookup_function_ != NULL;
  }

  // Lookup the location of a counter by name.  If the lookup
  // is successful, returns a non-NULL pointer for writing the
  // 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.
71
  int* FindLocation(const char* name) {
72 73 74 75
    if (!lookup_function_) return NULL;
    return lookup_function_(name);
  }

76 77 78 79 80
  // Create a histogram by name. If the create is successful,
  // returns a non-NULL pointer for use with AddHistogramSample
  // 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.
81 82 83 84
  void* CreateHistogram(const char* name,
                        int min,
                        int max,
                        size_t buckets) {
85 86 87 88 89 90
    if (!create_histogram_function_) return NULL;
    return create_histogram_function_(name, min, max, buckets);
  }

  // Add a sample to a histogram created with the CreateHistogram
  // function.
91
  void AddHistogramSample(void* histogram, int sample) {
92 93 94 95
    if (!add_histogram_sample_function_) return;
    return add_histogram_sample_function_(histogram, sample);
  }

96
 private:
97 98 99 100 101 102 103 104 105
  StatsTable();

  CounterLookupCallback lookup_function_;
  CreateHistogramCallback create_histogram_function_;
  AddHistogramSampleCallback add_histogram_sample_function_;

  friend class Isolate;

  DISALLOW_COPY_AND_ASSIGN(StatsTable);
106 107 108 109 110 111 112 113 114 115
};

// 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
// thread-specific, this class cannot be shared across threads.
116 117 118
class StatsCounter {
 public:
  StatsCounter() { }
119 120
  explicit StatsCounter(Isolate* isolate, const char* name)
      : isolate_(isolate), name_(name), ptr_(NULL), lookup_done_(false) { }
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168

  // Sets the counter to a specific value.
  void Set(int value) {
    int* loc = GetPtr();
    if (loc) *loc = value;
  }

  // Increments the counter.
  void Increment() {
    int* loc = GetPtr();
    if (loc) (*loc)++;
  }

  void Increment(int value) {
    int* loc = GetPtr();
    if (loc)
      (*loc) += value;
  }

  // Decrements the counter.
  void Decrement() {
    int* loc = GetPtr();
    if (loc) (*loc)--;
  }

  void Decrement(int value) {
    int* loc = GetPtr();
    if (loc) (*loc) -= value;
  }

  // Is this counter enabled?
  // Returns false if table is full.
  bool Enabled() {
    return GetPtr() != NULL;
  }

  // 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();
    ASSERT(loc != NULL);
    return loc;
  }

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

 private:
  int* FindLocationInStatsTable() const;
177

178
  Isolate* isolate_;
179 180 181
  const char* name_;
  int* ptr_;
  bool lookup_done_;
182 183
};

184
// A Histogram represents a dynamically created histogram in the StatsTable.
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
// It will be registered with the histogram system on first use.
class Histogram {
 public:
  Histogram() { }
  Histogram(const char* name,
            int min,
            int max,
            int num_buckets,
            Isolate* isolate)
      : name_(name),
        min_(min),
        max_(max),
        num_buckets_(num_buckets),
        histogram_(NULL),
        lookup_done_(false),
        isolate_(isolate) { }
201

202 203
  // Add a single sample to this histogram.
  void AddSample(int sample);
204

205 206 207
  // Returns true if this histogram is enabled.
  bool Enabled() {
    return GetHistogram() != NULL;
208 209
  }

210 211 212 213 214
  // Reset the cached internal pointer.
  void Reset() {
    lookup_done_ = false;
  }

215 216 217 218 219
 protected:
  // Returns the handle to the histogram.
  void* GetHistogram() {
    if (!lookup_done_) {
      lookup_done_ = true;
220
      histogram_ = CreateHistogram();
221
    }
222
    return histogram_;
223
  }
224

225 226 227
  const char* name() { return name_; }
  Isolate* isolate() const { return isolate_; }

228 229
 private:
  void* CreateHistogram() const;
230

231 232 233 234 235 236 237 238
  const char* name_;
  int min_;
  int max_;
  int num_buckets_;
  void* histogram_;
  bool lookup_done_;
  Isolate* isolate_;
};
239

240 241 242 243 244 245 246 247 248
// A HistogramTimer allows distributions of results to be created.
class HistogramTimer : public Histogram {
 public:
  HistogramTimer() { }
  HistogramTimer(const char* name,
                 int min,
                 int max,
                 int num_buckets,
                 Isolate* isolate)
249
      : Histogram(name, min, max, num_buckets, isolate) {}
250 251 252 253 254 255 256 257 258

  // Start the timer.
  void Start();

  // Stop the timer and record the results.
  void Stop();

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

262 263 264 265 266
  // TODO(bmeurer): Remove this when HistogramTimerScope is fixed.
#ifdef DEBUG
  ElapsedTimer* timer() { return &timer_; }
#endif

267
 private:
268
  ElapsedTimer timer_;
269 270
};

271
// Helper class for scoping a HistogramTimer.
272 273 274 275
// 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|.
276
class HistogramTimerScope BASE_EMBEDDED {
277
 public:
278 279 280 281 282 283 284 285 286 287 288 289
  explicit HistogramTimerScope(HistogramTimer* timer,
                               bool allow_nesting = false)
#ifdef DEBUG
      : timer_(timer),
        skipped_timer_start_(false) {
    if (timer_->timer()->IsStarted() && allow_nesting) {
      skipped_timer_start_ = true;
    } else {
      timer_->Start();
    }
#else
      : timer_(timer) {
290
    timer_->Start();
291
#endif
292
  }
293
  ~HistogramTimerScope() {
294 295 296 297 298
#ifdef DEBUG
    if (!skipped_timer_start_) {
      timer_->Stop();
    }
#else
299
    timer_->Stop();
300
#endif
301 302
  }
 private:
303
  HistogramTimer* timer_;
304 305 306
#ifdef DEBUG
  bool skipped_timer_start_;
#endif
307 308 309 310 311 312
};


} }  // namespace v8::internal

#endif  // V8_COUNTERS_H_