Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(190)

Side by Side Diff: statsreport/metrics.h

Issue 624713003: Keep only base/extractor.[cc|h]. (Closed) Base URL: https://chromium.googlesource.com/external/omaha.git@master
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « statsreport/formatter_unittest.cc ('k') | statsreport/metrics.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2006-2009 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 // ========================================================================
15 //
16 // Declares the interface to in-memory metrics capture
17 #ifndef OMAHA_STATSREPORT_METRICS_H__
18 #define OMAHA_STATSREPORT_METRICS_H__
19
20 #include <iterator>
21 #include "base/basictypes.h"
22 #include "omaha/base/highres_timer-win32.h"
23 #include "omaha/base/logging/logging.h"
24
25 /// Macros to declare & define named & typed metrics.
26 /// Put declarations in headers or in cpp files, where you need access
27 /// to the metrics. For each declared metric, there must be precisely
28 /// one definition in a compilation unit someplace.
29
30 /// A count metric should be used to report anything that monotonically
31 /// increases.
32 /// Examples:
33 /// # event count
34 /// how often does this condition hit, this function get called
35 /// # aggregate sums
36 /// how many bytes are written
37 #define DECLARE_METRIC_count(name) DECLARE_METRIC(CountMetric, name)
38 #define DEFINE_METRIC_count(name) DEFINE_METRIC(CountMetric, name)
39
40 /// Use timing metrics to report on the performance of important things.
41 /// A timing metric will report the count of occurrences, as well as the
42 /// average, min and max times.
43 /// Samples are measured in milliseconds if you use the TIME_SCOPE macro
44 /// or the HighResTimer class to collect samples.
45 #define DECLARE_METRIC_timing(name) DECLARE_METRIC(TimingMetric, name)
46 #define DEFINE_METRIC_timing(name) DEFINE_METRIC(TimingMetric, name)
47
48 /// Collects a sample from here to the end of the current scope, and
49 /// adds the sample to the timing metric supplied
50 #define TIME_SCOPE(timing) \
51 stats_report::TimingSample __xxsample__(timing)
52
53 /// Use integer metrics to report runtime values that fluctuate.
54 /// Examples:
55 /// # object count
56 /// How many objects of some type exist
57 /// # disk space or memory
58 /// How much disk space or memory is in use
59 #define DECLARE_METRIC_integer(name) DECLARE_METRIC(IntegerMetric, name)
60 #define DEFINE_METRIC_integer(name) DEFINE_METRIC(IntegerMetric, name)
61
62
63 /// Use boolean metrics to report the occurrence of important but rare events
64 /// or conditions. Note that a boolean metric is tri-state, so you typically
65 /// want to set it only in one direction, and typically to true.
66 /// Setting a boolean metric one way or another on a trigger event will report
67 /// the setting of the boolean immediately prior to reporting, which is
68 /// typically not what you want.
69 #define DECLARE_METRIC_bool(name) DECLARE_METRIC(BoolMetric, name)
70 #define DEFINE_METRIC_bool(name) DEFINE_METRIC(BoolMetric, name)
71
72
73 /// Implementation macros
74 #define DECLARE_METRIC(type, name) \
75 namespace omaha_client_statsreport { \
76 extern stats_report::type metric_##name; \
77 } \
78 using omaha_client_statsreport::metric_##name
79
80 #define DEFINE_METRIC(type, name) \
81 namespace omaha_client_statsreport { \
82 stats_report::type metric_##name(#name, \
83 &stats_report::g_global_metric_storage); \
84 } \
85 using omaha_client_statsreport::metric_##name
86
87
88 namespace stats_report {
89
90 enum MetricType {
91 // use zero for invalid, because global storage defaults to zero
92 kInvalidType = 0,
93 kCountType,
94 kTimingType,
95 kIntegerType,
96 kBoolType
97 };
98
99 // fwd.
100 struct MetricCollectionBase;
101 class MetricCollection;
102 class MetricBase;
103 class IntegerMetricBase;
104 class CountMetric;
105 class TimingMetric;
106 class IntegerMetric;
107 class BoolMetric;
108
109 /// Base class for all stats instances.
110 /// Stats instances are chained together against a MetricCollection to
111 /// allow enumerating stats.
112 ///
113 /// MetricCollection is factored into a class to make it easier to unittest
114 /// the implementation.
115 class MetricBase {
116 public:
117 /// @name Downcasts
118 /// @{
119 CountMetric &AsCount();
120 TimingMetric &AsTiming();
121 IntegerMetric &AsInteger();
122 BoolMetric &AsBool();
123
124 const CountMetric &AsCount() const;
125 const TimingMetric &AsTiming() const;
126 const IntegerMetric &AsInteger() const;
127 const BoolMetric &AsBool() const;
128 /// @}
129
130 /// @name Accessors
131 /// @{
132 MetricType type() const { return type_; }
133 MetricBase *next() const { return next_; }
134 const char *name() const { return name_; }
135 /// @}
136
137 // TODO(omaha): does this need to be virtual?
138 virtual ~MetricBase() = 0;
139
140 protected:
141 class ObjectLock;
142 void Lock() const;
143 void Unlock() const;
144
145 /// Constructs a MetricBase and adds to the provided MetricCollection.
146 /// @note Metrics can only be constructed up to the point where the
147 /// MetricCollection is initialized, and there's no locking performed.
148 /// The assumption is that outside unit tests, Metrics will we declared
149 /// as static/global variables, and initialized at static initialization
150 /// time - and static initialization is single-threaded.
151 MetricBase(const char *name, MetricType type, MetricCollectionBase *coll);
152
153 /// Constructs a named typed MetricBase
154 MetricBase(const char *name, MetricType type);
155
156 /// Our name
157 char const *const name_;
158
159 /// type of this metric
160 MetricType const type_;
161
162 /// chains to next stat instance
163 MetricBase *const next_;
164
165 /// The collection we're created against
166 MetricCollectionBase *const coll_;
167
168 private:
169 DISALLOW_EVIL_CONSTRUCTORS(MetricBase);
170 };
171
172 /// Must be a POD
173 struct MetricCollectionBase {
174 bool initialized_;
175 MetricBase *first_;
176 };
177
178 /// Inherit from base, which is a POD and can be initialized at link time.
179 ///
180 /// The global MetricCollection is aliased to a link-time initialized
181 /// instance of MetricCollectionBase, and must not extend the size of its
182 /// base class.
183 class MetricCollection: public MetricCollectionBase {
184 public:
185 MetricCollection() {
186 initialized_ = false;
187 first_ = NULL;
188 }
189 ~MetricCollection() {
190 DCHECK(NULL == first_);
191 }
192
193 /// Initialize must be called after all metrics have been added to the
194 /// collection, but before enumerating it for e.g. aggregation or reporting.
195 /// The intent is that outside unit tests, there will only be the global
196 /// metrics collection, which will accrue all metrics defined with the
197 /// DEFINE_METRIC_* macros.
198 /// Typically you'd call Initialize very early in your main function, and
199 /// Uninitialize towards the end of main.
200 /// It is an error to Initialize() when the collection is initialized().
201 void Initialize();
202
203 /// Uninitialize must be called before removing (deleting or deconstructing)
204 /// metrics from the collection.
205 /// It is an error to Uninitialize() when the collection is !initialized().
206 void Uninitialize();
207
208 MetricBase *first() const { return first_; }
209 bool initialized() const { return initialized_; }
210
211 private:
212 using MetricCollectionBase::initialized_;
213 using MetricCollectionBase::first_;
214
215 DISALLOW_EVIL_CONSTRUCTORS(MetricCollection);
216
217 /// MetricBase is intimate with us
218 friend class MetricBase;
219 };
220
221 /// Implements a forward_iterator for MetricCollection.
222 class MetricIterator: public std::iterator<std::forward_iterator_tag,
223 MetricBase *> {
224 public:
225 MetricIterator() : curr_(NULL) {
226 }
227 MetricIterator(const MetricIterator &other) : curr_(other.curr_) {
228 }
229 MetricIterator(const MetricCollection &coll) : curr_(coll.first()) {
230 DCHECK(coll.initialized());
231 }
232
233 MetricBase *operator*() const {
234 return curr_;
235 }
236 MetricBase *operator->() const {
237 return curr_;
238 }
239 MetricIterator operator++() { // preincrement
240 if (curr_)
241 curr_ = curr_->next();
242
243 return (*this);
244 }
245 MetricIterator operator++(int) {// postincrement
246 MetricIterator ret = *this;
247 ++*this;
248 return (ret);
249 }
250
251 private:
252 MetricBase *curr_;
253 };
254
255 inline bool operator == (const MetricIterator &a, const MetricIterator &b) {
256 return *a == *b;
257 }
258 inline bool operator != (const MetricIterator &a, const MetricIterator &b) {
259 return !operator == (a, b);
260 }
261
262 /// Globally defined counters are registered here
263 extern MetricCollectionBase g_global_metric_storage;
264
265 /// And more conveniently accessed through here
266 extern MetricCollection &g_global_metrics;
267
268 /// Base class for integer metrics
269 class IntegerMetricBase: public MetricBase {
270 public:
271 /// Sets the current value
272 void Set(int64 value);
273
274 /// Retrieves the current value
275 int64 value() const;
276
277 void operator ++ () { Increment(); }
278 void operator ++ (int) { Increment(); }
279 void operator += (int64 addend) { Add(addend); }
280
281 protected:
282 IntegerMetricBase(const char *name,
283 MetricType type,
284 MetricCollectionBase *coll)
285 : MetricBase(name, type, coll), value_(0) {
286 }
287 IntegerMetricBase(const char *name, MetricType type, int64 value)
288 : MetricBase(name, type), value_(value) {
289 }
290
291 void Increment();
292 void Decrement();
293 void Add(int64 value);
294 void Subtract(int64 value);
295
296 int64 value_;
297
298 private:
299 DISALLOW_EVIL_CONSTRUCTORS(IntegerMetricBase);
300 };
301
302 /// A count metric is a cumulative counter of events.
303 class CountMetric: public IntegerMetricBase {
304 public:
305 CountMetric(const char *name, MetricCollectionBase *coll)
306 : IntegerMetricBase(name, kCountType, coll) {
307 }
308
309 CountMetric(const char *name, int64 value)
310 : IntegerMetricBase(name, kCountType, value) {
311 }
312
313 /// Nulls the metric and returns the current values.
314 int64 Reset();
315
316 private:
317 DISALLOW_EVIL_CONSTRUCTORS(CountMetric);
318 };
319
320 class TimingMetric: public MetricBase {
321 public:
322 struct TimingData {
323 uint32 count;
324 uint32 align; // allow access to the alignment gap between count and sum,
325 // makes it esier to unittest.
326 int64 sum; // ms
327 int64 minimum; // ms
328 int64 maximum; // ms
329 };
330
331 TimingMetric(const char *name, MetricCollectionBase *coll)
332 : MetricBase(name, kTimingType, coll) {
333 Clear();
334 }
335
336 TimingMetric(const char *name, const TimingData &value)
337 : MetricBase(name, kTimingType), data_(value) {
338 }
339
340 uint32 count() const;
341 int64 sum() const;
342 int64 minimum() const;
343 int64 maximum() const;
344 int64 average() const;
345
346 /// Adds a single sample to the metric
347 /// @param time_ms time (in milliseconds) for this sample
348 void AddSample(int64 time_ms);
349
350 /// Adds count samples to the metric
351 /// @note use this when capturing time over a variable number of items to
352 /// normalize e.g. download time per byte or KB. This records one sample
353 /// over count items, which is numerically more stable for the average
354 /// than dividing the captured time by the item count. As a side benefit
355 /// the timer will also record the item count.
356 /// @note if count == 0, no sample will be recorded
357 /// @param count number of samples to add
358 /// @param total_time_ms the total time consumed by all the "count" samples
359 void AddSamples(int64 count, int64 total_time_ms);
360
361 /// Nulls the metric and returns the current values.
362 TimingData Reset();
363
364 private:
365 DISALLOW_EVIL_CONSTRUCTORS(TimingMetric);
366
367 void Clear();
368
369 TimingData data_;
370 };
371
372 /// A convenience class to sample the time from construction to destruction
373 /// against a given timing metric.
374 class TimingSample {
375 public:
376 /// @param timing the metric the sample is to be tallied against
377 explicit TimingSample(TimingMetric &timing) : timing_(timing), count_(1) {
378 }
379
380 /// @param timing the metric the sample is to be tallied against
381 /// @param item_count count of items processed, used to divide the sampled
382 /// time so as to capture time per item, which is often a better measure
383 /// than the total time over a varying number of items.
384 TimingSample(TimingMetric &timing, uint32 item_count) : timing_(timing),
385 count_(item_count) {
386 }
387
388 ~TimingSample() {
389 // We discard samples with a zero count
390 if(count_ == 1)
391 timing_.AddSample(timer_.GetElapsedMs());
392 else
393 timing_.AddSamples(count_, timer_.GetElapsedMs());
394 }
395
396 /// @name Accessors
397 /// @{
398 uint32 count() const { return count_; }
399 void set_count(uint32 count) { count_ = count; }
400 /// @}
401
402 private:
403 /// Collects the sample for us.
404 omaha::HighresTimer timer_;
405
406 /// The metric we tally against.
407 TimingMetric &timing_;
408
409 /// The item count we divide the captured time by
410 uint32 count_;
411
412 DISALLOW_EVIL_CONSTRUCTORS(TimingSample);
413 };
414
415 /// An integer metric is used to sample values that vary over time.
416 /// On aggregation the instantaneous value of the integer metric is captured.
417 class IntegerMetric: public IntegerMetricBase {
418 public:
419 IntegerMetric(const char *name, MetricCollectionBase *coll)
420 : IntegerMetricBase(name, kIntegerType, coll) {
421 }
422
423 IntegerMetric(const char *name, int64 value)
424 : IntegerMetricBase(name, kIntegerType, value) {
425 }
426
427 void operator = (int64 value) { Set(value); }
428
429 void operator -- () { Decrement(); }
430 void operator -- (int) { Decrement(); }
431 void operator -= (int64 sub) { Subtract(sub); }
432
433 private:
434 DISALLOW_EVIL_CONSTRUCTORS(IntegerMetric);
435 };
436
437 /// A bool metric is tri-state, and can be:
438 /// - unset,
439 /// - true or
440 /// - false
441 /// to match other metrics, which are implicitly unset if they've not changed
442 /// from their initial value.
443 class BoolMetric: public MetricBase {
444 public:
445 /// Values we can take
446 enum TristateBoolValue {
447 kBoolUnset = -1,
448 kBoolFalse,
449 kBoolTrue,
450 };
451
452 BoolMetric(const char *name, MetricCollectionBase *coll)
453 : MetricBase(name, kBoolType, coll), value_(kBoolUnset) {
454 }
455
456 BoolMetric(const char *name, uint32 value)
457 : MetricBase(name, kBoolType) {
458 switch (value) {
459 case kBoolFalse:
460 case kBoolTrue:
461 value_ = static_cast<TristateBoolValue>(value);
462 break;
463
464 default:
465 DCHECK(false && "Unexpected tristate bool value on construction");
466 value_ = kBoolUnset;
467 }
468 }
469
470 /// Sets the flag to the provided value.
471 void Set(bool value);
472
473 void operator = (bool value) {
474 Set(value);
475 }
476
477 /// Nulls the metric and returns the current values.
478 TristateBoolValue Reset();
479
480 /// Returns the current value - not threadsafe
481 TristateBoolValue value() const { return value_; };
482
483 private:
484 DISALLOW_EVIL_CONSTRUCTORS(BoolMetric);
485
486 TristateBoolValue value_;
487 };
488
489 inline CountMetric &MetricBase::AsCount() {
490 DCHECK_EQ(kCountType, type());
491
492 return static_cast<CountMetric&>(*this);
493 }
494
495 inline TimingMetric &MetricBase::AsTiming() {
496 DCHECK_EQ(kTimingType, type());
497
498 return static_cast<TimingMetric&>(*this);
499 }
500
501 inline IntegerMetric &MetricBase::AsInteger() {
502 DCHECK_EQ(kIntegerType, type());
503
504 return static_cast<IntegerMetric&>(*this);
505 }
506
507 inline BoolMetric &MetricBase::AsBool() {
508 DCHECK_EQ(kBoolType, type());
509
510 return static_cast<BoolMetric&>(*this);
511 }
512
513 inline const CountMetric &MetricBase::AsCount() const {
514 DCHECK_EQ(kCountType, type());
515
516 return static_cast<const CountMetric&>(*this);
517 }
518
519 inline const TimingMetric &MetricBase::AsTiming() const {
520 DCHECK_EQ(kTimingType, type());
521
522 return static_cast<const TimingMetric&>(*this);
523 }
524
525 inline const IntegerMetric &MetricBase::AsInteger() const {
526 DCHECK_EQ(kIntegerType, type());
527
528 return static_cast<const IntegerMetric&>(*this);
529 }
530
531 inline const BoolMetric &MetricBase::AsBool() const {
532 DCHECK_EQ(kBoolType, type());
533
534 return static_cast<const BoolMetric&>(*this);
535 }
536
537 } // namespace stats_report
538
539 #endif // OMAHA_STATSREPORT_METRICS_H__
OLDNEW
« no previous file with comments | « statsreport/formatter_unittest.cc ('k') | statsreport/metrics.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698