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