• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 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 // For Histogram(exponential histogram), LinearHistogram and CustomHistogram,
13 // the minimum for a declared range is 1 (instead of 0), while the maximum is
14 // (HistogramBase::kSampleType_MAX - 1). Currently you can declare histograms
15 // with ranges exceeding those limits (e.g. 0 as minimal or
16 // HistogramBase::kSampleType_MAX as maximal), but those excesses will be
17 // silently clamped to those limits (for backwards compatibility with existing
18 // code). Best practice is to not exceed the limits.
19 
20 // Each use of a histogram with the same name will reference the same underlying
21 // data, so it is safe to record to the same histogram from multiple locations
22 // in the code. It is a runtime error if all uses of the same histogram do not
23 // agree exactly in type, bucket size and range.
24 
25 // For Histogram and LinearHistogram, the maximum for a declared range should
26 // always be larger (not equal) than minimal range. Zero and
27 // HistogramBase::kSampleType_MAX are implicitly added as first and last ranges,
28 // so the smallest legal bucket_count is 3. However CustomHistogram can have
29 // bucket count as 2 (when you give a custom ranges vector containing only 1
30 // range).
31 // For these 3 kinds of histograms, the max bucket count is always
32 // (Histogram::kBucketCount_MAX - 1).
33 
34 // The buckets layout of class Histogram is exponential. For example, buckets
35 // might contain (sequentially) the count of values in the following intervals:
36 // [0,1), [1,2), [2,4), [4,8), [8,16), [16,32), [32,64), [64,infinity)
37 // That bucket allocation would actually result from construction of a histogram
38 // for values between 1 and 64, with 8 buckets, such as:
39 // Histogram count("some name", 1, 64, 8);
40 // Note that the underflow bucket [0,1) and the overflow bucket [64,infinity)
41 // are also counted by the constructor in the user supplied "bucket_count"
42 // argument.
43 // The above example has an exponential ratio of 2 (doubling the bucket width
44 // in each consecutive bucket.  The Histogram class automatically calculates
45 // the smallest ratio that it can use to construct the number of buckets
46 // selected in the constructor.  An another example, if you had 50 buckets,
47 // and millisecond time values from 1 to 10000, then the ratio between
48 // consecutive bucket widths will be approximately somewhere around the 50th
49 // root of 10000.  This approach provides very fine grain (narrow) buckets
50 // at the low end of the histogram scale, but allows the histogram to cover a
51 // gigantic range with the addition of very few buckets.
52 
53 // Usually we use macros to define and use a histogram, which are defined in
54 // base/metrics/histogram_macros.h. Note: Callers should include that header
55 // directly if they only access the histogram APIs through macros.
56 //
57 // Macros use a pattern involving a function static variable, that is a pointer
58 // to a histogram.  This static is explicitly initialized on any thread
59 // that detects a uninitialized (NULL) pointer.  The potentially racy
60 // initialization is not a problem as it is always set to point to the same
61 // value (i.e., the FactoryGet always returns the same value).  FactoryGet
62 // is also completely thread safe, which results in a completely thread safe,
63 // and relatively fast, set of counters.  To avoid races at shutdown, the static
64 // pointer is NOT deleted, and we leak the histograms at process termination.
65 
66 #ifndef BASE_METRICS_HISTOGRAM_H_
67 #define BASE_METRICS_HISTOGRAM_H_
68 
69 #include <stddef.h>
70 #include <stdint.h>
71 
72 #include <map>
73 #include <memory>
74 #include <string>
75 #include <vector>
76 
77 #include "base/base_export.h"
78 #include "base/compiler_specific.h"
79 #include "base/gtest_prod_util.h"
80 #include "base/logging.h"
81 #include "base/macros.h"
82 #include "base/metrics/bucket_ranges.h"
83 #include "base/metrics/histogram_base.h"
84 // TODO(asvitkine): Migrate callers to to include this directly and remove this.
85 #include "base/metrics/histogram_macros.h"
86 #include "base/metrics/histogram_samples.h"
87 #include "base/time/time.h"
88 
89 namespace base {
90 
91 class BooleanHistogram;
92 class CustomHistogram;
93 class Histogram;
94 class LinearHistogram;
95 class PersistentMemoryAllocator;
96 class Pickle;
97 class PickleIterator;
98 class SampleVector;
99 
100 class BASE_EXPORT Histogram : public HistogramBase {
101  public:
102   // Initialize maximum number of buckets in histograms as 16,384.
103   static const uint32_t kBucketCount_MAX;
104 
105   typedef std::vector<Count> Counts;
106 
107   ~Histogram() override;
108 
109   //----------------------------------------------------------------------------
110   // For a valid histogram, input should follow these restrictions:
111   // minimum > 0 (if a minimum below 1 is specified, it will implicitly be
112   //              normalized up to 1)
113   // maximum > minimum
114   // buckets > 2 [minimum buckets needed: underflow, overflow and the range]
115   // Additionally,
116   // buckets <= (maximum - minimum + 2) - this is to ensure that we don't have
117   // more buckets than the range of numbers; having more buckets than 1 per
118   // value in the range would be nonsensical.
119   static HistogramBase* FactoryGet(const std::string& name,
120                                    Sample minimum,
121                                    Sample maximum,
122                                    uint32_t bucket_count,
123                                    int32_t flags);
124   static HistogramBase* FactoryTimeGet(const std::string& name,
125                                        base::TimeDelta minimum,
126                                        base::TimeDelta maximum,
127                                        uint32_t bucket_count,
128                                        int32_t flags);
129 
130   // Overloads of the above two functions that take a const char* |name| param,
131   // to avoid code bloat from the std::string constructor being inlined into
132   // call sites.
133   static HistogramBase* FactoryGet(const char* name,
134                                    Sample minimum,
135                                    Sample maximum,
136                                    uint32_t bucket_count,
137                                    int32_t flags);
138   static HistogramBase* FactoryTimeGet(const char* name,
139                                        base::TimeDelta minimum,
140                                        base::TimeDelta maximum,
141                                        uint32_t bucket_count,
142                                        int32_t flags);
143 
144   // Create a histogram using data in persistent storage.
145   static std::unique_ptr<HistogramBase> PersistentCreate(
146       const std::string& name,
147       Sample minimum,
148       Sample maximum,
149       const BucketRanges* ranges,
150       HistogramBase::AtomicCount* counts,
151       HistogramBase::AtomicCount* logged_counts,
152       uint32_t counts_size,
153       HistogramSamples::Metadata* meta,
154       HistogramSamples::Metadata* logged_meta);
155 
156   static void InitializeBucketRanges(Sample minimum,
157                                      Sample maximum,
158                                      BucketRanges* ranges);
159 
160   // This constant if for FindCorruption. Since snapshots of histograms are
161   // taken asynchronously relative to sampling, and our counting code currently
162   // does not prevent race conditions, it is pretty likely that we'll catch a
163   // redundant count that doesn't match the sample count.  We allow for a
164   // certain amount of slop before flagging this as an inconsistency. Even with
165   // an inconsistency, we'll snapshot it again (for UMA in about a half hour),
166   // so we'll eventually get the data, if it was not the result of a corruption.
167   static const int kCommonRaceBasedCountMismatch;
168 
169   // Check to see if bucket ranges, counts and tallies in the snapshot are
170   // consistent with the bucket ranges and checksums in our histogram.  This can
171   // produce a false-alarm if a race occurred in the reading of the data during
172   // a SnapShot process, but should otherwise be false at all times (unless we
173   // have memory over-writes, or DRAM failures). Flag definitions are located
174   // under "enum Inconsistency" in base/metrics/histogram_base.h.
175   uint32_t FindCorruption(const HistogramSamples& samples) const override;
176 
177   //----------------------------------------------------------------------------
178   // Accessors for factory construction, serialization and testing.
179   //----------------------------------------------------------------------------
declared_min()180   Sample declared_min() const { return declared_min_; }
declared_max()181   Sample declared_max() const { return declared_max_; }
182   virtual Sample ranges(uint32_t i) const;
183   virtual uint32_t bucket_count() const;
bucket_ranges()184   const BucketRanges* bucket_ranges() const { return bucket_ranges_; }
185 
186   // This function validates histogram construction arguments. It returns false
187   // if some of the arguments are totally bad.
188   // Note. Currently it allow some bad input, e.g. 0 as minimum, but silently
189   // converts it to good input: 1.
190   // TODO(kaiwang): Be more restrict and return false for any bad input, and
191   // make this a readonly validating function.
192   static bool InspectConstructionArguments(const std::string& name,
193                                            Sample* minimum,
194                                            Sample* maximum,
195                                            uint32_t* bucket_count);
196 
197   // HistogramBase implementation:
198   uint64_t name_hash() const override;
199   HistogramType GetHistogramType() const override;
200   bool HasConstructionArguments(Sample expected_minimum,
201                                 Sample expected_maximum,
202                                 uint32_t expected_bucket_count) const override;
203   void Add(Sample value) override;
204   void AddCount(Sample value, int count) override;
205   std::unique_ptr<HistogramSamples> SnapshotSamples() const override;
206   std::unique_ptr<HistogramSamples> SnapshotDelta() override;
207   std::unique_ptr<HistogramSamples> SnapshotFinalDelta() const override;
208   void AddSamples(const HistogramSamples& samples) override;
209   bool AddSamplesFromPickle(base::PickleIterator* iter) override;
210   void WriteHTMLGraph(std::string* output) const override;
211   void WriteAscii(std::string* output) const override;
212 
213  protected:
214   // This class, defined entirely within the .cc file, contains all the
215   // common logic for building a Histogram and can be overridden by more
216   // specific types to alter details of how the creation is done. It is
217   // defined as an embedded class (rather than an anonymous one) so it
218   // can access the protected constructors.
219   class Factory;
220 
221   // |ranges| should contain the underflow and overflow buckets. See top
222   // comments for example.
223   Histogram(const std::string& name,
224             Sample minimum,
225             Sample maximum,
226             const BucketRanges* ranges);
227 
228   // Traditionally, histograms allocate their own memory for the bucket
229   // vector but "shared" histograms use memory regions allocated from a
230   // special memory segment that is passed in here.  It is assumed that
231   // the life of this memory is managed externally and exceeds the lifetime
232   // of this object. Practically, this memory is never released until the
233   // process exits and the OS cleans it up.
234   Histogram(const std::string& name,
235             Sample minimum,
236             Sample maximum,
237             const BucketRanges* ranges,
238             HistogramBase::AtomicCount* counts,
239             HistogramBase::AtomicCount* logged_counts,
240             uint32_t counts_size,
241             HistogramSamples::Metadata* meta,
242             HistogramSamples::Metadata* logged_meta);
243 
244   // HistogramBase implementation:
245   bool SerializeInfoImpl(base::Pickle* pickle) const override;
246 
247   // Method to override to skip the display of the i'th bucket if it's empty.
248   virtual bool PrintEmptyBucket(uint32_t index) const;
249 
250   // Get normalized size, relative to the ranges(i).
251   virtual double GetBucketSize(Count current, uint32_t i) const;
252 
253   // Return a string description of what goes in a given bucket.
254   // Most commonly this is the numeric value, but in derived classes it may
255   // be a name (or string description) given to the bucket.
256   virtual const std::string GetAsciiBucketRange(uint32_t it) const;
257 
258  private:
259   // Allow tests to corrupt our innards for testing purposes.
260   FRIEND_TEST_ALL_PREFIXES(HistogramTest, BoundsTest);
261   FRIEND_TEST_ALL_PREFIXES(HistogramTest, BucketPlacementTest);
262   FRIEND_TEST_ALL_PREFIXES(HistogramTest, CorruptSampleCounts);
263 
264   friend class StatisticsRecorder;  // To allow it to delete duplicates.
265   friend class StatisticsRecorderTest;
266 
267   friend BASE_EXPORT HistogramBase* DeserializeHistogramInfo(
268       base::PickleIterator* iter);
269   static HistogramBase* DeserializeInfoImpl(base::PickleIterator* iter);
270 
271   // Implementation of SnapshotSamples function.
272   std::unique_ptr<SampleVector> SnapshotSampleVector() const;
273 
274   //----------------------------------------------------------------------------
275   // Helpers for emitting Ascii graphic.  Each method appends data to output.
276 
277   void WriteAsciiImpl(bool graph_it,
278                       const std::string& newline,
279                       std::string* output) const;
280 
281   // Find out how large (graphically) the largest bucket will appear to be.
282   double GetPeakBucketSize(const SampleVector& samples) const;
283 
284   // Write a common header message describing this histogram.
285   void WriteAsciiHeader(const SampleVector& samples,
286                         Count sample_count,
287                         std::string* output) const;
288 
289   // Write information about previous, current, and next buckets.
290   // Information such as cumulative percentage, etc.
291   void WriteAsciiBucketContext(const int64_t past,
292                                const Count current,
293                                const int64_t remaining,
294                                const uint32_t i,
295                                std::string* output) const;
296 
297   // WriteJSON calls these.
298   void GetParameters(DictionaryValue* params) const override;
299 
300   void GetCountAndBucketData(Count* count,
301                              int64_t* sum,
302                              ListValue* buckets) const override;
303 
304   // Does not own this object. Should get from StatisticsRecorder.
305   const BucketRanges* bucket_ranges_;
306 
307   Sample declared_min_;  // Less than this goes into the first bucket.
308   Sample declared_max_;  // Over this goes into the last bucket.
309 
310   // Finally, provide the state that changes with the addition of each new
311   // sample.
312   std::unique_ptr<SampleVector> samples_;
313 
314   // Also keep a previous uploaded state for calculating deltas.
315   std::unique_ptr<HistogramSamples> logged_samples_;
316 
317   // Flag to indicate if PrepareFinalDelta has been previously called. It is
318   // used to DCHECK that a final delta is not created multiple times.
319   mutable bool final_delta_created_ = false;
320 
321   DISALLOW_COPY_AND_ASSIGN(Histogram);
322 };
323 
324 //------------------------------------------------------------------------------
325 
326 // LinearHistogram is a more traditional histogram, with evenly spaced
327 // buckets.
328 class BASE_EXPORT LinearHistogram : public Histogram {
329  public:
330   ~LinearHistogram() override;
331 
332   /* minimum should start from 1. 0 is as minimum is invalid. 0 is an implicit
333      default underflow bucket. */
334   static HistogramBase* FactoryGet(const std::string& name,
335                                    Sample minimum,
336                                    Sample maximum,
337                                    uint32_t bucket_count,
338                                    int32_t flags);
339   static HistogramBase* FactoryTimeGet(const std::string& name,
340                                        TimeDelta minimum,
341                                        TimeDelta maximum,
342                                        uint32_t bucket_count,
343                                        int32_t flags);
344 
345   // Overloads of the above two functions that take a const char* |name| param,
346   // to avoid code bloat from the std::string constructor being inlined into
347   // call sites.
348   static HistogramBase* FactoryGet(const char* name,
349                                    Sample minimum,
350                                    Sample maximum,
351                                    uint32_t bucket_count,
352                                    int32_t flags);
353   static HistogramBase* FactoryTimeGet(const char* name,
354                                        TimeDelta minimum,
355                                        TimeDelta maximum,
356                                        uint32_t bucket_count,
357                                        int32_t flags);
358 
359   // Create a histogram using data in persistent storage.
360   static std::unique_ptr<HistogramBase> PersistentCreate(
361       const std::string& name,
362       Sample minimum,
363       Sample maximum,
364       const BucketRanges* ranges,
365       HistogramBase::AtomicCount* counts,
366       HistogramBase::AtomicCount* logged_counts,
367       uint32_t counts_size,
368       HistogramSamples::Metadata* meta,
369       HistogramSamples::Metadata* logged_meta);
370 
371   struct DescriptionPair {
372     Sample sample;
373     const char* description;  // Null means end of a list of pairs.
374   };
375 
376   // Create a LinearHistogram and store a list of number/text values for use in
377   // writing the histogram graph.
378   // |descriptions| can be NULL, which means no special descriptions to set. If
379   // it's not NULL, the last element in the array must has a NULL in its
380   // "description" field.
381   static HistogramBase* FactoryGetWithRangeDescription(
382       const std::string& name,
383       Sample minimum,
384       Sample maximum,
385       uint32_t bucket_count,
386       int32_t flags,
387       const DescriptionPair descriptions[]);
388 
389   static void InitializeBucketRanges(Sample minimum,
390                                      Sample maximum,
391                                      BucketRanges* ranges);
392 
393   // Overridden from Histogram:
394   HistogramType GetHistogramType() const override;
395 
396  protected:
397   class Factory;
398 
399   LinearHistogram(const std::string& name,
400                   Sample minimum,
401                   Sample maximum,
402                   const BucketRanges* ranges);
403 
404   LinearHistogram(const std::string& name,
405                   Sample minimum,
406                   Sample maximum,
407                   const BucketRanges* ranges,
408                   HistogramBase::AtomicCount* counts,
409                   HistogramBase::AtomicCount* logged_counts,
410                   uint32_t counts_size,
411                   HistogramSamples::Metadata* meta,
412                   HistogramSamples::Metadata* logged_meta);
413 
414   double GetBucketSize(Count current, uint32_t i) const override;
415 
416   // If we have a description for a bucket, then return that.  Otherwise
417   // let parent class provide a (numeric) description.
418   const std::string GetAsciiBucketRange(uint32_t i) const override;
419 
420   // Skip printing of name for numeric range if we have a name (and if this is
421   // an empty bucket).
422   bool PrintEmptyBucket(uint32_t index) const override;
423 
424  private:
425   friend BASE_EXPORT HistogramBase* DeserializeHistogramInfo(
426       base::PickleIterator* iter);
427   static HistogramBase* DeserializeInfoImpl(base::PickleIterator* iter);
428 
429   // For some ranges, we store a printable description of a bucket range.
430   // If there is no description, then GetAsciiBucketRange() uses parent class
431   // to provide a description.
432   typedef std::map<Sample, std::string> BucketDescriptionMap;
433   BucketDescriptionMap bucket_description_;
434 
435   DISALLOW_COPY_AND_ASSIGN(LinearHistogram);
436 };
437 
438 //------------------------------------------------------------------------------
439 
440 // BooleanHistogram is a histogram for booleans.
441 class BASE_EXPORT BooleanHistogram : public LinearHistogram {
442  public:
443   static HistogramBase* FactoryGet(const std::string& name, int32_t flags);
444 
445   // Overload of the above function that takes a const char* |name| param,
446   // to avoid code bloat from the std::string constructor being inlined into
447   // call sites.
448   static HistogramBase* FactoryGet(const char* name, int32_t flags);
449 
450   // Create a histogram using data in persistent storage.
451   static std::unique_ptr<HistogramBase> PersistentCreate(
452       const std::string& name,
453       const BucketRanges* ranges,
454       HistogramBase::AtomicCount* counts,
455       HistogramBase::AtomicCount* logged_counts,
456       HistogramSamples::Metadata* meta,
457       HistogramSamples::Metadata* logged_meta);
458 
459   HistogramType GetHistogramType() const override;
460 
461  protected:
462   class Factory;
463 
464  private:
465   BooleanHistogram(const std::string& name, const BucketRanges* ranges);
466   BooleanHistogram(const std::string& name,
467                    const BucketRanges* ranges,
468                    HistogramBase::AtomicCount* counts,
469                    HistogramBase::AtomicCount* logged_counts,
470                    HistogramSamples::Metadata* meta,
471                    HistogramSamples::Metadata* logged_meta);
472 
473   friend BASE_EXPORT HistogramBase* DeserializeHistogramInfo(
474       base::PickleIterator* iter);
475   static HistogramBase* DeserializeInfoImpl(base::PickleIterator* iter);
476 
477   DISALLOW_COPY_AND_ASSIGN(BooleanHistogram);
478 };
479 
480 //------------------------------------------------------------------------------
481 
482 // CustomHistogram is a histogram for a set of custom integers.
483 class BASE_EXPORT CustomHistogram : public Histogram {
484  public:
485   // |custom_ranges| contains a vector of limits on ranges. Each limit should be
486   // > 0 and < kSampleType_MAX. (Currently 0 is still accepted for backward
487   // compatibility). The limits can be unordered or contain duplication, but
488   // client should not depend on this.
489   static HistogramBase* FactoryGet(const std::string& name,
490                                    const std::vector<Sample>& custom_ranges,
491                                    int32_t flags);
492 
493   // Overload of the above function that takes a const char* |name| param,
494   // to avoid code bloat from the std::string constructor being inlined into
495   // call sites.
496   static HistogramBase* FactoryGet(const char* name,
497                                    const std::vector<Sample>& custom_ranges,
498                                    int32_t flags);
499 
500   // Create a histogram using data in persistent storage.
501   static std::unique_ptr<HistogramBase> PersistentCreate(
502       const std::string& name,
503       const BucketRanges* ranges,
504       HistogramBase::AtomicCount* counts,
505       HistogramBase::AtomicCount* logged_counts,
506       uint32_t counts_size,
507       HistogramSamples::Metadata* meta,
508       HistogramSamples::Metadata* logged_meta);
509 
510   // Overridden from Histogram:
511   HistogramType GetHistogramType() const override;
512 
513   // Helper method for transforming an array of valid enumeration values
514   // to the std::vector<int> expected by UMA_HISTOGRAM_CUSTOM_ENUMERATION.
515   // This function ensures that a guard bucket exists right after any
516   // valid sample value (unless the next higher sample is also a valid value),
517   // so that invalid samples never fall into the same bucket as valid samples.
518   // TODO(kaiwang): Change name to ArrayToCustomEnumRanges.
519   static std::vector<Sample> ArrayToCustomRanges(const Sample* values,
520                                                  uint32_t num_values);
521  protected:
522   class Factory;
523 
524   CustomHistogram(const std::string& name,
525                   const BucketRanges* ranges);
526 
527   CustomHistogram(const std::string& name,
528                   const BucketRanges* ranges,
529                   HistogramBase::AtomicCount* counts,
530                   HistogramBase::AtomicCount* logged_counts,
531                   uint32_t counts_size,
532                   HistogramSamples::Metadata* meta,
533                   HistogramSamples::Metadata* logged_meta);
534 
535   // HistogramBase implementation:
536   bool SerializeInfoImpl(base::Pickle* pickle) const override;
537 
538   double GetBucketSize(Count current, uint32_t i) const override;
539 
540  private:
541   friend BASE_EXPORT HistogramBase* DeserializeHistogramInfo(
542       base::PickleIterator* iter);
543   static HistogramBase* DeserializeInfoImpl(base::PickleIterator* iter);
544 
545   static bool ValidateCustomRanges(const std::vector<Sample>& custom_ranges);
546 
547   DISALLOW_COPY_AND_ASSIGN(CustomHistogram);
548 };
549 
550 }  // namespace base
551 
552 #endif  // BASE_METRICS_HISTOGRAM_H_
553