• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2006-2008 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 
6 #ifndef BASE_STATS_COUNTERS_H__
7 #define BASE_STATS_COUNTERS_H__
8 
9 #include <string>
10 #include "base/stats_table.h"
11 #include "base/time.h"
12 
13 // StatsCounters are dynamically created values which can be tracked in
14 // the StatsTable.  They are designed to be lightweight to create and
15 // easy to use.
16 //
17 // Since StatsCounters can be created dynamically by name, there is
18 // a hash table lookup to find the counter in the table.  A StatsCounter
19 // object can be created once and used across multiple threads safely.
20 //
21 // Example usage:
22 //    {
23 //      StatsCounter request_count("RequestCount");
24 //      request_count.Increment();
25 //    }
26 //
27 // Note that creating counters on the stack does work, however creating
28 // the counter object requires a hash table lookup.  For inner loops, it
29 // may be better to create the counter either as a member of another object
30 // (or otherwise outside of the loop) for maximum performance.
31 //
32 // Internally, a counter represents a value in a row of a StatsTable.
33 // The row has a 32bit value for each process/thread in the table and also
34 // a name (stored in the table metadata).
35 //
36 // NOTE: In order to make stats_counters usable in lots of different code,
37 // avoid any dependencies inside this header file.
38 //
39 
40 //------------------------------------------------------------------------------
41 // Define macros for ease of use. They also allow us to change definitions
42 // as the implementation varies, or depending on compile options.
43 //------------------------------------------------------------------------------
44 // First provide generic macros, which exist in production as well as debug.
45 #define STATS_COUNTER(name, delta) do { \
46   static StatsCounter counter(name); \
47   counter.Add(delta); \
48 } while (0)
49 
50 #define SIMPLE_STATS_COUNTER(name) STATS_COUNTER(name, 1)
51 
52 #define RATE_COUNTER(name, duration) do { \
53   static StatsRate hit_count(name); \
54   hit_count.AddTime(duration); \
55 } while (0)
56 
57 // Define Debug vs non-debug flavors of macros.
58 #ifndef NDEBUG
59 
60 #define DSTATS_COUNTER(name, delta) STATS_COUNTER(name, delta)
61 #define DSIMPLE_STATS_COUNTER(name) SIMPLE_STATS_COUNTER(name)
62 #define DRATE_COUNTER(name, duration) RATE_COUNTER(name, duration)
63 
64 #else  // NDEBUG
65 
66 #define DSTATS_COUNTER(name, delta) do {} while (0)
67 #define DSIMPLE_STATS_COUNTER(name) do {} while (0)
68 #define DRATE_COUNTER(name, duration) do {} while (0)
69 
70 #endif  // NDEBUG
71 
72 //------------------------------------------------------------------------------
73 // StatsCounter represents a counter in the StatsTable class.
74 class StatsCounter {
75  public:
76   // Create a StatsCounter object.
StatsCounter(const std::string & name)77   explicit StatsCounter(const std::string& name)
78        : counter_id_(-1) {
79     // We prepend the name with 'c:' to indicate that it is a counter.
80     name_ = "c:";
81     name_.append(name);
82   };
83 
~StatsCounter()84   virtual ~StatsCounter() {}
85 
86   // Sets the counter to a specific value.
Set(int value)87   void Set(int value) {
88     int* loc = GetPtr();
89     if (loc) *loc = value;
90   }
91 
92   // Increments the counter.
Increment()93   void Increment() {
94     Add(1);
95   }
96 
Add(int value)97   virtual void Add(int value) {
98     int* loc = GetPtr();
99     if (loc)
100       (*loc) += value;
101   }
102 
103   // Decrements the counter.
Decrement()104   void Decrement() {
105     Add(-1);
106   }
107 
Subtract(int value)108   void Subtract(int value) {
109     Add(-value);
110   }
111 
112   // Is this counter enabled?
113   // Returns false if table is full.
Enabled()114   bool Enabled() {
115     return GetPtr() != NULL;
116   }
117 
value()118   int value() {
119     int* loc = GetPtr();
120     if (loc) return *loc;
121     return 0;
122   }
123 
124  protected:
StatsCounter()125   StatsCounter()
126     : counter_id_(-1) {
127   }
128 
129   // Returns the cached address of this counter location.
GetPtr()130   int* GetPtr() {
131     StatsTable* table = StatsTable::current();
132     if (!table)
133       return NULL;
134 
135     // If counter_id_ is -1, then we haven't looked it up yet.
136     if (counter_id_ == -1) {
137       counter_id_ = table->FindCounter(name_);
138       if (table->GetSlot() == 0) {
139         if (!table->RegisterThread("")) {
140           // There is no room for this thread.  This thread
141           // cannot use counters.
142           counter_id_ = 0;
143           return NULL;
144         }
145       }
146     }
147 
148     // If counter_id_ is > 0, then we have a valid counter.
149     if (counter_id_ > 0)
150       return table->GetLocation(counter_id_, table->GetSlot());
151 
152     // counter_id_ was zero, which means the table is full.
153     return NULL;
154   }
155 
156   std::string name_;
157   // The counter id in the table.  We initialize to -1 (an invalid value)
158   // and then cache it once it has been looked up.  The counter_id is
159   // valid across all threads and processes.
160   int32 counter_id_;
161 };
162 
163 
164 // A StatsCounterTimer is a StatsCounter which keeps a timer during
165 // the scope of the StatsCounterTimer.  On destruction, it will record
166 // its time measurement.
167 class StatsCounterTimer : protected StatsCounter {
168  public:
169   // Constructs and starts the timer.
StatsCounterTimer(const std::string & name)170   explicit StatsCounterTimer(const std::string& name) {
171     // we prepend the name with 't:' to indicate that it is a timer.
172     name_ = "t:";
173     name_.append(name);
174   }
175 
176   // Start the timer.
Start()177   void Start() {
178     if (!Enabled())
179       return;
180     start_time_ = base::TimeTicks::Now();
181     stop_time_ = base::TimeTicks();
182   }
183 
184   // Stop the timer and record the results.
Stop()185   void Stop() {
186     if (!Enabled() || !Running())
187       return;
188     stop_time_ = base::TimeTicks::Now();
189     Record();
190   }
191 
192   // Returns true if the timer is running.
Running()193   bool Running() {
194     return Enabled() && !start_time_.is_null() && stop_time_.is_null();
195   }
196 
197   // Accept a TimeDelta to increment.
AddTime(base::TimeDelta time)198   virtual void AddTime(base::TimeDelta time) {
199     Add(static_cast<int>(time.InMilliseconds()));
200   }
201 
202  protected:
203   // Compute the delta between start and stop, in milliseconds.
Record()204   void Record() {
205     AddTime(stop_time_ - start_time_);
206   }
207 
208   base::TimeTicks start_time_;
209   base::TimeTicks stop_time_;
210 };
211 
212 // A StatsRate is a timer that keeps a count of the number of intervals added so
213 // that several statistics can be produced:
214 //    min, max, avg, count, total
215 class StatsRate : public StatsCounterTimer {
216  public:
217   // Constructs and starts the timer.
StatsRate(const char * name)218   explicit StatsRate(const char* name)
219       : StatsCounterTimer(name),
220       counter_(name),
221       largest_add_(std::string(" ").append(name).append("MAX").c_str()) {
222   }
223 
Add(int value)224   virtual void Add(int value) {
225     counter_.Increment();
226     StatsCounterTimer::Add(value);
227     if (value > largest_add_.value())
228       largest_add_.Set(value);
229   }
230 
231  private:
232   StatsCounter counter_;
233   StatsCounter largest_add_;
234 };
235 
236 
237 // Helper class for scoping a timer or rate.
238 template<class T> class StatsScope {
239  public:
240   explicit StatsScope<T>(T& timer)
timer_(timer)241       : timer_(timer) {
242     timer_.Start();
243   }
244 
~StatsScope()245   ~StatsScope() {
246     timer_.Stop();
247   }
248 
Stop()249   void Stop() {
250     timer_.Stop();
251   }
252 
253  private:
254   T& timer_;
255 };
256 
257 #endif  // BASE_STATS_COUNTERS_H__
258