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