ipc/chromium/src/base/histogram.h

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:2cb538745fbe
1 // Copyright (c) 2011 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 // Histogram is an object that aggregates statistics, and can summarize them in
6 // various forms, including ASCII graphical, HTML, and numerically (as a
7 // vector of numbers corresponding to each of the aggregating buckets).
8
9 // It supports calls to accumulate either time intervals (which are processed
10 // as integral number of milliseconds), or arbitrary integral units.
11
12 // The default layout of buckets is exponential. For example, buckets might
13 // contain (sequentially) the count of values in the following intervals:
14 // [0,1), [1,2), [2,4), [4,8), [8,16), [16,32), [32,64), [64,infinity)
15 // That bucket allocation would actually result from construction of a histogram
16 // for values between 1 and 64, with 8 buckets, such as:
17 // Histogram count(L"some name", 1, 64, 8);
18 // Note that the underflow bucket [0,1) and the overflow bucket [64,infinity)
19 // are not counted by the constructor in the user supplied "bucket_count"
20 // argument.
21 // The above example has an exponential ratio of 2 (doubling the bucket width
22 // in each consecutive bucket. The Histogram class automatically calculates
23 // the smallest ratio that it can use to construct the number of buckets
24 // selected in the constructor. An another example, if you had 50 buckets,
25 // and millisecond time values from 1 to 10000, then the ratio between
26 // consecutive bucket widths will be approximately somewhere around the 50th
27 // root of 10000. This approach provides very fine grain (narrow) buckets
28 // at the low end of the histogram scale, but allows the histogram to cover a
29 // gigantic range with the addition of very few buckets.
30
31 // Histograms use a pattern involving a function static variable, that is a
32 // pointer to a histogram. This static is explicitly initialized on any thread
33 // that detects a uninitialized (NULL) pointer. The potentially racy
34 // initialization is not a problem as it is always set to point to the same
35 // value (i.e., the FactoryGet always returns the same value). FactoryGet
36 // is also completely thread safe, which results in a completely thread safe,
37 // and relatively fast, set of counters. To avoid races at shutdown, the static
38 // pointer is NOT deleted, and we leak the histograms at process termination.
39
40 #ifndef BASE_METRICS_HISTOGRAM_H_
41 #define BASE_METRICS_HISTOGRAM_H_
42 #pragma once
43
44 #include "mozilla/MemoryReporting.h"
45
46 #include <map>
47 #include <string>
48 #include <vector>
49
50 #include "base/time.h"
51 #include "base/lock.h"
52
53 class Pickle;
54
55 namespace base {
56 //------------------------------------------------------------------------------
57 // Provide easy general purpose histogram in a macro, just like stats counters.
58 // The first four macros use 50 buckets.
59
60 #define HISTOGRAM_TIMES(name, sample) HISTOGRAM_CUSTOM_TIMES( \
61 name, sample, base::TimeDelta::FromMilliseconds(1), \
62 base::TimeDelta::FromSeconds(10), 50)
63
64 #define HISTOGRAM_COUNTS(name, sample) HISTOGRAM_CUSTOM_COUNTS( \
65 name, sample, 1, 1000000, 50)
66
67 #define HISTOGRAM_COUNTS_100(name, sample) HISTOGRAM_CUSTOM_COUNTS( \
68 name, sample, 1, 100, 50)
69
70 #define HISTOGRAM_COUNTS_10000(name, sample) HISTOGRAM_CUSTOM_COUNTS( \
71 name, sample, 1, 10000, 50)
72
73 #define HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) do { \
74 static base::Histogram* counter(NULL); \
75 if (!counter) \
76 counter = base::Histogram::FactoryGet(name, min, max, bucket_count, \
77 base::Histogram::kNoFlags); \
78 DCHECK_EQ(name, counter->histogram_name()); \
79 counter->Add(sample); \
80 } while (0)
81
82 #define HISTOGRAM_PERCENTAGE(name, under_one_hundred) \
83 HISTOGRAM_ENUMERATION(name, under_one_hundred, 101)
84
85 // For folks that need real specific times, use this to select a precise range
86 // of times you want plotted, and the number of buckets you want used.
87 #define HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) do { \
88 static base::Histogram* counter(NULL); \
89 if (!counter) \
90 counter = base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
91 base::Histogram::kNoFlags); \
92 DCHECK_EQ(name, counter->histogram_name()); \
93 counter->AddTime(sample); \
94 } while (0)
95
96 // DO NOT USE THIS. It is being phased out, in favor of HISTOGRAM_CUSTOM_TIMES.
97 #define HISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) do { \
98 static base::Histogram* counter(NULL); \
99 if (!counter) \
100 counter = base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
101 base::Histogram::kNoFlags); \
102 DCHECK_EQ(name, counter->histogram_name()); \
103 if ((sample) < (max)) counter->AddTime(sample); \
104 } while (0)
105
106 // Support histograming of an enumerated value. The samples should always be
107 // less than boundary_value.
108
109 #define HISTOGRAM_ENUMERATION(name, sample, boundary_value) do { \
110 static base::Histogram* counter(NULL); \
111 if (!counter) \
112 counter = base::LinearHistogram::FactoryGet(name, 1, boundary_value, \
113 boundary_value + 1, base::Histogram::kNoFlags); \
114 DCHECK_EQ(name, counter->histogram_name()); \
115 counter->Add(sample); \
116 } while (0)
117
118 #define HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) do { \
119 static base::Histogram* counter(NULL); \
120 if (!counter) \
121 counter = base::CustomHistogram::FactoryGet(name, custom_ranges, \
122 base::Histogram::kNoFlags); \
123 DCHECK_EQ(name, counter->histogram_name()); \
124 counter->Add(sample); \
125 } while (0)
126
127
128 //------------------------------------------------------------------------------
129 // Define Debug vs non-debug flavors of macros.
130 #ifndef NDEBUG
131
132 #define DHISTOGRAM_TIMES(name, sample) HISTOGRAM_TIMES(name, sample)
133 #define DHISTOGRAM_COUNTS(name, sample) HISTOGRAM_COUNTS(name, sample)
134 #define DHISTOGRAM_PERCENTAGE(name, under_one_hundred) HISTOGRAM_PERCENTAGE(\
135 name, under_one_hundred)
136 #define DHISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \
137 HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count)
138 #define DHISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) \
139 HISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count)
140 #define DHISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \
141 HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count)
142 #define DHISTOGRAM_ENUMERATION(name, sample, boundary_value) \
143 HISTOGRAM_ENUMERATION(name, sample, boundary_value)
144 #define DHISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \
145 HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges)
146
147 #else // NDEBUG
148
149 #define DHISTOGRAM_TIMES(name, sample) do {} while (0)
150 #define DHISTOGRAM_COUNTS(name, sample) do {} while (0)
151 #define DHISTOGRAM_PERCENTAGE(name, under_one_hundred) do {} while (0)
152 #define DHISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \
153 do {} while (0)
154 #define DHISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) \
155 do {} while (0)
156 #define DHISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \
157 do {} while (0)
158 #define DHISTOGRAM_ENUMERATION(name, sample, boundary_value) do {} while (0)
159 #define DHISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \
160 do {} while (0)
161
162 #endif // NDEBUG
163
164 //------------------------------------------------------------------------------
165 // The following macros provide typical usage scenarios for callers that wish
166 // to record histogram data, and have the data submitted/uploaded via UMA.
167 // Not all systems support such UMA, but if they do, the following macros
168 // should work with the service.
169
170 #define UMA_HISTOGRAM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
171 name, sample, base::TimeDelta::FromMilliseconds(1), \
172 base::TimeDelta::FromSeconds(10), 50)
173
174 #define UMA_HISTOGRAM_MEDIUM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
175 name, sample, base::TimeDelta::FromMilliseconds(10), \
176 base::TimeDelta::FromMinutes(3), 50)
177
178 // Use this macro when times can routinely be much longer than 10 seconds.
179 #define UMA_HISTOGRAM_LONG_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
180 name, sample, base::TimeDelta::FromMilliseconds(1), \
181 base::TimeDelta::FromHours(1), 50)
182
183 #define UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) do { \
184 static base::Histogram* counter(NULL); \
185 if (!counter) \
186 counter = base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
187 base::Histogram::kUmaTargetedHistogramFlag); \
188 DCHECK_EQ(name, counter->histogram_name()); \
189 counter->AddTime(sample); \
190 } while (0)
191
192 // DO NOT USE THIS. It is being phased out, in favor of HISTOGRAM_CUSTOM_TIMES.
193 #define UMA_HISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) do { \
194 static base::Histogram* counter(NULL); \
195 if (!counter) \
196 counter = base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
197 base::Histogram::kUmaTargetedHistogramFlag); \
198 DCHECK_EQ(name, counter->histogram_name()); \
199 if ((sample) < (max)) counter->AddTime(sample); \
200 } while (0)
201
202 #define UMA_HISTOGRAM_COUNTS(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
203 name, sample, 1, 1000000, 50)
204
205 #define UMA_HISTOGRAM_COUNTS_100(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
206 name, sample, 1, 100, 50)
207
208 #define UMA_HISTOGRAM_COUNTS_10000(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
209 name, sample, 1, 10000, 50)
210
211 #define UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) do { \
212 static base::Histogram* counter(NULL); \
213 if (!counter) \
214 counter = base::Histogram::FactoryGet(name, min, max, bucket_count, \
215 base::Histogram::kUmaTargetedHistogramFlag); \
216 DCHECK_EQ(name, counter->histogram_name()); \
217 counter->Add(sample); \
218 } while (0)
219
220 #define UMA_HISTOGRAM_MEMORY_KB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
221 name, sample, 1000, 500000, 50)
222
223 #define UMA_HISTOGRAM_MEMORY_MB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
224 name, sample, 1, 1000, 50)
225
226 #define UMA_HISTOGRAM_PERCENTAGE(name, under_one_hundred) \
227 UMA_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101)
228
229 #define UMA_HISTOGRAM_BOOLEAN(name, sample) do { \
230 static base::Histogram* counter(NULL); \
231 if (!counter) \
232 counter = base::BooleanHistogram::FactoryGet(name, \
233 base::Histogram::kUmaTargetedHistogramFlag); \
234 DCHECK_EQ(name, counter->histogram_name()); \
235 counter->AddBoolean(sample); \
236 } while (0)
237
238 #define UMA_HISTOGRAM_ENUMERATION(name, sample, boundary_value) do { \
239 static base::Histogram* counter(NULL); \
240 if (!counter) \
241 counter = base::LinearHistogram::FactoryGet(name, 1, boundary_value, \
242 boundary_value + 1, base::Histogram::kUmaTargetedHistogramFlag); \
243 DCHECK_EQ(name, counter->histogram_name()); \
244 counter->Add(sample); \
245 } while (0)
246
247 #define UMA_HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) do { \
248 static base::Histogram* counter(NULL); \
249 if (!counter) \
250 counter = base::CustomHistogram::FactoryGet(name, custom_ranges, \
251 base::Histogram::kUmaTargetedHistogramFlag); \
252 DCHECK_EQ(name, counter->histogram_name()); \
253 counter->Add(sample); \
254 } while (0)
255
256 //------------------------------------------------------------------------------
257
258 class BooleanHistogram;
259 class CustomHistogram;
260 class Histogram;
261 class LinearHistogram;
262
263 class Histogram {
264 public:
265 typedef int Sample; // Used for samples (and ranges of samples).
266 typedef int Count; // Used to count samples in a bucket.
267 static const Sample kSampleType_MAX = INT_MAX;
268 // Initialize maximum number of buckets in histograms as 16,384.
269 static const size_t kBucketCount_MAX;
270
271 typedef std::vector<Count> Counts;
272 typedef std::vector<Sample> Ranges;
273
274 // These enums are used to facilitate deserialization of renderer histograms
275 // into the browser.
276 enum ClassType {
277 HISTOGRAM,
278 LINEAR_HISTOGRAM,
279 BOOLEAN_HISTOGRAM,
280 FLAG_HISTOGRAM,
281 CUSTOM_HISTOGRAM,
282 NOT_VALID_IN_RENDERER
283 };
284
285 enum BucketLayout {
286 EXPONENTIAL,
287 LINEAR,
288 CUSTOM
289 };
290
291 enum Flags {
292 kNoFlags = 0,
293 kUmaTargetedHistogramFlag = 0x1, // Histogram should be UMA uploaded.
294 kExtendedStatisticsFlag = 0x2, // OK to gather extended statistics on histograms.
295
296 // Indicate that the histogram was pickled to be sent across an IPC Channel.
297 // If we observe this flag on a histogram being aggregated into after IPC,
298 // then we are running in a single process mode, and the aggregation should
299 // not take place (as we would be aggregating back into the source
300 // histogram!).
301 kIPCSerializationSourceFlag = 0x10,
302
303 kHexRangePrintingFlag = 0x8000 // Fancy bucket-naming supported.
304 };
305
306 enum Inconsistencies {
307 NO_INCONSISTENCIES = 0x0,
308 RANGE_CHECKSUM_ERROR = 0x1,
309 BUCKET_ORDER_ERROR = 0x2,
310 COUNT_HIGH_ERROR = 0x4,
311 COUNT_LOW_ERROR = 0x8,
312
313 NEVER_EXCEEDED_VALUE = 0x10
314 };
315
316 struct DescriptionPair {
317 Sample sample;
318 const char* description; // Null means end of a list of pairs.
319 };
320
321 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
322
323 //----------------------------------------------------------------------------
324 // Statistic values, developed over the life of the histogram.
325
326 class SampleSet {
327 public:
328 explicit SampleSet();
329 ~SampleSet();
330
331 // Adjust size of counts_ for use with given histogram.
332 void Resize(const Histogram& histogram);
333 void CheckSize(const Histogram& histogram) const;
334
335 // Accessor for histogram to make routine additions.
336 void AccumulateWithLinearStats(Sample value, Count count, size_t index);
337 // Alternate routine for exponential histograms.
338 // computeExpensiveStatistics should be true if we want to compute log sums.
339 void AccumulateWithExponentialStats(Sample value, Count count, size_t index,
340 bool computeExtendedStatistics);
341
342 // Accessor methods.
343 Count counts(size_t i) const { return counts_[i]; }
344 Count TotalCount() const;
345 int64_t sum() const { return sum_; }
346 uint64_t sum_squares() const { return sum_squares_; }
347 double log_sum() const { return log_sum_; }
348 double log_sum_squares() const { return log_sum_squares_; }
349 int64_t redundant_count() const { return redundant_count_; }
350 size_t size() const { return counts_.size(); }
351
352 // Arithmetic manipulation of corresponding elements of the set.
353 void Add(const SampleSet& other);
354 void Subtract(const SampleSet& other);
355
356 bool Serialize(Pickle* pickle) const;
357 bool Deserialize(void** iter, const Pickle& pickle);
358
359 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf);
360
361 protected:
362 // Actual histogram data is stored in buckets, showing the count of values
363 // that fit into each bucket.
364 Counts counts_;
365
366 // Save simple stats locally. Note that this MIGHT get done in base class
367 // without shared memory at some point.
368 int64_t sum_; // sum of samples.
369 uint64_t sum_squares_; // sum of squares of samples.
370
371 // These fields may or may not be updated at the discretion of the
372 // histogram. We use the natural log and compute ln(sample+1) so that
373 // zeros are handled sanely.
374 double log_sum_; // sum of logs of samples.
375 double log_sum_squares_; // sum of squares of logs of samples
376
377 private:
378 void Accumulate(Sample value, Count count, size_t index);
379
380 // To help identify memory corruption, we reduntantly save the number of
381 // samples we've accumulated into all of our buckets. We can compare this
382 // count to the sum of the counts in all buckets, and detect problems. Note
383 // that due to races in histogram accumulation (if a histogram is indeed
384 // updated on several threads simultaneously), the tallies might mismatch,
385 // and also the snapshotting code may asynchronously get a mismatch (though
386 // generally either race based mismatch cause is VERY rare).
387 int64_t redundant_count_;
388 };
389
390 //----------------------------------------------------------------------------
391 // minimum should start from 1. 0 is invalid as a minimum. 0 is an implicit
392 // default underflow bucket.
393 static Histogram* FactoryGet(const std::string& name,
394 Sample minimum,
395 Sample maximum,
396 size_t bucket_count,
397 Flags flags);
398 static Histogram* FactoryTimeGet(const std::string& name,
399 base::TimeDelta minimum,
400 base::TimeDelta maximum,
401 size_t bucket_count,
402 Flags flags);
403
404 void Add(int value);
405 void Subtract(int value);
406
407 // This method is an interface, used only by BooleanHistogram.
408 virtual void AddBoolean(bool value);
409
410 // Accept a TimeDelta to increment.
411 void AddTime(TimeDelta time) {
412 Add(static_cast<int>(time.InMilliseconds()));
413 }
414
415 virtual void AddSampleSet(const SampleSet& sample);
416
417 void Clear();
418
419 // This method is an interface, used only by LinearHistogram.
420 virtual void SetRangeDescriptions(const DescriptionPair descriptions[]);
421
422 // The following methods provide graphical histogram displays.
423 void WriteHTMLGraph(std::string* output) const;
424 void WriteAscii(bool graph_it, const std::string& newline,
425 std::string* output) const;
426
427 // Support generic flagging of Histograms.
428 // 0x1 Currently used to mark this histogram to be recorded by UMA..
429 // 0x8000 means print ranges in hex.
430 void SetFlags(Flags flags) { flags_ = static_cast<Flags> (flags_ | flags); }
431 void ClearFlags(Flags flags) { flags_ = static_cast<Flags>(flags_ & ~flags); }
432 int flags() const { return flags_; }
433
434 // Convenience methods for serializing/deserializing the histograms.
435 // Histograms from Renderer process are serialized and sent to the browser.
436 // Browser process reconstructs the histogram from the pickled version
437 // accumulates the browser-side shadow copy of histograms (that mirror
438 // histograms created in the renderer).
439
440 // Serialize the given snapshot of a Histogram into a String. Uses
441 // Pickle class to flatten the object.
442 static std::string SerializeHistogramInfo(const Histogram& histogram,
443 const SampleSet& snapshot);
444 // The following method accepts a list of pickled histograms and
445 // builds a histogram and updates shadow copy of histogram data in the
446 // browser process.
447 static bool DeserializeHistogramInfo(const std::string& histogram_info);
448
449 // Check to see if bucket ranges, counts and tallies in the snapshot are
450 // consistent with the bucket ranges and checksums in our histogram. This can
451 // produce a false-alarm if a race occurred in the reading of the data during
452 // a SnapShot process, but should otherwise be false at all times (unless we
453 // have memory over-writes, or DRAM failures).
454 virtual Inconsistencies FindCorruption(const SampleSet& snapshot) const;
455
456 //----------------------------------------------------------------------------
457 // Accessors for factory constuction, serialization and testing.
458 //----------------------------------------------------------------------------
459 virtual ClassType histogram_type() const;
460 const std::string& histogram_name() const { return histogram_name_; }
461 Sample declared_min() const { return declared_min_; }
462 Sample declared_max() const { return declared_max_; }
463 virtual Sample ranges(size_t i) const;
464 uint32_t range_checksum() const { return range_checksum_; }
465 virtual size_t bucket_count() const;
466 // Snapshot the current complete set of sample data.
467 // Override with atomic/locked snapshot if needed.
468 virtual void SnapshotSample(SampleSet* sample) const;
469
470 virtual bool HasConstructorArguments(Sample minimum, Sample maximum,
471 size_t bucket_count);
472
473 virtual bool HasConstructorTimeDeltaArguments(TimeDelta minimum,
474 TimeDelta maximum,
475 size_t bucket_count);
476 // Return true iff the range_checksum_ matches current ranges_ vector.
477 bool HasValidRangeChecksum() const;
478
479 protected:
480 Histogram(const std::string& name, Sample minimum,
481 Sample maximum, size_t bucket_count);
482 Histogram(const std::string& name, TimeDelta minimum,
483 TimeDelta maximum, size_t bucket_count);
484
485 virtual ~Histogram();
486
487 // Initialize ranges_ mapping.
488 void InitializeBucketRange();
489
490 // Method to override to skip the display of the i'th bucket if it's empty.
491 virtual bool PrintEmptyBucket(size_t index) const;
492
493 //----------------------------------------------------------------------------
494 // Methods to override to create histogram with different bucket widths.
495 //----------------------------------------------------------------------------
496 // Find bucket to increment for sample value.
497 virtual size_t BucketIndex(Sample value) const;
498 // Get normalized size, relative to the ranges_[i].
499 virtual double GetBucketSize(Count current, size_t i) const;
500
501 // Recalculate range_checksum_.
502 void ResetRangeChecksum();
503
504 // Return a string description of what goes in a given bucket.
505 // Most commonly this is the numeric value, but in derived classes it may
506 // be a name (or string description) given to the bucket.
507 virtual const std::string GetAsciiBucketRange(size_t it) const;
508
509 //----------------------------------------------------------------------------
510 // Methods to override to create thread safe histogram.
511 //----------------------------------------------------------------------------
512 // Update all our internal data, including histogram
513 virtual void Accumulate(Sample value, Count count, size_t index);
514
515 //----------------------------------------------------------------------------
516 // Accessors for derived classes.
517 //----------------------------------------------------------------------------
518 void SetBucketRange(size_t i, Sample value);
519
520 // Validate that ranges_ was created sensibly (top and bottom range
521 // values relate properly to the declared_min_ and declared_max_)..
522 bool ValidateBucketRanges() const;
523
524 virtual uint32_t CalculateRangeChecksum() const;
525
526 // Finally, provide the state that changes with the addition of each new
527 // sample.
528 SampleSet sample_;
529
530 private:
531 friend class StatisticsRecorder; // To allow it to delete duplicates.
532
533 // Post constructor initialization.
534 void Initialize();
535
536 // Checksum function for accumulating range values into a checksum.
537 static uint32_t Crc32(uint32_t sum, Sample range);
538
539 //----------------------------------------------------------------------------
540 // Helpers for emitting Ascii graphic. Each method appends data to output.
541
542 // Find out how large the (graphically) the largest bucket will appear to be.
543 double GetPeakBucketSize(const SampleSet& snapshot) const;
544
545 // Write a common header message describing this histogram.
546 void WriteAsciiHeader(const SampleSet& snapshot,
547 Count sample_count, std::string* output) const;
548
549 // Write information about previous, current, and next buckets.
550 // Information such as cumulative percentage, etc.
551 void WriteAsciiBucketContext(const int64_t past, const Count current,
552 const int64_t remaining, const size_t i,
553 std::string* output) const;
554
555 // Write textual description of the bucket contents (relative to histogram).
556 // Output is the count in the buckets, as well as the percentage.
557 void WriteAsciiBucketValue(Count current, double scaled_sum,
558 std::string* output) const;
559
560 // Produce actual graph (set of blank vs non blank char's) for a bucket.
561 void WriteAsciiBucketGraph(double current_size, double max_size,
562 std::string* output) const;
563
564 //----------------------------------------------------------------------------
565 // Table for generating Crc32 values.
566 static const uint32_t kCrcTable[256];
567 //----------------------------------------------------------------------------
568 // Invariant values set at/near construction time
569
570 // ASCII version of original name given to the constructor. All identically
571 // named instances will be coalesced cross-project.
572 const std::string histogram_name_;
573 Sample declared_min_; // Less than this goes into counts_[0]
574 Sample declared_max_; // Over this goes into counts_[bucket_count_ - 1].
575 size_t bucket_count_; // Dimension of counts_[].
576
577 // Flag the histogram for recording by UMA via metric_services.h.
578 Flags flags_;
579
580 // For each index, show the least value that can be stored in the
581 // corresponding bucket. We also append one extra element in this array,
582 // containing kSampleType_MAX, to make calculations easy.
583 // The dimension of ranges_ is bucket_count + 1.
584 Ranges ranges_;
585
586 // For redundancy, we store a checksum of all the sample ranges when ranges
587 // are generated. If ever there is ever a difference, then the histogram must
588 // have been corrupted.
589 uint32_t range_checksum_;
590
591 DISALLOW_COPY_AND_ASSIGN(Histogram);
592 };
593
594 //------------------------------------------------------------------------------
595
596 // LinearHistogram is a more traditional histogram, with evenly spaced
597 // buckets.
598 class LinearHistogram : public Histogram {
599 public:
600 virtual ~LinearHistogram();
601
602 /* minimum should start from 1. 0 is as minimum is invalid. 0 is an implicit
603 default underflow bucket. */
604 static Histogram* FactoryGet(const std::string& name,
605 Sample minimum,
606 Sample maximum,
607 size_t bucket_count,
608 Flags flags);
609 static Histogram* FactoryTimeGet(const std::string& name,
610 TimeDelta minimum,
611 TimeDelta maximum,
612 size_t bucket_count,
613 Flags flags);
614
615 // Overridden from Histogram:
616 virtual ClassType histogram_type() const;
617
618 virtual void Accumulate(Sample value, Count count, size_t index);
619
620 // Store a list of number/text values for use in rendering the histogram.
621 // The last element in the array has a null in its "description" slot.
622 virtual void SetRangeDescriptions(const DescriptionPair descriptions[]);
623
624 protected:
625 LinearHistogram(const std::string& name, Sample minimum,
626 Sample maximum, size_t bucket_count);
627
628 LinearHistogram(const std::string& name, TimeDelta minimum,
629 TimeDelta maximum, size_t bucket_count);
630
631 // Initialize ranges_ mapping.
632 void InitializeBucketRange();
633 virtual double GetBucketSize(Count current, size_t i) const;
634
635 // If we have a description for a bucket, then return that. Otherwise
636 // let parent class provide a (numeric) description.
637 virtual const std::string GetAsciiBucketRange(size_t i) const;
638
639 // Skip printing of name for numeric range if we have a name (and if this is
640 // an empty bucket).
641 virtual bool PrintEmptyBucket(size_t index) const;
642
643 private:
644 // For some ranges, we store a printable description of a bucket range.
645 // If there is no desciption, then GetAsciiBucketRange() uses parent class
646 // to provide a description.
647 typedef std::map<Sample, std::string> BucketDescriptionMap;
648 BucketDescriptionMap bucket_description_;
649
650 DISALLOW_COPY_AND_ASSIGN(LinearHistogram);
651 };
652
653 //------------------------------------------------------------------------------
654
655 // BooleanHistogram is a histogram for booleans.
656 class BooleanHistogram : public LinearHistogram {
657 public:
658 static Histogram* FactoryGet(const std::string& name, Flags flags);
659
660 virtual ClassType histogram_type() const;
661
662 virtual void AddBoolean(bool value);
663
664 virtual void Accumulate(Sample value, Count count, size_t index);
665
666 protected:
667 explicit BooleanHistogram(const std::string& name);
668
669 DISALLOW_COPY_AND_ASSIGN(BooleanHistogram);
670 };
671
672 //------------------------------------------------------------------------------
673
674 // FlagHistogram is like boolean histogram, but only allows a single off/on value.
675 class FlagHistogram : public BooleanHistogram
676 {
677 public:
678 static Histogram *FactoryGet(const std::string &name, Flags flags);
679
680 virtual ClassType histogram_type() const;
681
682 virtual void Accumulate(Sample value, Count count, size_t index);
683
684 virtual void AddSampleSet(const SampleSet& sample);
685
686 private:
687 explicit FlagHistogram(const std::string &name);
688 bool mSwitched;
689
690 DISALLOW_COPY_AND_ASSIGN(FlagHistogram);
691 };
692
693 //------------------------------------------------------------------------------
694
695 // CustomHistogram is a histogram for a set of custom integers.
696 class CustomHistogram : public Histogram {
697 public:
698
699 static Histogram* FactoryGet(const std::string& name,
700 const std::vector<Sample>& custom_ranges,
701 Flags flags);
702
703 // Overridden from Histogram:
704 virtual ClassType histogram_type() const;
705
706 protected:
707 CustomHistogram(const std::string& name,
708 const std::vector<Sample>& custom_ranges);
709
710 // Initialize ranges_ mapping.
711 void InitializedCustomBucketRange(const std::vector<Sample>& custom_ranges);
712 virtual double GetBucketSize(Count current, size_t i) const;
713
714 DISALLOW_COPY_AND_ASSIGN(CustomHistogram);
715 };
716
717 //------------------------------------------------------------------------------
718 // StatisticsRecorder handles all histograms in the system. It provides a
719 // general place for histograms to register, and supports a global API for
720 // accessing (i.e., dumping, or graphing) the data in all the histograms.
721
722 class StatisticsRecorder {
723 public:
724 typedef std::vector<Histogram*> Histograms;
725
726 StatisticsRecorder();
727
728 ~StatisticsRecorder();
729
730 // Find out if histograms can now be registered into our list.
731 static bool IsActive();
732
733 // Register, or add a new histogram to the collection of statistics. If an
734 // identically named histogram is already registered, then the argument
735 // |histogram| will deleted. The returned value is always the registered
736 // histogram (either the argument, or the pre-existing registered histogram).
737 static Histogram* RegisterOrDeleteDuplicate(Histogram* histogram);
738
739 // Methods for printing histograms. Only histograms which have query as
740 // a substring are written to output (an empty string will process all
741 // registered histograms).
742 static void WriteHTMLGraph(const std::string& query, std::string* output);
743 static void WriteGraph(const std::string& query, std::string* output);
744
745 // Method for extracting histograms which were marked for use by UMA.
746 static void GetHistograms(Histograms* output);
747
748 // Find a histogram by name. It matches the exact name. This method is thread
749 // safe. If a matching histogram is not found, then the |histogram| is
750 // not changed.
751 static bool FindHistogram(const std::string& query, Histogram** histogram);
752
753 static bool dump_on_exit() { return dump_on_exit_; }
754
755 static void set_dump_on_exit(bool enable) { dump_on_exit_ = enable; }
756
757 // GetSnapshot copies some of the pointers to registered histograms into the
758 // caller supplied vector (Histograms). Only histograms with names matching
759 // query are returned. The query must be a substring of histogram name for its
760 // pointer to be copied.
761 static void GetSnapshot(const std::string& query, Histograms* snapshot);
762
763
764 private:
765 // We keep all registered histograms in a map, from name to histogram.
766 typedef std::map<std::string, Histogram*> HistogramMap;
767
768 static HistogramMap* histograms_;
769
770 // lock protects access to the above map.
771 static Lock* lock_;
772
773 // Dump all known histograms to log.
774 static bool dump_on_exit_;
775
776 DISALLOW_COPY_AND_ASSIGN(StatisticsRecorder);
777 };
778
779 } // namespace base
780
781 #endif // BASE_METRICS_HISTOGRAM_H_

mercurial