blob: eaff1b44dbde86bb18641c931a9a3ece27551584 [file] [log] [blame]
license.botf003cfe2008-08-24 09:55:55 +09001// 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.
initial.commit3f4a7322008-07-27 06:49:38 +09004
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.
74class StatsCounter {
75 public:
76 // Create a StatsCounter object.
77 explicit StatsCounter(const std::wstring& name)
78 : counter_id_(-1) {
79 // We prepend the name with 'c:' to indicate that it is a counter.
80 name_ = L"c:";
81 name_.append(name);
82 };
83
84 virtual ~StatsCounter() {}
85
86 // Sets the counter to a specific value.
87 void Set(int value) {
88 int* loc = GetPtr();
89 if (loc) *loc = value;
90 }
91
92 // Increments the counter.
93 void Increment() {
94 Add(1);
95 }
96
97 // TODO(jar) temporary hack include method till base and chrome use new name.
98 void Increment(int value) {
99 Add(value);
100 }
101
102 virtual void Add(int value) {
103 int* loc = GetPtr();
104 if (loc)
105 (*loc) += value;
106 }
107
108 // Decrements the counter.
109 void Decrement() {
110 Add(-1);
111 }
112
113 void Subtract(int value) {
114 Add(-value);
115 }
116
117 // TODO(jar) temporary hack includes method till base and chrome use new name.
118 void Decrement(int value) {
119 Add(-value);
120 }
121
122 // Is this counter enabled?
123 // Returns false if table is full.
124 bool Enabled() {
125 return GetPtr() != NULL;
126 }
127
128 int value() {
129 int* loc = GetPtr();
130 if (loc) return *loc;
131 return 0;
132 }
133
134 protected:
135 StatsCounter()
136 : counter_id_(-1) {
137 }
138
139 // Returns the cached address of this counter location.
140 int* GetPtr() {
141 StatsTable* table = StatsTable::current();
142 if (!table)
143 return NULL;
144
145 // If counter_id_ is -1, then we haven't looked it up yet.
146 if (counter_id_ == -1) {
147 counter_id_ = table->FindCounter(name_);
148 if (table->GetSlot() == 0) {
149 if (!table->RegisterThread(L"")) {
150 // There is no room for this thread. This thread
151 // cannot use counters.
152 counter_id_ = 0;
153 return NULL;
154 }
155 }
156 }
157
158 // If counter_id_ is > 0, then we have a valid counter.
159 if (counter_id_ > 0)
160 return table->GetLocation(counter_id_, table->GetSlot());
161
162 // counter_id_ was zero, which means the table is full.
163 return NULL;
164 }
165
166 std::wstring name_;
167 // The counter id in the table. We initialize to -1 (an invalid value)
168 // and then cache it once it has been looked up. The counter_id is
169 // valid across all threads and processes.
170 int32 counter_id_;
171};
172
173
174// A StatsCounterTimer is a StatsCounter which keeps a timer during
175// the scope of the StatsCounterTimer. On destruction, it will record
176// its time measurement.
177class StatsCounterTimer : protected StatsCounter {
178 public:
179 // Constructs and starts the timer.
180 explicit StatsCounterTimer(const std::wstring& name) {
181 // we prepend the name with 't:' to indicate that it is a timer.
182 name_ = L"t:";
183 name_.append(name);
184 }
185
186 // Start the timer.
187 void Start() {
188 if (!Enabled())
189 return;
190 start_time_ = TimeTicks::Now();
191 stop_time_ = TimeTicks();
192 }
193
194 // Stop the timer and record the results.
195 void Stop() {
196 if (!Enabled() || !Running())
197 return;
198 stop_time_ = TimeTicks::Now();
199 Record();
200 }
201
202 // Returns true if the timer is running.
203 bool Running() {
204 return Enabled() && !start_time_.is_null() && stop_time_.is_null();
205 }
206
207 // Accept a TimeDelta to increment.
208 virtual void AddTime(TimeDelta time) {
209 Add(static_cast<int>(time.InMilliseconds()));
210 }
211
212 // TODO(jar) temporary hack include method till base and chrome use new name.
213 void IncrementTimer(TimeDelta time) {
214 AddTime(time);
215 }
216
217 protected:
218 // Compute the delta between start and stop, in milliseconds.
219 void Record() {
220 AddTime(stop_time_ - start_time_);
221 }
222
223 TimeTicks start_time_;
224 TimeTicks stop_time_;
225};
226
227// A StatsRate is a timer that keeps a count of the number of intervals added so
228// that several statistics can be produced:
229// min, max, avg, count, total
230class StatsRate : public StatsCounterTimer {
231 public:
232 // Constructs and starts the timer.
233 explicit StatsRate(const wchar_t* name)
234 : StatsCounterTimer(name),
235 counter_(name),
236 largest_add_(std::wstring(L" ").append(name).append(L"MAX").c_str()) {
237 }
238
239 virtual void Add(int value) {
240 counter_.Increment();
241 StatsCounterTimer::Add(value);
242 if (value > largest_add_.value())
243 largest_add_.Set(value);
244 }
245
246 private:
247 StatsCounter counter_;
248 StatsCounter largest_add_;
249};
250
251
252// Helper class for scoping a timer or rate.
253template<class T> class StatsScope {
254 public:
255 explicit StatsScope<T>(T& timer)
256 : timer_(timer) {
257 timer_.Start();
258 }
259
260 ~StatsScope() {
261 timer_.Stop();
262 }
263
264 void Stop() {
265 timer_.Stop();
266 }
267
268 private:
269 T& timer_;
270};
271
272#endif // BASE_STATS_COUNTERS_H__
license.botf003cfe2008-08-24 09:55:55 +0900273