Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2006-2008 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 #ifndef BASE_HISTOGRAM_H_
     32 #define BASE_HISTOGRAM_H_
     33 
     34 #include <map>
     35 #include <string>
     36 #include <vector>
     37 
     38 #include "base/lock.h"
     39 #include "base/ref_counted.h"
     40 #include "base/logging.h"
     41 #include "base/time.h"
     42 
     43 //------------------------------------------------------------------------------
     44 // Provide easy general purpose histogram in a macro, just like stats counters.
     45 // The first four macros use 50 buckets.
     46 
     47 #define HISTOGRAM_TIMES(name, sample) HISTOGRAM_CUSTOM_TIMES( \
     48     name, sample, base::TimeDelta::FromMilliseconds(1), \
     49     base::TimeDelta::FromSeconds(10), 50)
     50 
     51 #define HISTOGRAM_COUNTS(name, sample) HISTOGRAM_CUSTOM_COUNTS( \
     52     name, sample, 1, 1000000, 50)
     53 
     54 #define HISTOGRAM_COUNTS_100(name, sample) HISTOGRAM_CUSTOM_COUNTS( \
     55     name, sample, 1, 100, 50)
     56 
     57 #define HISTOGRAM_COUNTS_10000(name, sample) HISTOGRAM_CUSTOM_COUNTS( \
     58     name, sample, 1, 10000, 50)
     59 
     60 #define HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) do { \
     61     static scoped_refptr<Histogram> counter = Histogram::FactoryGet( \
     62         name, min, max, bucket_count, Histogram::kNoFlags); \
     63     counter->Add(sample); \
     64   } while (0)
     65 
     66 #define HISTOGRAM_PERCENTAGE(name, under_one_hundred) \
     67     HISTOGRAM_ENUMERATION(name, under_one_hundred, 101)
     68 
     69 // For folks that need real specific times, use this to select a precise range
     70 // of times you want plotted, and the number of buckets you want used.
     71 #define HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) do { \
     72     static scoped_refptr<Histogram> counter = Histogram::FactoryGet( \
     73         name, min, max, bucket_count, Histogram::kNoFlags); \
     74     counter->AddTime(sample); \
     75   } while (0)
     76 
     77 // DO NOT USE THIS.  It is being phased out, in favor of HISTOGRAM_CUSTOM_TIMES.
     78 #define HISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) do { \
     79     static scoped_refptr<Histogram> counter = Histogram::FactoryGet( \
     80         name, min, max, bucket_count, Histogram::kNoFlags); \
     81     if ((sample) < (max)) counter->AddTime(sample); \
     82   } while (0)
     83 
     84 // Support histograming of an enumerated value.  The samples should always be
     85 // less than boundary_value.
     86 
     87 #define HISTOGRAM_ENUMERATION(name, sample, boundary_value) do { \
     88     static scoped_refptr<Histogram> counter = LinearHistogram::FactoryGet( \
     89         name, 1, boundary_value, boundary_value + 1, Histogram::kNoFlags); \
     90     counter->Add(sample); \
     91   } while (0)
     92 
     93 
     94 //------------------------------------------------------------------------------
     95 // Define Debug vs non-debug flavors of macros.
     96 #ifndef NDEBUG
     97 
     98 #define DHISTOGRAM_TIMES(name, sample) HISTOGRAM_TIMES(name, sample)
     99 #define DHISTOGRAM_COUNTS(name, sample) HISTOGRAM_COUNTS(name, sample)
    100 #define DHISTOGRAM_PERCENTAGE(name, under_one_hundred) HISTOGRAM_PERCENTAGE(\
    101     name, under_one_hundred)
    102 #define DHISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \
    103     HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count)
    104 #define DHISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) \
    105     HISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count)
    106 #define DHISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \
    107     HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count)
    108 #define DHISTOGRAM_ENUMERATION(name, sample, boundary_value) \
    109     HISTOGRAM_ENUMERATION(name, sample, boundary_value)
    110 
    111 #else  // NDEBUG
    112 
    113 #define DHISTOGRAM_TIMES(name, sample) do {} while (0)
    114 #define DHISTOGRAM_COUNTS(name, sample) do {} while (0)
    115 #define DHISTOGRAM_PERCENTAGE(name, under_one_hundred) do {} while (0)
    116 #define DHISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \
    117     do {} while (0)
    118 #define DHISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) \
    119     do {} while (0)
    120 #define DHISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \
    121     do {} while (0)
    122 #define DHISTOGRAM_ENUMERATION(name, sample, boundary_value) do {} while (0)
    123 
    124 #endif  // NDEBUG
    125 
    126 //------------------------------------------------------------------------------
    127 // The following macros provide typical usage scenarios for callers that wish
    128 // to record histogram data, and have the data submitted/uploaded via UMA.
    129 // Not all systems support such UMA, but if they do, the following macros
    130 // should work with the service.
    131 
    132 #define UMA_HISTOGRAM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
    133     name, sample, base::TimeDelta::FromMilliseconds(1), \
    134     base::TimeDelta::FromSeconds(10), 50)
    135 
    136 #define UMA_HISTOGRAM_MEDIUM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
    137     name, sample, base::TimeDelta::FromMilliseconds(10), \
    138     base::TimeDelta::FromMinutes(3), 50)
    139 
    140 // Use this macro when times can routinely be much longer than 10 seconds.
    141 #define UMA_HISTOGRAM_LONG_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
    142     name, sample, base::TimeDelta::FromMilliseconds(1), \
    143     base::TimeDelta::FromHours(1), 50)
    144 
    145 #define UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) do { \
    146     static scoped_refptr<Histogram> counter = Histogram::FactoryGet( \
    147         name, min, max, bucket_count, Histogram::kUmaTargetedHistogramFlag); \
    148     counter->AddTime(sample); \
    149   } while (0)
    150 
    151 // DO NOT USE THIS.  It is being phased out, in favor of HISTOGRAM_CUSTOM_TIMES.
    152 #define UMA_HISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) do { \
    153     static scoped_refptr<Histogram> counter = Histogram::FactoryGet( \
    154         name, min, max, bucket_count, Histogram::kUmaTargetedHistogramFlag); \
    155     if ((sample) < (max)) counter->AddTime(sample); \
    156   } while (0)
    157 
    158 #define UMA_HISTOGRAM_COUNTS(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
    159     name, sample, 1, 1000000, 50)
    160 
    161 #define UMA_HISTOGRAM_COUNTS_100(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
    162     name, sample, 1, 100, 50)
    163 
    164 #define UMA_HISTOGRAM_COUNTS_10000(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
    165     name, sample, 1, 10000, 50)
    166 
    167 #define UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) do { \
    168     static scoped_refptr<Histogram> counter = Histogram::FactoryGet( \
    169         name, min, max, bucket_count, Histogram::kUmaTargetedHistogramFlag); \
    170     counter->Add(sample); \
    171   } while (0)
    172 
    173 #define UMA_HISTOGRAM_MEMORY_KB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
    174     name, sample, 1000, 500000, 50)
    175 
    176 #define UMA_HISTOGRAM_MEMORY_MB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
    177     name, sample, 1, 1000, 50)
    178 
    179 #define UMA_HISTOGRAM_PERCENTAGE(name, under_one_hundred) \
    180     UMA_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101)
    181 
    182 #define UMA_HISTOGRAM_ENUMERATION(name, sample, boundary_value) do { \
    183     static scoped_refptr<Histogram> counter = LinearHistogram::FactoryGet( \
    184         name, 1, boundary_value, boundary_value + 1, \
    185         Histogram::kUmaTargetedHistogramFlag); \
    186     counter->Add(sample); \
    187   } while (0)
    188 
    189 
    190 //------------------------------------------------------------------------------
    191 
    192 class Pickle;
    193 class Histogram;
    194 class LinearHistogram;
    195 class BooleanHistogram;
    196 
    197 namespace disk_cache {
    198   class StatsHistogram;
    199 };  // namespace disk_cache
    200 
    201 
    202 class Histogram : public base::RefCountedThreadSafe<Histogram> {
    203  public:
    204   typedef int Sample;  // Used for samples (and ranges of samples).
    205   typedef int Count;  // Used to count samples in a bucket.
    206   static const Sample kSampleType_MAX = INT_MAX;
    207 
    208   typedef std::vector<Count> Counts;
    209   typedef std::vector<Sample> Ranges;
    210 
    211   /* These enums are meant to facilitate deserialization of renderer histograms
    212      into the browser. */
    213   enum ClassType {
    214     HISTOGRAM,
    215     LINEAR_HISTOGRAM,
    216     BOOLEAN_HISTOGRAM,
    217     NOT_VALID_IN_RENDERER
    218   };
    219 
    220   enum BucketLayout {
    221     EXPONENTIAL,
    222     LINEAR
    223   };
    224 
    225   enum Flags {
    226     kNoFlags = 0,
    227     kUmaTargetedHistogramFlag = 0x1,  // Histogram should be UMA uploaded.
    228 
    229     // Indicate that the histogram was pickled to be sent across an IPC Channel.
    230     // If we observe this flag on a histogram being aggregated into after IPC,
    231     // then we are running in a single process mode, and the aggregation should
    232     // not take place (as we would be aggregating back into the source
    233     // histogram!).
    234     kIPCSerializationSourceFlag = 0x10,
    235 
    236     kHexRangePrintingFlag = 0x8000,  // Fancy bucket-naming supported.
    237   };
    238 
    239   struct DescriptionPair {
    240     Sample sample;
    241     const char* description;  // Null means end of a list of pairs.
    242   };
    243 
    244   //----------------------------------------------------------------------------
    245   // Statistic values, developed over the life of the histogram.
    246 
    247   class SampleSet {
    248    public:
    249     explicit SampleSet();
    250     // Adjust size of counts_ for use with given histogram.
    251     void Resize(const Histogram& histogram);
    252     void CheckSize(const Histogram& histogram) const;
    253 
    254     // Accessor for histogram to make routine additions.
    255     void Accumulate(Sample value, Count count, size_t index);
    256 
    257     // Accessor methods.
    258     Count counts(size_t i) const { return counts_[i]; }
    259     Count TotalCount() const;
    260     int64 sum() const { return sum_; }
    261     int64 square_sum() const { return square_sum_; }
    262 
    263     // Arithmetic manipulation of corresponding elements of the set.
    264     void Add(const SampleSet& other);
    265     void Subtract(const SampleSet& other);
    266 
    267     bool Serialize(Pickle* pickle) const;
    268     bool Deserialize(void** iter, const Pickle& pickle);
    269 
    270    protected:
    271     // Actual histogram data is stored in buckets, showing the count of values
    272     // that fit into each bucket.
    273     Counts counts_;
    274 
    275     // Save simple stats locally.  Note that this MIGHT get done in base class
    276     // without shared memory at some point.
    277     int64 sum_;         // sum of samples.
    278     int64 square_sum_;  // sum of squares of samples.
    279   };
    280   //----------------------------------------------------------------------------
    281   // minimum should start from 1. 0 is invalid as a minimum. 0 is an implicit
    282   // default underflow bucket.
    283   static scoped_refptr<Histogram> FactoryGet(const std::string& name,
    284       Sample minimum, Sample maximum, size_t bucket_count, Flags flags);
    285   static scoped_refptr<Histogram> FactoryGet(const std::string& name,
    286       base::TimeDelta minimum, base::TimeDelta maximum, size_t bucket_count,
    287       Flags flags);
    288 
    289   void Add(int value);
    290 
    291   // This method is an interface, used only by BooleanHistogram.
    292   virtual void AddBoolean(bool value) { DCHECK(false); }
    293 
    294   // Accept a TimeDelta to increment.
    295   void AddTime(base::TimeDelta time) {
    296     Add(static_cast<int>(time.InMilliseconds()));
    297   }
    298 
    299   void AddSampleSet(const SampleSet& sample);
    300 
    301   // This method is an interface, used only by LinearHistogram.
    302   virtual void SetRangeDescriptions(const DescriptionPair descriptions[])
    303       { DCHECK(false); }
    304 
    305   // The following methods provide graphical histogram displays.
    306   void WriteHTMLGraph(std::string* output) const;
    307   void WriteAscii(bool graph_it, const std::string& newline,
    308                   std::string* output) const;
    309 
    310   // Support generic flagging of Histograms.
    311   // 0x1 Currently used to mark this histogram to be recorded by UMA..
    312   // 0x8000 means print ranges in hex.
    313   void SetFlags(Flags flags) { flags_ = static_cast<Flags> (flags_ | flags); }
    314   void ClearFlags(Flags flags) { flags_ = static_cast<Flags>(flags_ & ~flags); }
    315   int flags() const { return flags_; }
    316 
    317   // Convenience methods for serializing/deserializing the histograms.
    318   // Histograms from Renderer process are serialized and sent to the browser.
    319   // Browser process reconstructs the histogram from the pickled version
    320   // accumulates the browser-side shadow copy of histograms (that mirror
    321   // histograms created in the renderer).
    322 
    323   // Serialize the given snapshot of a Histogram into a String. Uses
    324   // Pickle class to flatten the object.
    325   static std::string SerializeHistogramInfo(const Histogram& histogram,
    326                                             const SampleSet& snapshot);
    327   // The following method accepts a list of pickled histograms and
    328   // builds a histogram and updates shadow copy of histogram data in the
    329   // browser process.
    330   static bool DeserializeHistogramInfo(const std::string& histogram_info);
    331 
    332   //----------------------------------------------------------------------------
    333   // Accessors for factory constuction, serialization and testing.
    334   //----------------------------------------------------------------------------
    335   virtual ClassType histogram_type() const { return HISTOGRAM; }
    336   const std::string histogram_name() const { return histogram_name_; }
    337   Sample declared_min() const { return declared_min_; }
    338   Sample declared_max() const { return declared_max_; }
    339   virtual Sample ranges(size_t i) const { return ranges_[i];}
    340   virtual size_t bucket_count() const { return bucket_count_; }
    341   // Snapshot the current complete set of sample data.
    342   // Override with atomic/locked snapshot if needed.
    343   virtual void SnapshotSample(SampleSet* sample) const;
    344 
    345   virtual bool HasConstructorArguments(Sample minimum, Sample maximum,
    346       size_t bucket_count) {
    347     return ((minimum == declared_min_) && (maximum == declared_max_) &&
    348             (bucket_count == bucket_count_));
    349   }
    350 
    351   virtual bool HasConstructorTimeDeltaArguments(base::TimeDelta minimum,
    352       base::TimeDelta maximum, size_t bucket_count) {
    353     return ((minimum.InMilliseconds() == declared_min_) &&
    354             (maximum.InMilliseconds() == declared_max_) &&
    355             (bucket_count == bucket_count_));
    356   }
    357 
    358  protected:
    359   friend class base::RefCountedThreadSafe<Histogram>;
    360   Histogram(const std::string& name, Sample minimum,
    361             Sample maximum, size_t bucket_count);
    362   Histogram(const std::string& name, base::TimeDelta minimum,
    363             base::TimeDelta maximum, size_t bucket_count);
    364 
    365   virtual ~Histogram();
    366 
    367   // Method to override to skip the display of the i'th bucket if it's empty.
    368   virtual bool PrintEmptyBucket(size_t index) const { return true; }
    369 
    370   //----------------------------------------------------------------------------
    371   // Methods to override to create histogram with different bucket widths.
    372   //----------------------------------------------------------------------------
    373   // Initialize ranges_ mapping.
    374   virtual void InitializeBucketRange();
    375   // Find bucket to increment for sample value.
    376   virtual size_t BucketIndex(Sample value) const;
    377   // Get normalized size, relative to the ranges_[i].
    378   virtual double GetBucketSize(Count current, size_t i) const;
    379 
    380   // Return a string description of what goes in a given bucket.
    381   // Most commonly this is the numeric value, but in derived classes it may
    382   // be a name (or string description) given to the bucket.
    383   virtual const std::string GetAsciiBucketRange(size_t it) const;
    384 
    385   //----------------------------------------------------------------------------
    386   // Methods to override to create thread safe histogram.
    387   //----------------------------------------------------------------------------
    388   // Update all our internal data, including histogram
    389   virtual void Accumulate(Sample value, Count count, size_t index);
    390 
    391   //----------------------------------------------------------------------------
    392   // Accessors for derived classes.
    393   //----------------------------------------------------------------------------
    394   void SetBucketRange(size_t i, Sample value);
    395 
    396   // Validate that ranges_ was created sensibly (top and bottom range
    397   // values relate properly to the declared_min_ and declared_max_)..
    398   bool ValidateBucketRanges() const;
    399 
    400  private:
    401   // Post constructor initialization.
    402   void Initialize();
    403 
    404   //----------------------------------------------------------------------------
    405   // Helpers for emitting Ascii graphic.  Each method appends data to output.
    406 
    407   // Find out how large the (graphically) the largest bucket will appear to be.
    408   double GetPeakBucketSize(const SampleSet& snapshot) const;
    409 
    410   // Write a common header message describing this histogram.
    411   void WriteAsciiHeader(const SampleSet& snapshot,
    412                         Count sample_count, std::string* output) const;
    413 
    414   // Write information about previous, current, and next buckets.
    415   // Information such as cumulative percentage, etc.
    416   void WriteAsciiBucketContext(const int64 past, const Count current,
    417                                const int64 remaining, const size_t i,
    418                                std::string* output) const;
    419 
    420   // Write textual description of the bucket contents (relative to histogram).
    421   // Output is the count in the buckets, as well as the percentage.
    422   void WriteAsciiBucketValue(Count current, double scaled_sum,
    423                              std::string* output) const;
    424 
    425   // Produce actual graph (set of blank vs non blank char's) for a bucket.
    426   void WriteAsciiBucketGraph(double current_size, double max_size,
    427                              std::string* output) const;
    428 
    429   //----------------------------------------------------------------------------
    430   // Invariant values set at/near construction time
    431 
    432   // ASCII version of original name given to the constructor.  All identically
    433   // named instances will  be coalesced cross-project TODO(jar).
    434   // If a user needs one histogram name to be called by several places in a
    435   // single process, a central function should be defined by the user, which
    436   // defins the single declared instance of the named histogram.
    437   const std::string histogram_name_;
    438   Sample declared_min_;  // Less than this goes into counts_[0]
    439   Sample declared_max_;  // Over this goes into counts_[bucket_count_ - 1].
    440   size_t bucket_count_;  // Dimension of counts_[].
    441 
    442   // Flag the histogram for recording by UMA via metric_services.h.
    443   Flags flags_;
    444 
    445   // For each index, show the least value that can be stored in the
    446   // corresponding bucket. We also append one extra element in this array,
    447   // containing kSampleType_MAX, to make calculations easy.
    448   // The dimension of ranges_ is bucket_count + 1.
    449   Ranges ranges_;
    450 
    451   // Finally, provide the state that changes with the addition of each new
    452   // sample.
    453   SampleSet sample_;
    454 
    455   DISALLOW_COPY_AND_ASSIGN(Histogram);
    456 };
    457 
    458 //------------------------------------------------------------------------------
    459 
    460 // LinearHistogram is a more traditional histogram, with evenly spaced
    461 // buckets.
    462 class LinearHistogram : public Histogram {
    463  public:
    464   virtual ClassType histogram_type() const { return LINEAR_HISTOGRAM; }
    465 
    466   // Store a list of number/text values for use in rendering the histogram.
    467   // The last element in the array has a null in its "description" slot.
    468   virtual void SetRangeDescriptions(const DescriptionPair descriptions[]);
    469 
    470   /* minimum should start from 1. 0 is as minimum is invalid. 0 is an implicit
    471      default underflow bucket. */
    472   static scoped_refptr<Histogram> FactoryGet(const std::string& name,
    473       Sample minimum, Sample maximum, size_t bucket_count, Flags flags);
    474   static scoped_refptr<Histogram> FactoryGet(const std::string& name,
    475       base::TimeDelta minimum, base::TimeDelta maximum, size_t bucket_count,
    476       Flags flags);
    477 
    478  protected:
    479   LinearHistogram(const std::string& name, Sample minimum,
    480                   Sample maximum, size_t bucket_count);
    481 
    482   LinearHistogram(const std::string& name, base::TimeDelta minimum,
    483                   base::TimeDelta maximum, size_t bucket_count);
    484 
    485   virtual ~LinearHistogram() {}
    486 
    487   // Initialize ranges_ mapping.
    488   virtual void InitializeBucketRange();
    489   virtual double GetBucketSize(Count current, size_t i) const;
    490 
    491   // If we have a description for a bucket, then return that.  Otherwise
    492   // let parent class provide a (numeric) description.
    493   virtual const std::string GetAsciiBucketRange(size_t i) const;
    494 
    495   // Skip printing of name for numeric range if we have a name (and if this is
    496   // an empty bucket).
    497   virtual bool PrintEmptyBucket(size_t index) const;
    498 
    499  private:
    500   // For some ranges, we store a printable description of a bucket range.
    501   // If there is no desciption, then GetAsciiBucketRange() uses parent class
    502   // to provide a description.
    503   typedef std::map<Sample, std::string> BucketDescriptionMap;
    504   BucketDescriptionMap bucket_description_;
    505 
    506   DISALLOW_COPY_AND_ASSIGN(LinearHistogram);
    507 };
    508 
    509 //------------------------------------------------------------------------------
    510 
    511 // BooleanHistogram is a histogram for booleans.
    512 class BooleanHistogram : public LinearHistogram {
    513  public:
    514   static scoped_refptr<Histogram> FactoryGet(const std::string& name,
    515       Flags flags);
    516 
    517   virtual ClassType histogram_type() const { return BOOLEAN_HISTOGRAM; }
    518 
    519   virtual void AddBoolean(bool value) { Add(value ? 1 : 0); }
    520 
    521  private:
    522   explicit BooleanHistogram(const std::string& name)
    523       : LinearHistogram(name, 1, 2, 3) {
    524   }
    525 
    526   DISALLOW_COPY_AND_ASSIGN(BooleanHistogram);
    527 };
    528 
    529 //------------------------------------------------------------------------------
    530 // StatisticsRecorder handles all histograms in the system.  It provides a
    531 // general place for histograms to register, and supports a global API for
    532 // accessing (i.e., dumping, or graphing) the data in all the histograms.
    533 
    534 class StatisticsRecorder {
    535  public:
    536   typedef std::vector<scoped_refptr<Histogram> > Histograms;
    537 
    538   StatisticsRecorder();
    539 
    540   ~StatisticsRecorder();
    541 
    542   // Find out if histograms can now be registered into our list.
    543   static bool WasStarted();
    544 
    545   // Register, or add a new histogram to the collection of statistics.
    546   static void Register(Histogram* histogram);
    547 
    548   // Methods for printing histograms.  Only histograms which have query as
    549   // a substring are written to output (an empty string will process all
    550   // registered histograms).
    551   static void WriteHTMLGraph(const std::string& query, std::string* output);
    552   static void WriteGraph(const std::string& query, std::string* output);
    553 
    554   // Method for extracting histograms which were marked for use by UMA.
    555   static void GetHistograms(Histograms* output);
    556 
    557   // Find a histogram by name. It matches the exact name. This method is thread
    558   // safe.
    559   static bool FindHistogram(const std::string& query,
    560                             scoped_refptr<Histogram>* histogram);
    561 
    562   static bool dump_on_exit() { return dump_on_exit_; }
    563 
    564   static void set_dump_on_exit(bool enable) { dump_on_exit_ = enable; }
    565 
    566   // GetSnapshot copies some of the pointers to registered histograms into the
    567   // caller supplied vector (Histograms).  Only histograms with names matching
    568   // query are returned. The query must be a substring of histogram name for its
    569   // pointer to be copied.
    570   static void GetSnapshot(const std::string& query, Histograms* snapshot);
    571 
    572 
    573  private:
    574   // We keep all registered histograms in a map, from name to histogram.
    575   typedef std::map<std::string, scoped_refptr<Histogram> > HistogramMap;
    576 
    577   static HistogramMap* histograms_;
    578 
    579   // lock protects access to the above map.
    580   static Lock* lock_;
    581 
    582   // Dump all known histograms to log.
    583   static bool dump_on_exit_;
    584 
    585   DISALLOW_COPY_AND_ASSIGN(StatisticsRecorder);
    586 };
    587 
    588 #endif  // BASE_HISTOGRAM_H_
    589