1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef BASE_METRICS_STATS_COUNTERS_H_
6#define BASE_METRICS_STATS_COUNTERS_H_
7
8#include <string>
9
10#include "base/base_export.h"
11#include "base/compiler_specific.h"
12#include "base/metrics/stats_table.h"
13#include "base/time/time.h"
14
15namespace base {
16
17// StatsCounters are dynamically created values which can be tracked in
18// the StatsTable.  They are designed to be lightweight to create and
19// easy to use.
20//
21// Since StatsCounters can be created dynamically by name, there is
22// a hash table lookup to find the counter in the table.  A StatsCounter
23// object can be created once and used across multiple threads safely.
24//
25// Example usage:
26//    {
27//      StatsCounter request_count("RequestCount");
28//      request_count.Increment();
29//    }
30//
31// Note that creating counters on the stack does work, however creating
32// the counter object requires a hash table lookup.  For inner loops, it
33// may be better to create the counter either as a member of another object
34// (or otherwise outside of the loop) for maximum performance.
35//
36// Internally, a counter represents a value in a row of a StatsTable.
37// The row has a 32bit value for each process/thread in the table and also
38// a name (stored in the table metadata).
39//
40// NOTE: In order to make stats_counters usable in lots of different code,
41// avoid any dependencies inside this header file.
42//
43
44//------------------------------------------------------------------------------
45// Define macros for ease of use. They also allow us to change definitions
46// as the implementation varies, or depending on compile options.
47//------------------------------------------------------------------------------
48// First provide generic macros, which exist in production as well as debug.
49#define STATS_COUNTER(name, delta) do { \
50  base::StatsCounter counter(name); \
51  counter.Add(delta); \
52} while (0)
53
54#define SIMPLE_STATS_COUNTER(name) STATS_COUNTER(name, 1)
55
56#define RATE_COUNTER(name, duration) do { \
57  base::StatsRate hit_count(name); \
58  hit_count.AddTime(duration); \
59} while (0)
60
61// Define Debug vs non-debug flavors of macros.
62#ifndef NDEBUG
63
64#define DSTATS_COUNTER(name, delta) STATS_COUNTER(name, delta)
65#define DSIMPLE_STATS_COUNTER(name) SIMPLE_STATS_COUNTER(name)
66#define DRATE_COUNTER(name, duration) RATE_COUNTER(name, duration)
67
68#else  // NDEBUG
69
70#define DSTATS_COUNTER(name, delta) do {} while (0)
71#define DSIMPLE_STATS_COUNTER(name) do {} while (0)
72#define DRATE_COUNTER(name, duration) do {} while (0)
73
74#endif  // NDEBUG
75
76//------------------------------------------------------------------------------
77// StatsCounter represents a counter in the StatsTable class.
78class BASE_EXPORT StatsCounter {
79 public:
80  // Create a StatsCounter object.
81  explicit StatsCounter(const std::string& name);
82  virtual ~StatsCounter();
83
84  // Sets the counter to a specific value.
85  void Set(int value);
86
87  // Increments the counter.
88  void Increment() {
89    Add(1);
90  }
91
92  virtual void Add(int value);
93
94  // Decrements the counter.
95  void Decrement() {
96    Add(-1);
97  }
98
99  void Subtract(int value) {
100    Add(-value);
101  }
102
103  // Is this counter enabled?
104  // Returns false if table is full.
105  bool Enabled() {
106    return GetPtr() != NULL;
107  }
108
109  int value() {
110    int* loc = GetPtr();
111    if (loc) return *loc;
112    return 0;
113  }
114
115 protected:
116  StatsCounter();
117
118  // Returns the cached address of this counter location.
119  int* GetPtr();
120
121  std::string name_;
122  // The counter id in the table.  We initialize to -1 (an invalid value)
123  // and then cache it once it has been looked up.  The counter_id is
124  // valid across all threads and processes.
125  int32 counter_id_;
126};
127
128
129// A StatsCounterTimer is a StatsCounter which keeps a timer during
130// the scope of the StatsCounterTimer.  On destruction, it will record
131// its time measurement.
132class BASE_EXPORT StatsCounterTimer : protected StatsCounter {
133 public:
134  // Constructs and starts the timer.
135  explicit StatsCounterTimer(const std::string& name);
136  virtual ~StatsCounterTimer();
137
138  // Start the timer.
139  void Start();
140
141  // Stop the timer and record the results.
142  void Stop();
143
144  // Returns true if the timer is running.
145  bool Running();
146
147  // Accept a TimeDelta to increment.
148  virtual void AddTime(TimeDelta time);
149
150 protected:
151  // Compute the delta between start and stop, in milliseconds.
152  void Record();
153
154  TimeTicks start_time_;
155  TimeTicks stop_time_;
156};
157
158// A StatsRate is a timer that keeps a count of the number of intervals added so
159// that several statistics can be produced:
160//    min, max, avg, count, total
161class BASE_EXPORT StatsRate : public StatsCounterTimer {
162 public:
163  // Constructs and starts the timer.
164  explicit StatsRate(const std::string& name);
165  virtual ~StatsRate();
166
167  virtual void Add(int value) OVERRIDE;
168
169 private:
170  StatsCounter counter_;
171  StatsCounter largest_add_;
172};
173
174
175// Helper class for scoping a timer or rate.
176template<class T> class StatsScope {
177 public:
178  explicit StatsScope<T>(T& timer)
179      : timer_(timer) {
180    timer_.Start();
181  }
182
183  ~StatsScope() {
184    timer_.Stop();
185  }
186
187  void Stop() {
188    timer_.Stop();
189  }
190
191 private:
192  T& timer_;
193};
194
195}  // namespace base
196
197#endif  // BASE_METRICS_STATS_COUNTERS_H_
198