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.
77 0 : explicit StatsCounter(const std::string& name)
78 0 : : counter_id_(-1) {
79 : // We prepend the name with 'c:' to indicate that it is a counter.
80 0 : name_ = "c:";
81 0 : name_.append(name);
82 0 : };
83 :
84 0 : virtual ~StatsCounter() {}
85 :
86 : // Sets the counter to a specific value.
87 0 : void Set(int value) {
88 0 : int* loc = GetPtr();
89 0 : if (loc) *loc = value;
90 0 : }
91 :
92 : // Increments the counter.
93 0 : void Increment() {
94 0 : Add(1);
95 0 : }
96 :
97 0 : virtual void Add(int value) {
98 0 : int* loc = GetPtr();
99 0 : if (loc)
100 0 : (*loc) += value;
101 0 : }
102 :
103 : // Decrements the counter.
104 : void Decrement() {
105 : Add(-1);
106 : }
107 :
108 : void Subtract(int value) {
109 : Add(-value);
110 : }
111 :
112 : // Is this counter enabled?
113 : // Returns false if table is full.
114 : bool Enabled() {
115 : return GetPtr() != NULL;
116 : }
117 :
118 0 : int value() {
119 0 : int* loc = GetPtr();
120 0 : if (loc) return *loc;
121 0 : return 0;
122 : }
123 :
124 : protected:
125 0 : StatsCounter()
126 0 : : counter_id_(-1) {
127 0 : }
128 :
129 : // Returns the cached address of this counter location.
130 0 : int* GetPtr() {
131 0 : StatsTable* table = StatsTable::current();
132 0 : if (!table)
133 0 : return NULL;
134 :
135 : // If counter_id_ is -1, then we haven't looked it up yet.
136 0 : if (counter_id_ == -1) {
137 0 : counter_id_ = table->FindCounter(name_);
138 0 : if (table->GetSlot() == 0) {
139 0 : if (!table->RegisterThread("")) {
140 : // There is no room for this thread. This thread
141 : // cannot use counters.
142 0 : counter_id_ = 0;
143 0 : return NULL;
144 : }
145 : }
146 : }
147 :
148 : // If counter_id_ is > 0, then we have a valid counter.
149 0 : if (counter_id_ > 0)
150 0 : return table->GetLocation(counter_id_, table->GetSlot());
151 :
152 : // counter_id_ was zero, which means the table is full.
153 0 : 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 0 : class StatsCounterTimer : protected StatsCounter {
168 : public:
169 : // Constructs and starts the timer.
170 0 : explicit StatsCounterTimer(const std::string& name) {
171 : // we prepend the name with 't:' to indicate that it is a timer.
172 0 : name_ = "t:";
173 0 : name_.append(name);
174 0 : }
175 :
176 : // Start the timer.
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.
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.
193 : bool Running() {
194 : return Enabled() && !start_time_.is_null() && stop_time_.is_null();
195 : }
196 :
197 : // Accept a TimeDelta to increment.
198 0 : virtual void AddTime(base::TimeDelta time) {
199 0 : Add(static_cast<int>(time.InMilliseconds()));
200 0 : }
201 :
202 : protected:
203 : // Compute the delta between start and stop, in milliseconds.
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 0 : class StatsRate : public StatsCounterTimer {
216 : public:
217 : // Constructs and starts the timer.
218 0 : explicit StatsRate(const char* name)
219 : : StatsCounterTimer(name),
220 : counter_(name),
221 0 : largest_add_(std::string(" ").append(name).append("MAX").c_str()) {
222 0 : }
223 :
224 0 : virtual void Add(int value) {
225 0 : counter_.Increment();
226 0 : StatsCounterTimer::Add(value);
227 0 : if (value > largest_add_.value())
228 0 : largest_add_.Set(value);
229 0 : }
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)
241 : : timer_(timer) {
242 : timer_.Start();
243 : }
244 :
245 : ~StatsScope() {
246 : timer_.Stop();
247 : }
248 :
249 : void Stop() {
250 : timer_.Stop();
251 : }
252 :
253 : private:
254 : T& timer_;
255 : };
256 :
257 : #endif // BASE_STATS_COUNTERS_H__
|