|
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 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 |
|
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 virtual void Add(int value) { |
|
98 int* loc = GetPtr(); |
|
99 if (loc) |
|
100 (*loc) += value; |
|
101 } |
|
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 int value() { |
|
119 int* loc = GetPtr(); |
|
120 if (loc) return *loc; |
|
121 return 0; |
|
122 } |
|
123 |
|
124 protected: |
|
125 StatsCounter() |
|
126 : counter_id_(-1) { |
|
127 } |
|
128 |
|
129 // Returns the cached address of this counter location. |
|
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_t 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. |
|
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. |
|
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 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. |
|
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. |
|
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 |
|
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) |
|
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__ |